linux: Ensure all init children are dead when it exits

This ensure that when using the host pid, we don't let process alive,
preventing Wait() to return until they all die.

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
This commit is contained in:
Kenfe-Mickael Laventure 2017-09-01 09:41:37 -07:00
parent 9d251cbd1b
commit 92772bd471
No known key found for this signature in database
GPG Key ID: 40CF16616B361216
2 changed files with 84 additions and 0 deletions

View File

@ -896,3 +896,79 @@ func TestContainerRuntimeOptions(t *testing.T) {
t.Errorf("task creation should have failed because of lack of executable. Instead failed with: %v", err.Error())
}
}
func TestContainerKillInitPidHost(t *testing.T) {
client, err := newClient(t, address)
if err != nil {
t.Fatal(err)
}
defer client.Close()
var (
image Image
ctx, cancel = testContext()
id = t.Name()
)
defer cancel()
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id,
withNewSnapshot(id, image),
WithNewSpec(withImageConfig(image),
withProcessArgs("sh", "-c", "sleep 42; echo hi"),
WithHostNamespace(specs.PIDNamespace),
),
)
if err != nil {
t.Error(err)
return
}
defer container.Delete(ctx, WithSnapshotCleanup)
stdout := bytes.NewBuffer(nil)
task, err := container.NewTask(ctx, NewIO(bytes.NewBuffer(nil), stdout, bytes.NewBuffer(nil)))
if err != nil {
t.Error(err)
return
}
defer task.Delete(ctx)
statusC, err := task.Wait(ctx)
if err != nil {
t.Error(err)
return
}
if err := task.Start(ctx); err != nil {
t.Error(err)
return
}
if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
t.Error(err)
}
// Give the shim time to reap the init process and kill the orphans
select {
case <-statusC:
case <-time.After(100 * time.Millisecond):
}
b, err := exec.Command("ps", "ax").CombinedOutput()
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(b), "sleep 42") {
t.Fatalf("killing init didn't kill all its children:\n%v", string(b))
}
if _, err := task.Delete(ctx, WithProcessKill); err != nil {
t.Error(err)
}
}

View File

@ -393,6 +393,14 @@ func (s *Service) checkProcesses(e runc.Exit) {
defer s.mu.Unlock()
for _, p := range s.processes {
if p.Pid() == e.Pid {
if ip, ok := p.(*initProcess); ok {
// Ensure all children are killed
if err := ip.killAll(s.context); err != nil {
log.G(s.context).WithError(err).WithField("id", ip.ID()).
Error("failed to kill init's children")
}
}
p.SetExited(e.Status)
s.events <- &eventsapi.TaskExit{
ContainerID: s.id,