Keeping the current behavior for exec, i.e., inheriting
variables from main process. New variables will be added
to current ones. If there's already a variable with that
name it will be overwritten.
Example of usage: docker exec -it -e TERM=vt100 <container> top
Closes #24355.
Signed-off-by: Jonh Wendell <jonh.wendell@redhat.com>
... | ... |
@@ -11,7 +11,9 @@ import ( |
11 | 11 |
"github.com/docker/docker/cli" |
12 | 12 |
"github.com/docker/docker/cli/command" |
13 | 13 |
apiclient "github.com/docker/docker/client" |
14 |
+ options "github.com/docker/docker/opts" |
|
14 | 15 |
"github.com/docker/docker/pkg/promise" |
16 |
+ runconfigopts "github.com/docker/docker/runconfig/opts" |
|
15 | 17 |
"github.com/spf13/cobra" |
16 | 18 |
) |
17 | 19 |
|
... | ... |
@@ -22,11 +24,19 @@ type execOptions struct { |
22 | 22 |
detach bool |
23 | 23 |
user string |
24 | 24 |
privileged bool |
25 |
+ env *options.ListOpts |
|
26 |
+} |
|
27 |
+ |
|
28 |
+func newExecOptions() *execOptions { |
|
29 |
+ var values []string |
|
30 |
+ return &execOptions{ |
|
31 |
+ env: options.NewListOptsRef(&values, runconfigopts.ValidateEnv), |
|
32 |
+ } |
|
25 | 33 |
} |
26 | 34 |
|
27 | 35 |
// NewExecCommand creats a new cobra.Command for `docker exec` |
28 | 36 |
func NewExecCommand(dockerCli *command.DockerCli) *cobra.Command { |
29 |
- var opts execOptions |
|
37 |
+ opts := newExecOptions() |
|
30 | 38 |
|
31 | 39 |
cmd := &cobra.Command{ |
32 | 40 |
Use: "exec [OPTIONS] CONTAINER COMMAND [ARG...]", |
... | ... |
@@ -35,7 +45,7 @@ func NewExecCommand(dockerCli *command.DockerCli) *cobra.Command { |
35 | 35 |
RunE: func(cmd *cobra.Command, args []string) error { |
36 | 36 |
container := args[0] |
37 | 37 |
execCmd := args[1:] |
38 |
- return runExec(dockerCli, &opts, container, execCmd) |
|
38 |
+ return runExec(dockerCli, opts, container, execCmd) |
|
39 | 39 |
}, |
40 | 40 |
} |
41 | 41 |
|
... | ... |
@@ -48,6 +58,7 @@ func NewExecCommand(dockerCli *command.DockerCli) *cobra.Command { |
48 | 48 |
flags.BoolVarP(&opts.detach, "detach", "d", false, "Detached mode: run command in the background") |
49 | 49 |
flags.StringVarP(&opts.user, "user", "u", "", "Username or UID (format: <name|uid>[:<group|gid>])") |
50 | 50 |
flags.BoolVarP(&opts.privileged, "privileged", "", false, "Give extended privileges to the command") |
51 |
+ flags.VarP(opts.env, "env", "e", "Set environment variables") |
|
51 | 52 |
|
52 | 53 |
return cmd |
53 | 54 |
} |
... | ... |
@@ -188,5 +199,9 @@ func parseExec(opts *execOptions, container string, execCmd []string) (*types.Ex |
188 | 188 |
} |
189 | 189 |
} |
190 | 190 |
|
191 |
+ if opts.env != nil { |
|
192 |
+ execConfig.Env = opts.env.GetAll() |
|
193 |
+ } |
|
194 |
+ |
|
191 | 195 |
return execConfig, nil |
192 | 196 |
} |
... | ... |
@@ -1274,7 +1274,7 @@ _docker_exec() { |
1274 | 1274 |
|
1275 | 1275 |
case "$cur" in |
1276 | 1276 |
-*) |
1277 |
- COMPREPLY=( $( compgen -W "--detach -d --detach-keys --help --interactive -i --privileged -t --tty -u --user" -- "$cur" ) ) |
|
1277 |
+ COMPREPLY=( $( compgen -W "--detach -d --detach-keys -e --env --help --interactive -i --privileged -t --tty -u --user" -- "$cur" ) ) |
|
1278 | 1278 |
;; |
1279 | 1279 |
*) |
1280 | 1280 |
__docker_complete_containers_running |
... | ... |
@@ -1679,6 +1679,7 @@ __docker_subcommand() { |
1679 | 1679 |
$opts_help \ |
1680 | 1680 |
$opts_attach_exec_run_start \ |
1681 | 1681 |
"($help -d --detach)"{-d,--detach}"[Detached mode: leave the container running in the background]" \ |
1682 |
+ "($help -e --env)"{-e,--env}"[Set environment variables]" \ |
|
1682 | 1683 |
"($help -i --interactive)"{-i,--interactive}"[Keep stdin open even if not attached]" \ |
1683 | 1684 |
"($help)--privileged[Give extended Linux capabilities to the command]" \ |
1684 | 1685 |
"($help -t --tty)"{-t,--tty}"[Allocate a pseudo-tty]" \ |
... | ... |
@@ -127,7 +127,7 @@ func (d *Daemon) ContainerExecCreate(name string, config *types.ExecConfig) (str |
127 | 127 |
if err != nil { |
128 | 128 |
return "", err |
129 | 129 |
} |
130 |
- execConfig.Env = utils.ReplaceOrAppendEnvValues(container.CreateDaemonEnvironment(config.Tty, linkedEnv), execConfig.Env) |
|
130 |
+ execConfig.Env = utils.ReplaceOrAppendEnvValues(container.CreateDaemonEnvironment(config.Tty, linkedEnv), config.Env) |
|
131 | 131 |
if len(execConfig.User) == 0 { |
132 | 132 |
execConfig.User = container.Config.User |
133 | 133 |
} |
... | ... |
@@ -131,6 +131,7 @@ This section lists each version from latest to oldest. Each listing includes a |
131 | 131 |
* `POST /containers/create` now takes `StopTimeout` field. |
132 | 132 |
* `POST /services/create` and `POST /services/(id or name)/update` now accept `Monitor` and `MaxFailureRatio` parameters, which control the response to failures during service updates. |
133 | 133 |
* `GET /networks/(name)` now returns `Created`. |
134 |
+* `POST /containers/(id or name)/exec` now accepts an `Env` field, which holds a list of environment variables to be set in the context of the command execution. |
|
134 | 135 |
|
135 | 136 |
### v1.24 API changes |
136 | 137 |
|
... | ... |
@@ -3151,6 +3151,10 @@ Sets up an exec instance in a running container `id` |
3151 | 3151 |
"AttachStderr": true, |
3152 | 3152 |
"Cmd": ["sh"], |
3153 | 3153 |
"DetachKeys": "ctrl-p,ctrl-q", |
3154 |
+ "Env": [ |
|
3155 |
+ "FOO=bar", |
|
3156 |
+ "BAZ=quux" |
|
3157 |
+ ], |
|
3154 | 3158 |
"Privileged": true, |
3155 | 3159 |
"Tty": true, |
3156 | 3160 |
"User": "123:456" |
... | ... |
@@ -3175,6 +3179,7 @@ Sets up an exec instance in a running container `id` |
3175 | 3175 |
container. Format is a single character `[a-Z]` or `ctrl-<value>` |
3176 | 3176 |
where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. |
3177 | 3177 |
- **Tty** - Boolean value to allocate a pseudo-TTY. |
3178 |
+- **Env** - A list of environment variables in the form of `["VAR=value", ...]` |
|
3178 | 3179 |
- **Cmd** - Command to run specified as a string or an array of strings. |
3179 | 3180 |
- **Privileged** - Boolean value, runs the exec process with extended privileges. |
3180 | 3181 |
- **User** - A string value specifying the user, and optionally, group to run |
... | ... |
@@ -14,6 +14,7 @@ Run a command in a running container |
14 | 14 |
Options: |
15 | 15 |
-d, --detach Detached mode: run command in the background |
16 | 16 |
--detach-keys Override the key sequence for detaching a container |
17 |
+ -e, --env=[] Set environment variables |
|
17 | 18 |
--help Print usage |
18 | 19 |
-i, --interactive Keep STDIN open even if not attached |
19 | 20 |
--privileged Give extended privileges to the command |
... | ... |
@@ -119,6 +119,17 @@ func (s *DockerSuite) TestExecEnv(c *check.C) { |
119 | 119 |
c.Assert(out, checker.Contains, "HOME=/root") |
120 | 120 |
} |
121 | 121 |
|
122 |
+func (s *DockerSuite) TestExecSetEnv(c *check.C) { |
|
123 |
+ testRequires(c, DaemonIsLinux) |
|
124 |
+ runSleepingContainer(c, "-e", "HOME=/root", "-d", "--name", "testing") |
|
125 |
+ c.Assert(waitRun("testing"), check.IsNil) |
|
126 |
+ |
|
127 |
+ out, _ := dockerCmd(c, "exec", "-e", "HOME=/another", "-e", "ABC=xyz", "testing", "env") |
|
128 |
+ c.Assert(out, checker.Not(checker.Contains), "HOME=/root") |
|
129 |
+ c.Assert(out, checker.Contains, "HOME=/another") |
|
130 |
+ c.Assert(out, checker.Contains, "ABC=xyz") |
|
131 |
+} |
|
132 |
+ |
|
122 | 133 |
func (s *DockerSuite) TestExecExitStatus(c *check.C) { |
123 | 134 |
runSleepingContainer(c, "-d", "--name", "top") |
124 | 135 |
|
... | ... |
@@ -45,7 +45,7 @@ func (clnt *client) AddProcess(ctx context.Context, containerID, processFriendly |
45 | 45 |
sp := spec.Process |
46 | 46 |
sp.Args = specp.Args |
47 | 47 |
sp.Terminal = specp.Terminal |
48 |
- if specp.Env != nil { |
|
48 |
+ if len(specp.Env) > 0 { |
|
49 | 49 |
sp.Env = specp.Env |
50 | 50 |
} |
51 | 51 |
if specp.Cwd != nil { |
... | ... |
@@ -8,6 +8,7 @@ docker-exec - Run a command in a running container |
8 | 8 |
**docker exec** |
9 | 9 |
[**-d**|**--detach**] |
10 | 10 |
[**--detach-keys**[=*[]*]] |
11 |
+[**-e**|**--env**[=*[]*]] |
|
11 | 12 |
[**--help**] |
12 | 13 |
[**-i**|**--interactive**] |
13 | 14 |
[**--privileged**] |
... | ... |
@@ -32,6 +33,12 @@ container is unpaused, and then run |
32 | 32 |
**--detach-keys**="" |
33 | 33 |
Override the key sequence for detaching a container. Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. |
34 | 34 |
|
35 |
+**-e**, **--env**=[] |
|
36 |
+ Set environment variables |
|
37 |
+ |
|
38 |
+ This option allows you to specify arbitrary environment variables that are |
|
39 |
+available for the command to be executed. |
|
40 |
+ |
|
35 | 41 |
**--help** |
36 | 42 |
Print usage statement |
37 | 43 |
|