spiegel_podman/cmd/podman/containers/wait.go
Valentin Rothberg f4d0496b54 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 <vrothberg@redhat.com>
2022-12-16 10:24:29 +01:00

117 lines
3.4 KiB
Go

package containers
import (
"context"
"errors"
"fmt"
"time"
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/cmd/podman/validate"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/spf13/cobra"
)
var (
waitDescription = `Block until one or more containers stop and then print their exit codes.
`
waitCommand = &cobra.Command{
Use: "wait [options] CONTAINER [CONTAINER...]",
Short: "Block on one or more containers",
Long: waitDescription,
RunE: wait,
ValidArgsFunction: common.AutocompleteContainers,
Example: `podman wait --interval 5s ctrID
podman wait ctrID1 ctrID2`,
}
containerWaitCommand = &cobra.Command{
Use: waitCommand.Use,
Short: waitCommand.Short,
Long: waitCommand.Long,
RunE: waitCommand.RunE,
ValidArgsFunction: waitCommand.ValidArgsFunction,
Example: `podman container wait --interval 5s ctrID
podman container wait ctrID1 ctrID2`,
}
)
var (
waitOptions = entities.WaitOptions{}
waitConditions []string
waitInterval string
)
func waitFlags(cmd *cobra.Command) {
flags := cmd.Flags()
intervalFlagName := "interval"
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)
}
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: waitCommand,
})
waitFlags(waitCommand)
validate.AddLatestFlag(waitCommand, &waitOptions.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: containerWaitCommand,
Parent: containerCmd,
})
waitFlags(containerWaitCommand)
validate.AddLatestFlag(containerWaitCommand, &waitOptions.Latest)
}
func wait(cmd *cobra.Command, args []string) error {
var (
err error
errs utils.OutputErrors
)
if waitOptions.Interval, err = time.ParseDuration(waitInterval); err != nil {
var err1 error
if waitOptions.Interval, err1 = time.ParseDuration(waitInterval + "ms"); err1 != nil {
return err
}
}
if !waitOptions.Latest && len(args) == 0 {
return fmt.Errorf("%q requires a name, id, or the \"--latest\" flag", cmd.CommandPath())
}
if waitOptions.Latest && len(args) > 0 {
return errors.New("--latest and containers cannot be used together")
}
for _, condition := range waitConditions {
cond, err := define.StringToContainerStatus(condition)
if err != nil {
return err
}
waitOptions.Condition = append(waitOptions.Condition, cond)
}
responses, err := registry.ContainerEngine().ContainerWait(context.Background(), args, waitOptions)
if err != nil {
return err
}
for _, r := range responses {
if r.Error == nil {
fmt.Println(r.ExitCode)
} else {
errs = append(errs, r.Error)
}
}
return errs.PrintErrors()
}