Add rm --filter option

--filter : remove the filtered container.

Signed-off-by: Toshiki Sonoda <sonoda.toshiki@fujitsu.com>
This commit is contained in:
Toshiki Sonoda 2022-07-30 09:28:22 +09:00
parent fed326d8a6
commit 53ec479685
13 changed files with 186 additions and 58 deletions

View File

@ -50,6 +50,7 @@ var (
var ( var (
killOptions = entities.KillOptions{} killOptions = entities.KillOptions{}
killCidFiles = []string{}
) )
func killFlags(cmd *cobra.Command) { 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") flags.StringVarP(&killOptions.Signal, signalFlagName, "s", "KILL", "Signal to send to the container")
_ = cmd.RegisterFlagCompletionFunc(signalFlagName, common.AutocompleteStopSignal) _ = cmd.RegisterFlagCompletionFunc(signalFlagName, common.AutocompleteStopSignal)
cidfileFlagName := "cidfile" 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) _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
} }
@ -94,7 +95,7 @@ func kill(_ *cobra.Command, args []string) error {
if sig < 1 || sig > 64 { if sig < 1 || sig > 64 {
return errors.New("valid signals are 1 through 64") return errors.New("valid signals are 1 through 64")
} }
for _, cidFile := range cidFiles { for _, cidFile := range killCidFiles {
content, err := ioutil.ReadFile(cidFile) content, err := ioutil.ReadFile(cidFile)
if err != nil { if err != nil {
return fmt.Errorf("error reading CIDFile: %w", err) return fmt.Errorf("error reading CIDFile: %w", err)

View File

@ -52,8 +52,10 @@ var (
) )
var ( var (
rmOptions = entities.RmOptions{} rmOptions = entities.RmOptions{
cidFiles = []string{} Filters: make(map[string][]string),
}
rmCidFiles = []string{}
) )
func rmFlags(cmd *cobra.Command) { 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") flags.BoolVarP(&rmOptions.Volumes, "volumes", "v", false, "Remove anonymous volumes associated with the container")
cidfileFlagName := "cidfile" 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) _ = 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() { if !registry.IsRemote() {
// This option is deprecated, but needs to still exists for backwards compatibility // This option is deprecated, but needs to still exists for backwards compatibility
flags.Bool("storage", false, "Remove container from storage library") flags.Bool("storage", false, "Remove container from storage library")
@ -101,7 +107,7 @@ func rm(cmd *cobra.Command, args []string) error {
} }
rmOptions.Timeout = &stopTimeout rmOptions.Timeout = &stopTimeout
} }
for _, cidFile := range cidFiles { for _, cidFile := range rmCidFiles {
content, err := ioutil.ReadFile(cidFile) content, err := ioutil.ReadFile(cidFile)
if err != nil { if err != nil {
return fmt.Errorf("error reading CIDFile: %w", err) return fmt.Errorf("error reading CIDFile: %w", err)
@ -110,6 +116,14 @@ func rm(cmd *cobra.Command, args []string) error {
args = append(args, id) 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 { if rmOptions.All {
logrus.Debug("--all is set: enforcing --depend=true") logrus.Debug("--all is set: enforcing --depend=true")
rmOptions.Depend = true rmOptions.Depend = true
@ -147,7 +161,7 @@ func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit
} }
errs = append(errs, r.Err) errs = append(errs, r.Err)
} else { } else {
fmt.Println(r.Id) fmt.Println(r.RawInput)
} }
} }
return errs.PrintErrors() return errs.PrintErrors()

View File

@ -52,6 +52,7 @@ var (
stopOptions = entities.StopOptions{ stopOptions = entities.StopOptions{
Filters: make(map[string][]string), Filters: make(map[string][]string),
} }
stopCidFiles = []string{}
stopTimeout uint stopTimeout uint
) )
@ -62,7 +63,7 @@ func stopFlags(cmd *cobra.Command) {
flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing") flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing")
cidfileFlagName := "cidfile" 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) _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
timeFlagName := "time" timeFlagName := "time"
@ -103,7 +104,7 @@ func stop(cmd *cobra.Command, args []string) error {
if cmd.Flag("time").Changed { if cmd.Flag("time").Changed {
stopOptions.Timeout = &stopTimeout stopOptions.Timeout = &stopTimeout
} }
for _, cidFile := range cidFiles { for _, cidFile := range stopCidFiles {
content, err := ioutil.ReadFile(cidFile) content, err := ioutil.ReadFile(cidFile)
if err != nil { if err != nil {
return fmt.Errorf("error reading CIDFile: %w", err) return fmt.Errorf("error reading CIDFile: %w", err)

View File

@ -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. 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**, **-f**
Force the removal of running and paused containers. Forcing a container removal also Force the removal of running and paused containers. Forcing a container removal also

View File

@ -995,7 +995,7 @@ func (r *Runtime) RemoveDepend(ctx context.Context, rmCtr *Container, force bool
return nil, err return nil, err
} }
for _, cID := range podContainerIDS { for _, cID := range podContainerIDS {
rmReports = append(rmReports, &reports.RmReport{Id: cID}) rmReports = append(rmReports, &reports.RmReport{Id: cID, RawInput: cID})
} }
return rmReports, nil return rmReports, nil
} }
@ -1023,7 +1023,7 @@ func (r *Runtime) RemoveDepend(ctx context.Context, rmCtr *Container, force bool
rmReports = append(rmReports, reports...) 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) report.Err = r.removeContainer(ctx, rmCtr, force, removeVolume, false, timeout)
return append(rmReports, &report), nil return append(rmReports, &report), nil
} }

View File

@ -131,6 +131,7 @@ type RestartReport struct {
} }
type RmOptions struct { type RmOptions struct {
Filters map[string][]string
All bool All bool
Depend bool Depend bool
Force bool Force bool

View File

@ -3,6 +3,7 @@ package reports
type RmReport struct { type RmReport struct {
Id string `json:"Id"` //nolint:revive,stylecheck Id string `json:"Id"` //nolint:revive,stylecheck
Err error `json:"Err,omitempty"` Err error `json:"Err,omitempty"`
RawInput string
} }
func RmReportsIds(r []*RmReport) []string { func RmReportsIds(r []*RmReport) []string {

View File

@ -142,10 +142,10 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri
if err != nil { if err != nil {
return nil, err return nil, err
} }
ctrMap := map[string]string{} idToRawInput := map[string]string{}
if len(rawInputs) == len(ctrs) { if len(rawInputs) == len(ctrs) {
for i := range ctrs { for i := range ctrs {
ctrMap[ctrs[i].ID()] = rawInputs[i] idToRawInput[ctrs[i].ID()] = rawInputs[i]
} }
} }
reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) 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{ reports = append(reports, &entities.PauseUnpauseReport{
Id: c.ID(), Id: c.ID(),
Err: err, Err: err,
RawInput: ctrMap[c.ID()], RawInput: idToRawInput[c.ID()],
}) })
} }
return reports, nil return reports, nil
@ -169,10 +169,10 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st
if err != nil { if err != nil {
return nil, err return nil, err
} }
ctrMap := map[string]string{} idToRawInput := map[string]string{}
if len(rawInputs) == len(ctrs) { if len(rawInputs) == len(ctrs) {
for i := range ctrs { for i := range ctrs {
ctrMap[ctrs[i].ID()] = rawInputs[i] idToRawInput[ctrs[i].ID()] = rawInputs[i]
} }
} }
reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) 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{ reports = append(reports, &entities.PauseUnpauseReport{
Id: c.ID(), Id: c.ID(),
Err: err, Err: err,
RawInput: ctrMap[c.ID()], RawInput: idToRawInput[c.ID()],
}) })
} }
return reports, nil 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)) { if err != nil && !(options.Ignore && errors.Is(err, define.ErrNoSuchCtr)) {
return nil, err return nil, err
} }
ctrMap := map[string]string{} idToRawInput := map[string]string{}
if len(rawInputs) == len(ctrs) { if len(rawInputs) == len(ctrs) {
for i := range 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 { 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 { if options.All {
report.RawInput = ctr.ID() report.RawInput = ctr.ID()
} else { } else {
report.RawInput = ctrMap[ctr.ID()] report.RawInput = idToRawInput[ctr.ID()]
} }
report.Err = err report.Err = err
reports = append(reports, report) reports = append(reports, report)
@ -275,10 +275,10 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin
if err != nil { if err != nil {
return nil, err return nil, err
} }
ctrMap := map[string]string{} idToRawInput := map[string]string{}
if len(rawInputs) == len(ctrs) { if len(rawInputs) == len(ctrs) {
for i := range ctrs { for i := range ctrs {
ctrMap[ctrs[i].ID()] = rawInputs[i] idToRawInput[ctrs[i].ID()] = rawInputs[i]
} }
} }
reports := make([]*entities.KillReport, 0, len(ctrs)) 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{ reports = append(reports, &entities.KillReport{
Id: con.ID(), Id: con.ID(),
Err: err, Err: err,
RawInput: ctrMap[con.ID()], RawInput: idToRawInput[con.ID()],
}) })
} }
return reports, nil 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.` // this will fail and code will fall through to removing the container from libpod.`
tmpNames := []string{} tmpNames := []string{}
for _, ctr := range names { for _, ctr := range names {
report := reports.RmReport{Id: ctr} report := reports.RmReport{Id: ctr, RawInput: ctr}
report.Err = ic.Libpod.RemoveStorageContainer(ctr, options.Force) report.Err = ic.Libpod.RemoveStorageContainer(ctr, options.Force)
//nolint:gocritic //nolint:gocritic
if report.Err == nil { if report.Err == nil {
@ -381,7 +381,16 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
} }
names = tmpNames 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)) { if err != nil && !(options.Ignore && errors.Is(err, define.ErrNoSuchCtr)) {
// Failed to get containers. If force is specified, get the containers ID // Failed to get containers. If force is specified, get the containers ID
// and evict them // and evict them
@ -391,7 +400,10 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
for _, ctr := range names { for _, ctr := range names {
logrus.Debugf("Evicting container %q", ctr) 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) _, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes)
if err != nil { if err != nil {
if options.Ignore && errors.Is(err, define.ErrNoSuchCtr) { 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 := new(reports.RmReport)
report.Id = ctr.ID() report.Id = ctr.ID()
report.Err = err report.Err = err
report.RawInput = idToRawInput[ctr.ID()]
rmReports = append(rmReports, report) rmReports = append(rmReports, report)
} }
return rmReports, nil return rmReports, nil

View File

@ -61,9 +61,9 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri
if err != nil { if err != nil {
return nil, err return nil, err
} }
ctrMap := map[string]string{} idToRawInput := map[string]string{}
for i := range ctrs { for i := range ctrs {
ctrMap[ctrs[i].ID] = rawInputs[i] idToRawInput[ctrs[i].ID] = rawInputs[i]
} }
reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs { for _, c := range ctrs {
@ -75,7 +75,7 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri
reports = append(reports, &entities.PauseUnpauseReport{ reports = append(reports, &entities.PauseUnpauseReport{
Id: c.ID, Id: c.ID,
Err: err, Err: err,
RawInput: ctrMap[c.ID], RawInput: idToRawInput[c.ID],
}) })
} }
return reports, nil return reports, nil
@ -86,9 +86,9 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st
if err != nil { if err != nil {
return nil, err return nil, err
} }
ctrMap := map[string]string{} idToRawInput := map[string]string{}
for i := range ctrs { for i := range ctrs {
ctrMap[ctrs[i].ID] = rawInputs[i] idToRawInput[ctrs[i].ID] = rawInputs[i]
} }
reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs { for _, c := range ctrs {
@ -100,7 +100,7 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st
reports = append(reports, &entities.PauseUnpauseReport{ reports = append(reports, &entities.PauseUnpauseReport{
Id: c.ID, Id: c.ID,
Err: err, Err: err,
RawInput: ctrMap[c.ID], RawInput: idToRawInput[c.ID],
}) })
} }
return reports, nil return reports, nil
@ -111,9 +111,9 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
if err != nil { if err != nil {
return nil, err return nil, err
} }
ctrMap := map[string]string{} idToRawInput := map[string]string{}
for i := range ctrs { for i := range ctrs {
ctrMap[ctrs[i].ID] = rawInputs[i] idToRawInput[ctrs[i].ID] = rawInputs[i]
} }
options := new(containers.StopOptions).WithIgnore(opts.Ignore) options := new(containers.StopOptions).WithIgnore(opts.Ignore)
if to := opts.Timeout; to != nil { if to := opts.Timeout; to != nil {
@ -123,7 +123,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
for _, c := range ctrs { for _, c := range ctrs {
report := entities.StopReport{ report := entities.StopReport{
Id: c.ID, Id: c.ID,
RawInput: ctrMap[c.ID], RawInput: idToRawInput[c.ID],
} }
if err = containers.Stop(ic.ClientCtx, c.ID, options); err != nil { if err = containers.Stop(ic.ClientCtx, c.ID, options); err != nil {
// These first two are considered non-fatal under the right conditions // 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 { if err != nil {
return nil, err return nil, err
} }
ctrMap := map[string]string{} idToRawInput := map[string]string{}
for i := range ctrs { for i := range ctrs {
ctrMap[ctrs[i].ID] = rawInputs[i] idToRawInput[ctrs[i].ID] = rawInputs[i]
} }
options := new(containers.KillOptions).WithSignal(opts.Signal) options := new(containers.KillOptions).WithSignal(opts.Signal)
reports := make([]*entities.KillReport, 0, len(ctrs)) 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{ reports = append(reports, &entities.KillReport{
Id: c.ID, Id: c.ID,
Err: err, Err: err,
RawInput: ctrMap[c.ID], RawInput: idToRawInput[c.ID],
}) })
} }
return reports, nil return reports, nil
@ -208,11 +208,18 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
toRemove := []string{} toRemove := []string{}
alreadyRemoved := make(map[string]bool) // Avoids trying to remove already removed containers alreadyRemoved := make(map[string]bool) // Avoids trying to remove already removed containers
if opts.All { idToRawInput := map[string]string{}
ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, nil)
if opts.All || len(opts.Filters) > 0 {
ctrs, rawInputs, err := getContainersAndInputByContext(ic.ClientCtx, opts.All, opts.Ignore, nil, opts.Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(rawInputs) == len(ctrs) {
for i := range ctrs {
idToRawInput[ctrs[i].ID] = rawInputs[i]
}
}
for _, c := range ctrs { for _, c := range ctrs {
toRemove = append(toRemove, c.ID) 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 // instead of the ID. Since this can only happen
// with external containers, it poses no threat // with external containers, it poses no threat
// to the `alreadyRemoved` checks below. // 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 { if err != nil {
return nil, err return nil, err
} }
if len(rawInputs) == len(ctrs) {
for i := range ctrs {
idToRawInput[ctrs[i].ID] = rawInputs[i]
}
}
id := ctr id := ctr
if len(ctrs) == 1 { if len(ctrs) == 1 {
id = ctrs[0].ID id = ctrs[0].ID
@ -238,13 +250,20 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
} }
rmReports := make([]*reports.RmReport, 0, len(toRemove)) rmReports := make([]*reports.RmReport, 0, len(toRemove))
for _, nameOrID := range toRemove { for _, rmCtr := range toRemove {
if alreadyRemoved[nameOrID] { if alreadyRemoved[rmCtr] {
continue 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 { 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 continue
} }
for i := range newReports { for i := range newReports {

View File

@ -14,7 +14,7 @@ import (
// FIXME: the `ignore` parameter is very likely wrong here as it should rather // FIXME: the `ignore` parameter is very likely wrong here as it should rather
// be used on *errors* from operations such as remove. // 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) ctrs, _, err := getContainersAndInputByContext(contextWithConnection, all, ignore, namesOrIDs, nil)
return ctrs, err return ctrs, err
} }

View File

@ -1,6 +1,7 @@
package integration package integration
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@ -51,6 +52,7 @@ var _ = Describe("Podman rm", func() {
result := podmanTest.Podman([]string{"rm", cid}) result := podmanTest.Podman([]string{"rm", cid})
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(2)) Expect(result).Should(Exit(2))
Expect(result.ErrorToString()).To(ContainSubstring("containers cannot be removed without force"))
}) })
It("podman rm created container", func() { It("podman rm created container", func() {
@ -140,11 +142,9 @@ var _ = Describe("Podman rm", func() {
output := result.OutputToString() output := result.OutputToString()
Expect(output).To(ContainSubstring(cid)) Expect(output).To(ContainSubstring(cid))
Expect(podmanTest.NumberOfContainers()).To(Equal(1)) Expect(podmanTest.NumberOfContainers()).To(Equal(1))
}) })
It("podman rm --cidfile", func() { It("podman rm --cidfile", func() {
tmpDir, err := ioutil.TempDir("", "") tmpDir, err := ioutil.TempDir("", "")
Expect(err).To(BeNil()) Expect(err).To(BeNil())
tmpFile := tmpDir + "cid" tmpFile := tmpDir + "cid"
@ -166,7 +166,6 @@ var _ = Describe("Podman rm", func() {
}) })
It("podman rm multiple --cidfile", func() { It("podman rm multiple --cidfile", func() {
tmpDir, err := ioutil.TempDir("", "") tmpDir, err := ioutil.TempDir("", "")
Expect(err).To(BeNil()) Expect(err).To(BeNil())
tmpFile1 := tmpDir + "cid-1" tmpFile1 := tmpDir + "cid-1"
@ -201,18 +200,22 @@ var _ = Describe("Podman rm", func() {
result := podmanTest.Podman([]string{"rm", "--cidfile", "foobar", "--latest"}) result := podmanTest.Podman([]string{"rm", "--cidfile", "foobar", "--latest"})
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(125)) 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 = podmanTest.Podman([]string{"rm", "--cidfile", "foobar", "--all"})
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(125)) 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 = podmanTest.Podman([]string{"rm", "--cidfile", "foobar", "--all", "--latest"})
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(125)) 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 = podmanTest.Podman([]string{"rm", "--latest", "--all"})
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(125)) Expect(result).Should(Exit(125))
Expect(result.ErrorToString()).To(ContainSubstring("--all and --latest cannot be used together"))
}) })
It("podman rm --all", func() { It("podman rm --all", func() {
@ -242,10 +245,17 @@ var _ = Describe("Podman rm", func() {
session = podmanTest.Podman([]string{"rm", "bogus", cid}) session = podmanTest.Podman([]string{"rm", "bogus", cid})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(1)) 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 = podmanTest.Podman([]string{"rm", "--ignore", "bogus", cid})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0)) Expect(session).Should(Exit(0))
if !IsRemote() {
Expect(session.OutputToString()).To(BeEquivalentTo(cid))
}
Expect(podmanTest.NumberOfContainers()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0))
}) })
@ -253,6 +263,7 @@ var _ = Describe("Podman rm", func() {
session := podmanTest.Podman([]string{"rm", "bogus"}) session := podmanTest.Podman([]string{"rm", "bogus"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(1)) 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() { 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 = podmanTest.Podman([]string{"rm", "bogus", "test1"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(1)) Expect(session).Should(Exit(1))
Expect(session.ErrorToString()).To(ContainSubstring("\"bogus\" found: no such container"))
session = podmanTest.Podman([]string{"rm", "test1", "bogus"}) session = podmanTest.Podman([]string{"rm", "test1", "bogus"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(1)) 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() { It("podman rm --ignore bogus container and a running container", func() {
@ -274,12 +287,52 @@ var _ = Describe("Podman rm", func() {
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0)) Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"rm", "--ignore", "test1", "bogus"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(2))
Expect(session.ErrorToString()).To(ContainSubstring("containers cannot be removed without force"))
session = podmanTest.Podman([]string{"rm", "-t", "0", "--force", "--ignore", "bogus", "test1"}) session = podmanTest.Podman([]string{"rm", "-t", "0", "--force", "--ignore", "bogus", "test1"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0)) Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(BeEquivalentTo("test1"))
})
session = podmanTest.Podman([]string{"rm", "--ignore", "test1", "bogus"}) It("podman rm --filter", func() {
session.WaitWithDefaultTimeout() session1 := podmanTest.RunTopContainer("test1")
Expect(session).Should(Exit(0)) 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))
}) })
}) })

View File

@ -18,6 +18,7 @@ load helpers
# Remove container; now 'inspect' should fail # Remove container; now 'inspect' should fail
run_podman rm $rand run_podman rm $rand
is "$output" "$rand" "display raw input"
run_podman 125 inspect $rand run_podman 125 inspect $rand
} }

View File

@ -345,10 +345,10 @@ failed | exited | 17
@test "rm a stopped container" { @test "rm a stopped container" {
run_podman rm myfailedcontainer run_podman rm myfailedcontainer
is "$output" "[0-9a-f]\\{64\\}" "podman rm myfailedcontainer" is "$output" "myfailedcontainer" "podman rm myfailedcontainer"
run_podman rm mydonecontainer run_podman rm mydonecontainer
is "$output" "[0-9a-f]\\{64\\}" "podman rm mydonecontainer" is "$output" "mydonecontainer" "podman rm mydonecontainer"
} }