From 19f2749d3906707717aeec9da27c499bcdc07da8 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof <nicolas.deloof@gmail.com> Date: Fri, 1 Dec 2017 09:06:07 +0100 Subject: [PATCH 1/2] introduce `workingdir` option for docker exec Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com> --- api/swagger.yaml | 3 +++ api/types/configs.go | 1 + daemon/exec.go | 6 +++++- daemon/exec/exec.go | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/api/swagger.yaml b/api/swagger.yaml index 07ee0674cd..a01926df6e 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -7269,6 +7269,9 @@ paths: User: type: "string" 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`." + WorkingDir: + type: "string" + description: "The working directory for the exec process inside the container." example: AttachStdin: false AttachStdout: true diff --git a/api/types/configs.go b/api/types/configs.go index 20c19f2132..54d3e39fb9 100644 --- a/api/types/configs.go +++ b/api/types/configs.go @@ -50,6 +50,7 @@ type ExecConfig struct { Detach bool // Execute in detach mode DetachKeys string // Escape keys for detach Env []string // Environment variables + WorkingDir string // Working directory Cmd []string // Execution commands and args } diff --git a/daemon/exec.go b/daemon/exec.go index 01670faa5d..83b7de2255 100644 --- a/daemon/exec.go +++ b/daemon/exec.go @@ -122,6 +122,7 @@ func (d *Daemon) ContainerExecCreate(name string, config *types.ExecConfig) (str execConfig.Tty = config.Tty execConfig.Privileged = config.Privileged execConfig.User = config.User + execConfig.WorkingDir = config.WorkingDir linkedEnv, err := d.setupLinkedContainers(cntr) if err != nil { @@ -131,6 +132,9 @@ func (d *Daemon) ContainerExecCreate(name string, config *types.ExecConfig) (str if len(execConfig.User) == 0 { execConfig.User = cntr.Config.User } + if len(execConfig.WorkingDir) == 0 { + execConfig.WorkingDir = cntr.Config.WorkingDir + } d.registerExecCommand(cntr, execConfig) @@ -211,7 +215,7 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R Args: append([]string{ec.Entrypoint}, ec.Args...), Env: ec.Env, Terminal: ec.Tty, - Cwd: c.Config.WorkingDir, + Cwd: ec.WorkingDir, } if p.Cwd == "" { p.Cwd = "/" diff --git a/daemon/exec/exec.go b/daemon/exec/exec.go index 193d32f022..370b4032c7 100644 --- a/daemon/exec/exec.go +++ b/daemon/exec/exec.go @@ -31,6 +31,7 @@ type Config struct { Tty bool Privileged bool User string + WorkingDir string Env []string Pid int } From 39d5ace6e1c8f3f7a008fcdf328592bfa799a243 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof <nicolas.deloof@gmail.com> Date: Sun, 3 Dec 2017 10:56:50 +0100 Subject: [PATCH 2/2] =?UTF-8?q?test=20case=20to=20check=20=C2=AB=C2=A0exec?= =?UTF-8?q?=C2=A0=C2=BB=20works=20as=20expected?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com> --- integration/container/exec_test.go | 60 ++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 integration/container/exec_test.go diff --git a/integration/container/exec_test.go b/integration/container/exec_test.go new file mode 100644 index 0000000000..22d7ec01cc --- /dev/null +++ b/integration/container/exec_test.go @@ -0,0 +1,60 @@ +package container + +import ( + "context" + "io/ioutil" + "testing" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/strslice" + "github.com/docker/docker/integration/util/request" + "github.com/stretchr/testify/require" +) + +func TestExec(t *testing.T) { + defer setupTest(t)() + ctx := context.Background() + client := request.NewAPIClient(t) + + container, err := client.ContainerCreate(ctx, + &container.Config{ + Image: "busybox", + Tty: true, + WorkingDir: "/root", + Cmd: strslice.StrSlice([]string{"top"}), + }, + &container.HostConfig{}, + &network.NetworkingConfig{}, + "foo", + ) + require.NoError(t, err) + err = client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}) + require.NoError(t, err) + + id, err := client.ContainerExecCreate(ctx, container.ID, + types.ExecConfig{ + WorkingDir: "/tmp", + Env: strslice.StrSlice([]string{"FOO=BAR"}), + AttachStdout: true, + Cmd: strslice.StrSlice([]string{"sh", "-c", "env"}), + }, + ) + require.NoError(t, err) + + resp, err := client.ContainerExecAttach(ctx, id.ID, + types.ExecStartCheck{ + Detach: false, + Tty: false, + }, + ) + require.NoError(t, err) + defer resp.Close() + r, err := ioutil.ReadAll(resp.Reader) + require.NoError(t, err) + out := string(r) + require.NoError(t, err) + require.Contains(t, out, "PWD=/tmp", "exec command not running in expected /tmp working directory") + require.Contains(t, out, "FOO=BAR", "exec command not running with expected environment variable FOO") +}