diff --git a/daemon/create.go b/daemon/create.go index 13ba5baba7..83a1a8b7e4 100644 --- a/daemon/create.go +++ b/daemon/create.go @@ -11,6 +11,7 @@ import ( "github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/runconfig" + "github.com/docker/docker/volume" "github.com/opencontainers/runc/libcontainer/label" ) @@ -148,5 +149,10 @@ func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]stri if err != nil { return nil, err } + + // keep "docker run -v existing_volume:/foo --volume-driver other_driver" work + if (driverName != "" && v.DriverName() != driverName) || (driverName == "" && v.DriverName() != volume.DefaultDriverName) { + return nil, derr.ErrorVolumeNameTaken.WithArgs(name, v.DriverName()) + } return volumeToAPIType(v), nil } diff --git a/docs/reference/commandline/volume_create.md b/docs/reference/commandline/volume_create.md index 3684bda6d5..35f8a00b38 100644 --- a/docs/reference/commandline/volume_create.md +++ b/docs/reference/commandline/volume_create.md @@ -29,6 +29,14 @@ The mount is created inside the container's `/src` directory. Docker does not su Multiple containers can use the same volume in the same time period. This is useful if two containers need access to shared data. For example, if one container writes and the other reads the data. +Volume names must be unique among drivers. This means you cannot use the same volume name with two different drivers. If you attempt this `docker` returns an error: + +``` +A volume named %s already exists with the %s driver. Choose a different volume name. +``` + +If you specify a volume name already in use on the current driver, Docker assumes you want to re-use the existing volume and does not return an error. + ## Driver specific options Some volume drivers may take options to customize the volume creation. Use the `-o` or `--opt` flags to pass driver options: diff --git a/errors/daemon.go b/errors/daemon.go index 7a6e61e61d..991388e4d7 100644 --- a/errors/daemon.go +++ b/errors/daemon.go @@ -863,4 +863,13 @@ var ( Description: "While verifying the container's 'HostConfig', cpuset memory nodes provided aren't available in the container's cgroup available set", HTTPStatusCode: http.StatusInternalServerError, }) + + // ErrorVolumeNameTaken is generated when an error occurred while + // trying to create a volume that has existed using different driver. + ErrorVolumeNameTaken = errcode.Register(errGroup, errcode.ErrorDescriptor{ + Value: "VOLUME_NAME_TAKEN", + Message: "A volume name %s already exists with the %s driver. Choose a different volume name.", + Description: "An attempt to create a volume using a driver but the volume already exists with a different driver", + HTTPStatusCode: http.StatusInternalServerError, + }) ) diff --git a/integration-cli/docker_cli_volume_test.go b/integration-cli/docker_cli_volume_test.go index cc9bed7d6c..a0c70693d5 100644 --- a/integration-cli/docker_cli_volume_test.go +++ b/integration-cli/docker_cli_volume_test.go @@ -4,7 +4,9 @@ import ( "os/exec" "strings" + derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/integration/checker" + "github.com/docker/docker/volume" "github.com/go-check/check" ) @@ -20,6 +22,18 @@ func (s *DockerSuite) TestVolumeCliCreate(c *check.C) { c.Assert(name, check.Equals, "test") } +func (s *DockerSuite) TestVolumeCliCreateOptionConflict(c *check.C) { + dockerCmd(c, "volume", "create", "--name=test") + out, _, err := dockerCmdWithError("volume", "create", "--name", "test", "--driver", "nosuchdriver") + c.Assert(err, check.NotNil, check.Commentf("volume create exception name already in use with another driver")) + stderr := derr.ErrorVolumeNameTaken.WithArgs("test", volume.DefaultDriverName).Error() + c.Assert(strings.Contains(out, strings.TrimPrefix(stderr, "volume name taken: ")), check.Equals, true) + + out, _ = dockerCmd(c, "volume", "inspect", "--format='{{ .Driver }}'", "test") + _, _, err = dockerCmdWithError("volume", "create", "--name", "test", "--driver", strings.TrimSpace(out)) + c.Assert(err, check.IsNil) +} + func (s *DockerSuite) TestVolumeCliInspect(c *check.C) { testRequires(c, DaemonIsLinux) c.Assert(