Browse code

Get process list after PID 1 dead

Fix #11087

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

Alexander Morozov authored on 2015/04/11 03:04:30
Showing 2 changed files
... ...
@@ -190,6 +190,34 @@ func notifyOnOOM(container libcontainer.Container) <-chan struct{} {
190 190
 	return oom
191 191
 }
192 192
 
193
+func killCgroupProcs(c libcontainer.Container) {
194
+	var procs []*os.Process
195
+	if err := c.Pause(); err != nil {
196
+		log.Warn(err)
197
+	}
198
+	pids, err := c.Processes()
199
+	if err != nil {
200
+		// don't care about childs if we can't get them, this is mostly because cgroup already deleted
201
+		log.Warnf("Failed to get processes from container %s: %v", c.ID(), err)
202
+	}
203
+	for _, pid := range pids {
204
+		if p, err := os.FindProcess(pid); err == nil {
205
+			procs = append(procs, p)
206
+			if err := p.Kill(); err != nil {
207
+				log.Warn(err)
208
+			}
209
+		}
210
+	}
211
+	if err := c.Resume(); err != nil {
212
+		log.Warn(err)
213
+	}
214
+	for _, p := range procs {
215
+		if _, err := p.Wait(); err != nil {
216
+			log.Warn(err)
217
+		}
218
+	}
219
+}
220
+
193 221
 func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*os.ProcessState, error) {
194 222
 	return func() (*os.ProcessState, error) {
195 223
 		pid, err := p.Pid()
... ...
@@ -197,8 +225,6 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o
197 197
 			return nil, err
198 198
 		}
199 199
 
200
-		processes, err := c.Processes()
201
-
202 200
 		process, err := os.FindProcess(pid)
203 201
 		s, err := process.Wait()
204 202
 		if err != nil {
... ...
@@ -208,19 +234,7 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o
208 208
 			}
209 209
 			s = execErr.ProcessState
210 210
 		}
211
-		if err != nil {
212
-			return s, err
213
-		}
214
-
215
-		for _, pid := range processes {
216
-			process, err := os.FindProcess(pid)
217
-			if err != nil {
218
-				log.Errorf("Failed to kill process: %d", pid)
219
-				continue
220
-			}
221
-			process.Kill()
222
-		}
223
-
211
+		killCgroupProcs(c)
224 212
 		p.Wait()
225 213
 		return s, err
226 214
 	}
... ...
@@ -3411,3 +3411,28 @@ func TestRunVolumesFromRestartAfterRemoved(t *testing.T) {
3411 3411
 
3412 3412
 	logDone("run - can restart a volumes-from container after producer is removed")
3413 3413
 }
3414
+
3415
+func TestRunPidHostWithChildIsKillable(t *testing.T) {
3416
+	defer deleteAllContainers()
3417
+	name := "ibuildthecloud"
3418
+	if out, err := exec.Command(dockerBinary, "run", "-d", "--pid=host", "--name", name, "busybox", "sh", "-c", "sleep 30; echo hi").CombinedOutput(); err != nil {
3419
+		t.Fatal(err, out)
3420
+	}
3421
+	time.Sleep(1 * time.Second)
3422
+	errchan := make(chan error)
3423
+	go func() {
3424
+		if out, err := exec.Command(dockerBinary, "kill", name).CombinedOutput(); err != nil {
3425
+			errchan <- fmt.Errorf("%v:\n%s", err, out)
3426
+		}
3427
+		close(errchan)
3428
+	}()
3429
+	select {
3430
+	case err := <-errchan:
3431
+		if err != nil {
3432
+			t.Fatal(err)
3433
+		}
3434
+	case <-time.After(5 * time.Second):
3435
+		t.Fatal("Kill container timed out")
3436
+	}
3437
+	logDone("run - can kill container with pid-host and some childs of pid 1")
3438
+}