-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Docker APIv2 container wait endpoint #9048
Fix Docker APIv2 container wait endpoint #9048
Conversation
bbf73df
to
ce81023
Compare
@mheon PTAL |
|
||
t POST "containers/nonExistent/wait?condition=next-exit" '' 404 | ||
|
||
podman create --name "${CTR}" --entrypoint '["sleep", "0.5"]' "${IMAGE}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wish I could have just --entrypoint '["true"]'
here, however such a container exits too fast. 😞
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
meaning the container is in running
state for such a short duration we are not capable of detecting that
pkg/api/handlers/utils/containers.go
Outdated
} | ||
|
||
func waitRemoved(ctx context.Context, con *libpod.Container, interval time.Duration) (int32, error) { | ||
code, err := con.WaitForConditionWithInterval(ctx, interval, define.ContainerStateUnknown) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I am not waiting for specific state but for an error.
@rhatdan I think this conflicts with some of the work you've been doing, and I think I prefer this version - it enables more functionality that we don't have yet. |
I disagree, I am fine with most of this, but it should all be implemented in the standard API code. We should not have three different ways of doing the same function. Too much risk of them drifting, as I have already seen with every single interface I have looked at. |
@rhatdan do you mean I should add the three new condition to the |
@rhatdan I disagree. Our API should not support the Docker-specific constants or the specifics of their operation mode. We can try and unify these but it's going to be a massive pain of conditional code |
My point being that podman-remote wait and podman wait should ultimately call into pkg/domain/infra/abi/ wait function. |
@rhatdan I don't believe the way Docker's Wait and our Wait work are compatible at this point. The handling for the custom condition codes is fundamentally different from the way our Wait code functions. |
I think that really different is |
Condition |
Note that |
I did experiment with condition variables it the shared memory as replacement for polling, but results weren't satisfactory. |
To make |
Let's get #9051 in and then rebase this on it. |
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: matejvasek, rhatdan The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
eec5e06
to
208a07a
Compare
Signed-off-by: Matej Vasek <[email protected]>
Signed-off-by: Matej Vasek <[email protected]>
f104da7
to
11ef933
Compare
Signed-off-by: Matej Vasek <[email protected]>
Signed-off-by: Matej Vasek <[email protected]>
Signed-off-by: Matej Vasek <[email protected]>
11ef933
to
2b8d6ca
Compare
@@ -176,7 +176,7 @@ type UnpauseOptions struct{} | |||
//go:generate go run ../generator/generator.go WaitOptions | |||
// WaitOptions are optional options for waiting on containers | |||
type WaitOptions struct { | |||
Condition *define.ContainerStatus | |||
Condition []define.ContainerStatus |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deliberately choose not to change this to plural for preserving some degree of compatibility.
With this, older client can call new server safely. Similarly new client can call older server, but only as long as the condition contains at most one element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand generator correctly uri param is derived just from member name. Maybe we can introduce some custom tag. So it could look like:
type WaitOptions struct {
Conditions []define.ContainerStatus `uriparam:"condition"`
Interval *string `uriparam:"interval"`
}
Meaning the name is changed, but on wire it's the same.
@@ -478,13 +479,15 @@ func (c *Container) RemoveArtifact(name string) error { | |||
} | |||
|
|||
// Wait blocks until the container exits and returns its exit code. | |||
func (c *Container) Wait() (int32, error) { | |||
return c.WaitWithInterval(DefaultWaitInterval) | |||
func (c *Container) Wait(ctx context.Context) (int32, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the wait functions cancel-able. Useful for not leaking gorutines when client cancels request (closes connection abruptly). For CLI podman it's not used since context passed here is not canceled on SIGTERM or SIGINT. CLI chooses IMO rather brutal os.Exit()
.
@@ -495,41 +498,111 @@ func (c *Container) WaitWithInterval(waitTimeout time.Duration) (int32, error) { | |||
} | |||
chWait := make(chan error, 1) | |||
|
|||
defer close(chWait) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like this could still be useful, given that ctx.Done()
is a goroutine and not guaranteed to fire at the end of the function, but rather when the entire handler returns, AFAIK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably shouldn't hurt, but also it's not necessary to close the channel here.
|
||
var wg sync.WaitGroup | ||
|
||
if waitForExit { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like both this and the len(wantedStates) > 0
below can both be active at the same time - it looks like we don't need that, though, that goroutine seems to take care of the same cases this one does. Should we only do this waitForExit
bit if the user is only waiting for Stopped
and Exited
, and return immediately after?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As of now in practice only one is active. I future they might be both active. Waiting for terminal state differs from non-terminal. For instance if user condition is [Stopped, Removing]
, both gorutines have to be active. One is waiting for Stopped
and the other one is waiting for Removing
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The len(wantedStates) > 0
gorutine is not taking care of non-terminal states.
Signed-off-by: Matej Vasek <[email protected]>
@containers/podman-maintainers PTAL |
Great work @matejvasek Thanks. |
/hold cancel |
resolves #8697
resolves #9157
context.Context
not-running
,removed
,next-exit