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