/** # Copyright 2021-2023 NVIDIA CORPORATION # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. **/ package docker import ( "fmt" "net" "syscall" "time" log "github.com/sirupsen/logrus" ) const ( reloadBackoff = 5 * time.Second maxReloadAttempts = 6 socketMessageToGetPID = "GET /info HTTP/1.0\r\n\r\n" ) // SignalDocker sends a SIGHUP signal to docker daemon func SignalDocker(socket string) error { log.Infof("Sending SIGHUP signal to docker") // Wrap the logic to perform the SIGHUP in a function so we can retry it on failure retriable := func() error { conn, err := net.Dial("unix", socket) if err != nil { return fmt.Errorf("unable to dial: %v", err) } defer conn.Close() sconn, err := conn.(*net.UnixConn).SyscallConn() if err != nil { return fmt.Errorf("unable to get syscall connection: %v", err) } err1 := sconn.Control(func(fd uintptr) { err = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1) }) if err1 != nil { return fmt.Errorf("unable to issue call on socket fd: %v", err1) } if err != nil { return fmt.Errorf("unable to SetsockoptInt on socket fd: %v", err) } _, _, err = conn.(*net.UnixConn).WriteMsgUnix([]byte(socketMessageToGetPID), nil, nil) if err != nil { return fmt.Errorf("unable to WriteMsgUnix on socket fd: %v", err) } oob := make([]byte, 1024) _, oobn, _, _, err := conn.(*net.UnixConn).ReadMsgUnix(nil, oob) if err != nil { return fmt.Errorf("unable to ReadMsgUnix on socket fd: %v", err) } oob = oob[:oobn] scm, err := syscall.ParseSocketControlMessage(oob) if err != nil { return fmt.Errorf("unable to ParseSocketControlMessage from message received on socket fd: %v", err) } ucred, err := syscall.ParseUnixCredentials(&scm[0]) if err != nil { return fmt.Errorf("unable to ParseUnixCredentials from message received on socket fd: %v", err) } err = syscall.Kill(int(ucred.Pid), syscall.SIGHUP) if err != nil { return fmt.Errorf("unable to send SIGHUP to 'docker' process: %v", err) } return nil } // Try to send a SIGHUP up to maxReloadAttempts times var err error for i := 0; i < maxReloadAttempts; i++ { err = retriable() if err == nil { break } if i == maxReloadAttempts-1 { break } log.Warningf("Error signaling docker, attempt %v/%v: %v", i+1, maxReloadAttempts, err) time.Sleep(reloadBackoff) } if err != nil { log.Warningf("Max retries reached %v/%v, aborting", maxReloadAttempts, maxReloadAttempts) return err } log.Infof("Successfully signaled docker") return nil }