diff --git a/cmd/podman/containers/wait.go b/cmd/podman/containers/wait.go index be92a3cbeb..f34e1a18a4 100644 --- a/cmd/podman/containers/wait.go +++ b/cmd/podman/containers/wait.go @@ -53,6 +53,8 @@ func waitFlags(cmd *cobra.Command) { flags.StringVarP(&waitInterval, intervalFlagName, "i", "250ms", "Time Interval to wait before polling for completion") _ = cmd.RegisterFlagCompletionFunc(intervalFlagName, completion.AutocompleteNone) + flags.BoolVarP(&waitOptions.Ignore, "ignore", "", false, "Ignore if a container does not exist") + conditionFlagName := "condition" flags.StringSliceVar(&waitConditions, conditionFlagName, []string{}, "Condition to wait on") _ = cmd.RegisterFlagCompletionFunc(conditionFlagName, common.AutocompleteWaitCondition) diff --git a/docs/source/markdown/podman-wait.1.md.in b/docs/source/markdown/podman-wait.1.md.in index ec942401ac..79d86c4fd0 100644 --- a/docs/source/markdown/podman-wait.1.md.in +++ b/docs/source/markdown/podman-wait.1.md.in @@ -23,6 +23,10 @@ Condition to wait on (default "stopped") Print usage statement + +#### **--ignore** +Ignore errors when a specified container is missing and mark its return code as -1. + #### **--interval**, **-i**=*duration* Time interval to wait before polling for completion. A duration string is a sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". Time unit defaults to "ms". @@ -46,6 +50,9 @@ $ podman wait 860a4b23 $ podman wait mywebserver myftpserver 0 125 + +$ podman wait --ignore does-not-exist +-1 ``` ## SEE ALSO diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 6e17ddf533..2deceaa12b 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -52,11 +52,11 @@ type ContainerRunlabelReport struct{} type WaitOptions struct { Condition []define.ContainerStatus Interval time.Duration + Ignore bool Latest bool } type WaitReport struct { - Id string //nolint:revive,stylecheck Error error ExitCode int32 } diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index e4aead7fa3..46aebdb8fc 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -139,13 +139,29 @@ func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string, } func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) { - ctrs, err := getContainersByContext(false, options.Latest, false, namesOrIds, ic.Libpod) - if err != nil { - return nil, err + responses := make([]entities.WaitReport, 0, len(namesOrIds)) + if options.Latest { + ctr, err := ic.Libpod.GetLatestContainer() + if err != nil { + if options.Ignore && errors.Is(err, define.ErrNoSuchCtr) { + responses = append(responses, entities.WaitReport{ExitCode: -1}) + return responses, nil + } + return nil, err + } + namesOrIds = append(namesOrIds, ctr.ID()) } - responses := make([]entities.WaitReport, 0, len(ctrs)) - for _, c := range ctrs { - response := entities.WaitReport{Id: c.ID()} + for _, n := range namesOrIds { + c, err := ic.Libpod.LookupContainer(n) + if err != nil { + if options.Ignore && errors.Is(err, define.ErrNoSuchCtr) { + responses = append(responses, entities.WaitReport{ExitCode: -1}) + continue + } + return nil, err + } + + response := entities.WaitReport{} if options.Condition == nil { options.Condition = []define.ContainerStatus{define.ContainerStateStopped, define.ContainerStateExited} } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index e8a09a7559..2e0b47e485 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -38,17 +38,17 @@ func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string, } func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, opts entities.WaitOptions) ([]entities.WaitReport, error) { - cons, err := getContainersByContext(ic.ClientCtx, false, false, namesOrIds) - if err != nil { - return nil, err - } - responses := make([]entities.WaitReport, 0, len(cons)) + responses := make([]entities.WaitReport, 0, len(namesOrIds)) options := new(containers.WaitOptions).WithCondition(opts.Condition).WithInterval(opts.Interval.String()) - for _, c := range cons { - response := entities.WaitReport{Id: c.ID} - exitCode, err := containers.Wait(ic.ClientCtx, c.ID, options) + for _, n := range namesOrIds { + response := entities.WaitReport{} + exitCode, err := containers.Wait(ic.ClientCtx, n, options) if err != nil { - response.Error = err + if opts.Ignore && errorhandling.Contains(err, define.ErrNoSuchCtr) { + response.ExitCode = -1 + } else { + response.Error = err + } } else { response.ExitCode = exitCode } diff --git a/test/system/055-rm.bats b/test/system/055-rm.bats index 613c60c960..a555bd2b5a 100644 --- a/test/system/055-rm.bats +++ b/test/system/055-rm.bats @@ -20,6 +20,15 @@ load helpers run_podman rm $rand is "$output" "$rand" "display raw input" run_podman 125 inspect $rand + run_podman 125 wait $rand + run_podman wait --ignore $rand + is "$output" "-1" "wait --ignore will mark missing containers with -1" + + if !is_remote; then + # remote does not support the --latest flag + run_podman wait --ignore --latest + is "$output" "-1" "wait --ignore will mark missing containers with -1" + fi } @test "podman rm - running container, w/o and w/ force" {