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