-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add patch opencontainers/runc#1807 to allow
runc and podman to work with sd_notify
- Loading branch information
Showing
1 changed file
with
200 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
From ecf53c23545092019602578583031c28fde4d2a1 Mon Sep 17 00:00:00 2001 | ||
From: Giuseppe Scrivano <gscrivan@redhat.com> | ||
Date: Fri, 25 May 2018 18:04:06 +0200 | ||
Subject: [PATCH] sd-notify: do not hang when NOTIFY_SOCKET is used with create | ||
|
||
if NOTIFY_SOCKET is used, do not block the main runc process waiting | ||
for events on the notify socket. Change the logic to create a new | ||
process that monitors exclusively the notify socket until an event is | ||
received. | ||
|
||
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com> | ||
--- | ||
init.go | 12 +++++++ | ||
notify_socket.go | 101 ++++++++++++++++++++++++++++++++++++++++++++++--------- | ||
signals.go | 5 +-- | ||
3 files changed, 99 insertions(+), 19 deletions(-) | ||
|
||
diff --git a/init.go b/init.go | ||
index c8f453192..6a3d9e91c 100644 | ||
--- a/init.go | ||
+++ b/init.go | ||
@@ -20,6 +20,18 @@ var initCommand = cli.Command{ | ||
Name: "init", | ||
Usage: `initialize the namespaces and launch the process (do not call it outside of runc)`, | ||
Action: func(context *cli.Context) error { | ||
+ // If NOTIFY_SOCKET is used create a new process that stays around | ||
+ // so to not block "runc start". It will automatically exits when the | ||
+ // container notifies that it is ready, or when the container is deleted | ||
+ if os.Getenv("_NOTIFY_SOCKET_FD") != "" { | ||
+ fd := os.Getenv("_NOTIFY_SOCKET_FD") | ||
+ pid := os.Getenv("_NOTIFY_SOCKET_PID") | ||
+ hostNotifySocket := os.Getenv("_NOTIFY_SOCKET_HOST") | ||
+ notifySocketPath := os.Getenv("_NOTIFY_SOCKET_PATH") | ||
+ notifySocketInit(fd, pid, hostNotifySocket, notifySocketPath) | ||
+ os.Exit(0) | ||
+ } | ||
+ | ||
factory, _ := libcontainer.New("") | ||
if err := factory.StartInitialization(); err != nil { | ||
// as the error is sent back to the parent there is no need to log | ||
diff --git a/notify_socket.go b/notify_socket.go | ||
index cd6c0a989..e04e9d660 100644 | ||
--- a/notify_socket.go | ||
+++ b/notify_socket.go | ||
@@ -6,10 +6,13 @@ import ( | ||
"bytes" | ||
"fmt" | ||
"net" | ||
+ "os" | ||
+ "os/exec" | ||
"path/filepath" | ||
+ "strconv" | ||
+ "time" | ||
|
||
"github.com/opencontainers/runtime-spec/specs-go" | ||
- | ||
"github.com/sirupsen/logrus" | ||
"github.com/urfave/cli" | ||
) | ||
@@ -64,24 +67,94 @@ func (s *notifySocket) setupSocket() error { | ||
return nil | ||
} | ||
|
||
+func (notifySocket *notifySocket) notifyNewPid(pid int) { | ||
+ notifySocketHostAddr := net.UnixAddr{Name: notifySocket.host, Net: "unixgram"} | ||
+ client, err := net.DialUnix("unixgram", nil, ¬ifySocketHostAddr) | ||
+ if err != nil { | ||
+ return | ||
+ } | ||
+ newPid := fmt.Sprintf("MAINPID=%d\n", pid) | ||
+ client.Write([]byte(newPid)) | ||
+} | ||
+ | ||
// pid1 must be set only with -d, as it is used to set the new process as the main process | ||
// for the service in systemd | ||
func (notifySocket *notifySocket) run(pid1 int) { | ||
- buf := make([]byte, 512) | ||
- notifySocketHostAddr := net.UnixAddr{Name: notifySocket.host, Net: "unixgram"} | ||
- client, err := net.DialUnix("unixgram", nil, ¬ifySocketHostAddr) | ||
+ file, err := notifySocket.socket.File() | ||
if err != nil { | ||
logrus.Error(err) | ||
return | ||
} | ||
- for { | ||
- r, err := notifySocket.socket.Read(buf) | ||
- if err != nil { | ||
- break | ||
+ defer file.Close() | ||
+ defer notifySocket.socket.Close() | ||
+ | ||
+ cmd := exec.Command("/proc/self/exe", "init") | ||
+ cmd.ExtraFiles = []*os.File{file} | ||
+ cmd.Env = append(cmd.Env, "_NOTIFY_SOCKET_FD=3", | ||
+ fmt.Sprintf("_NOTIFY_SOCKET_PID=%d", pid1), | ||
+ fmt.Sprintf("_NOTIFY_SOCKET_HOST=%s", notifySocket.host), | ||
+ fmt.Sprintf("_NOTIFY_SOCKET_PATH=%s", notifySocket.socketPath)) | ||
+ | ||
+ if err := cmd.Start(); err != nil { | ||
+ logrus.Fatal(err) | ||
+ } | ||
+ notifySocket.notifyNewPid(cmd.Process.Pid) | ||
+ cmd.Process.Release() | ||
+} | ||
+ | ||
+func notifySocketInit(envFd string, envPid string, notifySocketHost string, notifySocketPath string) { | ||
+ intFd, err := strconv.Atoi(envFd) | ||
+ if err != nil { | ||
+ return | ||
+ } | ||
+ pid1, err := strconv.Atoi(envPid) | ||
+ if err != nil { | ||
+ return | ||
+ } | ||
+ | ||
+ file := os.NewFile(uintptr(intFd), "unixgram") | ||
+ defer file.Close() | ||
+ | ||
+ fileChan := make(chan []byte) | ||
+ exitChan := make(chan bool) | ||
+ | ||
+ go func() { | ||
+ for { | ||
+ buf := make([]byte, 512) | ||
+ r, err := file.Read(buf) | ||
+ if err != nil { | ||
+ return | ||
+ } | ||
+ fileChan <- buf[0:r] | ||
} | ||
- var out bytes.Buffer | ||
- for _, line := range bytes.Split(buf[0:r], []byte{'\n'}) { | ||
- if bytes.HasPrefix(line, []byte("READY=")) { | ||
+ }() | ||
+ go func() { | ||
+ for { | ||
+ if _, err := os.Stat(notifySocketPath); os.IsNotExist(err) { | ||
+ exitChan <- true | ||
+ return | ||
+ } | ||
+ time.Sleep(time.Second) | ||
+ } | ||
+ }() | ||
+ | ||
+ notifySocketHostAddr := net.UnixAddr{Name: notifySocketHost, Net: "unixgram"} | ||
+ client, err := net.DialUnix("unixgram", nil, ¬ifySocketHostAddr) | ||
+ if err != nil { | ||
+ return | ||
+ } | ||
+ | ||
+ for { | ||
+ select { | ||
+ case <-exitChan: | ||
+ return | ||
+ case b := <-fileChan: | ||
+ for _, line := range bytes.Split(b, []byte{'\n'}) { | ||
+ if !bytes.HasPrefix(line, []byte("READY=")) { | ||
+ continue | ||
+ } | ||
+ | ||
+ var out bytes.Buffer | ||
_, err = out.Write(line) | ||
if err != nil { | ||
return | ||
@@ -98,10 +171,8 @@ func (notifySocket *notifySocket) run(pid1 int) { | ||
} | ||
|
||
// now we can inform systemd to use pid1 as the pid to monitor | ||
- if pid1 > 0 { | ||
- newPid := fmt.Sprintf("MAINPID=%d\n", pid1) | ||
- client.Write([]byte(newPid)) | ||
- } | ||
+ newPid := fmt.Sprintf("MAINPID=%d\n", pid1) | ||
+ client.Write([]byte(newPid)) | ||
return | ||
} | ||
} | ||
diff --git a/signals.go b/signals.go | ||
index 1811de837..d0988cb39 100644 | ||
--- a/signals.go | ||
+++ b/signals.go | ||
@@ -70,7 +70,7 @@ func (h *signalHandler) forward(process *libcontainer.Process, tty *tty, detach | ||
h.notifySocket.run(pid1) | ||
return 0, nil | ||
} else { | ||
- go h.notifySocket.run(0) | ||
+ h.notifySocket.run(os.Getpid()) | ||
} | ||
} | ||
|
||
@@ -98,9 +98,6 @@ func (h *signalHandler) forward(process *libcontainer.Process, tty *tty, detach | ||
// status because we must ensure that any of the go specific process | ||
// fun such as flushing pipes are complete before we return. | ||
process.Wait() | ||
- if h.notifySocket != nil { | ||
- h.notifySocket.Close() | ||
- } | ||
return e.status, nil | ||
} | ||
} |