diff options
-rw-r--r-- | cmd/podman/containers/kill.go | 8 | ||||
-rw-r--r-- | docs/source/markdown/podman-kill.1.md | 8 | ||||
-rw-r--r-- | libpod/image/utils.go | 57 | ||||
-rw-r--r-- | pkg/domain/entities/containers.go | 7 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 9 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 8 | ||||
-rw-r--r-- | test/e2e/exists_test.go | 1 | ||||
-rw-r--r-- | test/e2e/kill_test.go | 55 |
8 files changed, 135 insertions, 18 deletions
diff --git a/cmd/podman/containers/kill.go b/cmd/podman/containers/kill.go index 4640229a9..28040e08a 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 5956c03da..96c01ac09 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/libpod/image/utils.go b/libpod/image/utils.go index 7429a7f10..727c73a71 100644 --- a/libpod/image/utils.go +++ b/libpod/image/utils.go @@ -20,7 +20,11 @@ import ( // a match on name:tag func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, error) { _, searchName, searchSuspiciousTagValueForSearch := search.suspiciousRefNameTagValuesForSearch() - var results []*storage.Image + type Candidate struct { + name string + image *Image + } + var candidates []Candidate for _, image := range images { for _, name := range image.Names() { d, err := decompose(name) @@ -29,23 +33,52 @@ func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, er continue } _, dName, dSuspiciousTagValueForSearch := d.suspiciousRefNameTagValuesForSearch() - if dName == searchName && dSuspiciousTagValueForSearch == searchSuspiciousTagValueForSearch { - results = append(results, image.image) + if dSuspiciousTagValueForSearch != searchSuspiciousTagValueForSearch { continue } - // account for registry:/somedir/image - if strings.HasSuffix(dName, "/"+searchName) && dSuspiciousTagValueForSearch == searchSuspiciousTagValueForSearch { - results = append(results, image.image) - continue + if dName == searchName || strings.HasSuffix(dName, "/"+searchName) { + candidates = append(candidates, Candidate{ + name: name, + image: image, + }) } } } - if len(results) == 0 { - return &storage.Image{}, errors.Errorf("unable to find a name and tag match for %s in repotags", searchName) - } else if len(results) > 1 { - return &storage.Image{}, errors.Wrapf(define.ErrMultipleImages, searchName) + if len(candidates) == 0 { + return nil, errors.Errorf("unable to find a name and tag match for %s in repotags", searchName) + } + + // If more then one candidate and the candidates all have same name + // and only one is read/write return it. + // Othewise return error with the list of candidates + if len(candidates) > 1 { + var ( + rwImage *Image + rwImageCnt int + ) + names := make(map[string]bool) + for _, c := range candidates { + names[c.name] = true + if !c.image.IsReadOnly() { + rwImageCnt++ + rwImage = c.image + } + } + // If only one name used and have read/write image return it + if len(names) == 1 && rwImageCnt == 1 { + return rwImage.image, nil + } + keys := []string{} + for k := range names { + keys = append(keys, k) + } + if rwImageCnt > 1 { + return nil, errors.Wrapf(define.ErrMultipleImages, "found multiple read/write images %s", strings.Join(keys, ",")) + } else { + return nil, errors.Wrapf(define.ErrMultipleImages, "found multiple read/only images %s", strings.Join(keys, ",")) + } } - return results[0], nil + return candidates[0].image.image, nil } // getCopyOptions constructs a new containers/image/copy.Options{} struct from the given parameters, inheriting some from sc. diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 4442c0030..b8d49d067 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 ec65dbe44..efb4f866f 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 7704de210..0db985dff 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/exists_test.go b/test/e2e/exists_test.go index 7ff5d4207..480bfe5fc 100644 --- a/test/e2e/exists_test.go +++ b/test/e2e/exists_test.go @@ -38,7 +38,6 @@ var _ = Describe("Podman image|container exists", func() { Expect(session).Should(Exit(0)) }) It("podman image exists in local storage by short name", func() { - Skip("FIXME-8165: shortnames don't seem to work with quay (#8176)") session := podmanTest.Podman([]string{"image", "exists", "alpine"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) diff --git a/test/e2e/kill_test.go b/test/e2e/kill_test.go index 8a4828583..8b31cae72 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()) + }) + }) |