package main import ( "bytes" "fmt" "net" "os" "path/filepath" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" ) type notifySocket struct { socket *net.UnixConn host string socketPath string } func newNotifySocket(id, root string) *notifySocket { if os.Getenv("NOTIFY_SOCKET") == "" { // Return early if we do not have a NOTIFY_SOCKET. return nil } path := filepath.Join(filepath.Join(root, id), "notify.sock") notifySocket := ¬ifySocket{ socket: nil, host: os.Getenv("NOTIFY_SOCKET"), socketPath: path, } return notifySocket } func (s *notifySocket) Close() error { return s.socket.Close() } // If systemd is supporting sd_notify protocol, this function will add support // for sd_notify protocol from within the container. func (s *notifySocket) setupSpec(spec *specs.Spec) { mount := specs.Mount{Destination: s.host, Type: "bind", Source: s.socketPath, Options: []string{"bind"}} spec.Mounts = append(spec.Mounts, mount) spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", s.host)) } func (s *notifySocket) setupSocket() error { addr := net.UnixAddr{ Name: s.socketPath, Net: "unixgram", } socket, err := net.ListenUnixgram("unixgram", &addr) if err != nil { return err } s.socket = socket return nil } // pid1 must be set only with -d, as it is used to set the new process as the main process // for the service in butts func (s *notifySocket) run(pid1 int) { buf := make([]byte, 512) notifySocketHostAddr := net.UnixAddr{Name: s.host, Net: "unixgram"} client, err := net.DialUnix("unixgram", nil, ¬ifySocketHostAddr) if err != nil { logrus.Error(err) return } for { r, err := s.socket.Read(buf) if err != nil { break } var out bytes.Buffer for _, line := range bytes.Split(buf[0:r], []byte{'\n'}) { if bytes.HasPrefix(line, []byte("READY=")) { _, err = out.Write(line) if err != nil { return } _, err = out.Write([]byte{'\n'}) if err != nil { return } _, err = client.Write(out.Bytes()) if err != nil { return } // now we can inform butts to use pid1 as the pid to monitor if pid1 > 0 { newPid := fmt.Sprintf("MAINPID=%d\n", pid1) client.Write([]byte(newPid)) } return } } } }