diff options
-rw-r--r-- | cmd/podman/pod.go | 1 | ||||
-rw-r--r-- | cmd/podman/pod_kill.go | 114 | ||||
-rw-r--r-- | commands.md | 1 | ||||
-rw-r--r-- | completions/bash/podman | 24 | ||||
-rw-r--r-- | docs/podman-pod-kill.1.md | 43 | ||||
-rw-r--r-- | docs/podman-pod.1.md | 1 | ||||
-rw-r--r-- | test/e2e/pod_kill_test.go | 162 |
7 files changed, 346 insertions, 0 deletions
diff --git a/cmd/podman/pod.go b/cmd/podman/pod.go index 664af4252..277b16932 100644 --- a/cmd/podman/pod.go +++ b/cmd/podman/pod.go @@ -18,6 +18,7 @@ var ( UseShortOptionHandling: true, Subcommands: []cli.Command{ podCreateCommand, + podKillCommand, podPsCommand, podRestartCommand, podRmCommand, diff --git a/cmd/podman/pod_kill.go b/cmd/podman/pod_kill.go new file mode 100644 index 000000000..e233c76b1 --- /dev/null +++ b/cmd/podman/pod_kill.go @@ -0,0 +1,114 @@ +package main + +import ( + "fmt" + "syscall" + + "github.com/docker/docker/pkg/signal" + "github.com/pkg/errors" + "github.com/projectatomic/libpod/cmd/podman/libpodruntime" + "github.com/projectatomic/libpod/libpod" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" +) + +var ( + podKillFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "all, a", + Usage: "Kill all containers in all pods", + }, + cli.StringFlag{ + Name: "signal, s", + Usage: "Signal to send to the containers in the pod", + Value: "KILL", + }, + LatestFlag, + } + podKillDescription = "The main process of each container inside the specified pod will be sent SIGKILL, or any signal specified with option --signal." + podKillCommand = cli.Command{ + Name: "kill", + Usage: "Send the specified signal or SIGKILL to containers in pod", + Description: podKillDescription, + Flags: podKillFlags, + Action: podKillCmd, + ArgsUsage: "[POD_NAME_OR_ID]", + UseShortOptionHandling: true, + } +) + +// podKillCmd kills one or more pods with a signal +func podKillCmd(c *cli.Context) error { + if err := checkMutuallyExclusiveFlags(c); err != nil { + return err + } + + runtime, err := libpodruntime.GetRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + + args := c.Args() + var killSignal uint = uint(syscall.SIGTERM) + var lastError error + var pods []*libpod.Pod + + if c.String("signal") != "" { + // Check if the signalString provided by the user is valid + // Invalid signals will return err + sysSignal, err := signal.ParseSignal(c.String("signal")) + if err != nil { + return err + } + killSignal = uint(sysSignal) + } + + if c.Bool("all") { + pods, err = runtime.Pods() + if err != nil { + return errors.Wrapf(err, "unable to get pods") + } + } + if c.Bool("latest") { + pod, err := runtime.GetLatestPod() + if err != nil { + return errors.Wrapf(err, "unable to get latest pod") + } + pods = append(pods, pod) + } + for _, i := range args { + pod, err := runtime.LookupPod(i) + if err != nil { + logrus.Errorf("%q", lastError) + if lastError != nil { + logrus.Errorf("%q", lastError) + } + lastError = errors.Wrapf(err, "unable to find pods %s", i) + continue + } + pods = append(pods, pod) + } + + for _, pod := range pods { + ctr_errs, err := pod.Kill(killSignal) + if ctr_errs != nil { + for ctr, err := range ctr_errs { + if lastError != nil { + logrus.Errorf("%q", lastError) + } + lastError = errors.Wrapf(err, "unable to kill container %q in pod %q", ctr, pod.ID()) + } + continue + } + if err != nil { + if lastError != nil { + logrus.Errorf("%q", lastError) + } + lastError = errors.Wrapf(err, "unable to kill pod %q", pod.ID()) + continue + } + fmt.Println(pod.ID()) + } + return lastError +} diff --git a/commands.md b/commands.md index c74998319..8af63b60d 100644 --- a/commands.md +++ b/commands.md @@ -31,6 +31,7 @@ | [podman-pause(1)](/docs/podman-pause.1.md) | Pause one or more running containers |[![...](/docs/play.png)](https://asciinema.org/a/141292)| | [podman-pod(1)](/docs/podman-pod.1.md) | Simple management tool for groups of containers, called pods || | [podman-pod-create(1)](/docs/podman-pod-create.1.md) | Create a new pod || +| [podman-pod-kill(1)](podman-pod-kill.1.md) | Kill the main process of each container in pod. || | [podman-pod-ps(1)](/docs/podman-pod-ps.1.md) | List the pods on the system || | [podman-pod-restart](/docs/podman-pod-restart.1.md) | Restart one or more pods || | [podman-pod-rm(1)](/docs/podman-pod-rm.1.md) | Remove one or more pods || diff --git a/completions/bash/podman b/completions/bash/podman index 374a84a4c..0019343e2 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -2086,6 +2086,29 @@ _podman_pod_create() { _complete_ "$options_with_args" "$boolean_options" } +_podman_pod_kill() { + local options_with_args=" + " + + local boolean_options=" + --all + -a + --signal + -s + --latest + -l + " + _complete_ "$options_with_args" "$boolean_options" + case "$cur" in + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_pod_names + ;; + esac +} + __podman_pod_ps() { local options_with_args=" -f @@ -2215,6 +2238,7 @@ _podman_pod() { " subcommands=" create + kill ps restart rm diff --git a/docs/podman-pod-kill.1.md b/docs/podman-pod-kill.1.md new file mode 100644 index 000000000..2f4d37f92 --- /dev/null +++ b/docs/podman-pod-kill.1.md @@ -0,0 +1,43 @@ +% podman-pod-kill "1" + +## NAME +podman\-pod\-kill - Kills all containers in one or more pods with a signal + +## SYNOPSIS +**podman pod kill** [*options*] *pod* ... + +## DESCRIPTION +The main process of each container inside the pods specified will be sent SIGKILL, or any signal specified with option --signal. + +## OPTIONS +**--all, -a** + +Sends signal to all containers associated with a pod. + +**--latest, -l** + +Instead of providing the pod name or ID, use the last created pod. If you use methods other than Podman +to run pods such as CRI-O, the last started pod could be from either of those methods. + +**--signal, s** + +Signal to send to the containers in the pod. For more information on Linux signals, refer to *man signal(7)*. + + +## EXAMPLE + +podman pod kill mywebserver + +podman pod kill 860a4b23 + +podman pod kill --signal TERM 860a4b23 + +podman pod kill --latest + +podman pod kill --all + +## SEE ALSO +podman-pod(1), podman-pod-stop(1) + +## HISTORY +July 2018, Originally compiled by Peter Hunt <pehunt@redhat.com> diff --git a/docs/podman-pod.1.md b/docs/podman-pod.1.md index 9aee75e81..74b6d75b5 100644 --- a/docs/podman-pod.1.md +++ b/docs/podman-pod.1.md @@ -14,6 +14,7 @@ podman pod is a set of subcommands that manage pods, or groups of containers. | Subcommand | Description | | ------------------------------------------------- | ------------------------------------------------------------------------------ | | [podman-pod-create(1)](podman-pod-create.1.md) | Create a new pod. | +| [podman-pod-kill(1)](podman-pod-kill.1.md) | Kill the main process of each container in pod. | | [podman-pod-ps(1)](podman-pod-ps.1.md) | Prints out information about pods. | | [podman-pod-rm(1)](podman-pod-rm.1.md) | Remove one or more pods. | | [podman-pod-start(1)](podman-pod-start.1.md) | Start one or more pods. | diff --git a/test/e2e/pod_kill_test.go b/test/e2e/pod_kill_test.go new file mode 100644 index 000000000..9abc83262 --- /dev/null +++ b/test/e2e/pod_kill_test.go @@ -0,0 +1,162 @@ +package integration + +import ( + "os" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman pod kill", func() { + var ( + tempdir string + err error + podmanTest PodmanTest + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanCreate(tempdir) + podmanTest.RestoreAllArtifacts() + }) + + AfterEach(func() { + podmanTest.CleanupPod() + + }) + + It("podman pod kill bogus", func() { + session := podmanTest.Podman([]string{"pod", "kill", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) + + It("podman pod kill a pod by id", func() { + session := podmanTest.Podman([]string{"pod", "create"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podid := session.OutputToString() + + session = podmanTest.RunTopContainerInPod("", podid) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.RunTopContainerInPod("", podid) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + result := podmanTest.Podman([]string{"pod", "kill", podid}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + }) + + It("podman pod kill a pod by id with TERM", func() { + session := podmanTest.Podman([]string{"pod", "create"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podid := session.OutputToString() + + session = podmanTest.RunTopContainerInPod("", podid) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + result := podmanTest.Podman([]string{"pod", "kill", "-s", "9", podid}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + }) + + It("podman pod kill a pod by name", func() { + session := podmanTest.Podman([]string{"pod", "create", "--name", "test1"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podid := session.OutputToString() + + session = podmanTest.RunTopContainerInPod("", podid) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + result := podmanTest.Podman([]string{"pod", "kill", "test1"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + }) + + It("podman pod kill a pod by id with a bogus signal", func() { + session := podmanTest.Podman([]string{"pod", "create", "--name", "test1"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podid := session.OutputToString() + + session = podmanTest.RunTopContainerInPod("", podid) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + result := podmanTest.Podman([]string{"pod", "kill", "-s", "bogus", "test1"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(125)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + }) + + It("podman pod kill latest pod", func() { + session := podmanTest.Podman([]string{"pod", "create", "--name", "test1"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podid := session.OutputToString() + + session = podmanTest.RunTopContainerInPod("", podid) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"pod", "create", "--name", "test2"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podid2 := session.OutputToString() + + session = podmanTest.RunTopContainerInPod("", podid2) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.RunTopContainerInPod("", podid2) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + result := podmanTest.Podman([]string{"pod", "kill", "-l"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + }) + + It("podman pod kill all", func() { + session := podmanTest.Podman([]string{"pod", "create", "--name", "test1"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podid := session.OutputToString() + + session = podmanTest.RunTopContainerInPod("", podid) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.RunTopContainerInPod("", podid) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"pod", "create", "--name", "test2"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podid2 := session.OutputToString() + + session = podmanTest.RunTopContainerInPod("", podid2) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + result := podmanTest.Podman([]string{"pod", "kill", "-a"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + }) +}) |