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