introduce `workingdir` option for docker exec
Vincent Demeester authored on 2017/12/06 20:40:25... | ... |
@@ -7259,6 +7259,9 @@ paths: |
7259 | 7259 |
User: |
7260 | 7260 |
type: "string" |
7261 | 7261 |
description: "The user, and optionally, group to run the exec process inside the container. Format is one of: `user`, `user:group`, `uid`, or `uid:gid`." |
7262 |
+ WorkingDir: |
|
7263 |
+ type: "string" |
|
7264 |
+ description: "The working directory for the exec process inside the container." |
|
7262 | 7265 |
example: |
7263 | 7266 |
AttachStdin: false |
7264 | 7267 |
AttachStdout: true |
... | ... |
@@ -122,6 +122,7 @@ func (d *Daemon) ContainerExecCreate(name string, config *types.ExecConfig) (str |
122 | 122 |
execConfig.Tty = config.Tty |
123 | 123 |
execConfig.Privileged = config.Privileged |
124 | 124 |
execConfig.User = config.User |
125 |
+ execConfig.WorkingDir = config.WorkingDir |
|
125 | 126 |
|
126 | 127 |
linkedEnv, err := d.setupLinkedContainers(cntr) |
127 | 128 |
if err != nil { |
... | ... |
@@ -131,6 +132,9 @@ func (d *Daemon) ContainerExecCreate(name string, config *types.ExecConfig) (str |
131 | 131 |
if len(execConfig.User) == 0 { |
132 | 132 |
execConfig.User = cntr.Config.User |
133 | 133 |
} |
134 |
+ if len(execConfig.WorkingDir) == 0 { |
|
135 |
+ execConfig.WorkingDir = cntr.Config.WorkingDir |
|
136 |
+ } |
|
134 | 137 |
|
135 | 138 |
d.registerExecCommand(cntr, execConfig) |
136 | 139 |
|
... | ... |
@@ -211,7 +215,7 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R |
211 | 211 |
Args: append([]string{ec.Entrypoint}, ec.Args...), |
212 | 212 |
Env: ec.Env, |
213 | 213 |
Terminal: ec.Tty, |
214 |
- Cwd: c.Config.WorkingDir, |
|
214 |
+ Cwd: ec.WorkingDir, |
|
215 | 215 |
} |
216 | 216 |
if p.Cwd == "" { |
217 | 217 |
p.Cwd = "/" |
37 | 38 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,60 @@ |
0 |
+package container |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "context" |
|
4 |
+ "io/ioutil" |
|
5 |
+ "testing" |
|
6 |
+ |
|
7 |
+ "github.com/docker/docker/api/types" |
|
8 |
+ "github.com/docker/docker/api/types/container" |
|
9 |
+ "github.com/docker/docker/api/types/network" |
|
10 |
+ "github.com/docker/docker/api/types/strslice" |
|
11 |
+ "github.com/docker/docker/integration/util/request" |
|
12 |
+ "github.com/stretchr/testify/require" |
|
13 |
+) |
|
14 |
+ |
|
15 |
+func TestExec(t *testing.T) { |
|
16 |
+ defer setupTest(t)() |
|
17 |
+ ctx := context.Background() |
|
18 |
+ client := request.NewAPIClient(t) |
|
19 |
+ |
|
20 |
+ container, err := client.ContainerCreate(ctx, |
|
21 |
+ &container.Config{ |
|
22 |
+ Image: "busybox", |
|
23 |
+ Tty: true, |
|
24 |
+ WorkingDir: "/root", |
|
25 |
+ Cmd: strslice.StrSlice([]string{"top"}), |
|
26 |
+ }, |
|
27 |
+ &container.HostConfig{}, |
|
28 |
+ &network.NetworkingConfig{}, |
|
29 |
+ "foo", |
|
30 |
+ ) |
|
31 |
+ require.NoError(t, err) |
|
32 |
+ err = client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}) |
|
33 |
+ require.NoError(t, err) |
|
34 |
+ |
|
35 |
+ id, err := client.ContainerExecCreate(ctx, container.ID, |
|
36 |
+ types.ExecConfig{ |
|
37 |
+ WorkingDir: "/tmp", |
|
38 |
+ Env: strslice.StrSlice([]string{"FOO=BAR"}), |
|
39 |
+ AttachStdout: true, |
|
40 |
+ Cmd: strslice.StrSlice([]string{"sh", "-c", "env"}), |
|
41 |
+ }, |
|
42 |
+ ) |
|
43 |
+ require.NoError(t, err) |
|
44 |
+ |
|
45 |
+ resp, err := client.ContainerExecAttach(ctx, id.ID, |
|
46 |
+ types.ExecStartCheck{ |
|
47 |
+ Detach: false, |
|
48 |
+ Tty: false, |
|
49 |
+ }, |
|
50 |
+ ) |
|
51 |
+ require.NoError(t, err) |
|
52 |
+ defer resp.Close() |
|
53 |
+ r, err := ioutil.ReadAll(resp.Reader) |
|
54 |
+ require.NoError(t, err) |
|
55 |
+ out := string(r) |
|
56 |
+ require.NoError(t, err) |
|
57 |
+ require.Contains(t, out, "PWD=/tmp", "exec command not running in expected /tmp working directory") |
|
58 |
+ require.Contains(t, out, "FOO=BAR", "exec command not running with expected environment variable FOO") |
|
59 |
+} |