Skip to content

Commit

Permalink
container wait API: use string slice instead of state slice
Browse files Browse the repository at this point in the history
Massage the internal APIs to use a string slice instead of a state slice
for passing wait conditions.  This paves the way for waiting on
non-state conditions such as "healthy".

Signed-off-by: Valentin Rothberg <[email protected]>
  • Loading branch information
vrothberg committed Jun 23, 2023
1 parent 64153ac commit 8118672
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 34 deletions.
8 changes: 2 additions & 6 deletions cmd/podman/containers/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,11 @@ func execWait(ctr string, seconds int32) error {
ctx, cancel := context.WithTimeout(registry.Context(), maxDuration)
defer cancel()

cond, err := define.StringToContainerStatus("running")
if err != nil {
return err
}
waitOptions.Condition = append(waitOptions.Condition, cond)
waitOptions.Conditions = []string{define.ContainerStateRunning.String()}

startTime := time.Now()
for time.Since(startTime) < maxDuration {
_, err = registry.ContainerEngine().ContainerWait(ctx, []string{ctr}, waitOptions)
_, err := registry.ContainerEngine().ContainerWait(ctx, []string{ctr}, waitOptions)
if err == nil {
return nil
}
Expand Down
16 changes: 3 additions & 13 deletions cmd/podman/containers/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"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"
)
Expand Down Expand Up @@ -41,9 +40,8 @@ var (
)

var (
waitOptions = entities.WaitOptions{}
waitConditions []string
waitInterval string
waitOptions = entities.WaitOptions{}
waitInterval string
)

func waitFlags(cmd *cobra.Command) {
Expand All @@ -56,7 +54,7 @@ func waitFlags(cmd *cobra.Command) {
flags.BoolVarP(&waitOptions.Ignore, "ignore", "", false, "Ignore if a container does not exist")

conditionFlagName := "condition"
flags.StringSliceVar(&waitConditions, conditionFlagName, []string{}, "Condition to wait on")
flags.StringSliceVar(&waitOptions.Conditions, conditionFlagName, []string{}, "Condition to wait on")
_ = cmd.RegisterFlagCompletionFunc(conditionFlagName, common.AutocompleteWaitCondition)
}

Expand Down Expand Up @@ -95,14 +93,6 @@ func wait(cmd *cobra.Command, args []string) error {
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
Expand Down
8 changes: 6 additions & 2 deletions libpod/container_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ type waitResult struct {
err error
}

func (c *Container) WaitForConditionWithInterval(ctx context.Context, waitTimeout time.Duration, conditions ...define.ContainerStatus) (int32, error) {
func (c *Container) WaitForConditionWithInterval(ctx context.Context, waitTimeout time.Duration, conditions ...string) (int32, error) {
if !c.valid {
return -1, define.ErrCtrRemoved
}
Expand All @@ -699,7 +699,11 @@ func (c *Container) WaitForConditionWithInterval(ctx context.Context, waitTimeou
waitForExit := false
wantedStates := make(map[define.ContainerStatus]bool, len(conditions))

for _, condition := range conditions {
for _, rawCondition := range conditions {
condition, err := define.StringToContainerStatus(rawCondition)
if err != nil {
return -1, err
}
switch condition {
case define.ContainerStateExited, define.ContainerStateStopped:
waitForExit = true
Expand Down
4 changes: 2 additions & 2 deletions pkg/api/handlers/compat/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ func KillContainer(w http.ResponseWriter, r *http.Request) {
}
if sig == 0 || sig == syscall.SIGKILL {
opts := entities.WaitOptions{
Condition: []define.ContainerStatus{define.ContainerStateExited, define.ContainerStateStopped},
Interval: time.Millisecond * 250,
Conditions: []string{define.ContainerStateExited.String(), define.ContainerStateStopped.String()},
Interval: time.Millisecond * 250,
}
if _, err := containerEngine.ContainerWait(r.Context(), []string{name}, opts); err != nil {
utils.Error(w, http.StatusInternalServerError, err)
Expand Down
8 changes: 6 additions & 2 deletions pkg/api/handlers/utils/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,13 @@ func createContainerWaitFn(ctx context.Context, containerName string, interval t
var containerEngine entities.ContainerEngine = &abi.ContainerEngine{Libpod: runtime}

return func(conditions ...define.ContainerStatus) (int32, error) {
var rawConditions []string
for _, con := range conditions {
rawConditions = append(rawConditions, con.String())
}
opts := entities.WaitOptions{
Condition: conditions,
Interval: interval,
Conditions: rawConditions,
Interval: interval,
}
ctrWaitReport, err := containerEngine.ContainerWait(ctx, []string{containerName}, opts)
if err != nil {
Expand Down
20 changes: 15 additions & 5 deletions pkg/domain/entities/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,25 @@ type ContainerRunlabelOptions struct {
// ContainerRunlabelReport contains the results from executing container-runlabel.
type ContainerRunlabelReport struct{}

// WaitOptions are arguments for waiting for a container.
type WaitOptions struct {
Condition []define.ContainerStatus
Interval time.Duration
Ignore bool
Latest bool
// Conditions to wait on. Includes container statuses such as
// "running" or "stopped" and health-related values such "healthy".
Conditions []string
// Time interval to wait before polling for completion.
Interval time.Duration
// Ignore errors when a specified container is missing and mark its
// return code as -1.
Ignore bool
// Use the latest created container.
Latest bool
}

// WaitReport is the result of waiting a container.
type WaitReport struct {
Error error
// Error while waiting.
Error error
// ExitCode of the container.
ExitCode int32
}

Expand Down
9 changes: 6 additions & 3 deletions pkg/domain/infra/abi/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,13 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
}

response := entities.WaitReport{}
if options.Condition == nil {
options.Condition = []define.ContainerStatus{define.ContainerStateStopped, define.ContainerStateExited}
var conditions []string
if len(options.Conditions) == 0 {
conditions = []string{define.ContainerStateStopped.String(), define.ContainerStateExited.String()}
} else {
conditions = options.Conditions
}
exitCode, err := c.WaitForConditionWithInterval(ctx, options.Interval, options.Condition...)
exitCode, err := c.WaitForConditionWithInterval(ctx, options.Interval, conditions...)
if err != nil {
response.Error = err
} else {
Expand Down
11 changes: 10 additions & 1 deletion pkg/domain/infra/tunnel/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +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) {
conditions := make([]define.ContainerStatus, 0, len(opts.Conditions))
for _, condition := range opts.Conditions {
cond, err := define.StringToContainerStatus(condition)
if err != nil {
return nil, err
}
conditions = append(conditions, cond)
}

responses := make([]entities.WaitReport, 0, len(namesOrIds))
options := new(containers.WaitOptions).WithCondition(opts.Condition).WithInterval(opts.Interval.String())
options := new(containers.WaitOptions).WithCondition(conditions).WithInterval(opts.Interval.String())
for _, n := range namesOrIds {
response := entities.WaitReport{}
exitCode, err := containers.Wait(ic.ClientCtx, n, options)
Expand Down

0 comments on commit 8118672

Please sign in to comment.