Fix #11087
Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit ac8bd12b39d39a9361adc174bdff7837e771460d)
... | ... |
@@ -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 |
+} |