github.com/openshift/moby-moby@v1.13.2-0.20170601211448-f5ec1e2936dc/integration-cli/docker_cli_volume_test.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"github.com/docker/docker/pkg/integration/checker"
    13  	icmd "github.com/docker/docker/pkg/integration/cmd"
    14  	"github.com/go-check/check"
    15  )
    16  
    17  func (s *DockerSuite) TestVolumeCLICreate(c *check.C) {
    18  	dockerCmd(c, "volume", "create")
    19  
    20  	_, err := runCommand(exec.Command(dockerBinary, "volume", "create", "-d", "nosuchdriver"))
    21  	c.Assert(err, check.Not(check.IsNil))
    22  
    23  	// test using hidden --name option
    24  	out, _ := dockerCmd(c, "volume", "create", "--name=test")
    25  	name := strings.TrimSpace(out)
    26  	c.Assert(name, check.Equals, "test")
    27  
    28  	out, _ = dockerCmd(c, "volume", "create", "test2")
    29  	name = strings.TrimSpace(out)
    30  	c.Assert(name, check.Equals, "test2")
    31  }
    32  
    33  func (s *DockerSuite) TestVolumeCLIInspect(c *check.C) {
    34  	c.Assert(
    35  		exec.Command(dockerBinary, "volume", "inspect", "doesntexist").Run(),
    36  		check.Not(check.IsNil),
    37  		check.Commentf("volume inspect should error on non-existent volume"),
    38  	)
    39  
    40  	out, _ := dockerCmd(c, "volume", "create")
    41  	name := strings.TrimSpace(out)
    42  	out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Name }}", name)
    43  	c.Assert(strings.TrimSpace(out), check.Equals, name)
    44  
    45  	dockerCmd(c, "volume", "create", "test")
    46  	out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Name }}", "test")
    47  	c.Assert(strings.TrimSpace(out), check.Equals, "test")
    48  }
    49  
    50  func (s *DockerSuite) TestVolumeCLIInspectMulti(c *check.C) {
    51  	dockerCmd(c, "volume", "create", "test1")
    52  	dockerCmd(c, "volume", "create", "test2")
    53  	dockerCmd(c, "volume", "create", "not-shown")
    54  
    55  	result := dockerCmdWithResult("volume", "inspect", "--format={{ .Name }}", "test1", "test2", "doesntexist", "not-shown")
    56  	c.Assert(result, icmd.Matches, icmd.Expected{
    57  		ExitCode: 1,
    58  		Err:      "No such volume: doesntexist",
    59  	})
    60  
    61  	out := result.Stdout()
    62  	outArr := strings.Split(strings.TrimSpace(out), "\n")
    63  	c.Assert(len(outArr), check.Equals, 2, check.Commentf("\n%s", out))
    64  
    65  	c.Assert(out, checker.Contains, "test1")
    66  	c.Assert(out, checker.Contains, "test2")
    67  	c.Assert(out, checker.Not(checker.Contains), "not-shown")
    68  }
    69  
    70  func (s *DockerSuite) TestVolumeCLILs(c *check.C) {
    71  	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
    72  	dockerCmd(c, "volume", "create", "aaa")
    73  
    74  	dockerCmd(c, "volume", "create", "test")
    75  
    76  	dockerCmd(c, "volume", "create", "soo")
    77  	dockerCmd(c, "run", "-v", "soo:"+prefix+"/foo", "busybox", "ls", "/")
    78  
    79  	out, _ := dockerCmd(c, "volume", "ls")
    80  	outArr := strings.Split(strings.TrimSpace(out), "\n")
    81  	c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out))
    82  
    83  	assertVolList(c, out, []string{"aaa", "soo", "test"})
    84  }
    85  
    86  func (s *DockerSuite) TestVolumeLsFormat(c *check.C) {
    87  	dockerCmd(c, "volume", "create", "aaa")
    88  	dockerCmd(c, "volume", "create", "test")
    89  	dockerCmd(c, "volume", "create", "soo")
    90  
    91  	out, _ := dockerCmd(c, "volume", "ls", "--format", "{{.Name}}")
    92  	lines := strings.Split(strings.TrimSpace(string(out)), "\n")
    93  
    94  	expected := []string{"aaa", "soo", "test"}
    95  	var names []string
    96  	names = append(names, lines...)
    97  	c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
    98  }
    99  
   100  func (s *DockerSuite) TestVolumeLsFormatDefaultFormat(c *check.C) {
   101  	dockerCmd(c, "volume", "create", "aaa")
   102  	dockerCmd(c, "volume", "create", "test")
   103  	dockerCmd(c, "volume", "create", "soo")
   104  
   105  	config := `{
   106  		"volumesFormat": "{{ .Name }} default"
   107  }`
   108  	d, err := ioutil.TempDir("", "integration-cli-")
   109  	c.Assert(err, checker.IsNil)
   110  	defer os.RemoveAll(d)
   111  
   112  	err = ioutil.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644)
   113  	c.Assert(err, checker.IsNil)
   114  
   115  	out, _ := dockerCmd(c, "--config", d, "volume", "ls")
   116  	lines := strings.Split(strings.TrimSpace(string(out)), "\n")
   117  
   118  	expected := []string{"aaa default", "soo default", "test default"}
   119  	var names []string
   120  	names = append(names, lines...)
   121  	c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
   122  }
   123  
   124  // assertVolList checks volume retrieved with ls command
   125  // equals to expected volume list
   126  // note: out should be `volume ls [option]` result
   127  func assertVolList(c *check.C, out string, expectVols []string) {
   128  	lines := strings.Split(out, "\n")
   129  	var volList []string
   130  	for _, line := range lines[1 : len(lines)-1] {
   131  		volFields := strings.Fields(line)
   132  		// wrap all volume name in volList
   133  		volList = append(volList, volFields[1])
   134  	}
   135  
   136  	// volume ls should contains all expected volumes
   137  	c.Assert(volList, checker.DeepEquals, expectVols)
   138  }
   139  
   140  func (s *DockerSuite) TestVolumeCLILsFilterDangling(c *check.C) {
   141  	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
   142  	dockerCmd(c, "volume", "create", "testnotinuse1")
   143  	dockerCmd(c, "volume", "create", "testisinuse1")
   144  	dockerCmd(c, "volume", "create", "testisinuse2")
   145  
   146  	// Make sure both "created" (but not started), and started
   147  	// containers are included in reference counting
   148  	dockerCmd(c, "run", "--name", "volume-test1", "-v", "testisinuse1:"+prefix+"/foo", "busybox", "true")
   149  	dockerCmd(c, "create", "--name", "volume-test2", "-v", "testisinuse2:"+prefix+"/foo", "busybox", "true")
   150  
   151  	out, _ := dockerCmd(c, "volume", "ls")
   152  
   153  	// No filter, all volumes should show
   154  	c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   155  	c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
   156  	c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
   157  
   158  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=false")
   159  
   160  	// Explicitly disabling dangling
   161  	c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   162  	c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
   163  	c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
   164  
   165  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=true")
   166  
   167  	// Filter "dangling" volumes; only "dangling" (unused) volumes should be in the output
   168  	c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   169  	c.Assert(out, check.Not(checker.Contains), "testisinuse1\n", check.Commentf("volume 'testisinuse1' in output, but not expected"))
   170  	c.Assert(out, check.Not(checker.Contains), "testisinuse2\n", check.Commentf("volume 'testisinuse2' in output, but not expected"))
   171  
   172  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=1")
   173  	// Filter "dangling" volumes; only "dangling" (unused) volumes should be in the output, dangling also accept 1
   174  	c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   175  	c.Assert(out, check.Not(checker.Contains), "testisinuse1\n", check.Commentf("volume 'testisinuse1' in output, but not expected"))
   176  	c.Assert(out, check.Not(checker.Contains), "testisinuse2\n", check.Commentf("volume 'testisinuse2' in output, but not expected"))
   177  
   178  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=0")
   179  	// dangling=0 is same as dangling=false case
   180  	c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   181  	c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
   182  	c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
   183  
   184  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "name=testisin")
   185  	c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   186  	c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("execpeted volume 'testisinuse1' in output"))
   187  	c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
   188  
   189  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=invalidDriver")
   190  	outArr := strings.Split(strings.TrimSpace(out), "\n")
   191  	c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
   192  
   193  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=local")
   194  	outArr = strings.Split(strings.TrimSpace(out), "\n")
   195  	c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out))
   196  
   197  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=loc")
   198  	outArr = strings.Split(strings.TrimSpace(out), "\n")
   199  	c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out))
   200  
   201  }
   202  
   203  func (s *DockerSuite) TestVolumeCLILsErrorWithInvalidFilterName(c *check.C) {
   204  	out, _, err := dockerCmdWithError("volume", "ls", "-f", "FOO=123")
   205  	c.Assert(err, checker.NotNil)
   206  	c.Assert(out, checker.Contains, "Invalid filter")
   207  }
   208  
   209  func (s *DockerSuite) TestVolumeCLILsWithIncorrectFilterValue(c *check.C) {
   210  	out, _, err := dockerCmdWithError("volume", "ls", "-f", "dangling=invalid")
   211  	c.Assert(err, check.NotNil)
   212  	c.Assert(out, checker.Contains, "Invalid filter")
   213  }
   214  
   215  func (s *DockerSuite) TestVolumeCLIRm(c *check.C) {
   216  	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
   217  	out, _ := dockerCmd(c, "volume", "create")
   218  	id := strings.TrimSpace(out)
   219  
   220  	dockerCmd(c, "volume", "create", "test")
   221  	dockerCmd(c, "volume", "rm", id)
   222  	dockerCmd(c, "volume", "rm", "test")
   223  
   224  	out, _ = dockerCmd(c, "volume", "ls")
   225  	outArr := strings.Split(strings.TrimSpace(out), "\n")
   226  	c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
   227  
   228  	volumeID := "testing"
   229  	dockerCmd(c, "run", "-v", volumeID+":"+prefix+"/foo", "--name=test", "busybox", "sh", "-c", "echo hello > /foo/bar")
   230  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "volume", "rm", "testing"))
   231  	c.Assert(
   232  		err,
   233  		check.Not(check.IsNil),
   234  		check.Commentf("Should not be able to remove volume that is in use by a container\n%s", out))
   235  
   236  	out, _ = dockerCmd(c, "run", "--volumes-from=test", "--name=test2", "busybox", "sh", "-c", "cat /foo/bar")
   237  	c.Assert(strings.TrimSpace(out), check.Equals, "hello")
   238  	dockerCmd(c, "rm", "-fv", "test2")
   239  	dockerCmd(c, "volume", "inspect", volumeID)
   240  	dockerCmd(c, "rm", "-f", "test")
   241  
   242  	out, _ = dockerCmd(c, "run", "--name=test2", "-v", volumeID+":"+prefix+"/foo", "busybox", "sh", "-c", "cat /foo/bar")
   243  	c.Assert(strings.TrimSpace(out), check.Equals, "hello", check.Commentf("volume data was removed"))
   244  	dockerCmd(c, "rm", "test2")
   245  
   246  	dockerCmd(c, "volume", "rm", volumeID)
   247  	c.Assert(
   248  		exec.Command("volume", "rm", "doesntexist").Run(),
   249  		check.Not(check.IsNil),
   250  		check.Commentf("volume rm should fail with non-existent volume"),
   251  	)
   252  }
   253  
   254  func (s *DockerSuite) TestVolumeCLINoArgs(c *check.C) {
   255  	out, _ := dockerCmd(c, "volume")
   256  	// no args should produce the cmd usage output
   257  	usage := "Usage:	docker volume COMMAND"
   258  	c.Assert(out, checker.Contains, usage)
   259  
   260  	// invalid arg should error and show the command usage on stderr
   261  	_, stderr, _, err := runCommandWithStdoutStderr(exec.Command(dockerBinary, "volume", "somearg"))
   262  	c.Assert(err, check.NotNil, check.Commentf(stderr))
   263  	c.Assert(stderr, checker.Contains, usage)
   264  
   265  	// invalid flag should error and show the flag error and cmd usage
   266  	_, stderr, _, err = runCommandWithStdoutStderr(exec.Command(dockerBinary, "volume", "--no-such-flag"))
   267  	c.Assert(err, check.NotNil, check.Commentf(stderr))
   268  	c.Assert(stderr, checker.Contains, usage)
   269  	c.Assert(stderr, checker.Contains, "unknown flag: --no-such-flag")
   270  }
   271  
   272  func (s *DockerSuite) TestVolumeCLIInspectTmplError(c *check.C) {
   273  	out, _ := dockerCmd(c, "volume", "create")
   274  	name := strings.TrimSpace(out)
   275  
   276  	out, exitCode, err := dockerCmdWithError("volume", "inspect", "--format='{{ .FooBar }}'", name)
   277  	c.Assert(err, checker.NotNil, check.Commentf("Output: %s", out))
   278  	c.Assert(exitCode, checker.Equals, 1, check.Commentf("Output: %s", out))
   279  	c.Assert(out, checker.Contains, "Template parsing error")
   280  }
   281  
   282  func (s *DockerSuite) TestVolumeCLICreateWithOpts(c *check.C) {
   283  	testRequires(c, DaemonIsLinux)
   284  
   285  	dockerCmd(c, "volume", "create", "-d", "local", "test", "--opt=type=tmpfs", "--opt=device=tmpfs", "--opt=o=size=1m,uid=1000")
   286  	out, _ := dockerCmd(c, "run", "-v", "test:/foo", "busybox", "mount")
   287  
   288  	mounts := strings.Split(out, "\n")
   289  	var found bool
   290  	for _, m := range mounts {
   291  		if strings.Contains(m, "/foo") {
   292  			found = true
   293  			info := strings.Fields(m)
   294  			// tmpfs on <path> type tmpfs (rw,relatime,size=1024k,uid=1000)
   295  			c.Assert(info[0], checker.Equals, "tmpfs")
   296  			c.Assert(info[2], checker.Equals, "/foo")
   297  			c.Assert(info[4], checker.Equals, "tmpfs")
   298  			c.Assert(info[5], checker.Contains, "uid=1000")
   299  			c.Assert(info[5], checker.Contains, "size=1024k")
   300  		}
   301  	}
   302  	c.Assert(found, checker.Equals, true)
   303  }
   304  
   305  func (s *DockerSuite) TestVolumeCLICreateLabel(c *check.C) {
   306  	testVol := "testvolcreatelabel"
   307  	testLabel := "foo"
   308  	testValue := "bar"
   309  
   310  	out, _, err := dockerCmdWithError("volume", "create", "--label", testLabel+"="+testValue, testVol)
   311  	c.Assert(err, check.IsNil)
   312  
   313  	out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Labels."+testLabel+" }}", testVol)
   314  	c.Assert(strings.TrimSpace(out), check.Equals, testValue)
   315  }
   316  
   317  func (s *DockerSuite) TestVolumeCLICreateLabelMultiple(c *check.C) {
   318  	testVol := "testvolcreatelabel"
   319  
   320  	testLabels := map[string]string{
   321  		"foo": "bar",
   322  		"baz": "foo",
   323  	}
   324  
   325  	args := []string{
   326  		"volume",
   327  		"create",
   328  		testVol,
   329  	}
   330  
   331  	for k, v := range testLabels {
   332  		args = append(args, "--label", k+"="+v)
   333  	}
   334  
   335  	out, _, err := dockerCmdWithError(args...)
   336  	c.Assert(err, check.IsNil)
   337  
   338  	for k, v := range testLabels {
   339  		out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Labels."+k+" }}", testVol)
   340  		c.Assert(strings.TrimSpace(out), check.Equals, v)
   341  	}
   342  }
   343  
   344  func (s *DockerSuite) TestVolumeCLILsFilterLabels(c *check.C) {
   345  	testVol1 := "testvolcreatelabel-1"
   346  	out, _, err := dockerCmdWithError("volume", "create", "--label", "foo=bar1", testVol1)
   347  	c.Assert(err, check.IsNil)
   348  
   349  	testVol2 := "testvolcreatelabel-2"
   350  	out, _, err = dockerCmdWithError("volume", "create", "--label", "foo=bar2", testVol2)
   351  	c.Assert(err, check.IsNil)
   352  
   353  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=foo")
   354  
   355  	// filter with label=key
   356  	c.Assert(out, checker.Contains, "testvolcreatelabel-1\n", check.Commentf("expected volume 'testvolcreatelabel-1' in output"))
   357  	c.Assert(out, checker.Contains, "testvolcreatelabel-2\n", check.Commentf("expected volume 'testvolcreatelabel-2' in output"))
   358  
   359  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=foo=bar1")
   360  
   361  	// filter with label=key=value
   362  	c.Assert(out, checker.Contains, "testvolcreatelabel-1\n", check.Commentf("expected volume 'testvolcreatelabel-1' in output"))
   363  	c.Assert(out, check.Not(checker.Contains), "testvolcreatelabel-2\n", check.Commentf("expected volume 'testvolcreatelabel-2 in output"))
   364  
   365  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=non-exist")
   366  	outArr := strings.Split(strings.TrimSpace(out), "\n")
   367  	c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
   368  
   369  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=foo=non-exist")
   370  	outArr = strings.Split(strings.TrimSpace(out), "\n")
   371  	c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
   372  }
   373  
   374  func (s *DockerSuite) TestVolumeCLIRmForceUsage(c *check.C) {
   375  	out, _ := dockerCmd(c, "volume", "create")
   376  	id := strings.TrimSpace(out)
   377  
   378  	dockerCmd(c, "volume", "rm", "-f", id)
   379  	dockerCmd(c, "volume", "rm", "--force", "nonexist")
   380  
   381  	out, _ = dockerCmd(c, "volume", "ls")
   382  	outArr := strings.Split(strings.TrimSpace(out), "\n")
   383  	c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
   384  }
   385  
   386  func (s *DockerSuite) TestVolumeCLIRmForce(c *check.C) {
   387  	testRequires(c, SameHostDaemon, DaemonIsLinux)
   388  
   389  	name := "test"
   390  	out, _ := dockerCmd(c, "volume", "create", name)
   391  	id := strings.TrimSpace(out)
   392  	c.Assert(id, checker.Equals, name)
   393  
   394  	out, _ = dockerCmd(c, "volume", "inspect", "--format", "{{.Mountpoint}}", name)
   395  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   396  	// Mountpoint is in the form of "/var/lib/docker/volumes/.../_data", removing `/_data`
   397  	path := strings.TrimSuffix(strings.TrimSpace(out), "/_data")
   398  	out, _, err := runCommandWithOutput(exec.Command("rm", "-rf", path))
   399  	c.Assert(err, check.IsNil)
   400  
   401  	dockerCmd(c, "volume", "rm", "-f", name)
   402  	out, _ = dockerCmd(c, "volume", "ls")
   403  	c.Assert(out, checker.Not(checker.Contains), name)
   404  	dockerCmd(c, "volume", "create", name)
   405  	out, _ = dockerCmd(c, "volume", "ls")
   406  	c.Assert(out, checker.Contains, name)
   407  }
   408  
   409  // TestVolumeCLIRmForceInUse verifies that repeated `docker volume rm -f` calls does not remove a volume
   410  // if it is in use. Test case for https://github.com/docker/docker/issues/31446
   411  func (s *DockerSuite) TestVolumeCLIRmForceInUse(c *check.C) {
   412  	name := "testvolume"
   413  	out, _ := dockerCmd(c, "volume", "create", name)
   414  	id := strings.TrimSpace(out)
   415  	c.Assert(id, checker.Equals, name)
   416  
   417  	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
   418  	out, e := dockerCmd(c, "create", "-v", "testvolume:"+prefix+slash+"foo", "busybox")
   419  	cid := strings.TrimSpace(out)
   420  
   421  	_, _, err := dockerCmdWithError("volume", "rm", "-f", name)
   422  	c.Assert(err, check.NotNil)
   423  	c.Assert(err.Error(), checker.Contains, "volume is in use")
   424  	out, _ = dockerCmd(c, "volume", "ls")
   425  	c.Assert(out, checker.Contains, name)
   426  
   427  	// The original issue did not _remove_ the volume from the list
   428  	// the first time. But a second call to `volume rm` removed it.
   429  	// Calling `volume rm` a second time to confirm it's not removed
   430  	// when calling twice.
   431  	_, _, err = dockerCmdWithError("volume", "rm", "-f", name)
   432  	c.Assert(err, check.NotNil)
   433  	c.Assert(err.Error(), checker.Contains, "volume is in use")
   434  	out, _ = dockerCmd(c, "volume", "ls")
   435  	c.Assert(out, checker.Contains, name)
   436  
   437  	// Verify removing the volume after the container is removed works
   438  	_, e = dockerCmd(c, "rm", cid)
   439  	c.Assert(e, check.Equals, 0)
   440  
   441  	_, e = dockerCmd(c, "volume", "rm", "-f", name)
   442  	c.Assert(e, check.Equals, 0)
   443  
   444  	out, e = dockerCmd(c, "volume", "ls")
   445  	c.Assert(e, check.Equals, 0)
   446  	c.Assert(out, checker.Not(checker.Contains), name)
   447  }
   448  
   449  func (s *DockerSuite) TestVolumeCliInspectWithVolumeOpts(c *check.C) {
   450  	testRequires(c, DaemonIsLinux)
   451  
   452  	// Without options
   453  	name := "test1"
   454  	dockerCmd(c, "volume", "create", "-d", "local", name)
   455  	out, _ := dockerCmd(c, "volume", "inspect", "--format={{ .Options }}", name)
   456  	c.Assert(strings.TrimSpace(out), checker.Contains, "map[]")
   457  
   458  	// With options
   459  	name = "test2"
   460  	k1, v1 := "type", "tmpfs"
   461  	k2, v2 := "device", "tmpfs"
   462  	k3, v3 := "o", "size=1m,uid=1000"
   463  	dockerCmd(c, "volume", "create", "-d", "local", name, "--opt", fmt.Sprintf("%s=%s", k1, v1), "--opt", fmt.Sprintf("%s=%s", k2, v2), "--opt", fmt.Sprintf("%s=%s", k3, v3))
   464  	out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Options }}", name)
   465  	c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k1, v1))
   466  	c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k2, v2))
   467  	c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k3, v3))
   468  }
   469  
   470  // Test case (1) for 21845: duplicate targets for --volumes-from
   471  func (s *DockerSuite) TestDuplicateMountpointsForVolumesFrom(c *check.C) {
   472  	testRequires(c, DaemonIsLinux)
   473  
   474  	image := "vimage"
   475  	_, err := buildImage(
   476  		image,
   477  		`
   478      FROM busybox
   479      VOLUME ["/tmp/data"]
   480      `,
   481  		true)
   482  	c.Assert(err, check.IsNil)
   483  
   484  	dockerCmd(c, "run", "--name=data1", image, "true")
   485  	dockerCmd(c, "run", "--name=data2", image, "true")
   486  
   487  	out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
   488  	data1 := strings.TrimSpace(out)
   489  	c.Assert(data1, checker.Not(checker.Equals), "")
   490  
   491  	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
   492  	data2 := strings.TrimSpace(out)
   493  	c.Assert(data2, checker.Not(checker.Equals), "")
   494  
   495  	// Both volume should exist
   496  	out, _ = dockerCmd(c, "volume", "ls", "-q")
   497  	c.Assert(strings.TrimSpace(out), checker.Contains, data1)
   498  	c.Assert(strings.TrimSpace(out), checker.Contains, data2)
   499  
   500  	out, _, err = dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-d", "busybox", "top")
   501  	c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))
   502  
   503  	// Only the second volume will be referenced, this is backward compatible
   504  	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
   505  	c.Assert(strings.TrimSpace(out), checker.Equals, data2)
   506  
   507  	dockerCmd(c, "rm", "-f", "-v", "app")
   508  	dockerCmd(c, "rm", "-f", "-v", "data1")
   509  	dockerCmd(c, "rm", "-f", "-v", "data2")
   510  
   511  	// Both volume should not exist
   512  	out, _ = dockerCmd(c, "volume", "ls", "-q")
   513  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
   514  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
   515  }
   516  
   517  // Test case (2) for 21845: duplicate targets for --volumes-from and -v (bind)
   518  func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndBind(c *check.C) {
   519  	testRequires(c, DaemonIsLinux)
   520  
   521  	image := "vimage"
   522  	_, err := buildImage(image,
   523  		`
   524      FROM busybox
   525      VOLUME ["/tmp/data"]
   526      `,
   527  		true)
   528  	c.Assert(err, check.IsNil)
   529  
   530  	dockerCmd(c, "run", "--name=data1", image, "true")
   531  	dockerCmd(c, "run", "--name=data2", image, "true")
   532  
   533  	out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
   534  	data1 := strings.TrimSpace(out)
   535  	c.Assert(data1, checker.Not(checker.Equals), "")
   536  
   537  	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
   538  	data2 := strings.TrimSpace(out)
   539  	c.Assert(data2, checker.Not(checker.Equals), "")
   540  
   541  	// Both volume should exist
   542  	out, _ = dockerCmd(c, "volume", "ls", "-q")
   543  	c.Assert(strings.TrimSpace(out), checker.Contains, data1)
   544  	c.Assert(strings.TrimSpace(out), checker.Contains, data2)
   545  
   546  	out, _, err = dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-v", "/tmp/data:/tmp/data", "-d", "busybox", "top")
   547  	c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))
   548  
   549  	// No volume will be referenced (mount is /tmp/data), this is backward compatible
   550  	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
   551  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
   552  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
   553  
   554  	dockerCmd(c, "rm", "-f", "-v", "app")
   555  	dockerCmd(c, "rm", "-f", "-v", "data1")
   556  	dockerCmd(c, "rm", "-f", "-v", "data2")
   557  
   558  	// Both volume should not exist
   559  	out, _ = dockerCmd(c, "volume", "ls", "-q")
   560  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
   561  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
   562  }
   563  
   564  // Test case (3) for 21845: duplicate targets for --volumes-from and `Mounts` (API only)
   565  func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndMounts(c *check.C) {
   566  	testRequires(c, DaemonIsLinux)
   567  
   568  	image := "vimage"
   569  	_, err := buildImage(image,
   570  		`
   571      FROM busybox
   572      VOLUME ["/tmp/data"]
   573      `,
   574  		true)
   575  	c.Assert(err, check.IsNil)
   576  
   577  	dockerCmd(c, "run", "--name=data1", image, "true")
   578  	dockerCmd(c, "run", "--name=data2", image, "true")
   579  
   580  	out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
   581  	data1 := strings.TrimSpace(out)
   582  	c.Assert(data1, checker.Not(checker.Equals), "")
   583  
   584  	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
   585  	data2 := strings.TrimSpace(out)
   586  	c.Assert(data2, checker.Not(checker.Equals), "")
   587  
   588  	// Both volume should exist
   589  	out, _ = dockerCmd(c, "volume", "ls", "-q")
   590  	c.Assert(strings.TrimSpace(out), checker.Contains, data1)
   591  	c.Assert(strings.TrimSpace(out), checker.Contains, data2)
   592  
   593  	// Mounts is available in API
   594  	status, body, err := sockRequest("POST", "/containers/create?name=app", map[string]interface{}{
   595  		"Image": "busybox",
   596  		"Cmd":   []string{"top"},
   597  		"HostConfig": map[string]interface{}{
   598  			"VolumesFrom": []string{
   599  				"data1",
   600  				"data2",
   601  			},
   602  			"Mounts": []map[string]interface{}{
   603  				{
   604  					"Type":   "bind",
   605  					"Source": "/tmp/data",
   606  					"Target": "/tmp/data",
   607  				},
   608  			}},
   609  	})
   610  
   611  	c.Assert(err, checker.IsNil, check.Commentf(string(body)))
   612  	c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(body)))
   613  
   614  	// No volume will be referenced (mount is /tmp/data), this is backward compatible
   615  	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
   616  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
   617  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
   618  
   619  	dockerCmd(c, "rm", "-f", "-v", "app")
   620  	dockerCmd(c, "rm", "-f", "-v", "data1")
   621  	dockerCmd(c, "rm", "-f", "-v", "data2")
   622  
   623  	// Both volume should not exist
   624  	out, _ = dockerCmd(c, "volume", "ls", "-q")
   625  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
   626  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
   627  }