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