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 }