From b91f4ecce0845d2b29e135259fc37c7eb5da687da78799fea516d81aa0116d5a Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Tue, 14 Apr 2020 10:22:21 +0000 Subject: [PATCH] Accepting request 793807 from home:rhafer:branches:Virtualization:containers - Renamed patch: 0001-sd-notify-do-not-hang-when-NOTIFY_SOCKET-is-used-wit.patch to bsc1149954-0001-sd-notify-do-not-hang-when-NOTIFY_SOCKET-is-used-wit.patch - Added fix for bsc#1149954 * 0001-sd-notify-do-not-hang-when-NOTIFY_SOCKET-is-used-wit.patch (cherry pick of https://github.com/opencontainers/runc/pull/1807) OBS-URL: https://build.opensuse.org/request/show/793807 OBS-URL: https://build.opensuse.org/package/show/Virtualization:containers/runc?expand=0&rev=92 --- ...-hang-when-NOTIFY_SOCKET-is-used-wit.patch | 291 ++++++++++++++++++ runc.changes | 15 + runc.spec | 3 + 3 files changed, 309 insertions(+) create mode 100644 bsc1149954-0001-sd-notify-do-not-hang-when-NOTIFY_SOCKET-is-used-wit.patch diff --git a/bsc1149954-0001-sd-notify-do-not-hang-when-NOTIFY_SOCKET-is-used-wit.patch b/bsc1149954-0001-sd-notify-do-not-hang-when-NOTIFY_SOCKET-is-used-wit.patch new file mode 100644 index 0000000..e84eeed --- /dev/null +++ b/bsc1149954-0001-sd-notify-do-not-hang-when-NOTIFY_SOCKET-is-used-wit.patch @@ -0,0 +1,291 @@ +From 5d13416879fe0f50c300d94c569ea77950cbee94 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +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. Bind mount the parent directory of +the notify socket, so that "start" can create the socket and it is +still accessible from the container. + +Signed-off-by: Giuseppe Scrivano +(cherry picked from commit 25fd4a67571992b9121f77d2a4f0d89d4375f383) +--- + notify_socket.go | 132 +++++++++++++++++++++++++++++++++-------------- + signals.go | 4 +- + start.go | 13 ++++- + utils_linux.go | 12 ++++- + 4 files changed, 116 insertions(+), 45 deletions(-) + +diff --git a/notify_socket.go b/notify_socket.go +index e7453c62..f313a7a6 100644 +--- a/notify_socket.go ++++ b/notify_socket.go +@@ -7,11 +7,13 @@ import ( + "fmt" + "net" + "os" ++ "path" + "path/filepath" ++ "strconv" ++ "time" + ++ "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runtime-spec/specs-go" +- +- "github.com/sirupsen/logrus" + "github.com/urfave/cli" + ) + +@@ -27,12 +29,12 @@ func newNotifySocket(context *cli.Context, notifySocketHost string, id string) * + } + + root := filepath.Join(context.GlobalString("root"), id) +- path := filepath.Join(root, "notify.sock") ++ socketPath := filepath.Join(root, "notify", "notify.sock") + + notifySocket := ¬ifySocket{ + socket: nil, + host: notifySocketHost, +- socketPath: path, ++ socketPath: socketPath, + } + + return notifySocket +@@ -44,13 +46,19 @@ func (s *notifySocket) Close() error { + + // If systemd is supporting sd_notify protocol, this function will add support + // for sd_notify protocol from within the container. +-func (s *notifySocket) setupSpec(context *cli.Context, spec *specs.Spec) { +- mount := specs.Mount{Destination: s.host, Source: s.socketPath, Options: []string{"bind"}} ++func (s *notifySocket) setupSpec(context *cli.Context, spec *specs.Spec) error { ++ pathInContainer := filepath.Join("/run/notify", path.Base(s.socketPath)) ++ mount := specs.Mount{ ++ Destination: path.Dir(pathInContainer), ++ Source: path.Dir(s.socketPath), ++ Options: []string{"bind", "nosuid", "noexec", "nodev", "ro"}, ++ } + spec.Mounts = append(spec.Mounts, mount) +- spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", s.host)) ++ spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", pathInContainer)) ++ return nil + } + +-func (s *notifySocket) setupSocket() error { ++func (s *notifySocket) bindSocket() error { + addr := net.UnixAddr{ + Name: s.socketPath, + Net: "unixgram", +@@ -71,46 +79,92 @@ func (s *notifySocket) setupSocket() error { + 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 systemd +-func (s *notifySocket) run(pid1 int) { +- buf := make([]byte, 512) +- notifySocketHostAddr := net.UnixAddr{Name: s.host, Net: "unixgram"} ++func (s *notifySocket) setupSocketDirectory() error { ++ return os.Mkdir(path.Dir(s.socketPath), 0755) ++} ++ ++func notifySocketStart(context *cli.Context, notifySocketHost, id string) (*notifySocket, error) { ++ notifySocket := newNotifySocket(context, notifySocketHost, id) ++ if notifySocket == nil { ++ return nil, nil ++ } ++ ++ if err := notifySocket.bindSocket(); err != nil { ++ return nil, err ++ } ++ return notifySocket, nil ++} ++ ++func (n *notifySocket) waitForContainer(container libcontainer.Container) error { ++ s, err := container.State() ++ if err != nil { ++ return err ++ } ++ return n.run(s.InitProcessPid) ++} ++ ++func (n *notifySocket) run(pid1 int) error { ++ if n.socket == nil { ++ return nil ++ } ++ notifySocketHostAddr := net.UnixAddr{Name: n.host, Net: "unixgram"} + client, err := net.DialUnix("unixgram", nil, ¬ifySocketHostAddr) + if err != nil { +- logrus.Error(err) +- return ++ return err + } +- 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 +- } ++ ticker := time.NewTicker(time.Millisecond * 100) ++ defer ticker.Stop() + +- _, err = client.Write(out.Bytes()) +- if err != nil { ++ fileChan := make(chan []byte) ++ go func() { ++ for { ++ buf := make([]byte, 4096) ++ r, err := n.socket.Read(buf) ++ if err != nil { ++ return ++ } ++ got := buf[0:r] ++ // systemd-ready sends a single datagram with the state string as payload, ++ // so we don't need to worry about partial messages. ++ for _, line := range bytes.Split(got, []byte{'\n'}) { ++ if bytes.HasPrefix(got, []byte("READY=")) { ++ fileChan <- line + return + } ++ } + +- // 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)) +- } +- return ++ } ++ }() ++ ++ for { ++ select { ++ case <-ticker.C: ++ _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid1))) ++ if err != nil { ++ return nil + } ++ case b := <-fileChan: ++ var out bytes.Buffer ++ _, err = out.Write(b) ++ if err != nil { ++ return err ++ } ++ ++ _, err = out.Write([]byte{'\n'}) ++ if err != nil { ++ return err ++ } ++ ++ _, err = client.Write(out.Bytes()) ++ if err != nil { ++ return err ++ } ++ ++ // now we can inform systemd to use pid1 as the pid to monitor ++ newPid := fmt.Sprintf("MAINPID=%d\n", pid1) ++ client.Write([]byte(newPid)) ++ return nil + } + } + } +diff --git a/signals.go b/signals.go +index b67f65a0..dd25e094 100644 +--- a/signals.go ++++ b/signals.go +@@ -70,6 +70,7 @@ func (h *signalHandler) forward(process *libcontainer.Process, tty *tty, detach + h.notifySocket.run(pid1) + return 0, nil + } ++ h.notifySocket.run(os.Getpid()) + go h.notifySocket.run(0) + } + +@@ -97,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 + } + } +diff --git a/start.go b/start.go +index 2bb698b2..3a1769a4 100644 +--- a/start.go ++++ b/start.go +@@ -3,6 +3,7 @@ package main + import ( + "errors" + "fmt" ++ "os" + + "github.com/opencontainers/runc/libcontainer" + "github.com/urfave/cli" +@@ -31,7 +32,17 @@ your host.`, + } + switch status { + case libcontainer.Created: +- return container.Exec() ++ notifySocket, err := notifySocketStart(context, os.Getenv("NOTIFY_SOCKET"), container.ID()) ++ if err != nil { ++ return err ++ } ++ if err := container.Exec(); err != nil { ++ return err ++ } ++ if notifySocket != nil { ++ return notifySocket.waitForContainer(container) ++ } ++ return nil + case libcontainer.Stopped: + return errors.New("cannot start a container that has stopped") + case libcontainer.Running: +diff --git a/utils_linux.go b/utils_linux.go +index 984e6b0f..46c26246 100644 +--- a/utils_linux.go ++++ b/utils_linux.go +@@ -408,7 +408,9 @@ func startContainer(context *cli.Context, spec *specs.Spec, action CtAct, criuOp + + notifySocket := newNotifySocket(context, os.Getenv("NOTIFY_SOCKET"), id) + if notifySocket != nil { +- notifySocket.setupSpec(context, spec) ++ if err := notifySocket.setupSpec(context, spec); err != nil { ++ return -1, err ++ } + } + + container, err := createContainer(context, id, spec) +@@ -417,10 +419,16 @@ func startContainer(context *cli.Context, spec *specs.Spec, action CtAct, criuOp + } + + if notifySocket != nil { +- err := notifySocket.setupSocket() ++ err := notifySocket.setupSocketDirectory() + if err != nil { + return -1, err + } ++ if action == CT_ACT_RUN { ++ err := notifySocket.bindSocket() ++ if err != nil { ++ return -1, err ++ } ++ } + } + + // Support on-demand socket activation by passing file descriptors into the container init process. +-- +2.25.1 + diff --git a/runc.changes b/runc.changes index 4a8f523..8b6ae98 100644 --- a/runc.changes +++ b/runc.changes @@ -1,3 +1,18 @@ +------------------------------------------------------------------- +Tue Apr 14 10:16:21 UTC 2020 - Ralf Haferkamp + +- Renamed patch: + 0001-sd-notify-do-not-hang-when-NOTIFY_SOCKET-is-used-wit.patch + to + bsc1149954-0001-sd-notify-do-not-hang-when-NOTIFY_SOCKET-is-used-wit.patch + +------------------------------------------------------------------- +Wed Mar 18 08:57:34 UTC 2020 - Ralf Haferkamp + +- Added fix for bsc#1149954 + * 0001-sd-notify-do-not-hang-when-NOTIFY_SOCKET-is-used-wit.patch + (cherry pick of https://github.com/opencontainers/runc/pull/1807) + ------------------------------------------------------------------- Thu Jan 23 17:18:05 UTC 2020 - Aleksa Sarai diff --git a/runc.spec b/runc.spec index afd85ac..471b945 100644 --- a/runc.spec +++ b/runc.spec @@ -51,6 +51,8 @@ Source0: https://github.com/opencontainers/runc/releases/download/v%{_ver Source1: https://github.com/opencontainers/runc/releases/download/v%{_version}/runc.tar.xz.asc#/runc-%{_version}.tar.xz.asc Source2: runc.keyring Source3: runc-rpmlintrc +# FIX-UPSTREAM: cherry pick of https://github.com/opencontainers/runc/pull/1807 +Patch0: bsc1149954-0001-sd-notify-do-not-hang-when-NOTIFY_SOCKET-is-used-wit.patch BuildRequires: fdupes BuildRequires: go-go-md2man BuildRequires: golang(API) >= %{go_version} @@ -84,6 +86,7 @@ Test package for runc. It contains the source code and the tests. %prep %setup -q -n %{name}-%{_version} +%patch0 -p1 %build # Do not use symlinks. If you want to run the unit tests for this package at