github.com/stuarqi/moby@v1.13.1/integration-cli/docker_cli_volume_test.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"github.com/docker/docker/pkg/integration/checker"
    12  	icmd "github.com/docker/docker/pkg/integration/cmd"
    13  	"github.com/go-check/check"
    14  )
    15  
    16  func (s *DockerSuite) TestVolumeCLICreate(c *check.C) {
    17  	dockerCmd(c, "volume", "create")
    18  
    19  	_, err := runCommand(exec.Command(dockerBinary, "volume", "create", "-d", "nosuchdriver"))
    20  	c.Assert(err, check.Not(check.IsNil))
    21  
    22  	// test using hidden --name option
    23  	out, _ := dockerCmd(c, "volume", "create", "--name=test")
    24  	name := strings.TrimSpace(out)
    25  	c.Assert(name, check.Equals, "test")
    26  
    27  	out, _ = dockerCmd(c, "volume", "create", "test2")
    28  	name = strings.TrimSpace(out)
    29  	c.Assert(name, check.Equals, "test2")
    30  }
    31  
    32  func (s *DockerSuite) TestVolumeCLIInspect(c *check.C) {
    33  	c.Assert(
    34  		exec.Command(dockerBinary, "volume", "inspect", "doesntexist").Run(),
    35  		check.Not(check.IsNil),
    36  		check.Commentf("volume inspect should error on non-existent volume"),
    37  	)
    38  
    39  	out, _ := dockerCmd(c, "volume", "create")
    40  	name := strings.TrimSpace(out)
    41  	out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Name }}", name)
    42  	c.Assert(strings.TrimSpace(out), check.Equals, name)
    43  
    44  	dockerCmd(c, "volume", "create", "test")
    45  	out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Name }}", "test")
    46  	c.Assert(strings.TrimSpace(out), check.Equals, "test")
    47  }
    48  
    49  func (s *DockerSuite) TestVolumeCLIInspectMulti(c *check.C) {
    50  	dockerCmd(c, "volume", "create", "test1")
    51  	dockerCmd(c, "volume", "create", "test2")
    52  	dockerCmd(c, "volume", "create", "not-shown")
    53  
    54  	result := dockerCmdWithResult("volume", "inspect", "--format={{ .Name }}", "test1", "test2", "doesntexist", "not-shown")
    55  	c.Assert(result, icmd.Matches, icmd.Expected{
    56  		ExitCode: 1,
    57  		Err:      "No such volume: doesntexist",
    58  	})
    59  
    60  	out := result.Stdout()
    61  	outArr := strings.Split(strings.TrimSpace(out), "\n")
    62  	c.Assert(len(outArr), check.Equals, 2, check.Commentf("\n%s", out))
    63  
    64  	c.Assert(out, checker.Contains, "test1")
    65  	c.Assert(out, checker.Contains, "test2")
    66  	c.Assert(out, checker.Not(checker.Contains), "not-shown")
    67  }
    68  
    69  func (s *DockerSuite) TestVolumeCLILs(c *check.C) {
    70  	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
    71  	dockerCmd(c, "volume", "create", "aaa")
    72  
    73  	dockerCmd(c, "volume", "create", "test")
    74  
    75  	dockerCmd(c, "volume", "create", "soo")
    76  	dockerCmd(c, "run", "-v", "soo:"+prefix+"/foo", "busybox", "ls", "/")
    77  
    78  	out, _ := dockerCmd(c, "volume", "ls")
    79  	outArr := strings.Split(strings.TrimSpace(out), "\n")
    80  	c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out))
    81  
    82  	assertVolList(c, out, []string{"aaa", "soo", "test"})
    83  }
    84  
    85  func (s *DockerSuite) TestVolumeLsFormat(c *check.C) {
    86  	dockerCmd(c, "volume", "create", "aaa")
    87  	dockerCmd(c, "volume", "create", "test")
    88  	dockerCmd(c, "volume", "create", "soo")
    89  
    90  	out, _ := dockerCmd(c, "volume", "ls", "--format", "{{.Name}}")
    91  	lines := strings.Split(strings.TrimSpace(string(out)), "\n")
    92  
    93  	expected := []string{"aaa", "soo", "test"}
    94  	var names []string
    95  	names = append(names, lines...)
    96  	c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
    97  }
    98  
    99  func (s *DockerSuite) TestVolumeLsFormatDefaultFormat(c *check.C) {
   100  	dockerCmd(c, "volume", "create", "aaa")
   101  	dockerCmd(c, "volume", "create", "test")
   102  	dockerCmd(c, "volume", "create", "soo")
   103  
   104  	config := `{
   105  		"volumesFormat": "{{ .Name }} default"
   106  }`
   107  	d, err := ioutil.TempDir("", "integration-cli-")
   108  	c.Assert(err, checker.IsNil)
   109  	defer os.RemoveAll(d)
   110  
   111  	err = ioutil.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644)
   112  	c.Assert(err, checker.IsNil)
   113  
   114  	out, _ := dockerCmd(c, "--config", d, "volume", "ls")
   115  	lines := strings.Split(strings.TrimSpace(string(out)), "\n")
   116  
   117  	expected := []string{"aaa default", "soo default", "test default"}
   118  	var names []string
   119  	names = append(names, lines...)
   120  	c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
   121  }
   122  
   123  // assertVolList checks volume retrieved with ls command
   124  // equals to expected volume list
   125  // note: out should be `volume ls [option]` result
   126  func assertVolList(c *check.C, out string, expectVols []string) {
   127  	lines := strings.Split(out, "\n")
   128  	var volList []string
   129  	for _, line := range lines[1 : len(lines)-1] {
   130  		volFields := strings.Fields(line)
   131  		// wrap all volume name in volList
   132  		volList = append(volList, volFields[1])
   133  	}
   134  
   135  	// volume ls should contains all expected volumes
   136  	c.Assert(volList, checker.DeepEquals, expectVols)
   137  }
   138  
   139  func (s *DockerSuite) TestVolumeCLILsFilterDangling(c *check.C) {
   140  	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
   141  	dockerCmd(c, "volume", "create", "testnotinuse1")
   142  	dockerCmd(c, "volume", "create", "testisinuse1")
   143  	dockerCmd(c, "volume", "create", "testisinuse2")
   144  
   145  	// Make sure both "created" (but not started), and started
   146  	// containers are included in reference counting
   147  	dockerCmd(c, "run", "--name", "volume-test1", "-v", "testisinuse1:"+prefix+"/foo", "busybox", "true")
   148  	dockerCmd(c, "create", "--name", "volume-test2", "-v", "testisinuse2:"+prefix+"/foo", "busybox", "true")
   149  
   150  	out, _ := dockerCmd(c, "volume", "ls")
   151  
   152  	// No filter, all volumes should show
   153  	c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   154  	c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
   155  	c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
   156  
   157  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=false")
   158  
   159  	// Explicitly disabling dangling
   160  	c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   161  	c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
   162  	c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
   163  
   164  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=true")
   165  
   166  	// Filter "dangling" volumes; only "dangling" (unused) volumes should be in the output
   167  	c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   168  	c.Assert(out, check.Not(checker.Contains), "testisinuse1\n", check.Commentf("volume 'testisinuse1' in output, but not expected"))
   169  	c.Assert(out, check.Not(checker.Contains), "testisinuse2\n", check.Commentf("volume 'testisinuse2' in output, but not expected"))
   170  
   171  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=1")
   172  	// Filter "dangling" volumes; only "dangling" (unused) volumes should be in the output, dangling also accept 1
   173  	c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   174  	c.Assert(out, check.Not(checker.Contains), "testisinuse1\n", check.Commentf("volume 'testisinuse1' in output, but not expected"))
   175  	c.Assert(out, check.Not(checker.Contains), "testisinuse2\n", check.Commentf("volume 'testisinuse2' in output, but not expected"))
   176  
   177  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=0")
   178  	// dangling=0 is same as dangling=false case
   179  	c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   180  	c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
   181  	c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
   182  
   183  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "name=testisin")
   184  	c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
   185  	c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("execpeted volume 'testisinuse1' in output"))
   186  	c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
   187  
   188  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=invalidDriver")
   189  	outArr := strings.Split(strings.TrimSpace(out), "\n")
   190  	c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
   191  
   192  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=local")
   193  	outArr = strings.Split(strings.TrimSpace(out), "\n")
   194  	c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out))
   195  
   196  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=loc")
   197  	outArr = strings.Split(strings.TrimSpace(out), "\n")
   198  	c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out))
   199  
   200  }
   201  
   202  func (s *DockerSuite) TestVolumeCLILsErrorWithInvalidFilterName(c *check.C) {
   203  	out, _, err := dockerCmdWithError("volume", "ls", "-f", "FOO=123")
   204  	c.Assert(err, checker.NotNil)
   205  	c.Assert(out, checker.Contains, "Invalid filter")
   206  }
   207  
   208  func (s *DockerSuite) TestVolumeCLILsWithIncorrectFilterValue(c *check.C) {
   209  	out, _, err := dockerCmdWithError("volume", "ls", "-f", "dangling=invalid")
   210  	c.Assert(err, check.NotNil)
   211  	c.Assert(out, checker.Contains, "Invalid filter")
   212  }
   213  
   214  func (s *DockerSuite) TestVolumeCLIRm(c *check.C) {
   215  	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
   216  	out, _ := dockerCmd(c, "volume", "create")
   217  	id := strings.TrimSpace(out)
   218  
   219  	dockerCmd(c, "volume", "create", "test")
   220  	dockerCmd(c, "volume", "rm", id)
   221  	dockerCmd(c, "volume", "rm", "test")
   222  
   223  	out, _ = dockerCmd(c, "volume", "ls")
   224  	outArr := strings.Split(strings.TrimSpace(out), "\n")
   225  	c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
   226  
   227  	volumeID := "testing"
   228  	dockerCmd(c, "run", "-v", volumeID+":"+prefix+"/foo", "--name=test", "busybox", "sh", "-c", "echo hello > /foo/bar")
   229  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "volume", "rm", "testing"))
   230  	c.Assert(
   231  		err,
   232  		check.Not(check.IsNil),
   233  		check.Commentf("Should not be able to remove volume that is in use by a container\n%s", out))
   234  
   235  	out, _ = dockerCmd(c, "run", "--volumes-from=test", "--name=test2", "busybox", "sh", "-c", "cat /foo/bar")
   236  	c.Assert(strings.TrimSpace(out), check.Equals, "hello")
   237  	dockerCmd(c, "rm", "-fv", "test2")
   238  	dockerCmd(c, "volume", "inspect", volumeID)
   239  	dockerCmd(c, "rm", "-f", "test")
   240  
   241  	out, _ = dockerCmd(c, "run", "--name=test2", "-v", volumeID+":"+prefix+"/foo", "busybox", "sh", "-c", "cat /foo/bar")
   242  	c.Assert(strings.TrimSpace(out), check.Equals, "hello", check.Commentf("volume data was removed"))
   243  	dockerCmd(c, "rm", "test2")
   244  
   245  	dockerCmd(c, "volume", "rm", volumeID)
   246  	c.Assert(
   247  		exec.Command("volume", "rm", "doesntexist").Run(),
   248  		check.Not(check.IsNil),
   249  		check.Commentf("volume rm should fail with non-existent volume"),
   250  	)
   251  }
   252  
   253  func (s *DockerSuite) TestVolumeCLINoArgs(c *check.C) {
   254  	out, _ := dockerCmd(c, "volume")
   255  	// no args should produce the cmd usage output
   256  	usage := "Usage:	docker volume COMMAND"
   257  	c.Assert(out, checker.Contains, usage)
   258  
   259  	// invalid arg should error and show the command usage on stderr
   260  	_, stderr, _, err := runCommandWithStdoutStderr(exec.Command(dockerBinary, "volume", "somearg"))
   261  	c.Assert(err, check.NotNil, check.Commentf(stderr))
   262  	c.Assert(stderr, checker.Contains, usage)
   263  
   264  	// invalid flag should error and show the flag error and cmd usage
   265  	_, stderr, _, err = runCommandWithStdoutStderr(exec.Command(dockerBinary, "volume", "--no-such-flag"))
   266  	c.Assert(err, check.NotNil, check.Commentf(stderr))
   267  	c.Assert(stderr, checker.Contains, usage)
   268  	c.Assert(stderr, checker.Contains, "unknown flag: --no-such-flag")
   269  }
   270  
   271  func (s *DockerSuite) TestVolumeCLIInspectTmplError(c *check.C) {
   272  	out, _ := dockerCmd(c, "volume", "create")
   273  	name := strings.TrimSpace(out)
   274  
   275  	out, exitCode, err := dockerCmdWithError("volume", "inspect", "--format='{{ .FooBar }}'", name)
   276  	c.Assert(err, checker.NotNil, check.Commentf("Output: %s", out))
   277  	c.Assert(exitCode, checker.Equals, 1, check.Commentf("Output: %s", out))
   278  	c.Assert(out, checker.Contains, "Template parsing error")
   279  }
   280  
   281  func (s *DockerSuite) TestVolumeCLICreateWithOpts(c *check.C) {
   282  	testRequires(c, DaemonIsLinux)
   283  
   284  	dockerCmd(c, "volume", "create", "-d", "local", "test", "--opt=type=tmpfs", "--opt=device=tmpfs", "--opt=o=size=1m,uid=1000")
   285  	out, _ := dockerCmd(c, "run", "-v", "test:/foo", "busybox", "mount")
   286  
   287  	mounts := strings.Split(out, "\n")
   288  	var found bool
   289  	for _, m := range mounts {
   290  		if strings.Contains(m, "/foo") {
   291  			found = true
   292  			info := strings.Fields(m)
   293  			// tmpfs on <path> type tmpfs (rw,relatime,size=1024k,uid=1000)
   294  			c.Assert(info[0], checker.Equals, "tmpfs")
   295  			c.Assert(info[2], checker.Equals, "/foo")
   296  			c.Assert(info[4], checker.Equals, "tmpfs")
   297  			c.Assert(info[5], checker.Contains, "uid=1000")
   298  			c.Assert(info[5], checker.Contains, "size=1024k")
   299  		}
   300  	}
   301  	c.Assert(found, checker.Equals, true)
   302  }
   303  
   304  func (s *DockerSuite) TestVolumeCLICreateLabel(c *check.C) {
   305  	testVol := "testvolcreatelabel"
   306  	testLabel := "foo"
   307  	testValue := "bar"
   308  
   309  	out, _, err := dockerCmdWithError("volume", "create", "--label", testLabel+"="+testValue, testVol)
   310  	c.Assert(err, check.IsNil)
   311  
   312  	out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Labels."+testLabel+" }}", testVol)
   313  	c.Assert(strings.TrimSpace(out), check.Equals, testValue)
   314  }
   315  
   316  func (s *DockerSuite) TestVolumeCLICreateLabelMultiple(c *check.C) {
   317  	testVol := "testvolcreatelabel"
   318  
   319  	testLabels := map[string]string{
   320  		"foo": "bar",
   321  		"baz": "foo",
   322  	}
   323  
   324  	args := []string{
   325  		"volume",
   326  		"create",
   327  		testVol,
   328  	}
   329  
   330  	for k, v := range testLabels {
   331  		args = append(args, "--label", k+"="+v)
   332  	}
   333  
   334  	out, _, err := dockerCmdWithError(args...)
   335  	c.Assert(err, check.IsNil)
   336  
   337  	for k, v := range testLabels {
   338  		out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Labels."+k+" }}", testVol)
   339  		c.Assert(strings.TrimSpace(out), check.Equals, v)
   340  	}
   341  }
   342  
   343  func (s *DockerSuite) TestVolumeCLILsFilterLabels(c *check.C) {
   344  	testVol1 := "testvolcreatelabel-1"
   345  	out, _, err := dockerCmdWithError("volume", "create", "--label", "foo=bar1", testVol1)
   346  	c.Assert(err, check.IsNil)
   347  
   348  	testVol2 := "testvolcreatelabel-2"
   349  	out, _, err = dockerCmdWithError("volume", "create", "--label", "foo=bar2", testVol2)
   350  	c.Assert(err, check.IsNil)
   351  
   352  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=foo")
   353  
   354  	// filter with label=key
   355  	c.Assert(out, checker.Contains, "testvolcreatelabel-1\n", check.Commentf("expected volume 'testvolcreatelabel-1' in output"))
   356  	c.Assert(out, checker.Contains, "testvolcreatelabel-2\n", check.Commentf("expected volume 'testvolcreatelabel-2' in output"))
   357  
   358  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=foo=bar1")
   359  
   360  	// filter with label=key=value
   361  	c.Assert(out, checker.Contains, "testvolcreatelabel-1\n", check.Commentf("expected volume 'testvolcreatelabel-1' in output"))
   362  	c.Assert(out, check.Not(checker.Contains), "testvolcreatelabel-2\n", check.Commentf("expected volume 'testvolcreatelabel-2 in output"))
   363  
   364  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=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  	out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=foo=non-exist")
   369  	outArr = strings.Split(strings.TrimSpace(out), "\n")
   370  	c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
   371  }
   372  
   373  func (s *DockerSuite) TestVolumeCLIRmForceUsage(c *check.C) {
   374  	out, _ := dockerCmd(c, "volume", "create")
   375  	id := strings.TrimSpace(out)
   376  
   377  	dockerCmd(c, "volume", "rm", "-f", id)
   378  	dockerCmd(c, "volume", "rm", "--force", "nonexist")
   379  
   380  	out, _ = dockerCmd(c, "volume", "ls")
   381  	outArr := strings.Split(strings.TrimSpace(out), "\n")
   382  	c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
   383  }
   384  
   385  func (s *DockerSuite) TestVolumeCLIRmForce(c *check.C) {
   386  	testRequires(c, SameHostDaemon, DaemonIsLinux)
   387  
   388  	name := "test"
   389  	out, _ := dockerCmd(c, "volume", "create", name)
   390  	id := strings.TrimSpace(out)
   391  	c.Assert(id, checker.Equals, name)
   392  
   393  	out, _ = dockerCmd(c, "volume", "inspect", "--format", "{{.Mountpoint}}", name)
   394  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   395  	// Mountpoint is in the form of "/var/lib/docker/volumes/.../_data", removing `/_data`
   396  	path := strings.TrimSuffix(strings.TrimSpace(out), "/_data")
   397  	out, _, err := runCommandWithOutput(exec.Command("rm", "-rf", path))
   398  	c.Assert(err, check.IsNil)
   399  
   400  	dockerCmd(c, "volume", "rm", "-f", "test")
   401  	out, _ = dockerCmd(c, "volume", "ls")
   402  	c.Assert(out, checker.Not(checker.Contains), name)
   403  	dockerCmd(c, "volume", "create", "test")
   404  	out, _ = dockerCmd(c, "volume", "ls")
   405  	c.Assert(out, checker.Contains, name)
   406  }
   407  
   408  func (s *DockerSuite) TestVolumeCliInspectWithVolumeOpts(c *check.C) {
   409  	testRequires(c, DaemonIsLinux)
   410  
   411  	// Without options
   412  	name := "test1"
   413  	dockerCmd(c, "volume", "create", "-d", "local", name)
   414  	out, _ := dockerCmd(c, "volume", "inspect", "--format={{ .Options }}", name)
   415  	c.Assert(strings.TrimSpace(out), checker.Contains, "map[]")
   416  
   417  	// With options
   418  	name = "test2"
   419  	k1, v1 := "type", "tmpfs"
   420  	k2, v2 := "device", "tmpfs"
   421  	k3, v3 := "o", "size=1m,uid=1000"
   422  	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))
   423  	out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Options }}", name)
   424  	c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k1, v1))
   425  	c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k2, v2))
   426  	c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k3, v3))
   427  }