2016-09-08 13:11:39 -04:00
package container
import (
2018-05-03 21:02:44 -04:00
"context"
2016-09-08 13:11:39 -04:00
"fmt"
"io"
"strings"
"syscall"
2017-04-17 18:07:56 -04:00
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
2022-03-30 09:27:25 -04:00
"github.com/docker/cli/cli/command/completion"
2017-01-31 00:15:51 -05:00
"github.com/docker/cli/opts"
2017-03-07 17:19:54 -05:00
"github.com/docker/docker/api/types/container"
2021-08-09 13:15:46 -04:00
"github.com/moby/sys/signal"
2020-04-16 05:23:37 -04:00
"github.com/moby/term"
2017-03-27 21:21:59 -04:00
"github.com/pkg/errors"
2017-08-07 05:52:40 -04:00
"github.com/sirupsen/logrus"
2016-09-08 13:11:39 -04:00
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
type runOptions struct {
2018-03-08 08:35:17 -05:00
createOptions
2016-09-08 13:11:39 -04:00
detach bool
sigProxy bool
detachKeys string
}
// NewRunCommand create a new `docker run` command
2017-10-11 12:18:27 -04:00
func NewRunCommand ( dockerCli command . Cli ) * cobra . Command {
2022-06-23 13:35:40 -04:00
var options runOptions
2016-12-23 14:09:12 -05:00
var copts * containerOptions
2016-09-08 13:11:39 -04:00
cmd := & cobra . Command {
Use : "run [OPTIONS] IMAGE [COMMAND] [ARG...]" ,
2022-03-29 17:58:36 -04:00
Short : "Create and run a new container from an image" ,
2016-09-08 13:11:39 -04:00
Args : cli . RequiresMinArgs ( 1 ) ,
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
copts . Image = args [ 0 ]
if len ( args ) > 1 {
copts . Args = args [ 1 : ]
}
2023-09-09 18:27:44 -04:00
return runRun ( cmd . Context ( ) , dockerCli , cmd . Flags ( ) , & options , copts )
2016-09-08 13:11:39 -04:00
} ,
2022-03-30 09:27:25 -04:00
ValidArgsFunction : completion . ImageNames ( dockerCli ) ,
2022-03-30 03:37:08 -04:00
Annotations : map [ string ] string {
"category-top" : "1" ,
cli: use custom annotation for aliases
Cobra allows for aliases to be defined for a command, but only allows these
to be defined at the same level (for example, `docker image ls` as alias for
`docker image list`). Our CLI has some commands that are available both as a
top-level shorthand as well as `docker <object> <verb>` subcommands. For example,
`docker ps` is a shorthand for `docker container ps` / `docker container ls`.
This patch introduces a custom "aliases" annotation that can be used to print
all available aliases for a command. While this requires these aliases to be
defined manually, in practice the list of aliases rarely changes, so maintenance
should be minimal.
As a convention, we could consider the first command in this list to be the
canonical command, so that we can use this information to add redirects in
our documentation in future.
Before this patch:
docker images --help
Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]
List images
Options:
-a, --all Show all images (default hides intermediate images)
...
With this patch:
docker images --help
Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]
List images
Aliases:
docker image ls, docker image list, docker images
Options:
-a, --all Show all images (default hides intermediate images)
...
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-06-28 04:52:25 -04:00
"aliases" : "docker container run, docker run" ,
2022-03-30 03:37:08 -04:00
} ,
2016-09-08 13:11:39 -04:00
}
flags := cmd . Flags ( )
flags . SetInterspersed ( false )
// These are flags not stored in Config/HostConfig
2022-06-23 13:35:40 -04:00
flags . BoolVarP ( & options . detach , "detach" , "d" , false , "Run container in background and print container ID" )
flags . BoolVar ( & options . sigProxy , "sig-proxy" , true , "Proxy received signals to the process" )
flags . StringVar ( & options . name , "name" , "" , "Assign a name to the container" )
flags . StringVar ( & options . detachKeys , "detach-keys" , "" , "Override the key sequence for detaching a container" )
2023-01-03 05:12:24 -05:00
flags . StringVar ( & options . pull , "pull" , PullImageMissing , ` Pull image before running (" ` + PullImageAlways + ` ", " ` + PullImageMissing + ` ", " ` + PullImageNever + ` ") ` )
2022-06-23 13:35:40 -04:00
flags . BoolVarP ( & options . quiet , "quiet" , "q" , false , "Suppress the pull output" )
2016-09-08 13:11:39 -04:00
// Add an explicit help that doesn't have a `-h` to prevent the conflict
// with hostname
flags . Bool ( "help" , false , "Print usage" )
2022-06-23 13:35:40 -04:00
command . AddPlatformFlag ( flags , & options . platform )
command . AddTrustVerificationFlags ( flags , & options . untrusted , dockerCli . ContentTrustEnabled ( ) )
2016-12-23 14:09:12 -05:00
copts = addFlags ( flags )
2022-03-30 09:27:25 -04:00
2024-10-24 16:14:49 -04:00
_ = cmd . RegisterFlagCompletionFunc ( "detach-keys" , completeDetachKeys )
2024-10-22 15:40:31 -04:00
addCompletions ( cmd , dockerCli )
2024-10-30 16:10:37 -04:00
flags . VisitAll ( func ( flag * pflag . Flag ) {
// Set a default completion function if none was set. We don't look
// up if it does already have one set, because Cobra does this for
// us, and returns an error (which we ignore for this reason).
_ = cmd . RegisterFlagCompletionFunc ( flag . Name , completion . NoComplete )
} )
2016-09-08 13:11:39 -04:00
return cmd
}
2023-09-09 18:27:44 -04:00
func runRun ( ctx context . Context , dockerCli command . Cli , flags * pflag . FlagSet , ropts * runOptions , copts * containerOptions ) error {
2022-06-27 11:16:44 -04:00
if err := validatePullOpt ( ropts . pull ) ; err != nil {
cli/command/container: remove reportError, and put StatusError to use
The `reportError` utility was present because cli.StatusError would print
the error decorated with `Status: <error-message>, Code: <exit-code>`.
That was not desirable in many cases as it would mess-up the output. To
prevent this, the CLI had code to check for an empty `Status` (error message)
in which case the error would be "ignored" (and only used for the exit-status),
and the `reportError` utility would be used to manually print a custom error
message before returning the error.
Now that bca209006153d3e025cb3d31c3cd55eb2aec0c4f fixed the output format
of `cli.StatusError`, and 3dd6fc365d853e21f0e11f9e6ab62c4f8ae438e7 and
350a0b68a9584ec9ae712b6eca906c1018ba6dac no longer discard these error,
we can get rid of this utility, and just set the error-message for
the status-error.
This patch:
- Introduces a `withHelp` which takes care of decorating errors with
a "Run --help" hint for the user.
- Introduces a `toStatusError` utility that detects certain errors in
the container to assign a corresponding exit-code (these error-codes
can be used to distinguish "client" errors from "container" errors).
- Removes the `reportError` utility, and removes code that manually
printed errors before returning.
Behavior is mostly unmodified, with the exception of some slight reformatting
of the errors:
- `withHelp` adds a `docker:` prefix to the error, to indicate the error
is produced by the `docker` command. This prefix was already present
in most cases.
- The "--help" hint is slightly updated ("Run 'docker run --help' for
more information" instead of "See 'docker run --help'"), to make it
more clear that it's a "call to action".
- An empty is added before the "--help" hint to separate it better from
the error-message.
Before this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never".
See 'docker run --help'.
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
$ echo $?
127
With this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never"
Run 'docker run --help' for more information
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
Run 'docker run --help' for more information
$ echo $?
127
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-07-04 07:18:03 -04:00
return cli . StatusError {
Status : withHelp ( err , "run" ) . Error ( ) ,
StatusCode : 125 ,
}
2022-06-27 11:16:44 -04:00
}
2017-10-15 15:39:56 -04:00
proxyConfig := dockerCli . ConfigFile ( ) . ParseProxyConfig ( dockerCli . Client ( ) . DaemonHost ( ) , opts . ConvertKVStringsToMapWithNil ( copts . env . GetAll ( ) ) )
2017-01-31 00:15:51 -05:00
newEnv := [ ] string { }
for k , v := range proxyConfig {
if v == nil {
newEnv = append ( newEnv , k )
} else {
2023-06-12 12:19:50 -04:00
newEnv = append ( newEnv , k + "=" + * v )
2017-01-31 00:15:51 -05:00
}
}
copts . env = * opts . NewListOptsRef ( & newEnv , nil )
2023-01-18 11:39:35 -05:00
containerCfg , err := parse ( flags , copts , dockerCli . ServerInfo ( ) . OSType )
2016-12-23 14:09:12 -05:00
// just in case the parse does not exit
2016-09-08 13:11:39 -04:00
if err != nil {
cli/command/container: remove reportError, and put StatusError to use
The `reportError` utility was present because cli.StatusError would print
the error decorated with `Status: <error-message>, Code: <exit-code>`.
That was not desirable in many cases as it would mess-up the output. To
prevent this, the CLI had code to check for an empty `Status` (error message)
in which case the error would be "ignored" (and only used for the exit-status),
and the `reportError` utility would be used to manually print a custom error
message before returning the error.
Now that bca209006153d3e025cb3d31c3cd55eb2aec0c4f fixed the output format
of `cli.StatusError`, and 3dd6fc365d853e21f0e11f9e6ab62c4f8ae438e7 and
350a0b68a9584ec9ae712b6eca906c1018ba6dac no longer discard these error,
we can get rid of this utility, and just set the error-message for
the status-error.
This patch:
- Introduces a `withHelp` which takes care of decorating errors with
a "Run --help" hint for the user.
- Introduces a `toStatusError` utility that detects certain errors in
the container to assign a corresponding exit-code (these error-codes
can be used to distinguish "client" errors from "container" errors).
- Removes the `reportError` utility, and removes code that manually
printed errors before returning.
Behavior is mostly unmodified, with the exception of some slight reformatting
of the errors:
- `withHelp` adds a `docker:` prefix to the error, to indicate the error
is produced by the `docker` command. This prefix was already present
in most cases.
- The "--help" hint is slightly updated ("Run 'docker run --help' for
more information" instead of "See 'docker run --help'"), to make it
more clear that it's a "call to action".
- An empty is added before the "--help" hint to separate it better from
the error-message.
Before this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never".
See 'docker run --help'.
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
$ echo $?
127
With this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never"
Run 'docker run --help' for more information
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
Run 'docker run --help' for more information
$ echo $?
127
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-07-04 07:18:03 -04:00
return cli . StatusError {
Status : withHelp ( err , "run" ) . Error ( ) ,
StatusCode : 125 ,
}
2016-09-08 13:11:39 -04:00
}
2023-01-18 11:39:35 -05:00
if err = validateAPIVersion ( containerCfg , dockerCli . CurrentVersion ( ) ) ; err != nil {
cli/command/container: remove reportError, and put StatusError to use
The `reportError` utility was present because cli.StatusError would print
the error decorated with `Status: <error-message>, Code: <exit-code>`.
That was not desirable in many cases as it would mess-up the output. To
prevent this, the CLI had code to check for an empty `Status` (error message)
in which case the error would be "ignored" (and only used for the exit-status),
and the `reportError` utility would be used to manually print a custom error
message before returning the error.
Now that bca209006153d3e025cb3d31c3cd55eb2aec0c4f fixed the output format
of `cli.StatusError`, and 3dd6fc365d853e21f0e11f9e6ab62c4f8ae438e7 and
350a0b68a9584ec9ae712b6eca906c1018ba6dac no longer discard these error,
we can get rid of this utility, and just set the error-message for
the status-error.
This patch:
- Introduces a `withHelp` which takes care of decorating errors with
a "Run --help" hint for the user.
- Introduces a `toStatusError` utility that detects certain errors in
the container to assign a corresponding exit-code (these error-codes
can be used to distinguish "client" errors from "container" errors).
- Removes the `reportError` utility, and removes code that manually
printed errors before returning.
Behavior is mostly unmodified, with the exception of some slight reformatting
of the errors:
- `withHelp` adds a `docker:` prefix to the error, to indicate the error
is produced by the `docker` command. This prefix was already present
in most cases.
- The "--help" hint is slightly updated ("Run 'docker run --help' for
more information" instead of "See 'docker run --help'"), to make it
more clear that it's a "call to action".
- An empty is added before the "--help" hint to separate it better from
the error-message.
Before this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never".
See 'docker run --help'.
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
$ echo $?
127
With this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never"
Run 'docker run --help' for more information
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
Run 'docker run --help' for more information
$ echo $?
127
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-07-04 07:18:03 -04:00
return cli . StatusError {
Status : withHelp ( err , "run" ) . Error ( ) ,
StatusCode : 125 ,
}
2018-10-10 06:18:29 -04:00
}
2023-09-09 18:27:44 -04:00
return runContainer ( ctx , dockerCli , ropts , copts , containerCfg )
2017-03-07 17:19:54 -05:00
}
2016-09-08 13:11:39 -04:00
2022-07-13 06:29:49 -04:00
//nolint:gocyclo
2023-09-09 18:27:44 -04:00
func runContainer ( ctx context . Context , dockerCli command . Cli , runOpts * runOptions , copts * containerOptions , containerCfg * containerConfig ) error {
2023-01-18 11:39:35 -05:00
config := containerCfg . Config
2017-03-07 17:19:54 -05:00
stdout , stderr := dockerCli . Out ( ) , dockerCli . Err ( )
2023-11-06 04:34:37 -05:00
apiClient := dockerCli . Client ( )
2016-09-08 13:11:39 -04:00
config . ArgsEscaped = false
2023-11-20 11:38:50 -05:00
if ! runOpts . detach {
2016-09-08 13:11:39 -04:00
if err := dockerCli . In ( ) . CheckTty ( config . AttachStdin , config . Tty ) ; err != nil {
return err
}
} else {
2017-03-07 17:19:54 -05:00
if copts . attach . Len ( ) != 0 {
2024-10-01 05:44:59 -04:00
return errors . New ( "conflicting options: cannot specify both --attach and --detach" )
2016-09-08 13:11:39 -04:00
}
config . AttachStdin = false
config . AttachStdout = false
config . AttachStderr = false
config . StdinOnce = false
}
2023-11-20 11:38:50 -05:00
containerID , err := createContainer ( ctx , dockerCli , containerCfg , & runOpts . createOptions )
2016-09-08 13:11:39 -04:00
if err != nil {
cli/command/container: remove reportError, and put StatusError to use
The `reportError` utility was present because cli.StatusError would print
the error decorated with `Status: <error-message>, Code: <exit-code>`.
That was not desirable in many cases as it would mess-up the output. To
prevent this, the CLI had code to check for an empty `Status` (error message)
in which case the error would be "ignored" (and only used for the exit-status),
and the `reportError` utility would be used to manually print a custom error
message before returning the error.
Now that bca209006153d3e025cb3d31c3cd55eb2aec0c4f fixed the output format
of `cli.StatusError`, and 3dd6fc365d853e21f0e11f9e6ab62c4f8ae438e7 and
350a0b68a9584ec9ae712b6eca906c1018ba6dac no longer discard these error,
we can get rid of this utility, and just set the error-message for
the status-error.
This patch:
- Introduces a `withHelp` which takes care of decorating errors with
a "Run --help" hint for the user.
- Introduces a `toStatusError` utility that detects certain errors in
the container to assign a corresponding exit-code (these error-codes
can be used to distinguish "client" errors from "container" errors).
- Removes the `reportError` utility, and removes code that manually
printed errors before returning.
Behavior is mostly unmodified, with the exception of some slight reformatting
of the errors:
- `withHelp` adds a `docker:` prefix to the error, to indicate the error
is produced by the `docker` command. This prefix was already present
in most cases.
- The "--help" hint is slightly updated ("Run 'docker run --help' for
more information" instead of "See 'docker run --help'"), to make it
more clear that it's a "call to action".
- An empty is added before the "--help" hint to separate it better from
the error-message.
Before this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never".
See 'docker run --help'.
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
$ echo $?
127
With this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never"
Run 'docker run --help' for more information
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
Run 'docker run --help' for more information
$ echo $?
127
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-07-04 07:18:03 -04:00
return toStatusError ( err )
2016-09-08 13:11:39 -04:00
}
2023-11-20 11:38:50 -05:00
if runOpts . sigProxy {
2021-09-16 09:46:27 -04:00
sigc := notifyAllSignals ( )
2024-04-08 04:11:09 -04:00
// since we're explicitly setting up signal handling here, and the daemon will
// get notified independently of the clients ctx cancellation, we use this context
// but without cancellation to avoid ForwardAllSignals from returning
// before all signals are forwarded.
bgCtx := context . WithoutCancel ( ctx )
go ForwardAllSignals ( bgCtx , apiClient , containerID , sigc )
2016-09-08 13:11:39 -04:00
defer signal . StopCatch ( sigc )
}
2017-01-31 00:15:51 -05:00
2024-11-22 08:13:40 -05:00
ctx , cancelFun := context . WithCancel ( context . WithoutCancel ( ctx ) )
defer cancelFun ( )
2016-09-08 13:11:39 -04:00
var (
waitDisplayID chan struct { }
errCh chan error
)
if ! config . AttachStdout && ! config . AttachStderr {
// Make this asynchronous to allow the client to write to stdin before having to read the ID
waitDisplayID = make ( chan struct { } )
go func ( ) {
defer close ( waitDisplayID )
2023-06-08 10:46:15 -04:00
_ , _ = fmt . Fprintln ( stdout , containerID )
2016-09-08 13:11:39 -04:00
} ( )
}
attach := config . AttachStdin || config . AttachStdout || config . AttachStderr
if attach {
2023-06-08 10:53:30 -04:00
detachKeys := dockerCli . ConfigFile ( ) . DetachKeys
2023-11-20 11:38:50 -05:00
if runOpts . detachKeys != "" {
detachKeys = runOpts . detachKeys
2016-09-08 13:11:39 -04:00
}
2024-07-08 11:44:33 -04:00
// ctx should not be cancellable here, as this would kill the stream to the container
// and we want to keep the stream open until the process in the container exits or until
// the user forcefully terminates the CLI.
2024-07-11 03:49:14 -04:00
closeFn , err := attachContainer ( ctx , dockerCli , containerID , & errCh , config , container . AttachOptions {
2023-06-08 10:53:30 -04:00
Stream : true ,
Stdin : config . AttachStdin ,
Stdout : config . AttachStdout ,
Stderr : config . AttachStderr ,
DetachKeys : detachKeys ,
} )
2017-03-07 17:19:54 -05:00
if err != nil {
return err
2016-09-08 13:11:39 -04:00
}
2023-03-29 09:32:00 -04:00
defer closeFn ( )
2016-09-08 13:11:39 -04:00
}
2024-05-05 17:45:37 -04:00
// New context here because we don't to cancel waiting on container exit/remove
// when we cancel attach, etc.
statusCtx , cancelStatusCtx := context . WithCancel ( context . WithoutCancel ( ctx ) )
defer cancelStatusCtx ( )
statusChan := waitExitOrRemoved ( statusCtx , apiClient , containerID , copts . autoRemove )
2016-09-08 13:11:39 -04:00
2020-01-16 06:47:12 -05:00
// start the container
2023-11-06 04:34:37 -05:00
if err := apiClient . ContainerStart ( ctx , containerID , container . StartOptions { } ) ; err != nil {
2017-05-17 14:40:56 -04:00
// If we have hijackedIOStreamer, we should notify
// hijackedIOStreamer we are going to exit and wait
2016-09-08 13:11:39 -04:00
// to avoid the terminal are not restored.
if attach {
cancelFun ( )
<- errCh
}
Don't use AutoRemove on older daemons
Docker 1.13 moves the `--rm` flag to the daemon,
through an AutoRemove option in HostConfig.
When using API 1.24 and under, AutoRemove should not be
used, even if the daemon is version 1.13 or above and
"supports" this feature.
This patch fixes a situation where an 1.13 client,
talking to an 1.13 daemon, but using the 1.24 API
version, still set the AutoRemove property.
As a result, both the client _and_ the daemon
were attempting to remove the container, resulting
in an error:
ERRO[0000] error removing container: Error response from daemon:
removal of container ce0976ad22495c7cbe9487752ea32721a282164862db036b2f3377bd07461c3a
is already in progress
In addition, the validation of conflicting options
is moved from `docker run` to `opts.parse()`, so
that conflicting options are also detected when
running `docker create` and `docker start` separately.
To resolve the issue, the `AutoRemove` option is now
always set to `false` both by the client and the
daemon, if API version 1.24 or under is used.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2017-01-12 19:05:39 -05:00
if copts . autoRemove {
2016-09-08 13:11:39 -04:00
// wait container to be removed
<- statusChan
}
cli/command/container: remove reportError, and put StatusError to use
The `reportError` utility was present because cli.StatusError would print
the error decorated with `Status: <error-message>, Code: <exit-code>`.
That was not desirable in many cases as it would mess-up the output. To
prevent this, the CLI had code to check for an empty `Status` (error message)
in which case the error would be "ignored" (and only used for the exit-status),
and the `reportError` utility would be used to manually print a custom error
message before returning the error.
Now that bca209006153d3e025cb3d31c3cd55eb2aec0c4f fixed the output format
of `cli.StatusError`, and 3dd6fc365d853e21f0e11f9e6ab62c4f8ae438e7 and
350a0b68a9584ec9ae712b6eca906c1018ba6dac no longer discard these error,
we can get rid of this utility, and just set the error-message for
the status-error.
This patch:
- Introduces a `withHelp` which takes care of decorating errors with
a "Run --help" hint for the user.
- Introduces a `toStatusError` utility that detects certain errors in
the container to assign a corresponding exit-code (these error-codes
can be used to distinguish "client" errors from "container" errors).
- Removes the `reportError` utility, and removes code that manually
printed errors before returning.
Behavior is mostly unmodified, with the exception of some slight reformatting
of the errors:
- `withHelp` adds a `docker:` prefix to the error, to indicate the error
is produced by the `docker` command. This prefix was already present
in most cases.
- The "--help" hint is slightly updated ("Run 'docker run --help' for
more information" instead of "See 'docker run --help'"), to make it
more clear that it's a "call to action".
- An empty is added before the "--help" hint to separate it better from
the error-message.
Before this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never".
See 'docker run --help'.
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
$ echo $?
127
With this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never"
Run 'docker run --help' for more information
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
Run 'docker run --help' for more information
$ echo $?
127
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-07-04 07:18:03 -04:00
return toStatusError ( err )
2016-09-08 13:11:39 -04:00
}
if ( config . AttachStdin || config . AttachStdout || config . AttachStderr ) && config . Tty && dockerCli . Out ( ) . IsTerminal ( ) {
2023-06-08 10:46:15 -04:00
if err := MonitorTtySize ( ctx , dockerCli , containerID , false ) ; err != nil {
_ , _ = fmt . Fprintln ( stderr , "Error monitoring TTY size:" , err )
2016-09-08 13:11:39 -04:00
}
}
if errCh != nil {
if err := <- errCh ; err != nil {
2017-05-16 21:31:04 -04:00
if _ , ok := err . ( term . EscapeError ) ; ok {
// The user entered the detach escape sequence.
return nil
}
2016-09-08 13:11:39 -04:00
logrus . Debugf ( "Error hijack: %s" , err )
return err
}
}
// Detached mode: wait for the id to be displayed and return.
if ! config . AttachStdout && ! config . AttachStderr {
// Detached mode
<- waitDisplayID
return nil
}
status := <- statusChan
if status != 0 {
return cli . StatusError { StatusCode : status }
}
return nil
}
2023-10-13 14:34:32 -04:00
func attachContainer ( ctx context . Context , dockerCli command . Cli , containerID string , errCh * chan error , config * container . Config , options container . AttachOptions ) ( func ( ) , error ) {
2021-02-22 13:08:43 -05:00
resp , errAttach := dockerCli . Client ( ) . ContainerAttach ( ctx , containerID , options )
if errAttach != nil {
return nil , errAttach
}
2017-03-07 17:19:54 -05:00
var (
out , cerr io . Writer
in io . ReadCloser
)
2023-06-08 10:53:30 -04:00
if options . Stdin {
2017-03-07 17:19:54 -05:00
in = dockerCli . In ( )
}
2023-06-08 10:53:30 -04:00
if options . Stdout {
2021-02-22 13:08:43 -05:00
out = dockerCli . Out ( )
2017-03-07 17:19:54 -05:00
}
2023-06-08 10:53:30 -04:00
if options . Stderr {
2017-03-07 17:19:54 -05:00
if config . Tty {
2021-02-22 13:08:43 -05:00
cerr = dockerCli . Out ( )
2017-03-07 17:19:54 -05:00
} else {
2021-02-22 13:08:43 -05:00
cerr = dockerCli . Err ( )
2017-03-07 17:19:54 -05:00
}
}
2017-09-29 21:12:03 -04:00
ch := make ( chan error , 1 )
* errCh = ch
2017-09-29 08:18:19 -04:00
go func ( ) {
2017-09-29 21:12:03 -04:00
ch <- func ( ) error {
2017-09-29 08:18:19 -04:00
streamer := hijackedIOStreamer {
streams : dockerCli ,
inputStream : in ,
outputStream : out ,
errorStream : cerr ,
resp : resp ,
tty : config . Tty ,
detachKeys : options . DetachKeys ,
}
2017-05-17 14:40:56 -04:00
2017-09-29 08:18:19 -04:00
if errHijack := streamer . stream ( ctx ) ; errHijack != nil {
return errHijack
}
return errAttach
} ( )
} ( )
2017-03-07 17:19:54 -05:00
return resp . Close , nil
}
cli/command/container: remove reportError, and put StatusError to use
The `reportError` utility was present because cli.StatusError would print
the error decorated with `Status: <error-message>, Code: <exit-code>`.
That was not desirable in many cases as it would mess-up the output. To
prevent this, the CLI had code to check for an empty `Status` (error message)
in which case the error would be "ignored" (and only used for the exit-status),
and the `reportError` utility would be used to manually print a custom error
message before returning the error.
Now that bca209006153d3e025cb3d31c3cd55eb2aec0c4f fixed the output format
of `cli.StatusError`, and 3dd6fc365d853e21f0e11f9e6ab62c4f8ae438e7 and
350a0b68a9584ec9ae712b6eca906c1018ba6dac no longer discard these error,
we can get rid of this utility, and just set the error-message for
the status-error.
This patch:
- Introduces a `withHelp` which takes care of decorating errors with
a "Run --help" hint for the user.
- Introduces a `toStatusError` utility that detects certain errors in
the container to assign a corresponding exit-code (these error-codes
can be used to distinguish "client" errors from "container" errors).
- Removes the `reportError` utility, and removes code that manually
printed errors before returning.
Behavior is mostly unmodified, with the exception of some slight reformatting
of the errors:
- `withHelp` adds a `docker:` prefix to the error, to indicate the error
is produced by the `docker` command. This prefix was already present
in most cases.
- The "--help" hint is slightly updated ("Run 'docker run --help' for
more information" instead of "See 'docker run --help'"), to make it
more clear that it's a "call to action".
- An empty is added before the "--help" hint to separate it better from
the error-message.
Before this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never".
See 'docker run --help'.
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
$ echo $?
127
With this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never"
Run 'docker run --help' for more information
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
Run 'docker run --help' for more information
$ echo $?
127
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-07-04 07:18:03 -04:00
// withHelp decorates the error with a suggestion to use "--help".
func withHelp ( err error , commandName string ) error {
return fmt . Errorf ( "docker: %w\n\nRun 'docker %s --help' for more information" , err , commandName )
2016-09-08 13:11:39 -04:00
}
cli/command/container: remove reportError, and put StatusError to use
The `reportError` utility was present because cli.StatusError would print
the error decorated with `Status: <error-message>, Code: <exit-code>`.
That was not desirable in many cases as it would mess-up the output. To
prevent this, the CLI had code to check for an empty `Status` (error message)
in which case the error would be "ignored" (and only used for the exit-status),
and the `reportError` utility would be used to manually print a custom error
message before returning the error.
Now that bca209006153d3e025cb3d31c3cd55eb2aec0c4f fixed the output format
of `cli.StatusError`, and 3dd6fc365d853e21f0e11f9e6ab62c4f8ae438e7 and
350a0b68a9584ec9ae712b6eca906c1018ba6dac no longer discard these error,
we can get rid of this utility, and just set the error-message for
the status-error.
This patch:
- Introduces a `withHelp` which takes care of decorating errors with
a "Run --help" hint for the user.
- Introduces a `toStatusError` utility that detects certain errors in
the container to assign a corresponding exit-code (these error-codes
can be used to distinguish "client" errors from "container" errors).
- Removes the `reportError` utility, and removes code that manually
printed errors before returning.
Behavior is mostly unmodified, with the exception of some slight reformatting
of the errors:
- `withHelp` adds a `docker:` prefix to the error, to indicate the error
is produced by the `docker` command. This prefix was already present
in most cases.
- The "--help" hint is slightly updated ("Run 'docker run --help' for
more information" instead of "See 'docker run --help'"), to make it
more clear that it's a "call to action".
- An empty is added before the "--help" hint to separate it better from
the error-message.
Before this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never".
See 'docker run --help'.
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
$ echo $?
127
With this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never"
Run 'docker run --help' for more information
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
Run 'docker run --help' for more information
$ echo $?
127
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-07-04 07:18:03 -04:00
// toStatusError attempts to detect specific error-conditions to assign
// an appropriate exit-code for situations where the problem originates
// from the container. It returns [cli.StatusError] with the original
// error message and the Status field set as follows:
//
// - 125: for generic failures sent back from the daemon
// - 126: if container start fails with 'permission denied' error
// - 127: if container start fails with 'not found'/'no such' error
func toStatusError ( err error ) error {
// TODO(thaJeztah): some of these errors originate from the container: should we actually suggest "--help" for those?
errMsg := err . Error ( )
if strings . Contains ( errMsg , "executable file not found" ) || strings . Contains ( errMsg , "no such file or directory" ) || strings . Contains ( errMsg , "system cannot find the file specified" ) {
return cli . StatusError {
Status : withHelp ( err , "run" ) . Error ( ) ,
StatusCode : 127 ,
}
2016-09-08 13:11:39 -04:00
}
cli/command/container: remove reportError, and put StatusError to use
The `reportError` utility was present because cli.StatusError would print
the error decorated with `Status: <error-message>, Code: <exit-code>`.
That was not desirable in many cases as it would mess-up the output. To
prevent this, the CLI had code to check for an empty `Status` (error message)
in which case the error would be "ignored" (and only used for the exit-status),
and the `reportError` utility would be used to manually print a custom error
message before returning the error.
Now that bca209006153d3e025cb3d31c3cd55eb2aec0c4f fixed the output format
of `cli.StatusError`, and 3dd6fc365d853e21f0e11f9e6ab62c4f8ae438e7 and
350a0b68a9584ec9ae712b6eca906c1018ba6dac no longer discard these error,
we can get rid of this utility, and just set the error-message for
the status-error.
This patch:
- Introduces a `withHelp` which takes care of decorating errors with
a "Run --help" hint for the user.
- Introduces a `toStatusError` utility that detects certain errors in
the container to assign a corresponding exit-code (these error-codes
can be used to distinguish "client" errors from "container" errors).
- Removes the `reportError` utility, and removes code that manually
printed errors before returning.
Behavior is mostly unmodified, with the exception of some slight reformatting
of the errors:
- `withHelp` adds a `docker:` prefix to the error, to indicate the error
is produced by the `docker` command. This prefix was already present
in most cases.
- The "--help" hint is slightly updated ("Run 'docker run --help' for
more information" instead of "See 'docker run --help'"), to make it
more clear that it's a "call to action".
- An empty is added before the "--help" hint to separate it better from
the error-message.
Before this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never".
See 'docker run --help'.
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
$ echo $?
127
With this patch:
$ docker run --pull=invalid-option alpine
docker: invalid pull option: 'invalid-option': must be one of "always", "missing" or "never"
Run 'docker run --help' for more information
$ echo $?
125
$ docker run --rm alpine nosuchcommand
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "nosuchcommand": executable file not found in $PATH: unknown.
Run 'docker run --help' for more information
$ echo $?
127
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-07-04 07:18:03 -04:00
if strings . Contains ( errMsg , syscall . EACCES . Error ( ) ) || strings . Contains ( errMsg , syscall . EISDIR . Error ( ) ) {
return cli . StatusError {
Status : withHelp ( err , "run" ) . Error ( ) ,
StatusCode : 126 ,
}
}
return cli . StatusError {
Status : withHelp ( err , "run" ) . Error ( ) ,
StatusCode : 125 ,
}
2016-09-08 13:11:39 -04:00
}