diff --git a/daemon/volumes.go b/daemon/volumes.go index fdfc35a932..1cdcf6c29b 100644 --- a/daemon/volumes.go +++ b/daemon/volumes.go @@ -25,6 +25,7 @@ type Mount struct { Writable bool copyData bool from *Container + isBind bool } func (mnt *Mount) Export(resource string) (io.ReadCloser, error) { @@ -80,7 +81,7 @@ func (m *Mount) initialize() error { if hostPath, exists := m.container.Volumes[m.MountToPath]; exists { // If this is a bind-mount/volumes-from, maybe it was passed in at start instead of create // We need to make sure bind-mounts/volumes-from passed on start can override existing ones. - if !m.volume.IsBindMount && m.from == nil { + if (!m.volume.IsBindMount && !m.isBind) && m.from == nil { return nil } if m.volume.Path == hostPath { @@ -172,6 +173,7 @@ func (container *Container) parseVolumeMountConfig() (map[string]*Mount, error) volume: vol, MountToPath: mountToPath, Writable: writable, + isBind: true, // in case the volume itself is a normal volume, but is being mounted in as a bindmount here } } diff --git a/integration-cli/docker_api_containers_test.go b/integration-cli/docker_api_containers_test.go index ad995b73fb..b5ebc00e77 100644 --- a/integration-cli/docker_api_containers_test.go +++ b/integration-cli/docker_api_containers_test.go @@ -403,3 +403,40 @@ func TestBuildApiDockerfileSymlink(t *testing.T) { logDone("container REST API - check build w/bad Dockerfile symlink path") } + +// #9981 - Allow a docker created volume (ie, one in /var/lib/docker/volumes) to be used to overwrite (via passing in Binds on api start) an existing volume +func TestPostContainerBindNormalVolume(t *testing.T) { + defer deleteAllContainers() + + out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=one", "busybox")) + if err != nil { + t.Fatal(err, out) + } + + fooDir, err := inspectFieldMap("one", "Volumes", "/foo") + if err != nil { + t.Fatal(err) + } + + out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=two", "busybox")) + if err != nil { + t.Fatal(err, out) + } + + bindSpec := map[string][]string{"Binds": {fooDir + ":/foo"}} + _, err = sockRequest("POST", "/containers/two/start", bindSpec) + if err != nil && !strings.Contains(err.Error(), "204 No Content") { + t.Fatal(err) + } + + fooDir2, err := inspectFieldMap("two", "Volumes", "/foo") + if err != nil { + t.Fatal(err) + } + + if fooDir2 != fooDir { + t.Fatal("expected volume path to be %s, got: %s", fooDir, fooDir2) + } + + logDone("container REST API - can use path from normal volume as bind-mount to overwrite another volume") +}