Merge pull request #907 from baude/kpod_kill

Add support for kpod kill
This commit is contained in:
Daniel J Walsh 2017-09-28 12:59:38 -04:00 committed by GitHub
commit a40aa7ad54
10 changed files with 322 additions and 0 deletions

View file

@ -48,6 +48,7 @@ It is currently in active development in the Kubernetes community through the [d
| [kpod-images(1)](/docs/kpod-images.1.md) | List images in local storage |[![...](/docs/play.png)](https://asciinema.org/a/133649)| | [kpod-images(1)](/docs/kpod-images.1.md) | List images in local storage |[![...](/docs/play.png)](https://asciinema.org/a/133649)|
| [kpod-info(1)](/docs/kpod-info.1.md) | Display system information || | [kpod-info(1)](/docs/kpod-info.1.md) | Display system information ||
| [kpod-inspect(1)](/docs/kpod-inspect.1.md) | Display the configuration of a container or image |[![...](/docs/play.png)](https://asciinema.org/a/133418)| | [kpod-inspect(1)](/docs/kpod-inspect.1.md) | Display the configuration of a container or image |[![...](/docs/play.png)](https://asciinema.org/a/133418)|
| [kpod-kill(1)](/docs/kpod-kill.1.md) | Kill the main process in one or more running containers
| [kpod-load(1)](/docs/kpod-load.1.md) | Load an image from docker archive or oci |[![...](/docs/play.png)](https://asciinema.org/a/kp8kOaexEhEa20P1KLZ3L5X4g)| | [kpod-load(1)](/docs/kpod-load.1.md) | Load an image from docker archive or oci |[![...](/docs/play.png)](https://asciinema.org/a/kp8kOaexEhEa20P1KLZ3L5X4g)|
| [kpod-logs(1)](/docs/kpod-logs.1.md) | Display the logs of a container || | [kpod-logs(1)](/docs/kpod-logs.1.md) | Display the logs of a container ||
| [kpod-mount(1)](/docs/kpod-mount.1.md) | Mount a working container's root filesystem || | [kpod-mount(1)](/docs/kpod-mount.1.md) | Mount a working container's root filesystem ||

71
cmd/kpod/kill.go Normal file
View file

@ -0,0 +1,71 @@
package main
import (
"fmt"
"os"
"github.com/docker/docker/pkg/signal"
"github.com/kubernetes-incubator/cri-o/libkpod"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
var (
killFlags = []cli.Flag{
cli.StringFlag{
Name: "signal, s",
Usage: "Signal to send to the container",
Value: "KILL",
},
}
killDescription = "The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal."
killCommand = cli.Command{
Name: "kill",
Usage: "Kill one or more running containers with a specific signal",
Description: killDescription,
Flags: killFlags,
Action: killCmd,
ArgsUsage: "[CONTAINER_NAME_OR_ID]",
}
)
// killCmd kills one or more containers with a signal
func killCmd(c *cli.Context) error {
args := c.Args()
if len(args) == 0 {
return errors.Errorf("specify one or more containers to kill")
}
config, err := getConfig(c)
if err != nil {
return errors.Wrapf(err, "could not get config")
}
server, err := libkpod.New(config)
if err != nil {
return errors.Wrapf(err, "could not get container server")
}
killSignal := c.String("signal")
// Check if the signalString provided by the user is valid
// Invalid signals will return err
sysSignal, err := signal.ParseSignal(killSignal)
if err != nil {
return err
}
defer server.Shutdown()
err = server.Update()
if err != nil {
return errors.Wrapf(err, "could not update list of containers")
}
var lastError error
for _, container := range c.Args() {
id, err := server.ContainerKill(container, sysSignal)
if err != nil {
if lastError != nil {
fmt.Fprintln(os.Stderr, lastError)
}
lastError = errors.Wrapf(err, "unable to kill %v", container)
} else {
fmt.Println(id)
}
}
return lastError
}

View file

@ -37,6 +37,7 @@ func main() {
imagesCommand, imagesCommand,
infoCommand, infoCommand,
inspectCommand, inspectCommand,
killCommand,
loadCommand, loadCommand,
logsCommand, logsCommand,
mountCommand, mountCommand,

View file

@ -137,6 +137,15 @@ _kpod_inspect() {
;; ;;
esac esac
} }
_kpod_kill() {
local options_with_args="
--signal -s
"
local boolean_options="
--help
-h"
_complete_ "$options_with_args" "$boolean_options"
}
_kpod_logs() { _kpod_logs() {
local options_with_args=" local options_with_args="
@ -442,6 +451,7 @@ _kpod_kpod() {
images images
info info
inspect inspect
kill
load load
logs logs
mount mount

33
docs/kpod-kill.1.md Normal file
View file

@ -0,0 +1,33 @@
% kpod(1) kpod-kill- Kill one or more containers with a signal
% Brent Baude
# kpod-kill"1" "September 2017" "kpod"
## NAME
kpod kill - Kills one or more containers with a signal
## SYNOPSIS
**kpod kill [OPTIONS] CONTAINER [...]**
## DESCRIPTION
The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal.
## OPTIONS
**--signal, s**
Signal to send to the container. For more information on Linux signals, refer to *man signal(7)*.
## EXAMPLE
kpod kill mywebserver
kpod kill 860a4b23
kpod kill --signal TERM 860a4b23
## SEE ALSO
kpod(1), kpod-stop(1)
## HISTORY
September 2017, Originally compiled by Brent Baude <bbaude@redhat.com>

View file

@ -67,6 +67,9 @@ Displays system information
### inspect ### inspect
Display a container or image's configuration Display a container or image's configuration
### kill
Kill the main process in one or more containers
### load ### load
Load an image from docker archive Load an image from docker archive

45
libkpod/kill.go Normal file
View file

@ -0,0 +1,45 @@
package libkpod
import (
"github.com/docker/docker/pkg/signal"
"github.com/kubernetes-incubator/cri-o/oci"
"github.com/kubernetes-incubator/cri-o/utils"
"github.com/pkg/errors"
"os"
"syscall"
)
// Reverse lookup signal string from its map
func findStringInSignalMap(killSignal syscall.Signal) (string, error) {
for k, v := range signal.SignalMap {
if v == killSignal {
return k, nil
}
}
return "", errors.Errorf("unable to convert signal to string")
}
// ContainerKill sends the user provided signal to the containers primary process.
func (c *ContainerServer) ContainerKill(container string, killSignal syscall.Signal) (string, error) { // nolint
ctr, err := c.LookupContainer(container)
if err != nil {
return "", errors.Wrapf(err, "failed to find container %s", container)
}
c.runtime.UpdateStatus(ctr)
cStatus := c.runtime.ContainerStatus(ctr)
// If the container is not running, error and move on.
if cStatus.Status != oci.ContainerStateRunning {
return "", errors.Errorf("cannot kill container %s: it is not running", container)
}
signalString, err := findStringInSignalMap(killSignal)
if err != nil {
return "", err
}
if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, c.runtime.Path(ctr), "kill", ctr.ID(), signalString); err != nil {
return "", err
}
c.ContainerStateToDisk(ctr)
return ctr.ID(), nil
}

86
test/kpod_kill.bats Normal file
View file

@ -0,0 +1,86 @@
#!/usr/bin/env bats
load helpers
ROOT="$TESTDIR/crio"
RUNROOT="$TESTDIR/crio-run"
KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT ${STORAGE_OPTS} --runtime $RUNTIME_BINARY"
function teardown() {
cleanup_test
}
function start_sleep_container () {
pod_id=$(crioctl pod run --config "$TESTDATA"/sandbox_config.json)
ctr_id=$(crioctl ctr create --config "$TESTDATA"/container_config_sleep.json --pod "$pod_id")
crioctl ctr start --id "$ctr_id"
}
@test "kill a bogus container" {
run ${KPOD_BINARY} ${KPOD_OPTIONS} kill foobar
echo "$output"
[ "$status" -ne 0 ]
}
@test "kill a running container by id" {
start_crio
${KPOD_BINARY} ${KPOD_OPTIONS} pull docker.io/library/busybox:latest
ctr_id=$( start_sleep_container )
crioctl ctr status --id "$ctr_id"
${KPOD_BINARY} ${KPOD_OPTIONS} ps -a
${KPOD_BINARY} ${KPOD_OPTIONS} logs "$ctr_id"
crioctl ctr status --id "$ctr_id"
run ${KPOD_BINARY} ${KPOD_OPTIONS} kill "$ctr_id"
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
}
@test "kill a running container by id with TERM" {
start_crio
${KPOD_BINARY} ${KPOD_OPTIONS} pull docker.io/library/busybox:latest
ctr_id=$( start_sleep_container )
crioctl ctr status --id "$ctr_id"
${KPOD_BINARY} ${KPOD_OPTIONS} ps -a
${KPOD_BINARY} ${KPOD_OPTIONS} logs "$ctr_id"
crioctl ctr status --id "$ctr_id"
run ${KPOD_BINARY} ${KPOD_OPTIONS} kill -s TERM "$ctr_id"
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
}
@test "kill a running container by name" {
start_crio
${KPOD_BINARY} ${KPOD_OPTIONS} pull docker.io/library/busybox:latest
ctr_id=$( start_sleep_container )
crioctl ctr status --id "$ctr_id"
${KPOD_BINARY} ${KPOD_OPTIONS} ps -a
${KPOD_BINARY} ${KPOD_OPTIONS} logs "$ctr_id"
crioctl ctr status --id "$ctr_id"
${KPOD_BINARY} ${KPOD_OPTIONS} ps -a
run ${KPOD_BINARY} ${KPOD_OPTIONS} kill "k8s_container999_podsandbox1_redhat.test.crio_redhat-test-crio_1"
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
}
@test "kill a running container by id with a bogus signal" {
start_crio
${KPOD_BINARY} ${KPOD_OPTIONS} pull docker.io/library/busybox:latest
ctr_id=$( start_sleep_container )
crioctl ctr status --id "$ctr_id"
${KPOD_BINARY} ${KPOD_OPTIONS} logs "$ctr_id"
crioctl ctr status --id "$ctr_id"
run ${KPOD_BINARY} ${KPOD_OPTIONS} kill -s foobar "$ctr_id"
echo "$output"
[ "$status" -ne 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
}

View file

@ -0,0 +1,71 @@
{
"metadata": {
"name": "container999",
"attempt": 1
},
"image": {
"image": "docker.io/library/busybox:latest"
},
"command": [
"sleep",
"9999"
],
"args": [],
"working_dir": "/",
"envs": [
{
"key": "PATH",
"value": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
},
{
"key": "TERM",
"value": "xterm"
},
{
"key": "TESTDIR",
"value": "test/dir1"
},
{
"key": "TESTFILE",
"value": "test/file1"
}
],
"labels": {
"type": "small",
"batch": "no"
},
"annotations": {
"owner": "dragon",
"daemon": "crio"
},
"privileged": true,
"log_path": "",
"stdin": false,
"stdin_once": false,
"tty": false,
"linux": {
"resources": {
"cpu_period": 10000,
"cpu_quota": 20000,
"cpu_shares": 512,
"oom_score_adj": 30
},
"security_context": {
"readonly_rootfs": false,
"selinux_options": {
"user": "system_u",
"role": "system_r",
"type": "svirt_lxc_net_t",
"level": "s0:c4,c5"
},
"capabilities": {
"add_capabilities": [
"setuid",
"setgid"
],
"drop_capabilities": [
]
}
}
}
}

View file

@ -45,6 +45,7 @@ There are other equivalents for these tools
| `docker export` | [`kpod export`](./docs/kpod-export.1.md) | | `docker export` | [`kpod export`](./docs/kpod-export.1.md) |
| `docker history`| [`kpod history`](./docs/kpod-history.1.md)| | `docker history`| [`kpod history`](./docs/kpod-history.1.md)|
| `docker images` | [`kpod images`](./docs/kpod-images.1.md) | | `docker images` | [`kpod images`](./docs/kpod-images.1.md) |
| `docker kill` | [`kpod kill`](./docs/kpod-kill.1.md) |
| `docker load` | [`kpod load`](./docs/kpod-load.1.md) | | `docker load` | [`kpod load`](./docs/kpod-load.1.md) |
| `docker pause` | [`kpod pause`](./docs/kpod-pause.1.md) | | `docker pause` | [`kpod pause`](./docs/kpod-pause.1.md) |
| `docker ps` | [`kpod ps`](./docs/kpod-ps.1.md) | | `docker ps` | [`kpod ps`](./docs/kpod-ps.1.md) |