mirror of
https://github.com/clearlinux/docker.git
synced 2026-09-06 13:41:36 +00:00
Fix symlink handling in builder ADD/COPY commands
Fixes #17290 Fixes following issues: - Cache checksums turning off while walking a broken symlink. - Cache checksums were taken from symlinks while targets were actually copied. - Copying a symlink pointing to a file to a directory used the basename of the target as a destination basename, instead of basename of the symlink. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com> (cherry picked from commit 47da59f7ec4ee0f49d47a9b32abb137bb30b2c48)
This commit is contained in:
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/docker/docker/builder/dockerfile/command"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
@@ -6223,3 +6224,127 @@ func (s *DockerSuite) TestBuildNoNamedVolume(c *check.C) {
|
||||
_, err := buildImage("test", dockerFile, false)
|
||||
c.Assert(err, check.NotNil, check.Commentf("image build should have failed"))
|
||||
}
|
||||
|
||||
// #17290
|
||||
func (s *DockerSuite) TestBuildCacheBrokenSymlink(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "testbuildbrokensymlink"
|
||||
ctx, err := fakeContext(`
|
||||
FROM busybox
|
||||
COPY . ./`,
|
||||
map[string]string{
|
||||
"foo": "bar",
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer ctx.Close()
|
||||
|
||||
err = os.Symlink(filepath.Join(ctx.Dir, "nosuchfile"), filepath.Join(ctx.Dir, "asymlink"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// warm up cache
|
||||
_, err = buildImageFromContext(name, ctx, true)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// add new file to context, should invalidate cache
|
||||
err = ioutil.WriteFile(filepath.Join(ctx.Dir, "newfile"), []byte("foo"), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, out, err := buildImageFromContextWithOut(name, ctx, true)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(out, checker.Not(checker.Contains), "Using cache")
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildFollowSymlinkToFile(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "testbuildbrokensymlink"
|
||||
ctx, err := fakeContext(`
|
||||
FROM busybox
|
||||
COPY asymlink target`,
|
||||
map[string]string{
|
||||
"foo": "bar",
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer ctx.Close()
|
||||
|
||||
err = os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
id, err := buildImageFromContext(name, ctx, true)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--rm", id, "cat", "target")
|
||||
c.Assert(out, checker.Matches, "bar")
|
||||
|
||||
// change target file should invalidate cache
|
||||
err = ioutil.WriteFile(filepath.Join(ctx.Dir, "foo"), []byte("baz"), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
id, out, err = buildImageFromContextWithOut(name, ctx, true)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Not(checker.Contains), "Using cache")
|
||||
|
||||
out, _ = dockerCmd(c, "run", "--rm", id, "cat", "target")
|
||||
c.Assert(out, checker.Matches, "baz")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildFollowSymlinkToDir(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "testbuildbrokensymlink"
|
||||
ctx, err := fakeContext(`
|
||||
FROM busybox
|
||||
COPY asymlink /`,
|
||||
map[string]string{
|
||||
"foo/abc": "bar",
|
||||
"foo/def": "baz",
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer ctx.Close()
|
||||
|
||||
err = os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
id, err := buildImageFromContext(name, ctx, true)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--rm", id, "cat", "abc", "def")
|
||||
c.Assert(out, checker.Matches, "barbaz")
|
||||
|
||||
// change target file should invalidate cache
|
||||
err = ioutil.WriteFile(filepath.Join(ctx.Dir, "foo/def"), []byte("bax"), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
id, out, err = buildImageFromContextWithOut(name, ctx, true)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Not(checker.Contains), "Using cache")
|
||||
|
||||
out, _ = dockerCmd(c, "run", "--rm", id, "cat", "abc", "def")
|
||||
c.Assert(out, checker.Matches, "barbax")
|
||||
|
||||
}
|
||||
|
||||
// TestBuildSymlinkBasename tests that target file gets basename from symlink,
|
||||
// not from the target file.
|
||||
func (s *DockerSuite) TestBuildSymlinkBasename(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "testbuildbrokensymlink"
|
||||
ctx, err := fakeContext(`
|
||||
FROM busybox
|
||||
COPY asymlink /`,
|
||||
map[string]string{
|
||||
"foo": "bar",
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer ctx.Close()
|
||||
|
||||
err = os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
id, err := buildImageFromContext(name, ctx, true)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--rm", id, "cat", "asymlink")
|
||||
c.Assert(out, checker.Matches, "bar")
|
||||
|
||||
}
|
||||
|
||||
@@ -1214,6 +1214,14 @@ func buildImage(name, dockerfile string, useCache bool, buildFlags ...string) (s
|
||||
}
|
||||
|
||||
func buildImageFromContext(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, error) {
|
||||
id, _, err := buildImageFromContextWithOut(name, ctx, useCache, buildFlags...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func buildImageFromContextWithOut(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, string, error) {
|
||||
args := []string{"build", "-t", name}
|
||||
if !useCache {
|
||||
args = append(args, "--no-cache")
|
||||
@@ -1224,9 +1232,13 @@ func buildImageFromContext(name string, ctx *FakeContext, useCache bool, buildFl
|
||||
buildCmd.Dir = ctx.Dir
|
||||
out, exitCode, err := runCommandWithOutput(buildCmd)
|
||||
if err != nil || exitCode != 0 {
|
||||
return "", fmt.Errorf("failed to build the image: %s", out)
|
||||
return "", "", fmt.Errorf("failed to build the image: %s", out)
|
||||
}
|
||||
return getIDByName(name)
|
||||
id, err := getIDByName(name)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return id, out, nil
|
||||
}
|
||||
|
||||
func buildImageFromPath(name, path string, useCache bool, buildFlags ...string) (string, error) {
|
||||
|
||||
Reference in New Issue
Block a user