mirror of
https://github.com/containers/podman.git
synced 2025-09-19 00:56:15 +08:00
Fixes: #26691
Signed-off-by: Oleksandr Krutko <alexander.krutko@gmail.com>
This commit is contained in:
@ -56,6 +56,9 @@ func waitFlags(cmd *cobra.Command) {
|
||||
conditionFlagName := "condition"
|
||||
flags.StringSliceVar(&waitOptions.Conditions, conditionFlagName, []string{}, "Condition to wait on")
|
||||
_ = cmd.RegisterFlagCompletionFunc(conditionFlagName, common.AutocompleteWaitCondition)
|
||||
|
||||
waitExitFirst := "exit-first-match"
|
||||
flags.BoolVar(&waitOptions.ExitFirstMatch, waitExitFirst, false, "Wait for exit of first container which matches conditions, ignore other ones")
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -30,6 +30,9 @@ container to be fully removed. To wait for the removal of a container use
|
||||
#### **--condition**=*state*
|
||||
Container state or condition to wait for. Can be specified multiple times where at least one condition must match for the command to return. Supported values are "configured", "created", "exited", "healthy", "initialized", "paused", "removing", "running", "stopped", "stopping", "unhealthy". The default condition is "stopped".
|
||||
|
||||
#### **--exit-first-match**
|
||||
Wait for exit of first container which matches conditions, ignore other ones.
|
||||
|
||||
#### **--help**, **-h**
|
||||
|
||||
Print usage statement
|
||||
|
@ -62,6 +62,8 @@ type WaitOptions struct {
|
||||
Ignore bool
|
||||
// Use the latest created container.
|
||||
Latest bool
|
||||
// Wait for exit of first container which matches conditions, ignore other ones.
|
||||
ExitFirstMatch bool
|
||||
}
|
||||
|
||||
// WaitReport is the result of waiting a container.
|
||||
|
@ -184,6 +184,13 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if options.ExitFirstMatch {
|
||||
response := waitExitOnFirst(ctx, containers, options)
|
||||
responses = append(responses, response)
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
if c.doesNotExist { // Only set when `options.Ignore == true`
|
||||
responses = append(responses, entities.WaitReport{ExitCode: -1})
|
||||
@ -208,6 +215,43 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
func waitExitOnFirst(ctx context.Context, containers []containerWrapper, options entities.WaitOptions) entities.WaitReport {
|
||||
var waitChannel = make(chan entities.WaitReport, 1)
|
||||
var waitFunction = func(ctx context.Context, container containerWrapper, options entities.WaitOptions, waitChannel chan<- entities.WaitReport) {
|
||||
response := entities.WaitReport{}
|
||||
var conditions []string
|
||||
if len(options.Conditions) == 0 {
|
||||
conditions = []string{define.ContainerStateStopped.String(), define.ContainerStateExited.String()}
|
||||
} else {
|
||||
conditions = options.Conditions
|
||||
}
|
||||
|
||||
exitCode, err := container.WaitForConditionWithInterval(ctx, options.Interval, conditions...)
|
||||
if err != nil {
|
||||
response.Error = err
|
||||
} else {
|
||||
response.ExitCode = exitCode
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case waitChannel <- response:
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
for _, c := range containers {
|
||||
if c.doesNotExist {
|
||||
continue
|
||||
}
|
||||
go waitFunction(ctx, c, options, waitChannel)
|
||||
}
|
||||
|
||||
response := <-waitChannel
|
||||
return response
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
|
||||
containers, err := getContainers(ic.Libpod, getContainersOptions{all: options.All, latest: options.Latest, names: namesOrIds, filters: options.Filters})
|
||||
if err != nil {
|
||||
|
@ -40,6 +40,39 @@ func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string,
|
||||
func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, opts entities.WaitOptions) ([]entities.WaitReport, error) {
|
||||
responses := make([]entities.WaitReport, 0, len(namesOrIds))
|
||||
options := new(containers.WaitOptions).WithConditions(opts.Conditions).WithInterval(opts.Interval.String())
|
||||
|
||||
if opts.ExitFirstMatch {
|
||||
var waitChannel = make(chan entities.WaitReport, 1)
|
||||
var waitFunction = func(ctx context.Context, nameOrId string, options *containers.WaitOptions, waitChannel chan<- entities.WaitReport) {
|
||||
response := entities.WaitReport{}
|
||||
exitCode, err := containers.Wait(ic.ClientCtx, nameOrId, options)
|
||||
if err != nil {
|
||||
if opts.Ignore && errorhandling.Contains(err, define.ErrNoSuchCtr) {
|
||||
response.ExitCode = -1
|
||||
} else {
|
||||
response.Error = err
|
||||
}
|
||||
} else {
|
||||
response.ExitCode = exitCode
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case waitChannel <- response:
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
for _, n := range namesOrIds {
|
||||
go waitFunction(ctx, n, options, waitChannel)
|
||||
}
|
||||
|
||||
response := <-waitChannel
|
||||
responses = append(responses, response)
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
for _, n := range namesOrIds {
|
||||
response := entities.WaitReport{}
|
||||
exitCode, err := containers.Wait(ic.ClientCtx, n, options)
|
||||
|
@ -123,4 +123,16 @@ var _ = Describe("Podman wait", func() {
|
||||
Expect(session).Should(ExitCleanly())
|
||||
Expect(session.OutputToString()).To(Equal("-1"))
|
||||
})
|
||||
|
||||
It("podman wait for first return container", func() {
|
||||
session1 := podmanTest.PodmanExitCleanly("run", "-d", ALPINE, "sh", "-c", "sleep 100; exit 1")
|
||||
cid1 := session1.OutputToString()
|
||||
|
||||
session2 := podmanTest.PodmanExitCleanly("run", "-d", ALPINE, "sh", "-c", "sleep 3; exit 2")
|
||||
cid2 := session2.OutputToString()
|
||||
|
||||
waitSession := podmanTest.PodmanExitCleanly("wait", "--exit-first-match", "--condition", "exited", cid1, cid2)
|
||||
waitSession.Wait(10)
|
||||
Expect(waitSession.OutputToString()).To(Equal("2"))
|
||||
})
|
||||
})
|
||||
|
Reference in New Issue
Block a user