-
Notifications
You must be signed in to change notification settings - Fork 2.1k
publish RunExec for use by docker/compose #3436
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,62 +16,65 @@ import ( | |
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| type execOptions struct { | ||
| detachKeys string | ||
| interactive bool | ||
| tty bool | ||
| detach bool | ||
| user string | ||
| privileged bool | ||
| env opts.ListOpts | ||
| workdir string | ||
| container string | ||
| command []string | ||
| envFile opts.ListOpts | ||
| // ExecOptions group options for `exec` command | ||
| type ExecOptions struct { | ||
| DetachKeys string | ||
| Interactive bool | ||
| TTY bool | ||
| Detach bool | ||
| User string | ||
| Privileged bool | ||
| Env opts.ListOpts | ||
| Workdir string | ||
| Container string | ||
| Command []string | ||
| EnvFile opts.ListOpts | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one needs some thinking as well (besides env-file being a PITA overall); (no need to change, more "these are things we should look at") |
||
| } | ||
|
|
||
| func newExecOptions() execOptions { | ||
ndeloof marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return execOptions{ | ||
| env: opts.NewListOpts(opts.ValidateEnv), | ||
| envFile: opts.NewListOpts(nil), | ||
| // NewExecOptions creates a new ExecOptions | ||
| func NewExecOptions() ExecOptions { | ||
| return ExecOptions{ | ||
| Env: opts.NewListOpts(opts.ValidateEnv), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shows a bit why I think we should look at whether or not Some utilities for this, adding some methods to (again, one more "these are things we should look at") |
||
| EnvFile: opts.NewListOpts(nil), | ||
| } | ||
| } | ||
|
|
||
| // NewExecCommand creates a new cobra.Command for `docker exec` | ||
| func NewExecCommand(dockerCli command.Cli) *cobra.Command { | ||
| options := newExecOptions() | ||
| options := NewExecOptions() | ||
|
|
||
| cmd := &cobra.Command{ | ||
| Use: "exec [OPTIONS] CONTAINER COMMAND [ARG...]", | ||
| Short: "Run a command in a running container", | ||
| Args: cli.RequiresMinArgs(2), | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| options.container = args[0] | ||
| options.command = args[1:] | ||
| return runExec(dockerCli, options) | ||
| options.Container = args[0] | ||
| options.Command = args[1:] | ||
| return RunExec(dockerCli, options) | ||
| }, | ||
| } | ||
|
|
||
| flags := cmd.Flags() | ||
| flags.SetInterspersed(false) | ||
|
|
||
| flags.StringVarP(&options.detachKeys, "detach-keys", "", "", "Override the key sequence for detaching a container") | ||
| flags.BoolVarP(&options.interactive, "interactive", "i", false, "Keep STDIN open even if not attached") | ||
| flags.BoolVarP(&options.tty, "tty", "t", false, "Allocate a pseudo-TTY") | ||
| flags.BoolVarP(&options.detach, "detach", "d", false, "Detached mode: run command in the background") | ||
| flags.StringVarP(&options.user, "user", "u", "", "Username or UID (format: <name|uid>[:<group|gid>])") | ||
| flags.BoolVarP(&options.privileged, "privileged", "", false, "Give extended privileges to the command") | ||
| flags.VarP(&options.env, "env", "e", "Set environment variables") | ||
| flags.StringVarP(&options.DetachKeys, "detach-keys", "", "", "Override the key sequence for detaching a container") | ||
| flags.BoolVarP(&options.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached") | ||
| flags.BoolVarP(&options.TTY, "tty", "t", false, "Allocate a pseudo-TTY") | ||
| flags.BoolVarP(&options.Detach, "detach", "d", false, "Detached mode: run command in the background") | ||
| flags.StringVarP(&options.User, "user", "u", "", "Username or UID (format: <name|uid>[:<group|gid>])") | ||
| flags.BoolVarP(&options.Privileged, "privileged", "", false, "Give extended privileges to the command") | ||
| flags.VarP(&options.Env, "env", "e", "Set environment variables") | ||
| flags.SetAnnotation("env", "version", []string{"1.25"}) | ||
| flags.Var(&options.envFile, "env-file", "Read in a file of environment variables") | ||
| flags.Var(&options.EnvFile, "env-file", "Read in a file of environment variables") | ||
| flags.SetAnnotation("env-file", "version", []string{"1.25"}) | ||
| flags.StringVarP(&options.workdir, "workdir", "w", "", "Working directory inside the container") | ||
| flags.StringVarP(&options.Workdir, "workdir", "w", "", "Working directory inside the container") | ||
| flags.SetAnnotation("workdir", "version", []string{"1.35"}) | ||
|
|
||
| return cmd | ||
| } | ||
|
|
||
| func runExec(dockerCli command.Cli, options execOptions) error { | ||
| // RunExec executes an `exec` command | ||
| func RunExec(dockerCli command.Cli, options ExecOptions) error { | ||
| execConfig, err := parseExec(options, dockerCli.ConfigFile()) | ||
| if err != nil { | ||
| return err | ||
|
|
@@ -84,7 +87,7 @@ func runExec(dockerCli command.Cli, options execOptions) error { | |
| // otherwise if we error out we will leak execIDs on the server (and | ||
| // there's no easy way to clean those up). But also in order to make "not | ||
| // exist" errors take precedence we do a dummy inspect first. | ||
| if _, err := client.ContainerInspect(ctx, options.container); err != nil { | ||
| if _, err := client.ContainerInspect(ctx, options.Container); err != nil { | ||
| return err | ||
| } | ||
| if !execConfig.Detach { | ||
|
|
@@ -93,7 +96,7 @@ func runExec(dockerCli command.Cli, options execOptions) error { | |
| } | ||
| } | ||
|
|
||
| response, err := client.ContainerExecCreate(ctx, options.container, *execConfig) | ||
| response, err := client.ContainerExecCreate(ctx, options.Container, *execConfig) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
@@ -195,33 +198,33 @@ func getExecExitStatus(ctx context.Context, client apiclient.ContainerAPIClient, | |
|
|
||
| // parseExec parses the specified args for the specified command and generates | ||
| // an ExecConfig from it. | ||
| func parseExec(execOpts execOptions, configFile *configfile.ConfigFile) (*types.ExecConfig, error) { | ||
| func parseExec(execOpts ExecOptions, configFile *configfile.ConfigFile) (*types.ExecConfig, error) { | ||
| execConfig := &types.ExecConfig{ | ||
| User: execOpts.user, | ||
| Privileged: execOpts.privileged, | ||
| Tty: execOpts.tty, | ||
| Cmd: execOpts.command, | ||
| Detach: execOpts.detach, | ||
| WorkingDir: execOpts.workdir, | ||
| User: execOpts.User, | ||
| Privileged: execOpts.Privileged, | ||
| Tty: execOpts.TTY, | ||
| Cmd: execOpts.Command, | ||
| Detach: execOpts.Detach, | ||
| WorkingDir: execOpts.Workdir, | ||
| } | ||
|
|
||
| // collect all the environment variables for the container | ||
| var err error | ||
| if execConfig.Env, err = opts.ReadKVEnvStrings(execOpts.envFile.GetAll(), execOpts.env.GetAll()); err != nil { | ||
| if execConfig.Env, err = opts.ReadKVEnvStrings(execOpts.EnvFile.GetAll(), execOpts.Env.GetAll()); err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| // If -d is not set, attach to everything by default | ||
| if !execOpts.detach { | ||
| if !execOpts.Detach { | ||
| execConfig.AttachStdout = true | ||
| execConfig.AttachStderr = true | ||
| if execOpts.interactive { | ||
| if execOpts.Interactive { | ||
| execConfig.AttachStdin = true | ||
| } | ||
| } | ||
|
|
||
| if execOpts.detachKeys != "" { | ||
| execConfig.DetachKeys = execOpts.detachKeys | ||
| if execOpts.DetachKeys != "" { | ||
| execConfig.DetachKeys = execOpts.DetachKeys | ||
| } else { | ||
| execConfig.DetachKeys = configFile.DetachKeys | ||
| } | ||
|
|
||
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.
Not something to change, more "thinking out loud"; when we're gonna work on "slicing and dicing" bits to make them more reusable, we should have a good look at options like this (does it have to be a special
opts.ListOptstype here, or could a generic type (such as a[]string) work for these).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.
docker/compose uses
[]stringand some user reported the help make in unclear, as it says expected type isarray.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, yes, the way Cobra generates the names for value types being directly related to the "type" used is often not very handy 😞
Was discussing that recently again with @crazy-max on docker/cli-docs-tool#19 (comment), where (it's kinda tacky, but we should improve things) we added an annotation to allow a custom "name" for values to be set (which could be somewhat more descriptive than
stringArray(e.g.)