Przeglądaj źródła

Get process list after PID 1 dead

Fix #11087

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit ac8bd12b39d39a9361adc174bdff7837e771460d)
Alexander Morozov 10 lat temu
rodzic
commit
10affa8018

+ 29 - 15
daemon/execdriver/native/driver.go

@@ -190,6 +190,34 @@ func notifyOnOOM(container libcontainer.Container) <-chan struct{} {
 	return oom
 	return oom
 }
 }
 
 
+func killCgroupProcs(c libcontainer.Container) {
+	var procs []*os.Process
+	if err := c.Pause(); err != nil {
+		log.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
+		log.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 {
+				log.Warn(err)
+			}
+		}
+	}
+	if err := c.Resume(); err != nil {
+		log.Warn(err)
+	}
+	for _, p := range procs {
+		if _, err := p.Wait(); err != nil {
+			log.Warn(err)
+		}
+	}
+}
+
 func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*os.ProcessState, error) {
 func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*os.ProcessState, error) {
 	return func() (*os.ProcessState, error) {
 	return func() (*os.ProcessState, error) {
 		pid, err := p.Pid()
 		pid, err := p.Pid()
@@ -197,8 +225,6 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o
 			return nil, err
 			return nil, err
 		}
 		}
 
 
-		processes, err := c.Processes()
-
 		process, err := os.FindProcess(pid)
 		process, err := os.FindProcess(pid)
 		s, err := process.Wait()
 		s, err := process.Wait()
 		if err != nil {
 		if err != nil {
@@ -208,19 +234,7 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o
 			}
 			}
 			s = execErr.ProcessState
 			s = execErr.ProcessState
 		}
 		}
-		if err != nil {
-			return s, err
-		}
-
-		for _, pid := range processes {
-			process, err := os.FindProcess(pid)
-			if err != nil {
-				log.Errorf("Failed to kill process: %d", pid)
-				continue
-			}
-			process.Kill()
-		}
-
+		killCgroupProcs(c)
 		p.Wait()
 		p.Wait()
 		return s, err
 		return s, err
 	}
 	}

+ 25 - 0
integration-cli/docker_cli_run_test.go

@@ -3411,3 +3411,28 @@ func TestRunVolumesFromRestartAfterRemoved(t *testing.T) {
 
 
 	logDone("run - can restart a volumes-from container after producer is removed")
 	logDone("run - can restart a volumes-from container after producer is removed")
 }
 }
+
+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")
+}