From e58671e530eb04a233d953c6a56e56804703f80c Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 7 Nov 2016 15:22:27 -0800 Subject: [PATCH] Add --all flag to kill This allows a user to send a signal to all the processes in the container within a single atomic action to avoid new processes being forked off before the signal can be sent. This is basically taking functionality that we already use being `delete` and exposing it ok the `kill` command by adding a flag. Signed-off-by: Michael Crosby --- contrib/completions/bash/runc | 2 ++ delete.go | 4 ++-- kill.go | 8 +++++++- libcontainer/container.go | 5 ++++- libcontainer/container_linux.go | 5 ++++- libcontainer/init_linux.go | 6 +++--- libcontainer/process_linux.go | 2 +- libcontainer/state_linux.go | 2 +- man/runc-kill.8.md | 5 ++++- 9 files changed, 28 insertions(+), 11 deletions(-) diff --git a/contrib/completions/bash/runc b/contrib/completions/bash/runc index 682b7c62..d73af773 100644 --- a/contrib/completions/bash/runc +++ b/contrib/completions/bash/runc @@ -325,6 +325,8 @@ _runc_kill() { local boolean_options=" --help -h + --all + -a " case "$prev" in diff --git a/delete.go b/delete.go index 75a62994..43f53fc5 100644 --- a/delete.go +++ b/delete.go @@ -14,10 +14,10 @@ import ( ) func killContainer(container libcontainer.Container) error { - container.Signal(syscall.SIGKILL) + container.Signal(syscall.SIGKILL, false) for i := 0; i < 100; i++ { time.Sleep(100 * time.Millisecond) - if err := container.Signal(syscall.Signal(0)); err != nil { + if err := container.Signal(syscall.Signal(0), false); err != nil { destroy(container) return nil } diff --git a/kill.go b/kill.go index 3fb80c08..78e4c18a 100644 --- a/kill.go +++ b/kill.go @@ -62,6 +62,12 @@ For example, if the container id is "ubuntu01" the following will send a "KILL" signal to the init process of the "ubuntu01" container: # runc kill ubuntu01 KILL`, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "all, a", + Usage: "send the specified signal to all processes inside the container", + }, + }, Action: func(context *cli.Context) error { container, err := getContainer(context) if err != nil { @@ -77,7 +83,7 @@ signal to the init process of the "ubuntu01" container: if err != nil { return err } - if err := container.Signal(signal); err != nil { + if err := container.Signal(signal, context.Bool("all")); err != nil { return err } return nil diff --git a/libcontainer/container.go b/libcontainer/container.go index 2950a83e..d51b159b 100644 --- a/libcontainer/container.go +++ b/libcontainer/container.go @@ -145,9 +145,12 @@ type BaseContainer interface { // Signal sends the provided signal code to the container's initial process. // + // If all is specified the signal is sent to all processes in the container + // including the initial process. + // // errors: // SystemError - System error. - Signal(s os.Signal) error + Signal(s os.Signal, all bool) error // Exec signals the container to exec the users process at the end of the init. // diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go index 4ba2735d..82c6d8e4 100644 --- a/libcontainer/container_linux.go +++ b/libcontainer/container_linux.go @@ -282,7 +282,10 @@ func (c *linuxContainer) start(process *Process, isInit bool) error { return nil } -func (c *linuxContainer) Signal(s os.Signal) error { +func (c *linuxContainer) Signal(s os.Signal, all bool) error { + if all { + return signalAllProcesses(c.cgroupManager, s) + } if err := c.initProcess.signal(s); err != nil { return newSystemErrorWithCause(err, "signaling init process") } diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go index b1e6762e..aeccadd9 100644 --- a/libcontainer/init_linux.go +++ b/libcontainer/init_linux.go @@ -334,10 +334,10 @@ func setOomScoreAdj(oomScoreAdj int, pid int) error { return ioutil.WriteFile(path, []byte(strconv.Itoa(oomScoreAdj)), 0600) } -// killCgroupProcesses freezes then iterates over all the processes inside the +// signalAllProcesses freezes then iterates over all the processes inside the // manager's cgroups sending a SIGKILL to each process then waiting for them to // exit. -func killCgroupProcesses(m cgroups.Manager) error { +func signalAllProcesses(m cgroups.Manager, s os.Signal) error { var procs []*os.Process if err := m.Freeze(configs.Frozen); err != nil { logrus.Warn(err) @@ -354,7 +354,7 @@ func killCgroupProcesses(m cgroups.Manager) error { continue } procs = append(procs, p) - if err := p.Kill(); err != nil { + if err := p.Signal(s); err != nil { logrus.Warn(err) } } diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go index d2da7fbd..4b54e4b2 100644 --- a/libcontainer/process_linux.go +++ b/libcontainer/process_linux.go @@ -379,7 +379,7 @@ func (p *initProcess) wait() (*os.ProcessState, error) { } // we should kill all processes in cgroup when init is died if we use host PID namespace if p.sharePidns { - killCgroupProcesses(p.manager) + signalAllProcesses(p.manager, syscall.SIGKILL) } return p.cmd.ProcessState, nil } diff --git a/libcontainer/state_linux.go b/libcontainer/state_linux.go index d8ea4009..7aab4606 100644 --- a/libcontainer/state_linux.go +++ b/libcontainer/state_linux.go @@ -39,7 +39,7 @@ type containerState interface { func destroy(c *linuxContainer) error { if !c.config.Namespaces.Contains(configs.NEWPID) { - if err := killCgroupProcesses(c.cgroupManager); err != nil { + if err := signalAllProcesses(c.cgroupManager, syscall.SIGKILL); err != nil { logrus.Warn(err) } } diff --git a/man/runc-kill.8.md b/man/runc-kill.8.md index 65642d64..3566e5f3 100644 --- a/man/runc-kill.8.md +++ b/man/runc-kill.8.md @@ -2,11 +2,14 @@ runc kill - kill sends the specified signal (default: SIGTERM) to the container's init process # SYNOPSIS - runc kill + runc kill [command options] Where "" is the name for the instance of the container and "" is the signal to be sent to the init process. +# OPTIONS + --all, -a send the specified signal to all processes inside the container + # EXAMPLE For example, if the container id is "ubuntu01" the following will send a "KILL"