From f4d0496b54d8da7d685bb16fd69e8b54b3372802 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Thu, 15 Dec 2022 14:24:33 +0100 Subject: [PATCH] wait: add --ignore option In the recent past, I met the frequent need to wait for a container to exist that, at the same time, may get removed (e.g., system tests in [1]). Add an `--ignore` option to podman-wait which will ignore errors when a specified container is missing and mark its exit code as -1. Also remove ID fields from the WaitReport. It is actually not used by callers and removing it makes the code simpler and faster. Once merged, we can go over the tests and simplify them. [1] github.com/containers/podman/pull/16852 Signed-off-by: Valentin Rothberg --- cmd/podman/containers/wait.go | 2 ++ docs/source/markdown/podman-wait.1.md.in | 7 ++++++ pkg/domain/entities/containers.go | 2 +- pkg/domain/infra/abi/containers.go | 28 +++++++++++++++++++----- pkg/domain/infra/tunnel/containers.go | 18 +++++++-------- test/system/055-rm.bats | 9 ++++++++ 6 files changed, 50 insertions(+), 16 deletions(-) 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" {