diff options
-rw-r--r-- | cmd/podman/containers/kill.go | 7 | ||||
-rw-r--r-- | cmd/podman/containers/rm.go | 24 | ||||
-rw-r--r-- | cmd/podman/containers/stop.go | 7 | ||||
-rw-r--r-- | docs/source/markdown/podman-rm.1.md | 24 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 4 | ||||
-rw-r--r-- | pkg/domain/entities/containers.go | 1 | ||||
-rw-r--r-- | pkg/domain/entities/reports/containers.go | 5 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 43 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 57 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/helpers.go | 2 | ||||
-rw-r--r-- | test/e2e/rm_test.go | 65 | ||||
-rw-r--r-- | test/system/055-rm.bats | 1 | ||||
-rw-r--r-- | test/upgrade/test-upgrade.bats | 4 |
13 files changed, 186 insertions, 58 deletions
diff --git a/cmd/podman/containers/kill.go b/cmd/podman/containers/kill.go index 5a5379389..c08b3abb6 100644 --- a/cmd/podman/containers/kill.go +++ b/cmd/podman/containers/kill.go @@ -49,7 +49,8 @@ var ( ) var ( - killOptions = entities.KillOptions{} + killOptions = entities.KillOptions{} + killCidFiles = []string{} ) func killFlags(cmd *cobra.Command) { @@ -61,7 +62,7 @@ func killFlags(cmd *cobra.Command) { flags.StringVarP(&killOptions.Signal, signalFlagName, "s", "KILL", "Signal to send to the container") _ = cmd.RegisterFlagCompletionFunc(signalFlagName, common.AutocompleteStopSignal) cidfileFlagName := "cidfile" - flags.StringArrayVar(&cidFiles, cidfileFlagName, []string{}, "Read the container ID from the file") + flags.StringArrayVar(&killCidFiles, cidfileFlagName, nil, "Read the container ID from the file") _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault) } @@ -94,7 +95,7 @@ func kill(_ *cobra.Command, args []string) error { if sig < 1 || sig > 64 { return errors.New("valid signals are 1 through 64") } - for _, cidFile := range cidFiles { + for _, cidFile := range killCidFiles { content, err := ioutil.ReadFile(cidFile) if err != nil { return fmt.Errorf("error reading CIDFile: %w", err) diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go index 056e32651..1e3976389 100644 --- a/cmd/podman/containers/rm.go +++ b/cmd/podman/containers/rm.go @@ -52,8 +52,10 @@ var ( ) var ( - rmOptions = entities.RmOptions{} - cidFiles = []string{} + rmOptions = entities.RmOptions{ + Filters: make(map[string][]string), + } + rmCidFiles = []string{} ) func rmFlags(cmd *cobra.Command) { @@ -69,9 +71,13 @@ func rmFlags(cmd *cobra.Command) { flags.BoolVarP(&rmOptions.Volumes, "volumes", "v", false, "Remove anonymous volumes associated with the container") cidfileFlagName := "cidfile" - flags.StringArrayVar(&cidFiles, cidfileFlagName, nil, "Read the container ID from the file") + flags.StringArrayVar(&rmCidFiles, cidfileFlagName, nil, "Read the container ID from the file") _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault) + filterFlagName := "filter" + flags.StringSliceVar(&filters, filterFlagName, []string{}, "Filter output based on conditions given") + _ = cmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompletePsFilters) + if !registry.IsRemote() { // This option is deprecated, but needs to still exists for backwards compatibility flags.Bool("storage", false, "Remove container from storage library") @@ -101,7 +107,7 @@ func rm(cmd *cobra.Command, args []string) error { } rmOptions.Timeout = &stopTimeout } - for _, cidFile := range cidFiles { + for _, cidFile := range rmCidFiles { content, err := ioutil.ReadFile(cidFile) if err != nil { return fmt.Errorf("error reading CIDFile: %w", err) @@ -110,6 +116,14 @@ func rm(cmd *cobra.Command, args []string) error { args = append(args, id) } + for _, f := range filters { + split := strings.SplitN(f, "=", 2) + if len(split) < 2 { + return fmt.Errorf("invalid filter %q", f) + } + rmOptions.Filters[split[0]] = append(rmOptions.Filters[split[0]], split[1]) + } + if rmOptions.All { logrus.Debug("--all is set: enforcing --depend=true") rmOptions.Depend = true @@ -147,7 +161,7 @@ func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit } errs = append(errs, r.Err) } else { - fmt.Println(r.Id) + fmt.Println(r.RawInput) } } return errs.PrintErrors() diff --git a/cmd/podman/containers/stop.go b/cmd/podman/containers/stop.go index 261f441c3..b0f449266 100644 --- a/cmd/podman/containers/stop.go +++ b/cmd/podman/containers/stop.go @@ -52,7 +52,8 @@ var ( stopOptions = entities.StopOptions{ Filters: make(map[string][]string), } - stopTimeout uint + stopCidFiles = []string{} + stopTimeout uint ) func stopFlags(cmd *cobra.Command) { @@ -62,7 +63,7 @@ func stopFlags(cmd *cobra.Command) { flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing") cidfileFlagName := "cidfile" - flags.StringArrayVar(&cidFiles, cidfileFlagName, nil, "Read the container ID from the file") + flags.StringArrayVar(&stopCidFiles, cidfileFlagName, nil, "Read the container ID from the file") _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault) timeFlagName := "time" @@ -103,7 +104,7 @@ func stop(cmd *cobra.Command, args []string) error { if cmd.Flag("time").Changed { stopOptions.Timeout = &stopTimeout } - for _, cidFile := range cidFiles { + for _, cidFile := range stopCidFiles { content, err := ioutil.ReadFile(cidFile) if err != nil { return fmt.Errorf("error reading CIDFile: %w", err) diff --git a/docs/source/markdown/podman-rm.1.md b/docs/source/markdown/podman-rm.1.md index 1fac3aa34..1dbd1d0c3 100644 --- a/docs/source/markdown/podman-rm.1.md +++ b/docs/source/markdown/podman-rm.1.md @@ -26,6 +26,30 @@ Read container ID from the specified file and remove the container. Can be spec Remove selected container and recursively remove all containers that depend on it. +#### **--filter**=*filter* + +Filter what containers remove. +Multiple filters can be given with multiple uses of the --filter flag. +Filters with the same key work inclusive with the only exception being +`label` which is exclusive. Filters with different keys always work exclusive. + +Valid filters are listed below: + +| **Filter** | **Description** | +| --------------- | -------------------------------------------------------------------------------- | +| id | [ID] Container's ID (accepts regex) | +| name | [Name] Container's name (accepts regex) | +| label | [Key] or [Key=Value] Label assigned to a container | +| exited | [Int] Container's exit code | +| status | [Status] Container's status: 'created', 'exited', 'paused', 'running', 'unknown' | +| ancestor | [ImageName] Image or descendant used to create container | +| before | [ID] or [Name] Containers created before this container | +| since | [ID] or [Name] Containers created since this container | +| volume | [VolumeName] or [MountpointDestination] Volume mounted in container | +| health | [Status] healthy or unhealthy | +| pod | [Pod] name or full or partial ID of pod | +| network | [Network] name or full ID of network | + #### **--force**, **-f** Force the removal of running and paused containers. Forcing a container removal also diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index ce0fd869d..703ae5cbe 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -995,7 +995,7 @@ func (r *Runtime) RemoveDepend(ctx context.Context, rmCtr *Container, force bool return nil, err } for _, cID := range podContainerIDS { - rmReports = append(rmReports, &reports.RmReport{Id: cID}) + rmReports = append(rmReports, &reports.RmReport{Id: cID, RawInput: cID}) } return rmReports, nil } @@ -1023,7 +1023,7 @@ func (r *Runtime) RemoveDepend(ctx context.Context, rmCtr *Container, force bool rmReports = append(rmReports, reports...) } - report := reports.RmReport{Id: rmCtr.ID()} + report := reports.RmReport{Id: rmCtr.ID(), RawInput: rmCtr.ID()} report.Err = r.removeContainer(ctx, rmCtr, force, removeVolume, false, timeout) return append(rmReports, &report), nil } diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index df793034b..7048cd1d2 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -131,6 +131,7 @@ type RestartReport struct { } type RmOptions struct { + Filters map[string][]string All bool Depend bool Force bool diff --git a/pkg/domain/entities/reports/containers.go b/pkg/domain/entities/reports/containers.go index db9a66012..6759fc402 100644 --- a/pkg/domain/entities/reports/containers.go +++ b/pkg/domain/entities/reports/containers.go @@ -1,8 +1,9 @@ package reports type RmReport struct { - Id string `json:"Id"` //nolint:revive,stylecheck - Err error `json:"Err,omitempty"` + Id string `json:"Id"` //nolint:revive,stylecheck + Err error `json:"Err,omitempty"` + RawInput string } func RmReportsIds(r []*RmReport) []string { diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 783224e9c..ed149a869 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -142,10 +142,10 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri if err != nil { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} if len(rawInputs) == len(ctrs) { for i := range ctrs { - ctrMap[ctrs[i].ID()] = rawInputs[i] + idToRawInput[ctrs[i].ID()] = rawInputs[i] } } reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) @@ -158,7 +158,7 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri reports = append(reports, &entities.PauseUnpauseReport{ Id: c.ID(), Err: err, - RawInput: ctrMap[c.ID()], + RawInput: idToRawInput[c.ID()], }) } return reports, nil @@ -169,10 +169,10 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st if err != nil { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} if len(rawInputs) == len(ctrs) { for i := range ctrs { - ctrMap[ctrs[i].ID()] = rawInputs[i] + idToRawInput[ctrs[i].ID()] = rawInputs[i] } } reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) @@ -185,7 +185,7 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st reports = append(reports, &entities.PauseUnpauseReport{ Id: c.ID(), Err: err, - RawInput: ctrMap[c.ID()], + RawInput: idToRawInput[c.ID()], }) } return reports, nil @@ -196,10 +196,10 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin if err != nil && !(options.Ignore && errors.Is(err, define.ErrNoSuchCtr)) { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} if len(rawInputs) == len(ctrs) { for i := range ctrs { - ctrMap[ctrs[i].ID()] = rawInputs[i] + idToRawInput[ctrs[i].ID()] = rawInputs[i] } } errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error { @@ -245,7 +245,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin if options.All { report.RawInput = ctr.ID() } else { - report.RawInput = ctrMap[ctr.ID()] + report.RawInput = idToRawInput[ctr.ID()] } report.Err = err reports = append(reports, report) @@ -275,10 +275,10 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin if err != nil { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} if len(rawInputs) == len(ctrs) { for i := range ctrs { - ctrMap[ctrs[i].ID()] = rawInputs[i] + idToRawInput[ctrs[i].ID()] = rawInputs[i] } } reports := make([]*entities.KillReport, 0, len(ctrs)) @@ -291,7 +291,7 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin reports = append(reports, &entities.KillReport{ Id: con.ID(), Err: err, - RawInput: ctrMap[con.ID()], + RawInput: idToRawInput[con.ID()], }) } return reports, nil @@ -360,7 +360,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, // this will fail and code will fall through to removing the container from libpod.` tmpNames := []string{} for _, ctr := range names { - report := reports.RmReport{Id: ctr} + report := reports.RmReport{Id: ctr, RawInput: ctr} report.Err = ic.Libpod.RemoveStorageContainer(ctr, options.Force) //nolint:gocritic if report.Err == nil { @@ -381,7 +381,16 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, } names = tmpNames - ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod) + ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, names, options.Filters, ic.Libpod) + if err != nil && !(options.Ignore && errors.Is(err, define.ErrNoSuchCtr)) { + return nil, err + } + idToRawInput := map[string]string{} + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID()] = rawInputs[i] + } + } if err != nil && !(options.Ignore && errors.Is(err, define.ErrNoSuchCtr)) { // Failed to get containers. If force is specified, get the containers ID // and evict them @@ -391,7 +400,10 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, for _, ctr := range names { logrus.Debugf("Evicting container %q", ctr) - report := reports.RmReport{Id: ctr} + report := reports.RmReport{ + Id: ctr, + RawInput: idToRawInput[ctr], + } _, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes) if err != nil { if options.Ignore && errors.Is(err, define.ErrNoSuchCtr) { @@ -461,6 +473,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, report := new(reports.RmReport) report.Id = ctr.ID() report.Err = err + report.RawInput = idToRawInput[ctr.ID()] rmReports = append(rmReports, report) } return rmReports, nil diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 98c73c51a..225aee017 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -61,9 +61,9 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri if err != nil { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} for i := range ctrs { - ctrMap[ctrs[i].ID] = rawInputs[i] + idToRawInput[ctrs[i].ID] = rawInputs[i] } reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) for _, c := range ctrs { @@ -75,7 +75,7 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri reports = append(reports, &entities.PauseUnpauseReport{ Id: c.ID, Err: err, - RawInput: ctrMap[c.ID], + RawInput: idToRawInput[c.ID], }) } return reports, nil @@ -86,9 +86,9 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st if err != nil { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} for i := range ctrs { - ctrMap[ctrs[i].ID] = rawInputs[i] + idToRawInput[ctrs[i].ID] = rawInputs[i] } reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) for _, c := range ctrs { @@ -100,7 +100,7 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st reports = append(reports, &entities.PauseUnpauseReport{ Id: c.ID, Err: err, - RawInput: ctrMap[c.ID], + RawInput: idToRawInput[c.ID], }) } return reports, nil @@ -111,9 +111,9 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin if err != nil { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} for i := range ctrs { - ctrMap[ctrs[i].ID] = rawInputs[i] + idToRawInput[ctrs[i].ID] = rawInputs[i] } options := new(containers.StopOptions).WithIgnore(opts.Ignore) if to := opts.Timeout; to != nil { @@ -123,7 +123,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin for _, c := range ctrs { report := entities.StopReport{ Id: c.ID, - RawInput: ctrMap[c.ID], + RawInput: idToRawInput[c.ID], } if err = containers.Stop(ic.ClientCtx, c.ID, options); err != nil { // These first two are considered non-fatal under the right conditions @@ -154,9 +154,9 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin if err != nil { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} for i := range ctrs { - ctrMap[ctrs[i].ID] = rawInputs[i] + idToRawInput[ctrs[i].ID] = rawInputs[i] } options := new(containers.KillOptions).WithSignal(opts.Signal) reports := make([]*entities.KillReport, 0, len(ctrs)) @@ -169,7 +169,7 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin reports = append(reports, &entities.KillReport{ Id: c.ID, Err: err, - RawInput: ctrMap[c.ID], + RawInput: idToRawInput[c.ID], }) } return reports, nil @@ -208,11 +208,18 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, toRemove := []string{} alreadyRemoved := make(map[string]bool) // Avoids trying to remove already removed containers - if opts.All { - ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, nil) + idToRawInput := map[string]string{} + + if opts.All || len(opts.Filters) > 0 { + ctrs, rawInputs, err := getContainersAndInputByContext(ic.ClientCtx, opts.All, opts.Ignore, nil, opts.Filters) if err != nil { return nil, err } + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID] = rawInputs[i] + } + } for _, c := range ctrs { toRemove = append(toRemove, c.ID) } @@ -225,10 +232,15 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, // instead of the ID. Since this can only happen // with external containers, it poses no threat // to the `alreadyRemoved` checks below. - ctrs, err := getContainersByContext(ic.ClientCtx, false, true, []string{ctr}) + ctrs, rawInputs, err := getContainersAndInputByContext(ic.ClientCtx, false, true, []string{ctr}, opts.Filters) if err != nil { return nil, err } + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID] = rawInputs[i] + } + } id := ctr if len(ctrs) == 1 { id = ctrs[0].ID @@ -238,13 +250,20 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, } rmReports := make([]*reports.RmReport, 0, len(toRemove)) - for _, nameOrID := range toRemove { - if alreadyRemoved[nameOrID] { + for _, rmCtr := range toRemove { + if alreadyRemoved[rmCtr] { continue } - newReports, err := containers.Remove(ic.ClientCtx, nameOrID, options) + if ctr, exist := idToRawInput[rmCtr]; exist { + rmCtr = ctr + } + newReports, err := containers.Remove(ic.ClientCtx, rmCtr, options) if err != nil { - rmReports = append(rmReports, &reports.RmReport{Id: nameOrID, Err: err}) + rmReports = append(rmReports, &reports.RmReport{ + Id: rmCtr, + Err: err, + RawInput: idToRawInput[rmCtr], + }) continue } for i := range newReports { diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go index 9ff1641f0..a0b01dd71 100644 --- a/pkg/domain/infra/tunnel/helpers.go +++ b/pkg/domain/infra/tunnel/helpers.go @@ -14,7 +14,7 @@ import ( // FIXME: the `ignore` parameter is very likely wrong here as it should rather // be used on *errors* from operations such as remove. -func getContainersByContext(contextWithConnection context.Context, all, ignore bool, namesOrIDs []string) ([]entities.ListContainer, error) { +func getContainersByContext(contextWithConnection context.Context, all, ignore bool, namesOrIDs []string) ([]entities.ListContainer, error) { //nolint:unparam ctrs, _, err := getContainersAndInputByContext(contextWithConnection, all, ignore, namesOrIDs, nil) return ctrs, err } diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go index 7dbe5fed8..e76451824 100644 --- a/test/e2e/rm_test.go +++ b/test/e2e/rm_test.go @@ -1,6 +1,7 @@ package integration import ( + "fmt" "io/ioutil" "os" @@ -51,6 +52,7 @@ var _ = Describe("Podman rm", func() { result := podmanTest.Podman([]string{"rm", cid}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(2)) + Expect(result.ErrorToString()).To(ContainSubstring("containers cannot be removed without force")) }) It("podman rm created container", func() { @@ -140,11 +142,9 @@ var _ = Describe("Podman rm", func() { output := result.OutputToString() Expect(output).To(ContainSubstring(cid)) Expect(podmanTest.NumberOfContainers()).To(Equal(1)) - }) It("podman rm --cidfile", func() { - tmpDir, err := ioutil.TempDir("", "") Expect(err).To(BeNil()) tmpFile := tmpDir + "cid" @@ -166,7 +166,6 @@ var _ = Describe("Podman rm", func() { }) It("podman rm multiple --cidfile", func() { - tmpDir, err := ioutil.TempDir("", "") Expect(err).To(BeNil()) tmpFile1 := tmpDir + "cid-1" @@ -201,18 +200,22 @@ var _ = Describe("Podman rm", func() { result := podmanTest.Podman([]string{"rm", "--cidfile", "foobar", "--latest"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(125)) + Expect(result.ErrorToString()).To(ContainSubstring("--all, --latest, and --cidfile cannot be used together")) result = podmanTest.Podman([]string{"rm", "--cidfile", "foobar", "--all"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(125)) + Expect(result.ErrorToString()).To(ContainSubstring("--all, --latest, and --cidfile cannot be used together")) result = podmanTest.Podman([]string{"rm", "--cidfile", "foobar", "--all", "--latest"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(125)) + Expect(result.ErrorToString()).To(ContainSubstring("--all, --latest, and --cidfile cannot be used together")) result = podmanTest.Podman([]string{"rm", "--latest", "--all"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(125)) + Expect(result.ErrorToString()).To(ContainSubstring("--all and --latest cannot be used together")) }) It("podman rm --all", func() { @@ -242,10 +245,17 @@ var _ = Describe("Podman rm", func() { session = podmanTest.Podman([]string{"rm", "bogus", cid}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(1)) + Expect(session.ErrorToString()).To(ContainSubstring("\"bogus\" found: no such container")) + if IsRemote() { + Expect(session.OutputToString()).To(BeEquivalentTo(cid)) + } session = podmanTest.Podman([]string{"rm", "--ignore", "bogus", cid}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) + if !IsRemote() { + Expect(session.OutputToString()).To(BeEquivalentTo(cid)) + } Expect(podmanTest.NumberOfContainers()).To(Equal(0)) }) @@ -253,6 +263,7 @@ var _ = Describe("Podman rm", func() { session := podmanTest.Podman([]string{"rm", "bogus"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(1)) + Expect(session.ErrorToString()).To(ContainSubstring("\"bogus\" found: no such container")) }) It("podman rm bogus container and a running container", func() { @@ -263,10 +274,12 @@ var _ = Describe("Podman rm", func() { session = podmanTest.Podman([]string{"rm", "bogus", "test1"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(1)) + Expect(session.ErrorToString()).To(ContainSubstring("\"bogus\" found: no such container")) session = podmanTest.Podman([]string{"rm", "test1", "bogus"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(1)) + Expect(session.ErrorToString()).To(ContainSubstring("\"bogus\" found: no such container")) }) It("podman rm --ignore bogus container and a running container", func() { @@ -274,12 +287,52 @@ var _ = Describe("Podman rm", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - session = podmanTest.Podman([]string{"rm", "-t", "0", "--force", "--ignore", "bogus", "test1"}) + session = podmanTest.Podman([]string{"rm", "--ignore", "test1", "bogus"}) session.WaitWithDefaultTimeout() - Expect(session).Should(Exit(0)) + Expect(session).Should(Exit(2)) + Expect(session.ErrorToString()).To(ContainSubstring("containers cannot be removed without force")) - session = podmanTest.Podman([]string{"rm", "--ignore", "test1", "bogus"}) + session = podmanTest.Podman([]string{"rm", "-t", "0", "--force", "--ignore", "bogus", "test1"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(BeEquivalentTo("test1")) + }) + + It("podman rm --filter", func() { + session1 := podmanTest.RunTopContainer("test1") + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + cid1 := session1.OutputToString() + + session1 = podmanTest.RunTopContainer("test2") + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + cid2 := session1.OutputToString() + + session1 = podmanTest.RunTopContainer("test3") + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + cid3 := session1.OutputToString() + shortCid3 := cid3[0:5] + + session1 = podmanTest.Podman([]string{"rm", cid1, "-f", "--filter", "status=running"}) + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(125)) + Expect(session1.ErrorToString()).To(ContainSubstring("--filter takes no arguments")) + + session1 = podmanTest.Podman([]string{"rm", "-a", "-f", "--filter", fmt.Sprintf("id=%swrongid", shortCid3)}) + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + Expect(session1.OutputToString()).To(HaveLen(0)) + + session1 = podmanTest.Podman([]string{"rm", "-a", "-f", "--filter", fmt.Sprintf("id=%s", shortCid3)}) + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + Expect(session1.OutputToString()).To(BeEquivalentTo(cid3)) + + session1 = podmanTest.Podman([]string{"rm", "-f", "--filter", fmt.Sprintf("id=%s", cid2)}) + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + Expect(session1.OutputToString()).To(BeEquivalentTo(cid2)) }) }) diff --git a/test/system/055-rm.bats b/test/system/055-rm.bats index dcd679a1f..613c60c96 100644 --- a/test/system/055-rm.bats +++ b/test/system/055-rm.bats @@ -18,6 +18,7 @@ load helpers # Remove container; now 'inspect' should fail run_podman rm $rand + is "$output" "$rand" "display raw input" run_podman 125 inspect $rand } diff --git a/test/upgrade/test-upgrade.bats b/test/upgrade/test-upgrade.bats index 5efe05d49..dca97e324 100644 --- a/test/upgrade/test-upgrade.bats +++ b/test/upgrade/test-upgrade.bats @@ -345,10 +345,10 @@ failed | exited | 17 @test "rm a stopped container" { run_podman rm myfailedcontainer - is "$output" "[0-9a-f]\\{64\\}" "podman rm myfailedcontainer" + is "$output" "myfailedcontainer" "podman rm myfailedcontainer" run_podman rm mydonecontainer - is "$output" "[0-9a-f]\\{64\\}" "podman rm mydonecontainer" + is "$output" "mydonecontainer" "podman rm mydonecontainer" } |