From 156191d710101658edc1f9d170f626f5d586a9c2 Mon Sep 17 00:00:00 2001 From: Kara Alexandra Date: Fri, 30 Sep 2016 12:40:06 -0700 Subject: [PATCH] Add --chown flag to Dockerfile ADD and COPY Rebased by @estesp Signed-off-by: Kara Alexandra Signed-off-by: Phil Estes Upstream-commit: 858fad37954b198bb90aed36017b80b38ea88c1d Component: engine --- .../engine/builder/dockerfile/dispatchers.go | 2 + components/engine/container/container.go | 31 ++++++++ .../integration-cli/docker_cli_build_test.go | 72 +++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/components/engine/builder/dockerfile/dispatchers.go b/components/engine/builder/dockerfile/dispatchers.go index 1f74241248..182dd7ca8d 100644 --- a/components/engine/builder/dockerfile/dispatchers.go +++ b/components/engine/builder/dockerfile/dispatchers.go @@ -146,6 +146,7 @@ func add(req dispatchRequest) error { return errAtLeastTwoArguments("ADD") } + flChown := req.flags.AddString("chown", "") if err := req.flags.Parse(); err != nil { return err } @@ -172,6 +173,7 @@ func dispatchCopy(req dispatchRequest) error { } flFrom := req.flags.AddString("from", "") + flChown := req.flags.AddString("chown", "") if err := req.flags.Parse(); err != nil { return err } diff --git a/components/engine/container/container.go b/components/engine/container/container.go index 86e0111445..e719c96c4f 100644 --- a/components/engine/container/container.go +++ b/components/engine/container/container.go @@ -44,6 +44,7 @@ import ( "github.com/docker/libnetwork/options" "github.com/docker/libnetwork/types" agentexec "github.com/docker/swarmkit/agent/exec" + "github.com/opencontainers/runc/libcontainer/user" "golang.org/x/net/context" ) @@ -331,6 +332,36 @@ func (container *Container) GetRootResourcePath(path string) (string, error) { return symlink.FollowSymlinkInScope(filepath.Join(container.Root, cleanPath), container.Root) } +// ParseUserGrp takes `username` in the format of username, uid, username:groupname, +// uid:gid, username:gid, or uid:groupname and parses the passwd file in the container +// to return the ExecUser referred to by `username`. +func (container *Container) ParseUserGrp(username string) (*user.ExecUser, error) { + passwdPath, err := user.GetPasswdPath() + if err != nil { + return nil, err + } + passwdPath, err = container.GetResourcePath(passwdPath) + if err != nil { + return nil, err + } + + groupPath, err := user.GetGroupPath() + if err != nil { + return nil, err + } + groupPath, err = container.GetResourcePath(groupPath) + if err != nil { + return nil, err + } + + execUser, err := user.GetExecUserPath(username, nil, passwdPath, groupPath) + if err != nil { + return nil, err + } + + return execUser, nil +} + // ExitOnNext signals to the monitor that it should not restart the container // after we send the kill signal. func (container *Container) ExitOnNext() { diff --git a/components/engine/integration-cli/docker_cli_build_test.go b/components/engine/integration-cli/docker_cli_build_test.go index 5a3d3efc65..fbda41de90 100644 --- a/components/engine/integration-cli/docker_cli_build_test.go +++ b/components/engine/integration-cli/docker_cli_build_test.go @@ -602,6 +602,78 @@ RUN [ $(cat "/test dir/test_file6") = 'test6' ]`, command, command, command, com } } +func (s *DockerSuite) TestBuildAddChownFlag(c *check.C) { + testRequires(c, DaemonIsLinux) // Linux specific test + name := "testaddtonewdest" + ctx, err := fakeContext(`FROM busybox +RUN echo 'test1:x:1001:1001::/bin:/bin/false' >> /etc/passwd +RUN echo 'test1:x:1001:' >> /etc/group +RUN echo 'test2:x:1002:' >> /etc/group +ADD --chown=test1:1002 . /new_dir +RUN ls -l / +RUN [ $(ls -l / | grep new_dir | awk '{print $3":"$4}') = 'test1:test2' ]`, + map[string]string{ + "test_dir/test_file": "test file", + }) + if err != nil { + c.Fatal(err) + } + defer ctx.Close() + + if _, err := buildImageFromContext(name, ctx, true); err != nil { + c.Fatal(err) + } +} + +func (s *DockerDaemonSuite) TestBuildAddChownFlagUserNamespace(c *check.C) { + testRequires(c, DaemonIsLinux) // Linux specific test + + c.Assert(s.d.StartWithBusybox("--userns-remap", "default"), checker.IsNil) + + name := "testaddtonewdest" + ctx, err := fakeContext(`FROM busybox +RUN echo 'test1:x:1001:1001::/bin:/bin/false' >> /etc/passwd +RUN echo 'test1:x:1001:' >> /etc/group +RUN echo 'test2:x:1002:' >> /etc/group +ADD --chown=test1:1002 . /new_dir +RUN ls -l / +RUN [ $(ls -l / | grep new_dir | awk '{print $3":"$4}') = 'test1:test2' ]`, + map[string]string{ + "test_dir/test_file": "test file", + }) + if err != nil { + c.Fatal(err) + } + defer ctx.Close() + + if _, err := buildImageFromContext(name, ctx, true); err != nil { + c.Fatal(err) + } +} + +func (s *DockerSuite) TestBuildCopyChownFlag(c *check.C) { + testRequires(c, DaemonIsLinux) // Linux specific test + name := "testaddtonewdest" + ctx, err := fakeContext(`FROM busybox +RUN echo 'test1:x:1001:1001::/bin:/bin/false' >> /etc/passwd +RUN echo 'test1:x:1001:' >> /etc/group +RUN echo 'test2:x:1002:' >> /etc/group +COPY --chown=test1:1002 . /new_dir +RUN ls -l / +RUN [ $(ls -l / | grep new_dir | awk '{print $3":"$4}') = 'test1:test2' ]`, + map[string]string{ + "test_dir/test_file": "test file", + }) + if err != nil { + c.Fatal(err) + } + defer ctx.Close() + + if _, err := buildImageFromContext(name, ctx, true); err != nil { + c.Fatal(err) + } +} + func (s *DockerSuite) TestBuildCopyFileWithWhitespaceOnWindows(c *check.C) { testRequires(c, DaemonIsWindows) dockerfile := `FROM ` + testEnv.MinimalBaseImage() + `