diff options
author | Matej Vasek <mvasek@redhat.com> | 2021-05-07 22:35:20 +0200 |
---|---|---|
committer | Matej Vasek <mvasek@redhat.com> | 2021-05-10 13:40:06 +0200 |
commit | 66e38ca55d9a0079eb7d317b5a70c2623fc90d20 (patch) | |
tree | 3ea45c42923ca1954d9e8e01297c75114a0f4d4c | |
parent | 0ce6a65b3961465593470c3457d75b0a846c8d98 (diff) | |
download | podman-66e38ca55d9a0079eb7d317b5a70c2623fc90d20.tar.gz podman-66e38ca55d9a0079eb7d317b5a70c2623fc90d20.tar.bz2 podman-66e38ca55d9a0079eb7d317b5a70c2623fc90d20.zip |
fix: improved "containers/{name}/wait" endpoint
Using event API to detect changes to container instead of polling.
Polling was unreliable, sometime change of a state might have been
missed.
Signed-off-by: Matej Vasek <mvasek@redhat.com>
-rw-r--r-- | pkg/api/handlers/utils/containers.go | 35 | ||||
-rw-r--r-- | test/apiv2/26-containersWait.at | 2 |
2 files changed, 29 insertions, 8 deletions
diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go index c4c9cc2ea..6c708f74e 100644 --- a/pkg/api/handlers/utils/containers.go +++ b/pkg/api/handlers/utils/containers.go @@ -7,6 +7,7 @@ import ( "strconv" "time" + "github.com/containers/podman/v3/libpod/events" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/infra/abi" @@ -175,7 +176,7 @@ func waitDockerCondition(ctx context.Context, containerName string, interval tim var code int32 switch dockerCondition { case "next-exit": - code, err = waitNextExit(containerWait) + code, err = waitNextExit(ctx, containerName) case "removed": code, err = waitRemoved(containerWait) case "not-running", "": @@ -202,12 +203,32 @@ func waitRemoved(ctrWait containerWaitFn) (int32, error) { return code, err } -func waitNextExit(ctrWait containerWaitFn) (int32, error) { - _, err := ctrWait(define.ContainerStateRunning) - if err != nil { - return -1, err - } - return ctrWait(notRunningStates...) +func waitNextExit(ctx context.Context, containerName string) (int32, error) { + runtime := ctx.Value("runtime").(*libpod.Runtime) + containerEngine := &abi.ContainerEngine{Libpod: runtime} + eventChannel := make(chan *events.Event) + errChannel := make(chan error) + opts := entities.EventsOptions{ + EventChan: eventChannel, + Filter: []string{"event=died", fmt.Sprintf("container=%s", containerName)}, + Stream: true, + } + + // ctx is used to cancel event watching goroutine + ctx, cancel := context.WithCancel(ctx) + defer cancel() + go func() { + errChannel <- containerEngine.Events(ctx, opts) + }() + + evt, ok := <-eventChannel + if ok { + return int32(evt.ContainerExitCode), nil + } + // if ok == false then containerEngine.Events() has exited + // it may happen if request was canceled (e.g. client closed connection prematurely) or + // the server is in process of shutting down + return -1, <-errChannel } func waitNotRunning(ctrWait containerWaitFn) (int32, error) { diff --git a/test/apiv2/26-containersWait.at b/test/apiv2/26-containersWait.at index 6a628e55a..ec16c35df 100644 --- a/test/apiv2/26-containersWait.at +++ b/test/apiv2/26-containersWait.at @@ -15,7 +15,7 @@ CTR="WaitTestingCtr" t POST "containers/nonExistent/wait?condition=next-exit" 404 -podman create --name "${CTR}" --entrypoint '["sleep", "0.5"]' "${IMAGE}" +podman create --name "${CTR}" --entrypoint '["true"]' "${IMAGE}" t POST "containers/${CTR}/wait?condition=non-existent-cond" 400 |