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: cli prompt termination exit code #4888
Conversation
0bffacc
to
c532931
Compare
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## master #4888 +/- ##
==========================================
+ Coverage 61.31% 61.46% +0.15%
==========================================
Files 287 289 +2
Lines 20063 20228 +165
==========================================
+ Hits 12301 12434 +133
- Misses 6868 6894 +26
- Partials 894 900 +6 |
7ddd3b8
to
e67927c
Compare
@@ -1,36 +1,45 @@ | |||
package command | |||
package command_test |
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.
had cyclical import between the command
package and test
.
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.
Fine if we do this, but I wonder if the cyclical import was a smell that we should move something.
e67927c
to
5e14416
Compare
de7081a
to
e662a1e
Compare
@@ -142,6 +142,7 @@ func acceptPrivileges(dockerCli command.Cli, name string) func(privileges types. | |||
for _, privilege := range privileges { | |||
fmt.Fprintf(dockerCli.Out(), " - %s: %v\n", privilege.Name, privilege.Value) | |||
} | |||
return command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), "Do you grant the above permissions?"), nil | |||
ctx := context.TODO() |
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 the context isn't apparent. Either we use the top level dockerCli context or create a new context within the function. The moby project does not support passing context on this function call https://github.com/moby/moby/blob/d19d98b136f6a7e80029b65c5ae8886eacdf43d7/api/types/client.go#L292
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.
FWIW; if we would benefit from passing contexts, we should consider updating the moby code. For a lot of code in moby, context
didn't exist yet when it was written, and we started passing through contexts more, but there's still many areas where we didn't.
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'll take a look at also adding context in the moby api client. It will help greatly with otel and just task cleanup in general.
@@ -0,0 +1,2 @@ | |||
Please confirm you would like to delete all signature data for example/trust-demo? [y/N] | |||
Aborting action. |
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.
aah i guess this could be another confirmation prompt to "fix" by standardizing the output (aka not printing "Aborting action" and making it behave more like everything else). For another moment of course
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.
ah yeah true
f4e617d
to
77ad0c2
Compare
77ad0c2
to
d4d2552
Compare
ee32a21
to
ef1624c
Compare
@@ -0,0 +1,2 @@ | |||
Upgrading plugin foo/bar from localhost:5000/foo/bar:v0.1.0 to localhost:5000/foo/bar:v1.0.0 | |||
Plugin images do not match, are you sure? [y/N] |
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.
Missing a newline at the end here? (The other new golden files have them 🤔)
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.
@Benehiko could we fix this?
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.
hmm, i'm not sure why this is. The file is generated by the -update
command.
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.
Right, this is likely due to us missing a newline when printing things somewhere
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.
Really nice, thank you! Left a few comments (mostly nits), but overall a good change.
Not sure if I missed it, but are we explicitly testing the exit code anywhere?
4824d80
to
385e049
Compare
Hmm, I suppose we could check the status code, but the status code seems to be added to a specific error type. It seems the main package handles some exit codes based on the error type here https://github.com/docker/cli/blob/master/cmd/docker/docker.go#L35-L50 Since we gracefully propagate the error up we check for it inside the test, which I think should be enough. Wdyt? |
imo those tests are useful, but if we want to preserve the "exit code is 0 when user CTRL-C's a confirmation prompt" in the future, we could add this check in particular for the e2e tests for these commands. (But fine if you'd prefer to do it in another PR). |
Seems like this test is quite flaky 56.34 === FAIL: cli-plugins/socket TestConnectAndWait/connect_goroutine_exits_after_EOF |
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
f21679e
to
10bf91a
Compare
// NewWriterWithHook returns a new WriterWithHook that still writes to the actualWriter | ||
// but also calls the hook function after every write. | ||
// The hook function is useful for testing, or waiting for a write to complete. | ||
func NewWriterWithHook(actualWriter io.Writer, hook func([]byte)) *WriterWithHook { |
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.
Just noticed we're only using this in internal/test
and one other usage, I wonder if this needs to be public at all (thinking about this because otherwise we can relax a bit with the docstrings.
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.
Anyway, can address this (and e2e tests) in a follow-up (cc @Benehiko)
|
||
// Catch the termination signal and exit the prompt gracefully. | ||
// The caller is responsible for properly handling the termination. | ||
notifyCtx, notifyCancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) |
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'm not sure a utility function should set up signal handlers for the process as a side effect. I think this should just use the passed in context for cancellation, and if that context is tied to the os signals is up to the caller. Normally, a process already has a signal handler and this will conflict with it.
Fixes #4850
- What I did
The docker
command/utils.go
provides a function for prompting the user for a confirmation[Y/n]
. To fix the termination of the CLI while the prompt is active, the reader is blocked inside a gouroutine instead allowing for checks on context cancellation from the parent or from a SIGINT/SIGTERM. An error is then propagated up the stack when the prompt is terminated instead of an immediate program termination. The caller should respect the error and either close the reader or exit the CLI to prevent goroutine leaks and unexpected behavior on re-prompting.- How I did it
Catch the termination signal on prompt.
- How to verify it
Manually and with tests.
- Description for the changelog
CLI confirmation prompts will now safely cancel the operation on termination (SIGINT/SIGTERM) producing an exit code of 0.
These are the affected CLI commands:
docker system prune
docker volume prune
docker plugin upgrade
docker image prune
docker network prune
docker container prune
docker network rm
docker builder prune
docker trust revoke
Some commands above are replaced by plugins, which will not be affected.
- A picture of a cute animal (not mandatory but encouraged)
(https://www.rawpixel.com/image/6041428/photo-image-background-public-domain-cat)