From ac8bd12b39d39a9361adc174bdff7837e771460d Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Fri, 10 Apr 2015 11:04:30 -0700 Subject: [PATCH] Get process list after PID 1 dead Fix #11087 Signed-off-by: Alexander Morozov --- daemon/execdriver/native/driver.go | 44 +++++++++++++++++--------- integration-cli/docker_cli_run_test.go | 25 +++++++++++++++ 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index e5811bb852..6caa78390f 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -188,6 +188,34 @@ func notifyOnOOM(container libcontainer.Container) <-chan struct{} { return oom } +func killCgroupProcs(c libcontainer.Container) { + var procs []*os.Process + if err := c.Pause(); err != nil { + logrus.Warn(err) + } + pids, err := c.Processes() + if err != nil { + // don't care about childs if we can't get them, this is mostly because cgroup already deleted + logrus.Warnf("Failed to get processes from container %s: %v", c.ID(), err) + } + for _, pid := range pids { + if p, err := os.FindProcess(pid); err == nil { + procs = append(procs, p) + if err := p.Kill(); err != nil { + logrus.Warn(err) + } + } + } + if err := c.Resume(); err != nil { + logrus.Warn(err) + } + for _, p := range procs { + if _, err := p.Wait(); err != nil { + logrus.Warn(err) + } + } +} + func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*os.ProcessState, error) { return func() (*os.ProcessState, error) { pid, err := p.Pid() @@ -195,8 +223,6 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o return nil, err } - processes, err := c.Processes() - process, err := os.FindProcess(pid) s, err := process.Wait() if err != nil { @@ -206,19 +232,7 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o } s = execErr.ProcessState } - if err != nil { - return s, err - } - - for _, pid := range processes { - process, err := os.FindProcess(pid) - if err != nil { - logrus.Errorf("Failed to kill process: %d", pid) - continue - } - process.Kill() - } - + killCgroupProcs(c) p.Wait() return s, err } diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index a5d1e3e070..302286146c 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -3468,3 +3468,28 @@ func TestRunContainerWithRmFlagCannotStartContainer(t *testing.T) { logDone("run - container is removed if run with --rm and cannot start") } + +func TestRunPidHostWithChildIsKillable(t *testing.T) { + defer deleteAllContainers() + name := "ibuildthecloud" + if out, err := exec.Command(dockerBinary, "run", "-d", "--pid=host", "--name", name, "busybox", "sh", "-c", "sleep 30; echo hi").CombinedOutput(); err != nil { + t.Fatal(err, out) + } + time.Sleep(1 * time.Second) + errchan := make(chan error) + go func() { + if out, err := exec.Command(dockerBinary, "kill", name).CombinedOutput(); err != nil { + errchan <- fmt.Errorf("%v:\n%s", err, out) + } + close(errchan) + }() + select { + case err := <-errchan: + if err != nil { + t.Fatal(err) + } + case <-time.After(5 * time.Second): + t.Fatal("Kill container timed out") + } + logDone("run - can kill container with pid-host and some childs of pid 1") +}