Skip to content

Commit

Permalink
Merge branch 'rm_volume_fail' into 'huawei-1.11.2'
Browse files Browse the repository at this point in the history
Fix duplicate mount point for `--volumes-from` in `docker run`

This fix tries to fix the issue raised in 21845. The issue with 21845
is that if multiple `--volumes-from` with the same destination has been
specified, then one volume will be overridden by the other. This will mess
up with volumes reference and prevent the overridden volume from
being removed at the end.

Issue 21845 was observed with `docker-compose` though it is possible to
emulate the same behavior with `docker` alone:
```
$ cat Dockerfile
FROM busybox
VOLUME ["/tmp/data"]
$ docker build -t vimage .
$ docker run --name=data1 vimage true
$ docker run --name=data2 vimage true
$ docker run --name=app --volumes-from=data1 --volumes-from=data2 -d busybox top
$ docker rm -f -v $(docker ps -aq)
$ docker volume ls
$ docker volume rm ...
```
NOTE: Second case:
```
$ cat Dockerfile
FROM busybox
VOLUME ["/tmp/data"]
$ docker build -t vimage .
$ docker run --name=data1 vimage true
$ docker run --name=data2 vimage true
$ docker run --name=app --volumes-from=data1 --volumes-from=data2 -v /tmp/data:/tmp/data -d busybox top
$ docker rm -f -v $(docker ps -aq)
$ docker volume ls
$ docker volume rm ...
```
NOTE: Third case: Combination of --volumes-from and `HostConfig.Mounts` (API only)

This fix tries to address the issue by return an error if duplicate
mount points was used with `--volumes-from`.

An integration test has been added.

This fix fixes 21845.

cherry-picked from upstream moby#29563

Fix issue moby#338
Fix DTS2017070606746
note: Our code does not support API HostConfig.Mounts, so i delete
      the test case of third case.

Signed-off-by: Yong Tang <[email protected]>
Signed-off-by: Fengtu Wang <[email protected]>

Conflicts:
	daemon/volumes.go
	integration-cli/docker_cli_volume_test.go



See merge request docker/docker!661
  • Loading branch information
FengtuWang authored and hqhq committed Jul 10, 2017
2 parents dd719af + 3205df4 commit c4e6a48
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 1 deletion.
13 changes: 12 additions & 1 deletion daemon/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path/filepath"
"strings"

"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
"github.com/docker/docker/volume"
"github.com/docker/engine-api/types"
Expand Down Expand Up @@ -81,6 +82,15 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
}
}()

dereferenceIfExists := func(destination string) {
if v, ok := mountPoints[destination]; ok {
logrus.Debugf("Duplicate mount point '%s'", destination)
if v.Volume != nil {
daemon.volumes.Dereference(v.Volume, container.ID)
}
}
}

// 1. Read already configured mount points.
for name, point := range container.MountPoints {
mountPoints[name] = point
Expand Down Expand Up @@ -116,7 +126,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
}
cp.Volume = v
}

dereferenceIfExists(cp.Destination)
mountPoints[cp.Destination] = cp
}
}
Expand Down Expand Up @@ -156,6 +166,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
}
}
binds[bind.Destination] = true
dereferenceIfExists(bind.Destination)
mountPoints[bind.Destination] = bind
}

Expand Down
89 changes: 89 additions & 0 deletions integration-cli/docker_cli_volume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,92 @@ func (s *DockerSuite) TestVolumeCliCreateLabelMultiple(c *check.C) {
c.Assert(strings.TrimSpace(out), check.Equals, v)
}
}

// Test case (1) for 21845: duplicate targets for --volumes-from
func (s *DockerSuite) TestDuplicateMountpointsForVolumesFrom(c *check.C) {
testRequires(c, DaemonIsLinux)

image := "vimage"
_, err := buildImage(image, `
FROM busybox
VOLUME ["/tmp/data"]
`, true)
c.Assert(err, checker.IsNil, check.Commentf("error: %v", err))

dockerCmd(c, "run", "--name=data1", image, "true")
dockerCmd(c, "run", "--name=data2", image, "true")

out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
data1 := strings.TrimSpace(out)
c.Assert(data1, checker.Not(checker.Equals), "")

out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
data2 := strings.TrimSpace(out)
c.Assert(data2, checker.Not(checker.Equals), "")

// Both volume should exist
out, _ = dockerCmd(c, "volume", "ls", "-q")
c.Assert(strings.TrimSpace(out), checker.Contains, data1)
c.Assert(strings.TrimSpace(out), checker.Contains, data2)

out, _, err = dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-d", "busybox", "top")
c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))

// Only the second volume will be referenced, this is backward compatible
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
c.Assert(strings.TrimSpace(out), checker.Equals, data2)

dockerCmd(c, "rm", "-f", "-v", "app")
dockerCmd(c, "rm", "-f", "-v", "data1")
dockerCmd(c, "rm", "-f", "-v", "data2")

// Both volume should not exist
out, _ = dockerCmd(c, "volume", "ls", "-q")
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
}

// Test case (2) for 21845: duplicate targets for --volumes-from and -v (bind)
func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndBind(c *check.C) {
testRequires(c, DaemonIsLinux)

image := "vimage"
_, err := buildImage(image, `
FROM busybox
VOLUME ["/tmp/data"]
`, true)
c.Assert(err, checker.IsNil, check.Commentf("error: %v", err))

dockerCmd(c, "run", "--name=data1", image, "true")
dockerCmd(c, "run", "--name=data2", image, "true")

out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
data1 := strings.TrimSpace(out)
c.Assert(data1, checker.Not(checker.Equals), "")

out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
data2 := strings.TrimSpace(out)
c.Assert(data2, checker.Not(checker.Equals), "")

// Both volume should exist
out, _ = dockerCmd(c, "volume", "ls", "-q")
c.Assert(strings.TrimSpace(out), checker.Contains, data1)
c.Assert(strings.TrimSpace(out), checker.Contains, data2)

out, _, err = dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-v", "/tmp/data:/tmp/data", "-d", "busybox", "top")
c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))

// No volume will be referenced (mount is /tmp/data), this is backward compatible
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)

dockerCmd(c, "rm", "-f", "-v", "app")
dockerCmd(c, "rm", "-f", "-v", "data1")
dockerCmd(c, "rm", "-f", "-v", "data2")

// Both volume should not exist
out, _ = dockerCmd(c, "volume", "ls", "-q")
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
}

0 comments on commit c4e6a48

Please sign in to comment.