Skip to content

fix: cli prompt termination exit code - #4888

Merged
neersighted merged 1 commit into
docker:masterfrom
Benehiko:fix-prompt-termination
Mar 4, 2024
Merged

fix: cli prompt termination exit code#4888
neersighted merged 1 commit into
docker:masterfrom
Benehiko:fix-prompt-termination

Conversation

@Benehiko

@BenehikoBenehiko commented Feb 21, 2024

Copy link
Copy Markdown
Member

Fixes#4850

>~/g/s/g/d/cli on fix-prompt-termination ⨯ ./build/docker volume prune 16:35:17
WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue? [y/N] ^C
⋊>~/g/s/g/d/cli on fix-prompt-termination ⨯ echo$status 16:35:21
0
⋊>~/g/s/g/d/cli on fix-prompt-termination ⨯ bash 16:35:23
[benehiko@benehiko cli]$ ./build/docker volume prune
WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue? [y/N] ^C
[benehiko@benehiko cli]$ echo$?
0
⋊>~/g/s/g/d/cli on fix-prompt-termination ⨯ zsh 16:35:32
benehiko% ./build/docker volume prune
WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue? [y/N] ^C
benehiko% echo$?
0

- 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)
image
(https://www.rawpixel.com/image/6041428/photo-image-background-public-domain-cat)

@Benehiko
Benehikoforce-pushed the fix-prompt-termination branch 2 times, most recently from 0bffacc to c532931CompareFebruary 21, 2024 16:57
@Benehiko
Benehiko marked this pull request as ready for review February 21, 2024 16:59
@Benehiko
Benehiko requested a review from a teamFebruary 22, 2024 10:44
@codecov-commenter

codecov-commenter commented Feb 22, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 84.72222% with 11 lines in your changes missing coverage. Please review.

Project coverage is 61.45%. Comparing base (310daf2) to head (10bf91a).
Report is 636 commits behind head on master.

Additional details and impacted files
@@ Coverage Diff @@## master #4888 +/- ##
==========================================
+ Coverage 61.13% 61.45% +0.31% 
==========================================
Files 287 289 +2 Lines 20136 20229 +93 ==========================================
+ Hits 12310 12431 +121 + Misses 6933 6896 -37 - Partials 893 902 +9 

Comment threadcli/command/filename Outdated
Comment threadcli/command/plugin/upgrade_test.go Outdated
@Benehiko
Benehikoforce-pushed the fix-prompt-termination branch 6 times, most recently from 7ddd3b8 to e67927cCompareFebruary 23, 2024 09:18
Comment threadcli/command/utils.go Outdated
@@ -1,36 +1,45 @@
package command
package command_test

Copy link
Copy Markdown
MemberAuthor

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.

Copy link
Copy Markdown
Member

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.

Comment threadcli/command/utils.go Outdated
@Benehiko
Benehikoforce-pushed the fix-prompt-termination branch 5 times, most recently from de7081a to e662a1eCompareFebruary 27, 2024 10:00
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()

@BenehikoBenehikoFeb 27, 2024

Copy link
Copy Markdown
MemberAuthor

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

Copy link
Copy Markdown
Member

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.

Copy link
Copy Markdown
MemberAuthor

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.

Comment threadcli/command/utils_test.go Outdated
@@ -0,0 +1,2 @@
Please confirm you would like to delete all signature data for example/trust-demo? [y/N]
Aborting action.

Copy link
Copy Markdown
Contributor

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

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yeah true

@Benehiko
Benehikoforce-pushed the fix-prompt-termination branch 3 times, most recently from f4e617d to 77ad0c2CompareFebruary 28, 2024 12:14
@Benehiko
Benehikoforce-pushed the fix-prompt-termination branch from 77ad0c2 to d4d2552CompareFebruary 28, 2024 12:16
Comment threadinternal/test/cmd.go Outdated
@Benehiko
Benehikoforce-pushed the fix-prompt-termination branch 2 times, most recently from ee32a21 to ef1624cCompareFebruary 28, 2024 14:13
Comment threadcli/command/utils.go Outdated
Comment threadcli/command/utils.go Outdated
Comment threadcli/command/utils.go Outdated
@@ -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] No newline at end of file

Copy link
Copy Markdown
Member

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 🤔)

Copy link
Copy Markdown
Member

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?

Copy link
Copy Markdown
MemberAuthor

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.

Copy link
Copy Markdown
Member

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

@laurazardlaurazard left a comment

Copy link
Copy Markdown
Member

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?

Comment threadinternal/test/writer.go Outdated
Comment threadinternal/test/writer.go
Comment threadcli/command/utils.go Outdated
Comment threadcli/command/utils.go Outdated
@Benehiko
Benehikoforce-pushed the fix-prompt-termination branch 2 times, most recently from 4824d80 to 385e049CompareMarch 4, 2024 11:49
@Benehiko

Copy link
Copy Markdown
MemberAuthor

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?

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?

@laurazard

Copy link
Copy Markdown
Member

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).

@Benehiko

Copy link
Copy Markdown
MemberAuthor

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>
@Benehiko
Benehikoforce-pushed the fix-prompt-termination branch from f21679e to 10bf91aCompareMarch 4, 2024 14:28
@neersighted
neersighted merged commit 181575b into docker:masterMar 4, 2024
@Benehiko
Benehiko deleted the fix-prompt-termination branch March 4, 2024 14:57
Comment on lines +25 to +28
// 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 {

Copy link
Copy Markdown
Member

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.

Copy link
Copy Markdown
Member

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)

Comment threadcli/command/utils.go

// 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)

Copy link
Copy Markdown
Member

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.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

canceling "docker volume prune" does not consistently print a newline, and exits with non-zero status

7 participants

@Benehiko@codecov-commenter@laurazard@tonistiigi@neersighted@thaJeztah@krissetto