From c81e29525b0ea84107147d92283c2b88909d1f12 Mon Sep 17 00:00:00 2001 From: baude Date: Wed, 23 Dec 2020 11:02:52 -0600 Subject: [PATCH] add --cidfile to container kill Add the ability to read container ids from one or more files for the kill command. Fixes: #8443 Signed-off-by: baude --- cmd/podman/containers/kill.go | 8 +++- docs/source/markdown/podman-kill.1.md | 8 ++++ pkg/domain/entities/containers.go | 7 ++-- pkg/domain/infra/abi/containers.go | 9 +++++ pkg/domain/infra/tunnel/containers.go | 8 ++++ test/e2e/kill_test.go | 55 +++++++++++++++++++++++++++ 6 files changed, 90 insertions(+), 5 deletions(-) diff --git a/cmd/podman/containers/kill.go b/cmd/podman/containers/kill.go index 4640229a9e..28040e08a0 100644 --- a/cmd/podman/containers/kill.go +++ b/cmd/podman/containers/kill.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "github.com/containers/common/pkg/completion" "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" @@ -22,7 +23,7 @@ var ( Long: killDescription, RunE: kill, Args: func(cmd *cobra.Command, args []string) error { - return validate.CheckAllLatestAndCIDFile(cmd, args, false, false) + return validate.CheckAllLatestAndCIDFile(cmd, args, false, true) }, ValidArgsFunction: common.AutocompleteContainersRunning, Example: `podman kill mywebserver @@ -32,7 +33,7 @@ var ( containerKillCommand = &cobra.Command{ Args: func(cmd *cobra.Command, args []string) error { - return validate.CheckAllLatestAndCIDFile(cmd, args, false, false) + return validate.CheckAllLatestAndCIDFile(cmd, args, false, true) }, Use: killCommand.Use, Short: killCommand.Short, @@ -57,6 +58,9 @@ func killFlags(cmd *cobra.Command) { signalFlagName := "signal" flags.StringVarP(&killOptions.Signal, signalFlagName, "s", "KILL", "Signal to send to the container") _ = cmd.RegisterFlagCompletionFunc(signalFlagName, common.AutocompleteStopSignal) + cidfileFlagName := "cidfile" + flags.StringArrayVar(&killOptions.CIDFiles, cidfileFlagName, []string{}, "Read the container ID from the file") + _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault) } func init() { diff --git a/docs/source/markdown/podman-kill.1.md b/docs/source/markdown/podman-kill.1.md index 5956c03da6..96c01ac096 100644 --- a/docs/source/markdown/podman-kill.1.md +++ b/docs/source/markdown/podman-kill.1.md @@ -16,6 +16,10 @@ The main process inside each container specified will be sent SIGKILL, or any si Signal all running containers. This does not include paused containers. +#### **--cidfile** + +Read container ID from the specified file and remove the container. Can be specified multiple times. + #### **--latest**, **-l** Instead of providing the container name or ID, use the last created container. If you use methods other than Podman @@ -40,6 +44,10 @@ podman kill --latest podman kill --signal KILL -a +podman kill --cidfile /home/user/cidfile-1 + +podman kill --cidfile /home/user/cidfile-1 --cidfile ./cidfile-2 + ## SEE ALSO podman(1), podman-stop(1) diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 4442c00301..b8d49d0679 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -104,9 +104,10 @@ type TopOptions struct { } type KillOptions struct { - All bool - Latest bool - Signal string + All bool + Latest bool + Signal string + CIDFiles []string } type KillReport struct { diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index ec65dbe440..efb4f866f0 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -229,6 +229,14 @@ func (ic *ContainerEngine) pruneContainersHelper(filterFuncs []libpod.ContainerF } func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) { + for _, cidFile := range options.CIDFiles { + content, err := ioutil.ReadFile(cidFile) + if err != nil { + return nil, errors.Wrap(err, "error reading CIDFile") + } + id := strings.Split(string(content), "\n")[0] + namesOrIds = append(namesOrIds, id) + } sig, err := signal.ParseSignalNameOrNumber(options.Signal) if err != nil { return nil, err @@ -246,6 +254,7 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin } return reports, nil } + func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) { var ( ctrs []*libpod.Container diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 7704de2107..0db985dffb 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -125,6 +125,14 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin } func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, opts entities.KillOptions) ([]*entities.KillReport, error) { + for _, cidFile := range opts.CIDFiles { + content, err := ioutil.ReadFile(cidFile) + if err != nil { + return nil, errors.Wrap(err, "error reading CIDFile") + } + id := strings.Split(string(content), "\n")[0] + namesOrIds = append(namesOrIds, id) + } ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, false, namesOrIds) if err != nil { return nil, err diff --git a/test/e2e/kill_test.go b/test/e2e/kill_test.go index 8a48285835..8b31cae72a 100644 --- a/test/e2e/kill_test.go +++ b/test/e2e/kill_test.go @@ -1,6 +1,7 @@ package integration import ( + "io/ioutil" "os" . "github.com/containers/podman/v2/test/utils" @@ -112,4 +113,58 @@ var _ = Describe("Podman kill", func() { Expect(result.ExitCode()).To(Equal(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) }) + + It("podman kill --cidfile", func() { + tmpDir, err := ioutil.TempDir("", "") + Expect(err).To(BeNil()) + tmpFile := tmpDir + "cid" + defer os.RemoveAll(tmpDir) + + session := podmanTest.Podman([]string{"run", "-dt", "--cidfile", tmpFile, ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + cid := session.OutputToStringArray()[0] + + kill := podmanTest.Podman([]string{"kill", "--cidfile", tmpFile}) + kill.WaitWithDefaultTimeout() + Expect(kill.ExitCode()).To(BeZero()) + + wait := podmanTest.Podman([]string{"wait", "--condition", "exited", cid}) + wait.WaitWithDefaultTimeout() + Expect(wait.ExitCode()).To(BeZero()) + }) + + It("podman kill multiple --cidfile", func() { + tmpDir1, err := ioutil.TempDir("", "") + Expect(err).To(BeNil()) + tmpFile1 := tmpDir1 + "cid" + defer os.RemoveAll(tmpDir1) + + tmpDir2, err := ioutil.TempDir("", "") + Expect(err).To(BeNil()) + tmpFile2 := tmpDir2 + "cid" + defer os.RemoveAll(tmpDir2) + + session := podmanTest.Podman([]string{"run", "-dt", "--cidfile", tmpFile1, ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + cid1 := session.OutputToStringArray()[0] + + session2 := podmanTest.Podman([]string{"run", "-dt", "--cidfile", tmpFile2, ALPINE, "top"}) + session2.WaitWithDefaultTimeout() + Expect(session2.ExitCode()).To(Equal(0)) + cid2 := session2.OutputToStringArray()[0] + + kill := podmanTest.Podman([]string{"kill", "--cidfile", tmpFile1, "--cidfile", tmpFile2}) + kill.WaitWithDefaultTimeout() + Expect(kill.ExitCode()).To(BeZero()) + + wait := podmanTest.Podman([]string{"wait", "--condition", "exited", cid1}) + wait.WaitWithDefaultTimeout() + Expect(wait.ExitCode()).To(BeZero()) + wait = podmanTest.Podman([]string{"wait", "--condition", "exited", cid2}) + wait.WaitWithDefaultTimeout() + Expect(wait.ExitCode()).To(BeZero()) + }) + })