github.com/ruphin/docker@v1.10.1/integration-cli/docker_cli_run_test.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "bytes" 6 "fmt" 7 "io/ioutil" 8 "net" 9 "os" 10 "os/exec" 11 "path" 12 "path/filepath" 13 "reflect" 14 "regexp" 15 "sort" 16 "strconv" 17 "strings" 18 "sync" 19 "time" 20 21 "github.com/docker/docker/pkg/integration/checker" 22 "github.com/docker/docker/pkg/mount" 23 "github.com/docker/docker/runconfig" 24 "github.com/docker/go-connections/nat" 25 "github.com/docker/libnetwork/netutils" 26 "github.com/docker/libnetwork/resolvconf" 27 "github.com/go-check/check" 28 ) 29 30 // "test123" should be printed by docker run 31 func (s *DockerSuite) TestRunEchoStdout(c *check.C) { 32 out, _ := dockerCmd(c, "run", "busybox", "echo", "test123") 33 if out != "test123\n" { 34 c.Fatalf("container should've printed 'test123', got '%s'", out) 35 } 36 } 37 38 // "test" should be printed 39 func (s *DockerSuite) TestRunEchoNamedContainer(c *check.C) { 40 out, _ := dockerCmd(c, "run", "--name", "testfoonamedcontainer", "busybox", "echo", "test") 41 if out != "test\n" { 42 c.Errorf("container should've printed 'test'") 43 } 44 } 45 46 // docker run should not leak file descriptors. This test relies on Unix 47 // specific functionality and cannot run on Windows. 48 func (s *DockerSuite) TestRunLeakyFileDescriptors(c *check.C) { 49 testRequires(c, DaemonIsLinux) 50 out, _ := dockerCmd(c, "run", "busybox", "ls", "-C", "/proc/self/fd") 51 52 // normally, we should only get 0, 1, and 2, but 3 gets created by "ls" when it does "opendir" on the "fd" directory 53 if out != "0 1 2 3\n" { 54 c.Errorf("container should've printed '0 1 2 3', not: %s", out) 55 } 56 } 57 58 // it should be possible to lookup Google DNS 59 // this will fail when Internet access is unavailable 60 func (s *DockerSuite) TestRunLookupGoogleDns(c *check.C) { 61 testRequires(c, Network) 62 image := DefaultImage 63 if daemonPlatform == "windows" { 64 // nslookup isn't present in Windows busybox. Is built-in. 65 image = WindowsBaseImage 66 } 67 dockerCmd(c, "run", image, "nslookup", "google.com") 68 } 69 70 // the exit code should be 0 71 func (s *DockerSuite) TestRunExitCodeZero(c *check.C) { 72 dockerCmd(c, "run", "busybox", "true") 73 } 74 75 // the exit code should be 1 76 func (s *DockerSuite) TestRunExitCodeOne(c *check.C) { 77 _, exitCode, err := dockerCmdWithError("run", "busybox", "false") 78 if err != nil && !strings.Contains("exit status 1", fmt.Sprintf("%s", err)) { 79 c.Fatal(err) 80 } 81 if exitCode != 1 { 82 c.Errorf("container should've exited with exit code 1. Got %d", exitCode) 83 } 84 } 85 86 // it should be possible to pipe in data via stdin to a process running in a container 87 func (s *DockerSuite) TestRunStdinPipe(c *check.C) { 88 // TODO Windows: This needs some work to make compatible. 89 testRequires(c, DaemonIsLinux) 90 runCmd := exec.Command(dockerBinary, "run", "-i", "-a", "stdin", "busybox", "cat") 91 runCmd.Stdin = strings.NewReader("blahblah") 92 out, _, _, err := runCommandWithStdoutStderr(runCmd) 93 if err != nil { 94 c.Fatalf("failed to run container: %v, output: %q", err, out) 95 } 96 97 out = strings.TrimSpace(out) 98 dockerCmd(c, "wait", out) 99 100 logsOut, _ := dockerCmd(c, "logs", out) 101 102 containerLogs := strings.TrimSpace(logsOut) 103 if containerLogs != "blahblah" { 104 c.Errorf("logs didn't print the container's logs %s", containerLogs) 105 } 106 107 dockerCmd(c, "rm", out) 108 } 109 110 // the container's ID should be printed when starting a container in detached mode 111 func (s *DockerSuite) TestRunDetachedContainerIDPrinting(c *check.C) { 112 out, _ := dockerCmd(c, "run", "-d", "busybox", "true") 113 114 out = strings.TrimSpace(out) 115 dockerCmd(c, "wait", out) 116 117 rmOut, _ := dockerCmd(c, "rm", out) 118 119 rmOut = strings.TrimSpace(rmOut) 120 if rmOut != out { 121 c.Errorf("rm didn't print the container ID %s %s", out, rmOut) 122 } 123 } 124 125 // the working directory should be set correctly 126 func (s *DockerSuite) TestRunWorkingDirectory(c *check.C) { 127 // TODO Windows: There's a Windows bug stopping this from working. 128 testRequires(c, DaemonIsLinux) 129 dir := "/root" 130 image := "busybox" 131 if daemonPlatform == "windows" { 132 dir = `/windows` 133 image = WindowsBaseImage 134 } 135 136 // First with -w 137 out, _ := dockerCmd(c, "run", "-w", dir, image, "pwd") 138 out = strings.TrimSpace(out) 139 if out != dir { 140 c.Errorf("-w failed to set working directory") 141 } 142 143 // Then with --workdir 144 out, _ = dockerCmd(c, "run", "--workdir", dir, image, "pwd") 145 out = strings.TrimSpace(out) 146 if out != dir { 147 c.Errorf("--workdir failed to set working directory") 148 } 149 } 150 151 // pinging Google's DNS resolver should fail when we disable the networking 152 func (s *DockerSuite) TestRunWithoutNetworking(c *check.C) { 153 count := "-c" 154 image := "busybox" 155 if daemonPlatform == "windows" { 156 count = "-n" 157 image = WindowsBaseImage 158 } 159 160 // First using the long form --net 161 out, exitCode, err := dockerCmdWithError("run", "--net=none", image, "ping", count, "1", "8.8.8.8") 162 if err != nil && exitCode != 1 { 163 c.Fatal(out, err) 164 } 165 if exitCode != 1 { 166 c.Errorf("--net=none should've disabled the network; the container shouldn't have been able to ping 8.8.8.8") 167 } 168 } 169 170 //test --link use container name to link target 171 func (s *DockerSuite) TestRunLinksContainerWithContainerName(c *check.C) { 172 // TODO Windows: This test cannot run on a Windows daemon as the networking 173 // settings are not populated back yet on inspect. 174 testRequires(c, DaemonIsLinux) 175 dockerCmd(c, "run", "-i", "-t", "-d", "--name", "parent", "busybox") 176 177 ip, err := inspectField("parent", "NetworkSettings.Networks.bridge.IPAddress") 178 c.Assert(err, check.IsNil) 179 180 out, _ := dockerCmd(c, "run", "--link", "parent:test", "busybox", "/bin/cat", "/etc/hosts") 181 if !strings.Contains(out, ip+" test") { 182 c.Fatalf("use a container name to link target failed") 183 } 184 } 185 186 //test --link use container id to link target 187 func (s *DockerSuite) TestRunLinksContainerWithContainerId(c *check.C) { 188 // TODO Windows: This test cannot run on a Windows daemon as the networking 189 // settings are not populated back yet on inspect. 190 testRequires(c, DaemonIsLinux) 191 cID, _ := dockerCmd(c, "run", "-i", "-t", "-d", "busybox") 192 193 cID = strings.TrimSpace(cID) 194 ip, err := inspectField(cID, "NetworkSettings.Networks.bridge.IPAddress") 195 c.Assert(err, check.IsNil) 196 197 out, _ := dockerCmd(c, "run", "--link", cID+":test", "busybox", "/bin/cat", "/etc/hosts") 198 if !strings.Contains(out, ip+" test") { 199 c.Fatalf("use a container id to link target failed") 200 } 201 } 202 203 func (s *DockerSuite) TestUserDefinedNetworkLinks(c *check.C) { 204 testRequires(c, DaemonIsLinux, NotUserNamespace) 205 dockerCmd(c, "network", "create", "-d", "bridge", "udlinkNet") 206 207 dockerCmd(c, "run", "-d", "--net=udlinkNet", "--name=first", "busybox", "top") 208 c.Assert(waitRun("first"), check.IsNil) 209 210 // run a container in user-defined network udlinkNet with a link for an existing container 211 // and a link for a container that doesnt exist 212 dockerCmd(c, "run", "-d", "--net=udlinkNet", "--name=second", "--link=first:foo", 213 "--link=third:bar", "busybox", "top") 214 c.Assert(waitRun("second"), check.IsNil) 215 216 // ping to first and its alias foo must succeed 217 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 218 c.Assert(err, check.IsNil) 219 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 220 c.Assert(err, check.IsNil) 221 222 // ping to third and its alias must fail 223 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "third") 224 c.Assert(err, check.NotNil) 225 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar") 226 c.Assert(err, check.NotNil) 227 228 // start third container now 229 dockerCmd(c, "run", "-d", "--net=udlinkNet", "--name=third", "busybox", "top") 230 c.Assert(waitRun("third"), check.IsNil) 231 232 // ping to third and its alias must succeed now 233 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "third") 234 c.Assert(err, check.IsNil) 235 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar") 236 c.Assert(err, check.IsNil) 237 } 238 239 func (s *DockerSuite) TestUserDefinedNetworkLinksWithRestart(c *check.C) { 240 testRequires(c, DaemonIsLinux, NotUserNamespace) 241 dockerCmd(c, "network", "create", "-d", "bridge", "udlinkNet") 242 243 dockerCmd(c, "run", "-d", "--net=udlinkNet", "--name=first", "busybox", "top") 244 c.Assert(waitRun("first"), check.IsNil) 245 246 dockerCmd(c, "run", "-d", "--net=udlinkNet", "--name=second", "--link=first:foo", 247 "busybox", "top") 248 c.Assert(waitRun("second"), check.IsNil) 249 250 // ping to first and its alias foo must succeed 251 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 252 c.Assert(err, check.IsNil) 253 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 254 c.Assert(err, check.IsNil) 255 256 // Restart first container 257 dockerCmd(c, "restart", "first") 258 c.Assert(waitRun("first"), check.IsNil) 259 260 // ping to first and its alias foo must still succeed 261 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 262 c.Assert(err, check.IsNil) 263 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 264 c.Assert(err, check.IsNil) 265 266 // Restart second container 267 dockerCmd(c, "restart", "second") 268 c.Assert(waitRun("second"), check.IsNil) 269 270 // ping to first and its alias foo must still succeed 271 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 272 c.Assert(err, check.IsNil) 273 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 274 c.Assert(err, check.IsNil) 275 } 276 277 func (s *DockerSuite) TestUserDefinedNetworkAlias(c *check.C) { 278 testRequires(c, DaemonIsLinux, NotUserNamespace) 279 dockerCmd(c, "network", "create", "-d", "bridge", "net1") 280 281 dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo1", "--net-alias=foo2", "busybox", "top") 282 c.Assert(waitRun("first"), check.IsNil) 283 284 dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox", "top") 285 c.Assert(waitRun("second"), check.IsNil) 286 287 // ping to first and its network-scoped aliases 288 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 289 c.Assert(err, check.IsNil) 290 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo1") 291 c.Assert(err, check.IsNil) 292 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo2") 293 c.Assert(err, check.IsNil) 294 295 // Restart first container 296 dockerCmd(c, "restart", "first") 297 c.Assert(waitRun("first"), check.IsNil) 298 299 // ping to first and its network-scoped aliases must succeed 300 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 301 c.Assert(err, check.IsNil) 302 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo1") 303 c.Assert(err, check.IsNil) 304 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo2") 305 c.Assert(err, check.IsNil) 306 } 307 308 // Issue 9677. 309 func (s *DockerSuite) TestRunWithDaemonFlags(c *check.C) { 310 out, _, err := dockerCmdWithError("--exec-opt", "foo=bar", "run", "-i", "busybox", "true") 311 if err != nil { 312 if !strings.Contains(out, "flag provided but not defined: --exec-opt") { // no daemon (client-only) 313 c.Fatal(err, out) 314 } 315 } 316 } 317 318 // Regression test for #4979 319 func (s *DockerSuite) TestRunWithVolumesFromExited(c *check.C) { 320 321 var ( 322 out string 323 exitCode int 324 ) 325 326 // Create a file in a volume 327 if daemonPlatform == "windows" { 328 out, exitCode = dockerCmd(c, "run", "--name", "test-data", "--volume", `c:\some\dir`, WindowsBaseImage, `cmd /c echo hello > c:\some\dir\file`) 329 } else { 330 out, exitCode = dockerCmd(c, "run", "--name", "test-data", "--volume", "/some/dir", "busybox", "touch", "/some/dir/file") 331 } 332 if exitCode != 0 { 333 c.Fatal("1", out, exitCode) 334 } 335 336 // Read the file from another container using --volumes-from to access the volume in the second container 337 if daemonPlatform == "windows" { 338 out, exitCode = dockerCmd(c, "run", "--volumes-from", "test-data", WindowsBaseImage, `cmd /c type c:\some\dir\file`) 339 } else { 340 out, exitCode = dockerCmd(c, "run", "--volumes-from", "test-data", "busybox", "cat", "/some/dir/file") 341 } 342 if exitCode != 0 { 343 c.Fatal("2", out, exitCode) 344 } 345 } 346 347 // Volume path is a symlink which also exists on the host, and the host side is a file not a dir 348 // But the volume call is just a normal volume, not a bind mount 349 func (s *DockerSuite) TestRunCreateVolumesInSymlinkDir(c *check.C) { 350 var ( 351 dockerFile string 352 containerPath string 353 cmd string 354 ) 355 testRequires(c, SameHostDaemon) 356 name := "test-volume-symlink" 357 358 dir, err := ioutil.TempDir("", name) 359 if err != nil { 360 c.Fatal(err) 361 } 362 defer os.RemoveAll(dir) 363 364 f, err := os.OpenFile(filepath.Join(dir, "test"), os.O_CREATE, 0700) 365 if err != nil { 366 c.Fatal(err) 367 } 368 f.Close() 369 370 if daemonPlatform == "windows" { 371 dockerFile = fmt.Sprintf("FROM %s\nRUN mkdir %s\nRUN mklink /D c:\\test %s", WindowsBaseImage, dir, dir) 372 containerPath = `c:\test\test` 373 cmd = "tasklist" 374 } else { 375 dockerFile = fmt.Sprintf("FROM busybox\nRUN mkdir -p %s\nRUN ln -s %s /test", dir, dir) 376 containerPath = "/test/test" 377 cmd = "true" 378 } 379 if _, err := buildImage(name, dockerFile, false); err != nil { 380 c.Fatal(err) 381 } 382 383 dockerCmd(c, "run", "-v", containerPath, name, cmd) 384 } 385 386 func (s *DockerSuite) TestRunVolumesMountedAsReadonly(c *check.C) { 387 // TODO Windows (Post TP4): This test cannot run on a Windows daemon as 388 // Windows does not support read-only bind mounts. 389 testRequires(c, DaemonIsLinux) 390 if _, code, err := dockerCmdWithError("run", "-v", "/test:/test:ro", "busybox", "touch", "/test/somefile"); err == nil || code == 0 { 391 c.Fatalf("run should fail because volume is ro: exit code %d", code) 392 } 393 } 394 395 func (s *DockerSuite) TestRunVolumesFromInReadonlyModeFails(c *check.C) { 396 // TODO Windows (Post TP4): This test cannot run on a Windows daemon as 397 // Windows does not support read-only bind mounts. Modified for when ro is supported. 398 testRequires(c, DaemonIsLinux) 399 var ( 400 volumeDir string 401 fileInVol string 402 ) 403 if daemonPlatform == "windows" { 404 volumeDir = `c:/test` // Forward-slash as using busybox 405 fileInVol = `c:/test/file` 406 } else { 407 testRequires(c, DaemonIsLinux) 408 volumeDir = "/test" 409 fileInVol = `/test/file` 410 } 411 dockerCmd(c, "run", "--name", "parent", "-v", volumeDir, "busybox", "true") 412 413 if _, code, err := dockerCmdWithError("run", "--volumes-from", "parent:ro", "busybox", "touch", fileInVol); err == nil || code == 0 { 414 c.Fatalf("run should fail because volume is ro: exit code %d", code) 415 } 416 } 417 418 // Regression test for #1201 419 func (s *DockerSuite) TestRunVolumesFromInReadWriteMode(c *check.C) { 420 var ( 421 volumeDir string 422 fileInVol string 423 ) 424 if daemonPlatform == "windows" { 425 volumeDir = `c:/test` // Forward-slash as using busybox 426 fileInVol = `c:/test/file` 427 } else { 428 testRequires(c, DaemonIsLinux) 429 volumeDir = "/test" 430 fileInVol = "/test/file" 431 } 432 433 dockerCmd(c, "run", "--name", "parent", "-v", volumeDir, "busybox", "true") 434 dockerCmd(c, "run", "--volumes-from", "parent:rw", "busybox", "touch", fileInVol) 435 436 if out, _, err := dockerCmdWithError("run", "--volumes-from", "parent:bar", "busybox", "touch", fileInVol); err == nil || !strings.Contains(out, `invalid mode: "bar"`) { 437 c.Fatalf("running --volumes-from parent:bar should have failed with invalid mode: %q", out) 438 } 439 440 dockerCmd(c, "run", "--volumes-from", "parent", "busybox", "touch", fileInVol) 441 } 442 443 func (s *DockerSuite) TestVolumesFromGetsProperMode(c *check.C) { 444 // TODO Windows: This test cannot yet run on a Windows daemon as Windows does 445 // not support read-only bind mounts as at TP4 446 testRequires(c, DaemonIsLinux) 447 dockerCmd(c, "run", "--name", "parent", "-v", "/test:/test:ro", "busybox", "true") 448 449 // Expect this "rw" mode to be be ignored since the inherited volume is "ro" 450 if _, _, err := dockerCmdWithError("run", "--volumes-from", "parent:rw", "busybox", "touch", "/test/file"); err == nil { 451 c.Fatal("Expected volumes-from to inherit read-only volume even when passing in `rw`") 452 } 453 454 dockerCmd(c, "run", "--name", "parent2", "-v", "/test:/test:ro", "busybox", "true") 455 456 // Expect this to be read-only since both are "ro" 457 if _, _, err := dockerCmdWithError("run", "--volumes-from", "parent2:ro", "busybox", "touch", "/test/file"); err == nil { 458 c.Fatal("Expected volumes-from to inherit read-only volume even when passing in `ro`") 459 } 460 } 461 462 // Test for GH#10618 463 func (s *DockerSuite) TestRunNoDupVolumes(c *check.C) { 464 path1 := randomTmpDirPath("test1", daemonPlatform) 465 path2 := randomTmpDirPath("test2", daemonPlatform) 466 467 someplace := ":/someplace" 468 if daemonPlatform == "windows" { 469 // Windows requires that the source directory exists before calling HCS 470 testRequires(c, SameHostDaemon) 471 someplace = `:c:\someplace` 472 if err := os.MkdirAll(path1, 0755); err != nil { 473 c.Fatalf("Failed to create %s: %q", path1, err) 474 } 475 defer os.RemoveAll(path1) 476 if err := os.MkdirAll(path2, 0755); err != nil { 477 c.Fatalf("Failed to create %s: %q", path1, err) 478 } 479 defer os.RemoveAll(path2) 480 } 481 mountstr1 := path1 + someplace 482 mountstr2 := path2 + someplace 483 484 if out, _, err := dockerCmdWithError("run", "-v", mountstr1, "-v", mountstr2, "busybox", "true"); err == nil { 485 c.Fatal("Expected error about duplicate mount definitions") 486 } else { 487 if !strings.Contains(out, "Duplicate mount point") { 488 c.Fatalf("Expected 'duplicate mount point' error, got %v", out) 489 } 490 } 491 } 492 493 // Test for #1351 494 func (s *DockerSuite) TestRunApplyVolumesFromBeforeVolumes(c *check.C) { 495 prefix := "" 496 if daemonPlatform == "windows" { 497 prefix = `c:` 498 } 499 dockerCmd(c, "run", "--name", "parent", "-v", prefix+"/test", "busybox", "touch", prefix+"/test/foo") 500 dockerCmd(c, "run", "--volumes-from", "parent", "-v", prefix+"/test", "busybox", "cat", prefix+"/test/foo") 501 } 502 503 func (s *DockerSuite) TestRunMultipleVolumesFrom(c *check.C) { 504 prefix := "" 505 if daemonPlatform == "windows" { 506 prefix = `c:` 507 } 508 dockerCmd(c, "run", "--name", "parent1", "-v", prefix+"/test", "busybox", "touch", prefix+"/test/foo") 509 dockerCmd(c, "run", "--name", "parent2", "-v", prefix+"/other", "busybox", "touch", prefix+"/other/bar") 510 dockerCmd(c, "run", "--volumes-from", "parent1", "--volumes-from", "parent2", "busybox", "sh", "-c", "cat /test/foo && cat /other/bar") 511 } 512 513 // this tests verifies the ID format for the container 514 func (s *DockerSuite) TestRunVerifyContainerID(c *check.C) { 515 out, exit, err := dockerCmdWithError("run", "-d", "busybox", "true") 516 if err != nil { 517 c.Fatal(err) 518 } 519 if exit != 0 { 520 c.Fatalf("expected exit code 0 received %d", exit) 521 } 522 523 match, err := regexp.MatchString("^[0-9a-f]{64}$", strings.TrimSuffix(out, "\n")) 524 if err != nil { 525 c.Fatal(err) 526 } 527 if !match { 528 c.Fatalf("Invalid container ID: %s", out) 529 } 530 } 531 532 // Test that creating a container with a volume doesn't crash. Regression test for #995. 533 func (s *DockerSuite) TestRunCreateVolume(c *check.C) { 534 prefix := "" 535 if daemonPlatform == "windows" { 536 prefix = `c:` 537 } 538 dockerCmd(c, "run", "-v", prefix+"/var/lib/data", "busybox", "true") 539 } 540 541 // Test that creating a volume with a symlink in its path works correctly. Test for #5152. 542 // Note that this bug happens only with symlinks with a target that starts with '/'. 543 func (s *DockerSuite) TestRunCreateVolumeWithSymlink(c *check.C) { 544 // Cannot run on Windows as relies on Linux-specific functionality (sh -c mount...) 545 testRequires(c, DaemonIsLinux) 546 image := "docker-test-createvolumewithsymlink" 547 548 buildCmd := exec.Command(dockerBinary, "build", "-t", image, "-") 549 buildCmd.Stdin = strings.NewReader(`FROM busybox 550 RUN ln -s home /bar`) 551 buildCmd.Dir = workingDirectory 552 err := buildCmd.Run() 553 if err != nil { 554 c.Fatalf("could not build '%s': %v", image, err) 555 } 556 557 _, exitCode, err := dockerCmdWithError("run", "-v", "/bar/foo", "--name", "test-createvolumewithsymlink", image, "sh", "-c", "mount | grep -q /home/foo") 558 if err != nil || exitCode != 0 { 559 c.Fatalf("[run] err: %v, exitcode: %d", err, exitCode) 560 } 561 562 volPath, err := inspectMountSourceField("test-createvolumewithsymlink", "/bar/foo") 563 if err != nil { 564 c.Fatalf("[inspect] err: %v", err) 565 } 566 567 _, exitCode, err = dockerCmdWithError("rm", "-v", "test-createvolumewithsymlink") 568 if err != nil || exitCode != 0 { 569 c.Fatalf("[rm] err: %v, exitcode: %d", err, exitCode) 570 } 571 572 _, err = os.Stat(volPath) 573 if !os.IsNotExist(err) { 574 c.Fatalf("[open] (expecting 'file does not exist' error) err: %v, volPath: %s", err, volPath) 575 } 576 } 577 578 // Tests that a volume path that has a symlink exists in a container mounting it with `--volumes-from`. 579 func (s *DockerSuite) TestRunVolumesFromSymlinkPath(c *check.C) { 580 name := "docker-test-volumesfromsymlinkpath" 581 prefix := "" 582 dfContents := `FROM busybox 583 RUN ln -s home /foo 584 VOLUME ["/foo/bar"]` 585 586 if daemonPlatform == "windows" { 587 prefix = `c:` 588 dfContents = `FROM ` + WindowsBaseImage + ` 589 RUN mkdir c:\home 590 RUN mklink /D c:\foo c:\home 591 VOLUME ["c:/foo/bar"] 592 ENTRYPOINT c:\windows\system32\cmd.exe` 593 } 594 595 buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-") 596 buildCmd.Stdin = strings.NewReader(dfContents) 597 buildCmd.Dir = workingDirectory 598 err := buildCmd.Run() 599 if err != nil { 600 c.Fatalf("could not build 'docker-test-volumesfromsymlinkpath': %v", err) 601 } 602 603 out, exitCode, err := dockerCmdWithError("run", "--name", "test-volumesfromsymlinkpath", name) 604 if err != nil || exitCode != 0 { 605 c.Fatalf("[run] (volume) err: %v, exitcode: %d, out: %s", err, exitCode, out) 606 } 607 608 _, exitCode, err = dockerCmdWithError("run", "--volumes-from", "test-volumesfromsymlinkpath", "busybox", "sh", "-c", "ls "+prefix+"/foo | grep -q bar") 609 if err != nil || exitCode != 0 { 610 c.Fatalf("[run] err: %v, exitcode: %d", err, exitCode) 611 } 612 } 613 614 func (s *DockerSuite) TestRunExitCode(c *check.C) { 615 var ( 616 exit int 617 err error 618 ) 619 620 _, exit, err = dockerCmdWithError("run", "busybox", "/bin/sh", "-c", "exit 72") 621 622 if err == nil { 623 c.Fatal("should not have a non nil error") 624 } 625 if exit != 72 { 626 c.Fatalf("expected exit code 72 received %d", exit) 627 } 628 } 629 630 func (s *DockerSuite) TestRunUserDefaults(c *check.C) { 631 expected := "uid=0(root) gid=0(root)" 632 if daemonPlatform == "windows" { 633 expected = "uid=1000(SYSTEM) gid=1000(SYSTEM)" 634 } 635 out, _ := dockerCmd(c, "run", "busybox", "id") 636 if !strings.Contains(out, expected) { 637 c.Fatalf("expected '%s' got %s", expected, out) 638 } 639 } 640 641 func (s *DockerSuite) TestRunUserByName(c *check.C) { 642 // TODO Windows: This test cannot run on a Windows daemon as Windows does 643 // not support the use of -u 644 testRequires(c, DaemonIsLinux) 645 out, _ := dockerCmd(c, "run", "-u", "root", "busybox", "id") 646 if !strings.Contains(out, "uid=0(root) gid=0(root)") { 647 c.Fatalf("expected root user got %s", out) 648 } 649 } 650 651 func (s *DockerSuite) TestRunUserByID(c *check.C) { 652 // TODO Windows: This test cannot run on a Windows daemon as Windows does 653 // not support the use of -u 654 testRequires(c, DaemonIsLinux) 655 out, _ := dockerCmd(c, "run", "-u", "1", "busybox", "id") 656 if !strings.Contains(out, "uid=1(daemon) gid=1(daemon)") { 657 c.Fatalf("expected daemon user got %s", out) 658 } 659 } 660 661 func (s *DockerSuite) TestRunUserByIDBig(c *check.C) { 662 // TODO Windows: This test cannot run on a Windows daemon as Windows does 663 // not support the use of -u 664 testRequires(c, DaemonIsLinux) 665 out, _, err := dockerCmdWithError("run", "-u", "2147483648", "busybox", "id") 666 if err == nil { 667 c.Fatal("No error, but must be.", out) 668 } 669 if !strings.Contains(out, "Uids and gids must be in range") { 670 c.Fatalf("expected error about uids range, got %s", out) 671 } 672 } 673 674 func (s *DockerSuite) TestRunUserByIDNegative(c *check.C) { 675 // TODO Windows: This test cannot run on a Windows daemon as Windows does 676 // not support the use of -u 677 testRequires(c, DaemonIsLinux) 678 out, _, err := dockerCmdWithError("run", "-u", "-1", "busybox", "id") 679 if err == nil { 680 c.Fatal("No error, but must be.", out) 681 } 682 if !strings.Contains(out, "Uids and gids must be in range") { 683 c.Fatalf("expected error about uids range, got %s", out) 684 } 685 } 686 687 func (s *DockerSuite) TestRunUserByIDZero(c *check.C) { 688 // TODO Windows: This test cannot run on a Windows daemon as Windows does 689 // not support the use of -u 690 testRequires(c, DaemonIsLinux) 691 out, _, err := dockerCmdWithError("run", "-u", "0", "busybox", "id") 692 if err != nil { 693 c.Fatal(err, out) 694 } 695 if !strings.Contains(out, "uid=0(root) gid=0(root) groups=10(wheel)") { 696 c.Fatalf("expected daemon user got %s", out) 697 } 698 } 699 700 func (s *DockerSuite) TestRunUserNotFound(c *check.C) { 701 // TODO Windows: This test cannot run on a Windows daemon as Windows does 702 // not support the use of -u 703 testRequires(c, DaemonIsLinux) 704 _, _, err := dockerCmdWithError("run", "-u", "notme", "busybox", "id") 705 if err == nil { 706 c.Fatal("unknown user should cause container to fail") 707 } 708 } 709 710 func (s *DockerSuite) TestRunTwoConcurrentContainers(c *check.C) { 711 // TODO Windows. There are two bugs in TP4 which means this test cannot 712 // be reliably enabled. The first is a race condition where sometimes 713 // HCS CreateComputeSystem() will fail "Invalid class string". #4985252 and 714 // #4493430. 715 // 716 // The second, which is seen more readily by increasing the number of concurrent 717 // containers to 5 or more, is that CSRSS hangs. This may fixed in the TP4 ZDP. 718 // #4898773. 719 testRequires(c, DaemonIsLinux) 720 sleepTime := "2" 721 if daemonPlatform == "windows" { 722 sleepTime = "5" // Make more reliable on Windows 723 } 724 group := sync.WaitGroup{} 725 group.Add(2) 726 727 errChan := make(chan error, 2) 728 for i := 0; i < 2; i++ { 729 go func() { 730 defer group.Done() 731 _, _, err := dockerCmdWithError("run", "busybox", "sleep", sleepTime) 732 errChan <- err 733 }() 734 } 735 736 group.Wait() 737 close(errChan) 738 739 for err := range errChan { 740 c.Assert(err, check.IsNil) 741 } 742 } 743 744 func (s *DockerSuite) TestRunEnvironment(c *check.C) { 745 // TODO Windows: Environment handling is different between Linux and 746 // Windows and this test relies currently on unix functionality. 747 testRequires(c, DaemonIsLinux) 748 cmd := exec.Command(dockerBinary, "run", "-h", "testing", "-e=FALSE=true", "-e=TRUE", "-e=TRICKY", "-e=HOME=", "busybox", "env") 749 cmd.Env = append(os.Environ(), 750 "TRUE=false", 751 "TRICKY=tri\ncky\n", 752 ) 753 754 out, _, err := runCommandWithOutput(cmd) 755 if err != nil { 756 c.Fatal(err, out) 757 } 758 759 actualEnv := strings.Split(strings.TrimSpace(out), "\n") 760 sort.Strings(actualEnv) 761 762 goodEnv := []string{ 763 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 764 "HOSTNAME=testing", 765 "FALSE=true", 766 "TRUE=false", 767 "TRICKY=tri", 768 "cky", 769 "", 770 "HOME=/root", 771 } 772 sort.Strings(goodEnv) 773 if len(goodEnv) != len(actualEnv) { 774 c.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", ")) 775 } 776 for i := range goodEnv { 777 if actualEnv[i] != goodEnv[i] { 778 c.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i]) 779 } 780 } 781 } 782 783 func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) { 784 // TODO Windows: Environment handling is different between Linux and 785 // Windows and this test relies currently on unix functionality. 786 testRequires(c, DaemonIsLinux) 787 788 // Test to make sure that when we use -e on env vars that are 789 // not set in our local env that they're removed (if present) in 790 // the container 791 792 cmd := exec.Command(dockerBinary, "run", "-e", "FOO", "-e", "HOSTNAME", "busybox", "env") 793 cmd.Env = appendBaseEnv([]string{}) 794 795 out, _, err := runCommandWithOutput(cmd) 796 if err != nil { 797 c.Fatal(err, out) 798 } 799 800 actualEnv := strings.Split(strings.TrimSpace(out), "\n") 801 sort.Strings(actualEnv) 802 803 goodEnv := []string{ 804 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 805 "HOME=/root", 806 } 807 sort.Strings(goodEnv) 808 if len(goodEnv) != len(actualEnv) { 809 c.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", ")) 810 } 811 for i := range goodEnv { 812 if actualEnv[i] != goodEnv[i] { 813 c.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i]) 814 } 815 } 816 } 817 818 func (s *DockerSuite) TestRunEnvironmentOverride(c *check.C) { 819 // TODO Windows: Environment handling is different between Linux and 820 // Windows and this test relies currently on unix functionality. 821 testRequires(c, DaemonIsLinux) 822 823 // Test to make sure that when we use -e on env vars that are 824 // already in the env that we're overriding them 825 826 cmd := exec.Command(dockerBinary, "run", "-e", "HOSTNAME", "-e", "HOME=/root2", "busybox", "env") 827 cmd.Env = appendBaseEnv([]string{"HOSTNAME=bar"}) 828 829 out, _, err := runCommandWithOutput(cmd) 830 if err != nil { 831 c.Fatal(err, out) 832 } 833 834 actualEnv := strings.Split(strings.TrimSpace(out), "\n") 835 sort.Strings(actualEnv) 836 837 goodEnv := []string{ 838 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 839 "HOME=/root2", 840 "HOSTNAME=bar", 841 } 842 sort.Strings(goodEnv) 843 if len(goodEnv) != len(actualEnv) { 844 c.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", ")) 845 } 846 for i := range goodEnv { 847 if actualEnv[i] != goodEnv[i] { 848 c.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i]) 849 } 850 } 851 } 852 853 func (s *DockerSuite) TestRunContainerNetwork(c *check.C) { 854 if daemonPlatform == "windows" { 855 // Windows busybox does not have ping. Use built in ping instead. 856 dockerCmd(c, "run", WindowsBaseImage, "ping", "-n", "1", "127.0.0.1") 857 } else { 858 dockerCmd(c, "run", "busybox", "ping", "-c", "1", "127.0.0.1") 859 } 860 } 861 862 func (s *DockerSuite) TestRunNetHostNotAllowedWithLinks(c *check.C) { 863 // TODO Windows: This is Linux specific as --link is not supported and 864 // this will be deprecated in favor of container networking model. 865 testRequires(c, DaemonIsLinux, NotUserNamespace) 866 dockerCmd(c, "run", "--name", "linked", "busybox", "true") 867 868 _, _, err := dockerCmdWithError("run", "--net=host", "--link", "linked:linked", "busybox", "true") 869 if err == nil { 870 c.Fatal("Expected error") 871 } 872 } 873 874 // #7851 hostname outside container shows FQDN, inside only shortname 875 // For testing purposes it is not required to set host's hostname directly 876 // and use "--net=host" (as the original issue submitter did), as the same 877 // codepath is executed with "docker run -h <hostname>". Both were manually 878 // tested, but this testcase takes the simpler path of using "run -h .." 879 func (s *DockerSuite) TestRunFullHostnameSet(c *check.C) { 880 // TODO Windows: -h is not yet functional. 881 testRequires(c, DaemonIsLinux) 882 out, _ := dockerCmd(c, "run", "-h", "foo.bar.baz", "busybox", "hostname") 883 if actual := strings.Trim(out, "\r\n"); actual != "foo.bar.baz" { 884 c.Fatalf("expected hostname 'foo.bar.baz', received %s", actual) 885 } 886 } 887 888 func (s *DockerSuite) TestRunPrivilegedCanMknod(c *check.C) { 889 // Not applicable for Windows as Windows daemon does not support 890 // the concept of --privileged, and mknod is a Unix concept. 891 testRequires(c, DaemonIsLinux, NotUserNamespace) 892 out, _ := dockerCmd(c, "run", "--privileged", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 893 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 894 c.Fatalf("expected output ok received %s", actual) 895 } 896 } 897 898 func (s *DockerSuite) TestRunUnprivilegedCanMknod(c *check.C) { 899 // Not applicable for Windows as Windows daemon does not support 900 // the concept of --privileged, and mknod is a Unix concept. 901 testRequires(c, DaemonIsLinux, NotUserNamespace) 902 out, _ := dockerCmd(c, "run", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 903 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 904 c.Fatalf("expected output ok received %s", actual) 905 } 906 } 907 908 func (s *DockerSuite) TestRunCapDropInvalid(c *check.C) { 909 // Not applicable for Windows as there is no concept of --cap-drop 910 testRequires(c, DaemonIsLinux) 911 out, _, err := dockerCmdWithError("run", "--cap-drop=CHPASS", "busybox", "ls") 912 if err == nil { 913 c.Fatal(err, out) 914 } 915 } 916 917 func (s *DockerSuite) TestRunCapDropCannotMknod(c *check.C) { 918 // Not applicable for Windows as there is no concept of --cap-drop or mknod 919 testRequires(c, DaemonIsLinux) 920 out, _, err := dockerCmdWithError("run", "--cap-drop=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 921 922 if err == nil { 923 c.Fatal(err, out) 924 } 925 if actual := strings.Trim(out, "\r\n"); actual == "ok" { 926 c.Fatalf("expected output not ok received %s", actual) 927 } 928 } 929 930 func (s *DockerSuite) TestRunCapDropCannotMknodLowerCase(c *check.C) { 931 // Not applicable for Windows as there is no concept of --cap-drop or mknod 932 testRequires(c, DaemonIsLinux) 933 out, _, err := dockerCmdWithError("run", "--cap-drop=mknod", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 934 935 if err == nil { 936 c.Fatal(err, out) 937 } 938 if actual := strings.Trim(out, "\r\n"); actual == "ok" { 939 c.Fatalf("expected output not ok received %s", actual) 940 } 941 } 942 943 func (s *DockerSuite) TestRunCapDropALLCannotMknod(c *check.C) { 944 // Not applicable for Windows as there is no concept of --cap-drop or mknod 945 testRequires(c, DaemonIsLinux) 946 out, _, err := dockerCmdWithError("run", "--cap-drop=ALL", "--cap-add=SETGID", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 947 if err == nil { 948 c.Fatal(err, out) 949 } 950 if actual := strings.Trim(out, "\r\n"); actual == "ok" { 951 c.Fatalf("expected output not ok received %s", actual) 952 } 953 } 954 955 func (s *DockerSuite) TestRunCapDropALLAddMknodCanMknod(c *check.C) { 956 // Not applicable for Windows as there is no concept of --cap-drop or mknod 957 testRequires(c, DaemonIsLinux, NotUserNamespace) 958 out, _ := dockerCmd(c, "run", "--cap-drop=ALL", "--cap-add=MKNOD", "--cap-add=SETGID", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 959 960 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 961 c.Fatalf("expected output ok received %s", actual) 962 } 963 } 964 965 func (s *DockerSuite) TestRunCapAddInvalid(c *check.C) { 966 // Not applicable for Windows as there is no concept of --cap-add 967 testRequires(c, DaemonIsLinux) 968 out, _, err := dockerCmdWithError("run", "--cap-add=CHPASS", "busybox", "ls") 969 if err == nil { 970 c.Fatal(err, out) 971 } 972 } 973 974 func (s *DockerSuite) TestRunCapAddCanDownInterface(c *check.C) { 975 // Not applicable for Windows as there is no concept of --cap-add 976 testRequires(c, DaemonIsLinux) 977 out, _ := dockerCmd(c, "run", "--cap-add=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") 978 979 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 980 c.Fatalf("expected output ok received %s", actual) 981 } 982 } 983 984 func (s *DockerSuite) TestRunCapAddALLCanDownInterface(c *check.C) { 985 // Not applicable for Windows as there is no concept of --cap-add 986 testRequires(c, DaemonIsLinux) 987 out, _ := dockerCmd(c, "run", "--cap-add=ALL", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") 988 989 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 990 c.Fatalf("expected output ok received %s", actual) 991 } 992 } 993 994 func (s *DockerSuite) TestRunCapAddALLDropNetAdminCanDownInterface(c *check.C) { 995 // Not applicable for Windows as there is no concept of --cap-add 996 testRequires(c, DaemonIsLinux) 997 out, _, err := dockerCmdWithError("run", "--cap-add=ALL", "--cap-drop=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") 998 if err == nil { 999 c.Fatal(err, out) 1000 } 1001 if actual := strings.Trim(out, "\r\n"); actual == "ok" { 1002 c.Fatalf("expected output not ok received %s", actual) 1003 } 1004 } 1005 1006 func (s *DockerSuite) TestRunGroupAdd(c *check.C) { 1007 // Not applicable for Windows as there is no concept of --group-add 1008 testRequires(c, DaemonIsLinux) 1009 out, _ := dockerCmd(c, "run", "--group-add=audio", "--group-add=staff", "--group-add=777", "busybox", "sh", "-c", "id") 1010 1011 groupsList := "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777" 1012 if actual := strings.Trim(out, "\r\n"); actual != groupsList { 1013 c.Fatalf("expected output %s received %s", groupsList, actual) 1014 } 1015 } 1016 1017 func (s *DockerSuite) TestRunPrivilegedCanMount(c *check.C) { 1018 // Not applicable for Windows as there is no concept of --privileged 1019 testRequires(c, DaemonIsLinux, NotUserNamespace) 1020 out, _ := dockerCmd(c, "run", "--privileged", "busybox", "sh", "-c", "mount -t tmpfs none /tmp && echo ok") 1021 1022 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 1023 c.Fatalf("expected output ok received %s", actual) 1024 } 1025 } 1026 1027 func (s *DockerSuite) TestRunUnprivilegedCannotMount(c *check.C) { 1028 // Not applicable for Windows as there is no concept of unprivileged 1029 testRequires(c, DaemonIsLinux) 1030 out, _, err := dockerCmdWithError("run", "busybox", "sh", "-c", "mount -t tmpfs none /tmp && echo ok") 1031 1032 if err == nil { 1033 c.Fatal(err, out) 1034 } 1035 if actual := strings.Trim(out, "\r\n"); actual == "ok" { 1036 c.Fatalf("expected output not ok received %s", actual) 1037 } 1038 } 1039 1040 func (s *DockerSuite) TestRunSysNotWritableInNonPrivilegedContainers(c *check.C) { 1041 // Not applicable for Windows as there is no concept of unprivileged 1042 testRequires(c, DaemonIsLinux) 1043 if _, code, err := dockerCmdWithError("run", "busybox", "touch", "/sys/kernel/profiling"); err == nil || code == 0 { 1044 c.Fatal("sys should not be writable in a non privileged container") 1045 } 1046 } 1047 1048 func (s *DockerSuite) TestRunSysWritableInPrivilegedContainers(c *check.C) { 1049 // Not applicable for Windows as there is no concept of unprivileged 1050 testRequires(c, DaemonIsLinux, NotUserNamespace) 1051 if _, code, err := dockerCmdWithError("run", "--privileged", "busybox", "touch", "/sys/kernel/profiling"); err != nil || code != 0 { 1052 c.Fatalf("sys should be writable in privileged container") 1053 } 1054 } 1055 1056 func (s *DockerSuite) TestRunProcNotWritableInNonPrivilegedContainers(c *check.C) { 1057 // Not applicable for Windows as there is no concept of unprivileged 1058 testRequires(c, DaemonIsLinux) 1059 if _, code, err := dockerCmdWithError("run", "busybox", "touch", "/proc/sysrq-trigger"); err == nil || code == 0 { 1060 c.Fatal("proc should not be writable in a non privileged container") 1061 } 1062 } 1063 1064 func (s *DockerSuite) TestRunProcWritableInPrivilegedContainers(c *check.C) { 1065 // Not applicable for Windows as there is no concept of --privileged 1066 testRequires(c, DaemonIsLinux, NotUserNamespace) 1067 if _, code := dockerCmd(c, "run", "--privileged", "busybox", "touch", "/proc/sysrq-trigger"); code != 0 { 1068 c.Fatalf("proc should be writable in privileged container") 1069 } 1070 } 1071 1072 func (s *DockerSuite) TestRunDeviceNumbers(c *check.C) { 1073 // Not applicable on Windows as /dev/ is a Unix specific concept 1074 // TODO: NotUserNamespace could be removed here if "root" "root" is replaced w user 1075 testRequires(c, DaemonIsLinux, NotUserNamespace) 1076 out, _ := dockerCmd(c, "run", "busybox", "sh", "-c", "ls -l /dev/null") 1077 deviceLineFields := strings.Fields(out) 1078 deviceLineFields[6] = "" 1079 deviceLineFields[7] = "" 1080 deviceLineFields[8] = "" 1081 expected := []string{"crw-rw-rw-", "1", "root", "root", "1,", "3", "", "", "", "/dev/null"} 1082 1083 if !(reflect.DeepEqual(deviceLineFields, expected)) { 1084 c.Fatalf("expected output\ncrw-rw-rw- 1 root root 1, 3 May 24 13:29 /dev/null\n received\n %s\n", out) 1085 } 1086 } 1087 1088 func (s *DockerSuite) TestRunThatCharacterDevicesActLikeCharacterDevices(c *check.C) { 1089 // Not applicable on Windows as /dev/ is a Unix specific concept 1090 testRequires(c, DaemonIsLinux) 1091 out, _ := dockerCmd(c, "run", "busybox", "sh", "-c", "dd if=/dev/zero of=/zero bs=1k count=5 2> /dev/null ; du -h /zero") 1092 if actual := strings.Trim(out, "\r\n"); actual[0] == '0' { 1093 c.Fatalf("expected a new file called /zero to be create that is greater than 0 bytes long, but du says: %s", actual) 1094 } 1095 } 1096 1097 func (s *DockerSuite) TestRunUnprivilegedWithChroot(c *check.C) { 1098 // Not applicable on Windows as it does not support chroot 1099 testRequires(c, DaemonIsLinux) 1100 dockerCmd(c, "run", "busybox", "chroot", "/", "true") 1101 } 1102 1103 func (s *DockerSuite) TestRunAddingOptionalDevices(c *check.C) { 1104 // Not applicable on Windows as Windows does not support --device 1105 testRequires(c, DaemonIsLinux, NotUserNamespace) 1106 out, _ := dockerCmd(c, "run", "--device", "/dev/zero:/dev/nulo", "busybox", "sh", "-c", "ls /dev/nulo") 1107 if actual := strings.Trim(out, "\r\n"); actual != "/dev/nulo" { 1108 c.Fatalf("expected output /dev/nulo, received %s", actual) 1109 } 1110 } 1111 1112 func (s *DockerSuite) TestRunAddingOptionalDevicesNoSrc(c *check.C) { 1113 // Not applicable on Windows as Windows does not support --device 1114 testRequires(c, DaemonIsLinux, NotUserNamespace) 1115 out, _ := dockerCmd(c, "run", "--device", "/dev/zero:rw", "busybox", "sh", "-c", "ls /dev/zero") 1116 if actual := strings.Trim(out, "\r\n"); actual != "/dev/zero" { 1117 c.Fatalf("expected output /dev/zero, received %s", actual) 1118 } 1119 } 1120 1121 func (s *DockerSuite) TestRunAddingOptionalDevicesInvalidMode(c *check.C) { 1122 // Not applicable on Windows as Windows does not support --device 1123 testRequires(c, DaemonIsLinux, NotUserNamespace) 1124 _, _, err := dockerCmdWithError("run", "--device", "/dev/zero:ro", "busybox", "sh", "-c", "ls /dev/zero") 1125 if err == nil { 1126 c.Fatalf("run container with device mode ro should fail") 1127 } 1128 } 1129 1130 func (s *DockerSuite) TestRunModeHostname(c *check.C) { 1131 // Not applicable on Windows as Windows does not support -h 1132 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 1133 1134 out, _ := dockerCmd(c, "run", "-h=testhostname", "busybox", "cat", "/etc/hostname") 1135 1136 if actual := strings.Trim(out, "\r\n"); actual != "testhostname" { 1137 c.Fatalf("expected 'testhostname', but says: %q", actual) 1138 } 1139 1140 out, _ = dockerCmd(c, "run", "--net=host", "busybox", "cat", "/etc/hostname") 1141 1142 hostname, err := os.Hostname() 1143 if err != nil { 1144 c.Fatal(err) 1145 } 1146 if actual := strings.Trim(out, "\r\n"); actual != hostname { 1147 c.Fatalf("expected %q, but says: %q", hostname, actual) 1148 } 1149 } 1150 1151 func (s *DockerSuite) TestRunRootWorkdir(c *check.C) { 1152 out, _ := dockerCmd(c, "run", "--workdir", "/", "busybox", "pwd") 1153 expected := "/\n" 1154 if daemonPlatform == "windows" { 1155 expected = "C:" + expected 1156 } 1157 if out != expected { 1158 c.Fatalf("pwd returned %q (expected %s)", s, expected) 1159 } 1160 } 1161 1162 func (s *DockerSuite) TestRunAllowBindMountingRoot(c *check.C) { 1163 if daemonPlatform == "windows" { 1164 // Windows busybox will fail with Permission Denied on items such as pagefile.sys 1165 dockerCmd(c, "run", "-v", `c:\:c:\host`, WindowsBaseImage, "cmd", "-c", "dir", `c:\host`) 1166 } else { 1167 dockerCmd(c, "run", "-v", "/:/host", "busybox", "ls", "/host") 1168 } 1169 } 1170 1171 func (s *DockerSuite) TestRunDisallowBindMountingRootToRoot(c *check.C) { 1172 mount := "/:/" 1173 targetDir := "/host" 1174 if daemonPlatform == "windows" { 1175 mount = `c:\:c\` 1176 targetDir = "c:/host" // Forward slash as using busybox 1177 } 1178 out, _, err := dockerCmdWithError("run", "-v", mount, "busybox", "ls", targetDir) 1179 if err == nil { 1180 c.Fatal(out, err) 1181 } 1182 } 1183 1184 // Verify that a container gets default DNS when only localhost resolvers exist 1185 func (s *DockerSuite) TestRunDnsDefaultOptions(c *check.C) { 1186 // Not applicable on Windows as this is testing Unix specific functionality 1187 testRequires(c, SameHostDaemon, DaemonIsLinux) 1188 1189 // preserve original resolv.conf for restoring after test 1190 origResolvConf, err := ioutil.ReadFile("/etc/resolv.conf") 1191 if os.IsNotExist(err) { 1192 c.Fatalf("/etc/resolv.conf does not exist") 1193 } 1194 // defer restored original conf 1195 defer func() { 1196 if err := ioutil.WriteFile("/etc/resolv.conf", origResolvConf, 0644); err != nil { 1197 c.Fatal(err) 1198 } 1199 }() 1200 1201 // test 3 cases: standard IPv4 localhost, commented out localhost, and IPv6 localhost 1202 // 2 are removed from the file at container start, and the 3rd (commented out) one is ignored by 1203 // GetNameservers(), leading to a replacement of nameservers with the default set 1204 tmpResolvConf := []byte("nameserver 127.0.0.1\n#nameserver 127.0.2.1\nnameserver ::1") 1205 if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil { 1206 c.Fatal(err) 1207 } 1208 1209 actual, _ := dockerCmd(c, "run", "busybox", "cat", "/etc/resolv.conf") 1210 // check that the actual defaults are appended to the commented out 1211 // localhost resolver (which should be preserved) 1212 // NOTE: if we ever change the defaults from google dns, this will break 1213 expected := "#nameserver 127.0.2.1\n\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n" 1214 if actual != expected { 1215 c.Fatalf("expected resolv.conf be: %q, but was: %q", expected, actual) 1216 } 1217 } 1218 1219 func (s *DockerSuite) TestRunDnsOptions(c *check.C) { 1220 // Not applicable on Windows as Windows does not support --dns*, or 1221 // the Unix-specific functionality of resolv.conf. 1222 testRequires(c, DaemonIsLinux) 1223 out, stderr, _ := dockerCmdWithStdoutStderr(c, "run", "--dns=127.0.0.1", "--dns-search=mydomain", "--dns-opt=ndots:9", "busybox", "cat", "/etc/resolv.conf") 1224 1225 // The client will get a warning on stderr when setting DNS to a localhost address; verify this: 1226 if !strings.Contains(stderr, "Localhost DNS setting") { 1227 c.Fatalf("Expected warning on stderr about localhost resolver, but got %q", stderr) 1228 } 1229 1230 actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1) 1231 if actual != "search mydomain nameserver 127.0.0.1 options ndots:9" { 1232 c.Fatalf("expected 'search mydomain nameserver 127.0.0.1 options ndots:9', but says: %q", actual) 1233 } 1234 1235 out, stderr, _ = dockerCmdWithStdoutStderr(c, "run", "--dns=127.0.0.1", "--dns-search=.", "--dns-opt=ndots:3", "busybox", "cat", "/etc/resolv.conf") 1236 1237 actual = strings.Replace(strings.Trim(strings.Trim(out, "\r\n"), " "), "\n", " ", -1) 1238 if actual != "nameserver 127.0.0.1 options ndots:3" { 1239 c.Fatalf("expected 'nameserver 127.0.0.1 options ndots:3', but says: %q", actual) 1240 } 1241 } 1242 1243 func (s *DockerSuite) TestRunDnsRepeatOptions(c *check.C) { 1244 testRequires(c, DaemonIsLinux) 1245 out, _, _ := dockerCmdWithStdoutStderr(c, "run", "--dns=1.1.1.1", "--dns=2.2.2.2", "--dns-search=mydomain", "--dns-search=mydomain2", "--dns-opt=ndots:9", "--dns-opt=timeout:3", "busybox", "cat", "/etc/resolv.conf") 1246 1247 actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1) 1248 if actual != "search mydomain mydomain2 nameserver 1.1.1.1 nameserver 2.2.2.2 options ndots:9 timeout:3" { 1249 c.Fatalf("expected 'search mydomain mydomain2 nameserver 1.1.1.1 nameserver 2.2.2.2 options ndots:9 timeout:3', but says: %q", actual) 1250 } 1251 } 1252 1253 func (s *DockerSuite) TestRunDnsOptionsBasedOnHostResolvConf(c *check.C) { 1254 // Not applicable on Windows as testing Unix specific functionality 1255 testRequires(c, SameHostDaemon, DaemonIsLinux) 1256 1257 origResolvConf, err := ioutil.ReadFile("/etc/resolv.conf") 1258 if os.IsNotExist(err) { 1259 c.Fatalf("/etc/resolv.conf does not exist") 1260 } 1261 1262 hostNamservers := resolvconf.GetNameservers(origResolvConf, netutils.IP) 1263 hostSearch := resolvconf.GetSearchDomains(origResolvConf) 1264 1265 var out string 1266 out, _ = dockerCmd(c, "run", "--dns=127.0.0.1", "busybox", "cat", "/etc/resolv.conf") 1267 1268 if actualNameservers := resolvconf.GetNameservers([]byte(out), netutils.IP); string(actualNameservers[0]) != "127.0.0.1" { 1269 c.Fatalf("expected '127.0.0.1', but says: %q", string(actualNameservers[0])) 1270 } 1271 1272 actualSearch := resolvconf.GetSearchDomains([]byte(out)) 1273 if len(actualSearch) != len(hostSearch) { 1274 c.Fatalf("expected %q search domain(s), but it has: %q", len(hostSearch), len(actualSearch)) 1275 } 1276 for i := range actualSearch { 1277 if actualSearch[i] != hostSearch[i] { 1278 c.Fatalf("expected %q domain, but says: %q", actualSearch[i], hostSearch[i]) 1279 } 1280 } 1281 1282 out, _ = dockerCmd(c, "run", "--dns-search=mydomain", "busybox", "cat", "/etc/resolv.conf") 1283 1284 actualNameservers := resolvconf.GetNameservers([]byte(out), netutils.IP) 1285 if len(actualNameservers) != len(hostNamservers) { 1286 c.Fatalf("expected %q nameserver(s), but it has: %q", len(hostNamservers), len(actualNameservers)) 1287 } 1288 for i := range actualNameservers { 1289 if actualNameservers[i] != hostNamservers[i] { 1290 c.Fatalf("expected %q nameserver, but says: %q", actualNameservers[i], hostNamservers[i]) 1291 } 1292 } 1293 1294 if actualSearch = resolvconf.GetSearchDomains([]byte(out)); string(actualSearch[0]) != "mydomain" { 1295 c.Fatalf("expected 'mydomain', but says: %q", string(actualSearch[0])) 1296 } 1297 1298 // test with file 1299 tmpResolvConf := []byte("search example.com\nnameserver 12.34.56.78\nnameserver 127.0.0.1") 1300 if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil { 1301 c.Fatal(err) 1302 } 1303 // put the old resolvconf back 1304 defer func() { 1305 if err := ioutil.WriteFile("/etc/resolv.conf", origResolvConf, 0644); err != nil { 1306 c.Fatal(err) 1307 } 1308 }() 1309 1310 resolvConf, err := ioutil.ReadFile("/etc/resolv.conf") 1311 if os.IsNotExist(err) { 1312 c.Fatalf("/etc/resolv.conf does not exist") 1313 } 1314 1315 hostNamservers = resolvconf.GetNameservers(resolvConf, netutils.IP) 1316 hostSearch = resolvconf.GetSearchDomains(resolvConf) 1317 1318 out, _ = dockerCmd(c, "run", "busybox", "cat", "/etc/resolv.conf") 1319 if actualNameservers = resolvconf.GetNameservers([]byte(out), netutils.IP); string(actualNameservers[0]) != "12.34.56.78" || len(actualNameservers) != 1 { 1320 c.Fatalf("expected '12.34.56.78', but has: %v", actualNameservers) 1321 } 1322 1323 actualSearch = resolvconf.GetSearchDomains([]byte(out)) 1324 if len(actualSearch) != len(hostSearch) { 1325 c.Fatalf("expected %q search domain(s), but it has: %q", len(hostSearch), len(actualSearch)) 1326 } 1327 for i := range actualSearch { 1328 if actualSearch[i] != hostSearch[i] { 1329 c.Fatalf("expected %q domain, but says: %q", actualSearch[i], hostSearch[i]) 1330 } 1331 } 1332 } 1333 1334 // Test to see if a non-root user can resolve a DNS name. Also 1335 // check if the container resolv.conf file has at least 0644 perm. 1336 func (s *DockerSuite) TestRunNonRootUserResolvName(c *check.C) { 1337 // Not applicable on Windows as Windows does not support --user 1338 testRequires(c, SameHostDaemon, Network, DaemonIsLinux) 1339 1340 dockerCmd(c, "run", "--name=testperm", "--user=nobody", "busybox", "nslookup", "apt.dockerproject.org") 1341 1342 cID, err := getIDByName("testperm") 1343 if err != nil { 1344 c.Fatal(err) 1345 } 1346 1347 fmode := (os.FileMode)(0644) 1348 finfo, err := os.Stat(containerStorageFile(cID, "resolv.conf")) 1349 if err != nil { 1350 c.Fatal(err) 1351 } 1352 1353 if (finfo.Mode() & fmode) != fmode { 1354 c.Fatalf("Expected container resolv.conf mode to be at least %s, instead got %s", fmode.String(), finfo.Mode().String()) 1355 } 1356 } 1357 1358 // Test if container resolv.conf gets updated the next time it restarts 1359 // if host /etc/resolv.conf has changed. This only applies if the container 1360 // uses the host's /etc/resolv.conf and does not have any dns options provided. 1361 func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) { 1362 // Not applicable on Windows as testing unix specific functionality 1363 testRequires(c, SameHostDaemon, DaemonIsLinux) 1364 1365 tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\n") 1366 tmpLocalhostResolvConf := []byte("nameserver 127.0.0.1") 1367 1368 //take a copy of resolv.conf for restoring after test completes 1369 resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf") 1370 if err != nil { 1371 c.Fatal(err) 1372 } 1373 1374 // This test case is meant to test monitoring resolv.conf when it is 1375 // a regular file not a bind mounc. So we unmount resolv.conf and replace 1376 // it with a file containing the original settings. 1377 cmd := exec.Command("umount", "/etc/resolv.conf") 1378 if _, err = runCommand(cmd); err != nil { 1379 c.Fatal(err) 1380 } 1381 1382 //cleanup 1383 defer func() { 1384 if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { 1385 c.Fatal(err) 1386 } 1387 }() 1388 1389 //1. test that a restarting container gets an updated resolv.conf 1390 dockerCmd(c, "run", "--name='first'", "busybox", "true") 1391 containerID1, err := getIDByName("first") 1392 if err != nil { 1393 c.Fatal(err) 1394 } 1395 1396 // replace resolv.conf with our temporary copy 1397 bytesResolvConf := []byte(tmpResolvConf) 1398 if err := ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil { 1399 c.Fatal(err) 1400 } 1401 1402 // start the container again to pickup changes 1403 dockerCmd(c, "start", "first") 1404 1405 // check for update in container 1406 containerResolv, err := readContainerFile(containerID1, "resolv.conf") 1407 if err != nil { 1408 c.Fatal(err) 1409 } 1410 if !bytes.Equal(containerResolv, bytesResolvConf) { 1411 c.Fatalf("Restarted container does not have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv)) 1412 } 1413 1414 /* //make a change to resolv.conf (in this case replacing our tmp copy with orig copy) 1415 if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { 1416 c.Fatal(err) 1417 } */ 1418 //2. test that a restarting container does not receive resolv.conf updates 1419 // if it modified the container copy of the starting point resolv.conf 1420 dockerCmd(c, "run", "--name='second'", "busybox", "sh", "-c", "echo 'search mylittlepony.com' >>/etc/resolv.conf") 1421 containerID2, err := getIDByName("second") 1422 if err != nil { 1423 c.Fatal(err) 1424 } 1425 1426 //make a change to resolv.conf (in this case replacing our tmp copy with orig copy) 1427 if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { 1428 c.Fatal(err) 1429 } 1430 1431 // start the container again 1432 dockerCmd(c, "start", "second") 1433 1434 // check for update in container 1435 containerResolv, err = readContainerFile(containerID2, "resolv.conf") 1436 if err != nil { 1437 c.Fatal(err) 1438 } 1439 1440 if bytes.Equal(containerResolv, resolvConfSystem) { 1441 c.Fatalf("Container's resolv.conf should not have been updated with host resolv.conf: %q", string(containerResolv)) 1442 } 1443 1444 //3. test that a running container's resolv.conf is not modified while running 1445 out, _ := dockerCmd(c, "run", "-d", "busybox", "top") 1446 runningContainerID := strings.TrimSpace(out) 1447 1448 // replace resolv.conf 1449 if err := ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil { 1450 c.Fatal(err) 1451 } 1452 1453 // check for update in container 1454 containerResolv, err = readContainerFile(runningContainerID, "resolv.conf") 1455 if err != nil { 1456 c.Fatal(err) 1457 } 1458 1459 if bytes.Equal(containerResolv, bytesResolvConf) { 1460 c.Fatalf("Running container should not have updated resolv.conf; expected %q, got %q", string(resolvConfSystem), string(containerResolv)) 1461 } 1462 1463 //4. test that a running container's resolv.conf is updated upon restart 1464 // (the above container is still running..) 1465 dockerCmd(c, "restart", runningContainerID) 1466 1467 // check for update in container 1468 containerResolv, err = readContainerFile(runningContainerID, "resolv.conf") 1469 if err != nil { 1470 c.Fatal(err) 1471 } 1472 if !bytes.Equal(containerResolv, bytesResolvConf) { 1473 c.Fatalf("Restarted container should have updated resolv.conf; expected %q, got %q", string(bytesResolvConf), string(containerResolv)) 1474 } 1475 1476 //5. test that additions of a localhost resolver are cleaned from 1477 // host resolv.conf before updating container's resolv.conf copies 1478 1479 // replace resolv.conf with a localhost-only nameserver copy 1480 bytesResolvConf = []byte(tmpLocalhostResolvConf) 1481 if err = ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil { 1482 c.Fatal(err) 1483 } 1484 1485 // start the container again to pickup changes 1486 dockerCmd(c, "start", "first") 1487 1488 // our first exited container ID should have been updated, but with default DNS 1489 // after the cleanup of resolv.conf found only a localhost nameserver: 1490 containerResolv, err = readContainerFile(containerID1, "resolv.conf") 1491 if err != nil { 1492 c.Fatal(err) 1493 } 1494 1495 expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n" 1496 if !bytes.Equal(containerResolv, []byte(expected)) { 1497 c.Fatalf("Container does not have cleaned/replaced DNS in resolv.conf; expected %q, got %q", expected, string(containerResolv)) 1498 } 1499 1500 //6. Test that replacing (as opposed to modifying) resolv.conf triggers an update 1501 // of containers' resolv.conf. 1502 1503 // Restore the original resolv.conf 1504 if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { 1505 c.Fatal(err) 1506 } 1507 1508 // Run the container so it picks up the old settings 1509 dockerCmd(c, "run", "--name='third'", "busybox", "true") 1510 containerID3, err := getIDByName("third") 1511 if err != nil { 1512 c.Fatal(err) 1513 } 1514 1515 // Create a modified resolv.conf.aside and override resolv.conf with it 1516 bytesResolvConf = []byte(tmpResolvConf) 1517 if err := ioutil.WriteFile("/etc/resolv.conf.aside", bytesResolvConf, 0644); err != nil { 1518 c.Fatal(err) 1519 } 1520 1521 err = os.Rename("/etc/resolv.conf.aside", "/etc/resolv.conf") 1522 if err != nil { 1523 c.Fatal(err) 1524 } 1525 1526 // start the container again to pickup changes 1527 dockerCmd(c, "start", "third") 1528 1529 // check for update in container 1530 containerResolv, err = readContainerFile(containerID3, "resolv.conf") 1531 if err != nil { 1532 c.Fatal(err) 1533 } 1534 if !bytes.Equal(containerResolv, bytesResolvConf) { 1535 c.Fatalf("Stopped container does not have updated resolv.conf; expected\n%q\n got\n%q", tmpResolvConf, string(containerResolv)) 1536 } 1537 1538 //cleanup, restore original resolv.conf happens in defer func() 1539 } 1540 1541 func (s *DockerSuite) TestRunAddHost(c *check.C) { 1542 // Not applicable on Windows as it does not support --add-host 1543 testRequires(c, DaemonIsLinux) 1544 out, _ := dockerCmd(c, "run", "--add-host=extra:86.75.30.9", "busybox", "grep", "extra", "/etc/hosts") 1545 1546 actual := strings.Trim(out, "\r\n") 1547 if actual != "86.75.30.9\textra" { 1548 c.Fatalf("expected '86.75.30.9\textra', but says: %q", actual) 1549 } 1550 } 1551 1552 // Regression test for #6983 1553 func (s *DockerSuite) TestRunAttachStdErrOnlyTTYMode(c *check.C) { 1554 _, exitCode := dockerCmd(c, "run", "-t", "-a", "stderr", "busybox", "true") 1555 if exitCode != 0 { 1556 c.Fatalf("Container should have exited with error code 0") 1557 } 1558 } 1559 1560 // Regression test for #6983 1561 func (s *DockerSuite) TestRunAttachStdOutOnlyTTYMode(c *check.C) { 1562 _, exitCode := dockerCmd(c, "run", "-t", "-a", "stdout", "busybox", "true") 1563 if exitCode != 0 { 1564 c.Fatalf("Container should have exited with error code 0") 1565 } 1566 } 1567 1568 // Regression test for #6983 1569 func (s *DockerSuite) TestRunAttachStdOutAndErrTTYMode(c *check.C) { 1570 _, exitCode := dockerCmd(c, "run", "-t", "-a", "stdout", "-a", "stderr", "busybox", "true") 1571 if exitCode != 0 { 1572 c.Fatalf("Container should have exited with error code 0") 1573 } 1574 } 1575 1576 // Test for #10388 - this will run the same test as TestRunAttachStdOutAndErrTTYMode 1577 // but using --attach instead of -a to make sure we read the flag correctly 1578 func (s *DockerSuite) TestRunAttachWithDetach(c *check.C) { 1579 cmd := exec.Command(dockerBinary, "run", "-d", "--attach", "stdout", "busybox", "true") 1580 _, stderr, _, err := runCommandWithStdoutStderr(cmd) 1581 if err == nil { 1582 c.Fatal("Container should have exited with error code different than 0") 1583 } else if !strings.Contains(stderr, "Conflicting options: -a and -d") { 1584 c.Fatal("Should have been returned an error with conflicting options -a and -d") 1585 } 1586 } 1587 1588 func (s *DockerSuite) TestRunState(c *check.C) { 1589 // TODO Windows: This needs some rework as Windows busybox does not support top 1590 testRequires(c, DaemonIsLinux) 1591 out, _ := dockerCmd(c, "run", "-d", "busybox", "top") 1592 1593 id := strings.TrimSpace(out) 1594 state, err := inspectField(id, "State.Running") 1595 c.Assert(err, check.IsNil) 1596 if state != "true" { 1597 c.Fatal("Container state is 'not running'") 1598 } 1599 pid1, err := inspectField(id, "State.Pid") 1600 c.Assert(err, check.IsNil) 1601 if pid1 == "0" { 1602 c.Fatal("Container state Pid 0") 1603 } 1604 1605 dockerCmd(c, "stop", id) 1606 state, err = inspectField(id, "State.Running") 1607 c.Assert(err, check.IsNil) 1608 if state != "false" { 1609 c.Fatal("Container state is 'running'") 1610 } 1611 pid2, err := inspectField(id, "State.Pid") 1612 c.Assert(err, check.IsNil) 1613 if pid2 == pid1 { 1614 c.Fatalf("Container state Pid %s, but expected %s", pid2, pid1) 1615 } 1616 1617 dockerCmd(c, "start", id) 1618 state, err = inspectField(id, "State.Running") 1619 c.Assert(err, check.IsNil) 1620 if state != "true" { 1621 c.Fatal("Container state is 'not running'") 1622 } 1623 pid3, err := inspectField(id, "State.Pid") 1624 c.Assert(err, check.IsNil) 1625 if pid3 == pid1 { 1626 c.Fatalf("Container state Pid %s, but expected %s", pid2, pid1) 1627 } 1628 } 1629 1630 // Test for #1737 1631 func (s *DockerSuite) TestRunCopyVolumeUidGid(c *check.C) { 1632 // Not applicable on Windows as it does not support uid or gid in this way 1633 testRequires(c, DaemonIsLinux) 1634 name := "testrunvolumesuidgid" 1635 _, err := buildImage(name, 1636 `FROM busybox 1637 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1638 RUN echo 'dockerio:x:1001:' >> /etc/group 1639 RUN mkdir -p /hello && touch /hello/test && chown dockerio.dockerio /hello`, 1640 true) 1641 if err != nil { 1642 c.Fatal(err) 1643 } 1644 1645 // Test that the uid and gid is copied from the image to the volume 1646 out, _ := dockerCmd(c, "run", "--rm", "-v", "/hello", name, "sh", "-c", "ls -l / | grep hello | awk '{print $3\":\"$4}'") 1647 out = strings.TrimSpace(out) 1648 if out != "dockerio:dockerio" { 1649 c.Fatalf("Wrong /hello ownership: %s, expected dockerio:dockerio", out) 1650 } 1651 } 1652 1653 // Test for #1582 1654 func (s *DockerSuite) TestRunCopyVolumeContent(c *check.C) { 1655 // TODO Windows, post TP4. Windows does not yet support volume functionality 1656 // that copies from the image to the volume. 1657 testRequires(c, DaemonIsLinux) 1658 name := "testruncopyvolumecontent" 1659 _, err := buildImage(name, 1660 `FROM busybox 1661 RUN mkdir -p /hello/local && echo hello > /hello/local/world`, 1662 true) 1663 if err != nil { 1664 c.Fatal(err) 1665 } 1666 1667 // Test that the content is copied from the image to the volume 1668 out, _ := dockerCmd(c, "run", "--rm", "-v", "/hello", name, "find", "/hello") 1669 if !(strings.Contains(out, "/hello/local/world") && strings.Contains(out, "/hello/local")) { 1670 c.Fatal("Container failed to transfer content to volume") 1671 } 1672 } 1673 1674 func (s *DockerSuite) TestRunCleanupCmdOnEntrypoint(c *check.C) { 1675 name := "testrunmdcleanuponentrypoint" 1676 if _, err := buildImage(name, 1677 `FROM busybox 1678 ENTRYPOINT ["echo"] 1679 CMD ["testingpoint"]`, 1680 true); err != nil { 1681 c.Fatal(err) 1682 } 1683 1684 out, exit := dockerCmd(c, "run", "--entrypoint", "whoami", name) 1685 if exit != 0 { 1686 c.Fatalf("expected exit code 0 received %d, out: %q", exit, out) 1687 } 1688 out = strings.TrimSpace(out) 1689 expected := "root" 1690 if daemonPlatform == "windows" { 1691 expected = `nt authority\system` 1692 } 1693 if out != expected { 1694 c.Fatalf("Expected output %s, got %q", expected, out) 1695 } 1696 } 1697 1698 // TestRunWorkdirExistsAndIsFile checks that if 'docker run -w' with existing file can be detected 1699 func (s *DockerSuite) TestRunWorkdirExistsAndIsFile(c *check.C) { 1700 existingFile := "/bin/cat" 1701 expected := "Cannot mkdir: /bin/cat is not a directory" 1702 if daemonPlatform == "windows" { 1703 existingFile = `\windows\system32\ntdll.dll` 1704 expected = "The directory name is invalid" 1705 } 1706 1707 out, exitCode, err := dockerCmdWithError("run", "-w", existingFile, "busybox") 1708 if !(err != nil && exitCode == 125 && strings.Contains(out, expected)) { 1709 c.Fatalf("Docker must complains about making dir with exitCode 125 but we got out: %s, exitCode: %d", out, exitCode) 1710 } 1711 } 1712 1713 func (s *DockerSuite) TestRunExitOnStdinClose(c *check.C) { 1714 name := "testrunexitonstdinclose" 1715 1716 meow := "/bin/cat" 1717 delay := 1 1718 if daemonPlatform == "windows" { 1719 meow = "cat" 1720 delay = 5 1721 } 1722 runCmd := exec.Command(dockerBinary, "run", "--name", name, "-i", "busybox", meow) 1723 1724 stdin, err := runCmd.StdinPipe() 1725 if err != nil { 1726 c.Fatal(err) 1727 } 1728 stdout, err := runCmd.StdoutPipe() 1729 if err != nil { 1730 c.Fatal(err) 1731 } 1732 1733 if err := runCmd.Start(); err != nil { 1734 c.Fatal(err) 1735 } 1736 if _, err := stdin.Write([]byte("hello\n")); err != nil { 1737 c.Fatal(err) 1738 } 1739 1740 r := bufio.NewReader(stdout) 1741 line, err := r.ReadString('\n') 1742 if err != nil { 1743 c.Fatal(err) 1744 } 1745 line = strings.TrimSpace(line) 1746 if line != "hello" { 1747 c.Fatalf("Output should be 'hello', got '%q'", line) 1748 } 1749 if err := stdin.Close(); err != nil { 1750 c.Fatal(err) 1751 } 1752 finish := make(chan error) 1753 go func() { 1754 finish <- runCmd.Wait() 1755 close(finish) 1756 }() 1757 select { 1758 case err := <-finish: 1759 c.Assert(err, check.IsNil) 1760 case <-time.After(time.Duration(delay) * time.Second): 1761 c.Fatal("docker run failed to exit on stdin close") 1762 } 1763 state, err := inspectField(name, "State.Running") 1764 c.Assert(err, check.IsNil) 1765 1766 if state != "false" { 1767 c.Fatal("Container must be stopped after stdin closing") 1768 } 1769 } 1770 1771 // Test for #2267 1772 func (s *DockerSuite) TestRunWriteHostsFileAndNotCommit(c *check.C) { 1773 // Cannot run on Windows as Windows does not support diff. 1774 testRequires(c, DaemonIsLinux) 1775 name := "writehosts" 1776 out, _ := dockerCmd(c, "run", "--name", name, "busybox", "sh", "-c", "echo test2267 >> /etc/hosts && cat /etc/hosts") 1777 if !strings.Contains(out, "test2267") { 1778 c.Fatal("/etc/hosts should contain 'test2267'") 1779 } 1780 1781 out, _ = dockerCmd(c, "diff", name) 1782 if len(strings.Trim(out, "\r\n")) != 0 && !eqToBaseDiff(out, c) { 1783 c.Fatal("diff should be empty") 1784 } 1785 } 1786 1787 func eqToBaseDiff(out string, c *check.C) bool { 1788 out1, _ := dockerCmd(c, "run", "-d", "busybox", "echo", "hello") 1789 cID := strings.TrimSpace(out1) 1790 1791 baseDiff, _ := dockerCmd(c, "diff", cID) 1792 baseArr := strings.Split(baseDiff, "\n") 1793 sort.Strings(baseArr) 1794 outArr := strings.Split(out, "\n") 1795 sort.Strings(outArr) 1796 return sliceEq(baseArr, outArr) 1797 } 1798 1799 func sliceEq(a, b []string) bool { 1800 if len(a) != len(b) { 1801 return false 1802 } 1803 1804 for i := range a { 1805 if a[i] != b[i] { 1806 return false 1807 } 1808 } 1809 1810 return true 1811 } 1812 1813 // Test for #2267 1814 func (s *DockerSuite) TestRunWriteHostnameFileAndNotCommit(c *check.C) { 1815 // Cannot run on Windows as Windows does not support diff. 1816 testRequires(c, DaemonIsLinux) 1817 name := "writehostname" 1818 out, _ := dockerCmd(c, "run", "--name", name, "busybox", "sh", "-c", "echo test2267 >> /etc/hostname && cat /etc/hostname") 1819 if !strings.Contains(out, "test2267") { 1820 c.Fatal("/etc/hostname should contain 'test2267'") 1821 } 1822 1823 out, _ = dockerCmd(c, "diff", name) 1824 if len(strings.Trim(out, "\r\n")) != 0 && !eqToBaseDiff(out, c) { 1825 c.Fatal("diff should be empty") 1826 } 1827 } 1828 1829 // Test for #2267 1830 func (s *DockerSuite) TestRunWriteResolvFileAndNotCommit(c *check.C) { 1831 // Cannot run on Windows as Windows does not support diff. 1832 testRequires(c, DaemonIsLinux) 1833 name := "writeresolv" 1834 out, _ := dockerCmd(c, "run", "--name", name, "busybox", "sh", "-c", "echo test2267 >> /etc/resolv.conf && cat /etc/resolv.conf") 1835 if !strings.Contains(out, "test2267") { 1836 c.Fatal("/etc/resolv.conf should contain 'test2267'") 1837 } 1838 1839 out, _ = dockerCmd(c, "diff", name) 1840 if len(strings.Trim(out, "\r\n")) != 0 && !eqToBaseDiff(out, c) { 1841 c.Fatal("diff should be empty") 1842 } 1843 } 1844 1845 func (s *DockerSuite) TestRunWithBadDevice(c *check.C) { 1846 // Cannot run on Windows as Windows does not support --device 1847 testRequires(c, DaemonIsLinux) 1848 name := "baddevice" 1849 out, _, err := dockerCmdWithError("run", "--name", name, "--device", "/etc", "busybox", "true") 1850 1851 if err == nil { 1852 c.Fatal("Run should fail with bad device") 1853 } 1854 expected := `"/etc": not a device node` 1855 if !strings.Contains(out, expected) { 1856 c.Fatalf("Output should contain %q, actual out: %q", expected, out) 1857 } 1858 } 1859 1860 func (s *DockerSuite) TestRunEntrypoint(c *check.C) { 1861 name := "entrypoint" 1862 1863 // Note Windows does not have an echo.exe built in. 1864 var out, expected string 1865 if daemonPlatform == "windows" { 1866 out, _ = dockerCmd(c, "run", "--name", name, "--entrypoint", "cmd /s /c echo", "busybox", "foobar") 1867 expected = "foobar\r\n" 1868 } else { 1869 out, _ = dockerCmd(c, "run", "--name", name, "--entrypoint", "/bin/echo", "busybox", "-n", "foobar") 1870 expected = "foobar" 1871 } 1872 1873 if out != expected { 1874 c.Fatalf("Output should be %q, actual out: %q", expected, out) 1875 } 1876 } 1877 1878 func (s *DockerSuite) TestRunBindMounts(c *check.C) { 1879 testRequires(c, SameHostDaemon) 1880 if daemonPlatform == "linux" { 1881 testRequires(c, DaemonIsLinux, NotUserNamespace) 1882 } 1883 1884 tmpDir, err := ioutil.TempDir("", "docker-test-container") 1885 if err != nil { 1886 c.Fatal(err) 1887 } 1888 1889 defer os.RemoveAll(tmpDir) 1890 writeFile(path.Join(tmpDir, "touch-me"), "", c) 1891 1892 // TODO Windows Post TP4. Windows does not yet support :ro binds 1893 if daemonPlatform != "windows" { 1894 // Test reading from a read-only bind mount 1895 out, _ := dockerCmd(c, "run", "-v", fmt.Sprintf("%s:/tmp:ro", tmpDir), "busybox", "ls", "/tmp") 1896 if !strings.Contains(out, "touch-me") { 1897 c.Fatal("Container failed to read from bind mount") 1898 } 1899 } 1900 1901 // test writing to bind mount 1902 if daemonPlatform == "windows" { 1903 dockerCmd(c, "run", "-v", fmt.Sprintf(`%s:c:\tmp:rw`, tmpDir), "busybox", "touch", "c:/tmp/holla") 1904 } else { 1905 dockerCmd(c, "run", "-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "busybox", "touch", "/tmp/holla") 1906 } 1907 1908 readFile(path.Join(tmpDir, "holla"), c) // Will fail if the file doesn't exist 1909 1910 // test mounting to an illegal destination directory 1911 _, _, err = dockerCmdWithError("run", "-v", fmt.Sprintf("%s:.", tmpDir), "busybox", "ls", ".") 1912 if err == nil { 1913 c.Fatal("Container bind mounted illegal directory") 1914 } 1915 1916 // Windows does not (and likely never will) support mounting a single file 1917 if daemonPlatform != "windows" { 1918 // test mount a file 1919 dockerCmd(c, "run", "-v", fmt.Sprintf("%s/holla:/tmp/holla:rw", tmpDir), "busybox", "sh", "-c", "echo -n 'yotta' > /tmp/holla") 1920 content := readFile(path.Join(tmpDir, "holla"), c) // Will fail if the file doesn't exist 1921 expected := "yotta" 1922 if content != expected { 1923 c.Fatalf("Output should be %q, actual out: %q", expected, content) 1924 } 1925 } 1926 } 1927 1928 // Ensure that CIDFile gets deleted if it's empty 1929 // Perform this test by making `docker run` fail 1930 func (s *DockerSuite) TestRunCidFileCleanupIfEmpty(c *check.C) { 1931 tmpDir, err := ioutil.TempDir("", "TestRunCidFile") 1932 if err != nil { 1933 c.Fatal(err) 1934 } 1935 defer os.RemoveAll(tmpDir) 1936 tmpCidFile := path.Join(tmpDir, "cid") 1937 1938 image := "emptyfs" 1939 if daemonPlatform == "windows" { 1940 // Windows can't support an emptyfs image. Just use the regular Windows image 1941 image = WindowsBaseImage 1942 } 1943 out, _, err := dockerCmdWithError("run", "--cidfile", tmpCidFile, image) 1944 if err == nil { 1945 c.Fatalf("Run without command must fail. out=%s", out) 1946 } else if !strings.Contains(out, "No command specified") { 1947 c.Fatalf("Run without command failed with wrong output. out=%s\nerr=%v", out, err) 1948 } 1949 1950 if _, err := os.Stat(tmpCidFile); err == nil { 1951 c.Fatalf("empty CIDFile %q should've been deleted", tmpCidFile) 1952 } 1953 } 1954 1955 // #2098 - Docker cidFiles only contain short version of the containerId 1956 //sudo docker run --cidfile /tmp/docker_tesc.cid ubuntu echo "test" 1957 // TestRunCidFile tests that run --cidfile returns the longid 1958 func (s *DockerSuite) TestRunCidFileCheckIDLength(c *check.C) { 1959 tmpDir, err := ioutil.TempDir("", "TestRunCidFile") 1960 if err != nil { 1961 c.Fatal(err) 1962 } 1963 tmpCidFile := path.Join(tmpDir, "cid") 1964 defer os.RemoveAll(tmpDir) 1965 1966 out, _ := dockerCmd(c, "run", "-d", "--cidfile", tmpCidFile, "busybox", "true") 1967 1968 id := strings.TrimSpace(out) 1969 buffer, err := ioutil.ReadFile(tmpCidFile) 1970 if err != nil { 1971 c.Fatal(err) 1972 } 1973 cid := string(buffer) 1974 if len(cid) != 64 { 1975 c.Fatalf("--cidfile should be a long id, not %q", id) 1976 } 1977 if cid != id { 1978 c.Fatalf("cid must be equal to %s, got %s", id, cid) 1979 } 1980 } 1981 1982 func (s *DockerSuite) TestRunSetMacAddress(c *check.C) { 1983 mac := "12:34:56:78:9a:bc" 1984 var out string 1985 if daemonPlatform == "windows" { 1986 out, _ = dockerCmd(c, "run", "-i", "--rm", fmt.Sprintf("--mac-address=%s", mac), "busybox", "sh", "-c", "ipconfig /all | grep 'Physical Address' | awk '{print $12}'") 1987 mac = strings.Replace(strings.ToUpper(mac), ":", "-", -1) // To Windows-style MACs 1988 } else { 1989 out, _ = dockerCmd(c, "run", "-i", "--rm", fmt.Sprintf("--mac-address=%s", mac), "busybox", "/bin/sh", "-c", "ip link show eth0 | tail -1 | awk '{print $2}'") 1990 } 1991 1992 actualMac := strings.TrimSpace(out) 1993 if actualMac != mac { 1994 c.Fatalf("Set MAC address with --mac-address failed. The container has an incorrect MAC address: %q, expected: %q", actualMac, mac) 1995 } 1996 } 1997 1998 func (s *DockerSuite) TestRunInspectMacAddress(c *check.C) { 1999 // TODO Windows. Network settings are not propagated back to inspect. 2000 testRequires(c, DaemonIsLinux) 2001 mac := "12:34:56:78:9a:bc" 2002 out, _ := dockerCmd(c, "run", "-d", "--mac-address="+mac, "busybox", "top") 2003 2004 id := strings.TrimSpace(out) 2005 inspectedMac, err := inspectField(id, "NetworkSettings.Networks.bridge.MacAddress") 2006 c.Assert(err, check.IsNil) 2007 if inspectedMac != mac { 2008 c.Fatalf("docker inspect outputs wrong MAC address: %q, should be: %q", inspectedMac, mac) 2009 } 2010 } 2011 2012 // test docker run use a invalid mac address 2013 func (s *DockerSuite) TestRunWithInvalidMacAddress(c *check.C) { 2014 out, _, err := dockerCmdWithError("run", "--mac-address", "92:d0:c6:0a:29", "busybox") 2015 //use a invalid mac address should with a error out 2016 if err == nil || !strings.Contains(out, "is not a valid mac address") { 2017 c.Fatalf("run with an invalid --mac-address should with error out") 2018 } 2019 } 2020 2021 func (s *DockerSuite) TestRunDeallocatePortOnMissingIptablesRule(c *check.C) { 2022 // TODO Windows. Network settings are not propagated back to inspect. 2023 testRequires(c, SameHostDaemon, DaemonIsLinux) 2024 2025 out, _ := dockerCmd(c, "run", "-d", "-p", "23:23", "busybox", "top") 2026 2027 id := strings.TrimSpace(out) 2028 ip, err := inspectField(id, "NetworkSettings.Networks.bridge.IPAddress") 2029 c.Assert(err, check.IsNil) 2030 iptCmd := exec.Command("iptables", "-D", "DOCKER", "-d", fmt.Sprintf("%s/32", ip), 2031 "!", "-i", "docker0", "-o", "docker0", "-p", "tcp", "-m", "tcp", "--dport", "23", "-j", "ACCEPT") 2032 out, _, err = runCommandWithOutput(iptCmd) 2033 if err != nil { 2034 c.Fatal(err, out) 2035 } 2036 if err := deleteContainer(id); err != nil { 2037 c.Fatal(err) 2038 } 2039 2040 dockerCmd(c, "run", "-d", "-p", "23:23", "busybox", "top") 2041 } 2042 2043 func (s *DockerSuite) TestRunPortInUse(c *check.C) { 2044 // TODO Windows. The duplicate NAT message returned by Windows will be 2045 // changing as is currently completely undecipherable. Does need modifying 2046 // to run sh rather than top though as top isn't in Windows busybox. 2047 testRequires(c, SameHostDaemon, DaemonIsLinux) 2048 2049 port := "1234" 2050 dockerCmd(c, "run", "-d", "-p", port+":80", "busybox", "top") 2051 2052 out, _, err := dockerCmdWithError("run", "-d", "-p", port+":80", "busybox", "top") 2053 if err == nil { 2054 c.Fatalf("Binding on used port must fail") 2055 } 2056 if !strings.Contains(out, "port is already allocated") { 2057 c.Fatalf("Out must be about \"port is already allocated\", got %s", out) 2058 } 2059 } 2060 2061 // https://github.com/docker/docker/issues/12148 2062 func (s *DockerSuite) TestRunAllocatePortInReservedRange(c *check.C) { 2063 // TODO Windows. -P is not yet supported 2064 testRequires(c, DaemonIsLinux) 2065 // allocate a dynamic port to get the most recent 2066 out, _ := dockerCmd(c, "run", "-d", "-P", "-p", "80", "busybox", "top") 2067 2068 id := strings.TrimSpace(out) 2069 out, _ = dockerCmd(c, "port", id, "80") 2070 2071 strPort := strings.Split(strings.TrimSpace(out), ":")[1] 2072 port, err := strconv.ParseInt(strPort, 10, 64) 2073 if err != nil { 2074 c.Fatalf("invalid port, got: %s, error: %s", strPort, err) 2075 } 2076 2077 // allocate a static port and a dynamic port together, with static port 2078 // takes the next recent port in dynamic port range. 2079 dockerCmd(c, "run", "-d", "-P", "-p", "80", "-p", fmt.Sprintf("%d:8080", port+1), "busybox", "top") 2080 } 2081 2082 // Regression test for #7792 2083 func (s *DockerSuite) TestRunMountOrdering(c *check.C) { 2084 // TODO Windows: Post TP4. Updated, but Windows does not support nested mounts currently. 2085 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 2086 prefix := "" 2087 if daemonPlatform == "windows" { 2088 prefix = "c:" 2089 } 2090 2091 tmpDir, err := ioutil.TempDir("", "docker_nested_mount_test") 2092 if err != nil { 2093 c.Fatal(err) 2094 } 2095 defer os.RemoveAll(tmpDir) 2096 2097 tmpDir2, err := ioutil.TempDir("", "docker_nested_mount_test2") 2098 if err != nil { 2099 c.Fatal(err) 2100 } 2101 defer os.RemoveAll(tmpDir2) 2102 2103 // Create a temporary tmpfs mounc. 2104 fooDir := filepath.Join(tmpDir, "foo") 2105 if err := os.MkdirAll(filepath.Join(tmpDir, "foo"), 0755); err != nil { 2106 c.Fatalf("failed to mkdir at %s - %s", fooDir, err) 2107 } 2108 2109 if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", fooDir), []byte{}, 0644); err != nil { 2110 c.Fatal(err) 2111 } 2112 2113 if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", tmpDir), []byte{}, 0644); err != nil { 2114 c.Fatal(err) 2115 } 2116 2117 if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", tmpDir2), []byte{}, 0644); err != nil { 2118 c.Fatal(err) 2119 } 2120 2121 dockerCmd(c, "run", 2122 "-v", fmt.Sprintf("%s:"+prefix+"/tmp", tmpDir), 2123 "-v", fmt.Sprintf("%s:"+prefix+"/tmp/foo", fooDir), 2124 "-v", fmt.Sprintf("%s:"+prefix+"/tmp/tmp2", tmpDir2), 2125 "-v", fmt.Sprintf("%s:"+prefix+"/tmp/tmp2/foo", fooDir), 2126 "busybox:latest", "sh", "-c", 2127 "ls "+prefix+"/tmp/touch-me && ls "+prefix+"/tmp/foo/touch-me && ls "+prefix+"/tmp/tmp2/touch-me && ls "+prefix+"/tmp/tmp2/foo/touch-me") 2128 } 2129 2130 // Regression test for https://github.com/docker/docker/issues/8259 2131 func (s *DockerSuite) TestRunReuseBindVolumeThatIsSymlink(c *check.C) { 2132 // Not applicable on Windows as Windows does not support volumes 2133 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 2134 prefix := "" 2135 if daemonPlatform == "windows" { 2136 prefix = "c:" 2137 } 2138 2139 tmpDir, err := ioutil.TempDir(os.TempDir(), "testlink") 2140 if err != nil { 2141 c.Fatal(err) 2142 } 2143 defer os.RemoveAll(tmpDir) 2144 2145 linkPath := os.TempDir() + "/testlink2" 2146 if err := os.Symlink(tmpDir, linkPath); err != nil { 2147 c.Fatal(err) 2148 } 2149 defer os.RemoveAll(linkPath) 2150 2151 // Create first container 2152 dockerCmd(c, "run", "-v", fmt.Sprintf("%s:"+prefix+"/tmp/test", linkPath), "busybox", "ls", prefix+"/tmp/test") 2153 2154 // Create second container with same symlinked path 2155 // This will fail if the referenced issue is hit with a "Volume exists" error 2156 dockerCmd(c, "run", "-v", fmt.Sprintf("%s:"+prefix+"/tmp/test", linkPath), "busybox", "ls", prefix+"/tmp/test") 2157 } 2158 2159 //GH#10604: Test an "/etc" volume doesn't overlay special bind mounts in container 2160 func (s *DockerSuite) TestRunCreateVolumeEtc(c *check.C) { 2161 // While Windows supports volumes, it does not support --add-host hence 2162 // this test is not applicable on Windows. 2163 testRequires(c, DaemonIsLinux) 2164 out, _ := dockerCmd(c, "run", "--dns=127.0.0.1", "-v", "/etc", "busybox", "cat", "/etc/resolv.conf") 2165 if !strings.Contains(out, "nameserver 127.0.0.1") { 2166 c.Fatal("/etc volume mount hides /etc/resolv.conf") 2167 } 2168 2169 out, _ = dockerCmd(c, "run", "-h=test123", "-v", "/etc", "busybox", "cat", "/etc/hostname") 2170 if !strings.Contains(out, "test123") { 2171 c.Fatal("/etc volume mount hides /etc/hostname") 2172 } 2173 2174 out, _ = dockerCmd(c, "run", "--add-host=test:192.168.0.1", "-v", "/etc", "busybox", "cat", "/etc/hosts") 2175 out = strings.Replace(out, "\n", " ", -1) 2176 if !strings.Contains(out, "192.168.0.1\ttest") || !strings.Contains(out, "127.0.0.1\tlocalhost") { 2177 c.Fatal("/etc volume mount hides /etc/hosts") 2178 } 2179 } 2180 2181 func (s *DockerSuite) TestVolumesNoCopyData(c *check.C) { 2182 // TODO Windows (Post TP4). Windows does not support volumes which 2183 // are pre-populated such as is built in the dockerfile used in this test. 2184 testRequires(c, DaemonIsLinux) 2185 if _, err := buildImage("dataimage", 2186 `FROM busybox 2187 RUN mkdir -p /foo 2188 RUN touch /foo/bar`, 2189 true); err != nil { 2190 c.Fatal(err) 2191 } 2192 2193 dockerCmd(c, "run", "--name", "test", "-v", "/foo", "busybox") 2194 2195 if out, _, err := dockerCmdWithError("run", "--volumes-from", "test", "dataimage", "ls", "-lh", "/foo/bar"); err == nil || !strings.Contains(out, "No such file or directory") { 2196 c.Fatalf("Data was copied on volumes-from but shouldn't be:\n%q", out) 2197 } 2198 2199 tmpDir := randomTmpDirPath("docker_test_bind_mount_copy_data", daemonPlatform) 2200 if out, _, err := dockerCmdWithError("run", "-v", tmpDir+":/foo", "dataimage", "ls", "-lh", "/foo/bar"); err == nil || !strings.Contains(out, "No such file or directory") { 2201 c.Fatalf("Data was copied on bind-mount but shouldn't be:\n%q", out) 2202 } 2203 } 2204 2205 func (s *DockerSuite) TestRunNoOutputFromPullInStdout(c *check.C) { 2206 // just run with unknown image 2207 cmd := exec.Command(dockerBinary, "run", "asdfsg") 2208 stdout := bytes.NewBuffer(nil) 2209 cmd.Stdout = stdout 2210 if err := cmd.Run(); err == nil { 2211 c.Fatal("Run with unknown image should fail") 2212 } 2213 if stdout.Len() != 0 { 2214 c.Fatalf("Stdout contains output from pull: %s", stdout) 2215 } 2216 } 2217 2218 func (s *DockerSuite) TestRunVolumesCleanPaths(c *check.C) { 2219 testRequires(c, SameHostDaemon) 2220 prefix := "" 2221 slash := `/` 2222 if daemonPlatform == "windows" { 2223 prefix = "c:" 2224 slash = `\` 2225 } 2226 if _, err := buildImage("run_volumes_clean_paths", 2227 `FROM busybox 2228 VOLUME `+prefix+`/foo/`, 2229 true); err != nil { 2230 c.Fatal(err) 2231 } 2232 2233 dockerCmd(c, "run", "-v", prefix+"/foo", "-v", prefix+"/bar/", "--name", "dark_helmet", "run_volumes_clean_paths") 2234 2235 out, err := inspectMountSourceField("dark_helmet", prefix+slash+"foo"+slash) 2236 if err != errMountNotFound { 2237 c.Fatalf("Found unexpected volume entry for '%s/foo/' in volumes\n%q", prefix, out) 2238 } 2239 2240 out, err = inspectMountSourceField("dark_helmet", prefix+slash+`foo`) 2241 c.Assert(err, check.IsNil) 2242 if !strings.Contains(strings.ToLower(out), strings.ToLower(volumesConfigPath)) { 2243 c.Fatalf("Volume was not defined for %s/foo\n%q", prefix, out) 2244 } 2245 2246 out, err = inspectMountSourceField("dark_helmet", prefix+slash+"bar"+slash) 2247 if err != errMountNotFound { 2248 c.Fatalf("Found unexpected volume entry for '%s/bar/' in volumes\n%q", prefix, out) 2249 } 2250 2251 out, err = inspectMountSourceField("dark_helmet", prefix+slash+"bar") 2252 c.Assert(err, check.IsNil) 2253 if !strings.Contains(strings.ToLower(out), strings.ToLower(volumesConfigPath)) { 2254 c.Fatalf("Volume was not defined for %s/bar\n%q", prefix, out) 2255 } 2256 } 2257 2258 // Regression test for #3631 2259 func (s *DockerSuite) TestRunSlowStdoutConsumer(c *check.C) { 2260 // TODO Windows: This should be able to run on Windows if can find an 2261 // alternate to /dev/zero and /dev/stdout. 2262 testRequires(c, DaemonIsLinux) 2263 cont := exec.Command(dockerBinary, "run", "--rm", "busybox", "/bin/sh", "-c", "dd if=/dev/zero of=/dev/stdout bs=1024 count=2000 | catv") 2264 2265 stdout, err := cont.StdoutPipe() 2266 if err != nil { 2267 c.Fatal(err) 2268 } 2269 2270 if err := cont.Start(); err != nil { 2271 c.Fatal(err) 2272 } 2273 n, err := consumeWithSpeed(stdout, 10000, 5*time.Millisecond, nil) 2274 if err != nil { 2275 c.Fatal(err) 2276 } 2277 2278 expected := 2 * 1024 * 2000 2279 if n != expected { 2280 c.Fatalf("Expected %d, got %d", expected, n) 2281 } 2282 } 2283 2284 func (s *DockerSuite) TestRunAllowPortRangeThroughExpose(c *check.C) { 2285 // TODO Windows: -P is not currently supported. Also network 2286 // settings are not propagated back. 2287 testRequires(c, DaemonIsLinux) 2288 out, _ := dockerCmd(c, "run", "-d", "--expose", "3000-3003", "-P", "busybox", "top") 2289 2290 id := strings.TrimSpace(out) 2291 portstr, err := inspectFieldJSON(id, "NetworkSettings.Ports") 2292 c.Assert(err, check.IsNil) 2293 var ports nat.PortMap 2294 if err = unmarshalJSON([]byte(portstr), &ports); err != nil { 2295 c.Fatal(err) 2296 } 2297 for port, binding := range ports { 2298 portnum, _ := strconv.Atoi(strings.Split(string(port), "/")[0]) 2299 if portnum < 3000 || portnum > 3003 { 2300 c.Fatalf("Port %d is out of range ", portnum) 2301 } 2302 if binding == nil || len(binding) != 1 || len(binding[0].HostPort) == 0 { 2303 c.Fatalf("Port is not mapped for the port %s", port) 2304 } 2305 } 2306 } 2307 2308 // test docker run expose a invalid port 2309 func (s *DockerSuite) TestRunExposePort(c *check.C) { 2310 out, _, err := dockerCmdWithError("run", "--expose", "80000", "busybox") 2311 //expose a invalid port should with a error out 2312 if err == nil || !strings.Contains(out, "Invalid range format for --expose") { 2313 c.Fatalf("run --expose a invalid port should with error out") 2314 } 2315 } 2316 2317 func (s *DockerSuite) TestRunUnknownCommand(c *check.C) { 2318 out, _, _ := dockerCmdWithStdoutStderr(c, "create", "busybox", "/bin/nada") 2319 2320 cID := strings.TrimSpace(out) 2321 _, _, err := dockerCmdWithError("start", cID) 2322 2323 // Windows and Linux are different here by architectural design. Linux will 2324 // fail to start the container, so an error is expected. Windows will 2325 // successfully start the container, and once started attempt to execute 2326 // the command which will fail. 2327 if daemonPlatform == "windows" { 2328 // Wait for it to exit. 2329 waitExited(cID, 30*time.Second) 2330 c.Assert(err, check.IsNil) 2331 } else { 2332 c.Assert(err, check.NotNil) 2333 } 2334 2335 rc, err := inspectField(cID, "State.ExitCode") 2336 c.Assert(err, check.IsNil) 2337 if rc == "0" { 2338 c.Fatalf("ExitCode(%v) cannot be 0", rc) 2339 } 2340 } 2341 2342 func (s *DockerSuite) TestRunModeIpcHost(c *check.C) { 2343 // Not applicable on Windows as uses Unix-specific capabilities 2344 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 2345 2346 hostIpc, err := os.Readlink("/proc/1/ns/ipc") 2347 if err != nil { 2348 c.Fatal(err) 2349 } 2350 2351 out, _ := dockerCmd(c, "run", "--ipc=host", "busybox", "readlink", "/proc/self/ns/ipc") 2352 out = strings.Trim(out, "\n") 2353 if hostIpc != out { 2354 c.Fatalf("IPC different with --ipc=host %s != %s\n", hostIpc, out) 2355 } 2356 2357 out, _ = dockerCmd(c, "run", "busybox", "readlink", "/proc/self/ns/ipc") 2358 out = strings.Trim(out, "\n") 2359 if hostIpc == out { 2360 c.Fatalf("IPC should be different without --ipc=host %s == %s\n", hostIpc, out) 2361 } 2362 } 2363 2364 func (s *DockerSuite) TestRunModeIpcContainer(c *check.C) { 2365 // Not applicable on Windows as uses Unix-specific capabilities 2366 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 2367 2368 out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && touch /dev/mqueue/toto && top") 2369 2370 id := strings.TrimSpace(out) 2371 state, err := inspectField(id, "State.Running") 2372 c.Assert(err, check.IsNil) 2373 if state != "true" { 2374 c.Fatal("Container state is 'not running'") 2375 } 2376 pid1, err := inspectField(id, "State.Pid") 2377 c.Assert(err, check.IsNil) 2378 2379 parentContainerIpc, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/ipc", pid1)) 2380 if err != nil { 2381 c.Fatal(err) 2382 } 2383 2384 out, _ = dockerCmd(c, "run", fmt.Sprintf("--ipc=container:%s", id), "busybox", "readlink", "/proc/self/ns/ipc") 2385 out = strings.Trim(out, "\n") 2386 if parentContainerIpc != out { 2387 c.Fatalf("IPC different with --ipc=container:%s %s != %s\n", id, parentContainerIpc, out) 2388 } 2389 2390 catOutput, _ := dockerCmd(c, "run", fmt.Sprintf("--ipc=container:%s", id), "busybox", "cat", "/dev/shm/test") 2391 if catOutput != "test" { 2392 c.Fatalf("Output of /dev/shm/test expected test but found: %s", catOutput) 2393 } 2394 2395 // check that /dev/mqueue is actually of mqueue type 2396 grepOutput, _ := dockerCmd(c, "run", fmt.Sprintf("--ipc=container:%s", id), "busybox", "grep", "/dev/mqueue", "/proc/mounts") 2397 if !strings.HasPrefix(grepOutput, "mqueue /dev/mqueue mqueue rw") { 2398 c.Fatalf("Output of 'grep /proc/mounts' expected 'mqueue /dev/mqueue mqueue rw' but found: %s", grepOutput) 2399 } 2400 2401 lsOutput, _ := dockerCmd(c, "run", fmt.Sprintf("--ipc=container:%s", id), "busybox", "ls", "/dev/mqueue") 2402 lsOutput = strings.Trim(lsOutput, "\n") 2403 if lsOutput != "toto" { 2404 c.Fatalf("Output of 'ls /dev/mqueue' expected 'toto' but found: %s", lsOutput) 2405 } 2406 } 2407 2408 func (s *DockerSuite) TestRunModeIpcContainerNotExists(c *check.C) { 2409 // Not applicable on Windows as uses Unix-specific capabilities 2410 testRequires(c, DaemonIsLinux, NotUserNamespace) 2411 out, _, err := dockerCmdWithError("run", "-d", "--ipc", "container:abcd1234", "busybox", "top") 2412 if !strings.Contains(out, "abcd1234") || err == nil { 2413 c.Fatalf("run IPC from a non exists container should with correct error out") 2414 } 2415 } 2416 2417 func (s *DockerSuite) TestRunModeIpcContainerNotRunning(c *check.C) { 2418 // Not applicable on Windows as uses Unix-specific capabilities 2419 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 2420 2421 out, _ := dockerCmd(c, "create", "busybox") 2422 2423 id := strings.TrimSpace(out) 2424 out, _, err := dockerCmdWithError("run", fmt.Sprintf("--ipc=container:%s", id), "busybox") 2425 if err == nil { 2426 c.Fatalf("Run container with ipc mode container should fail with non running container: %s\n%s", out, err) 2427 } 2428 } 2429 2430 func (s *DockerSuite) TestRunMountShmMqueueFromHost(c *check.C) { 2431 // Not applicable on Windows as uses Unix-specific capabilities 2432 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 2433 2434 dockerCmd(c, "run", "-d", "--name", "shmfromhost", "-v", "/dev/shm:/dev/shm", "-v", "/dev/mqueue:/dev/mqueue", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && touch /dev/mqueue/toto && top") 2435 defer os.Remove("/dev/mqueue/toto") 2436 defer os.Remove("/dev/shm/test") 2437 volPath, err := inspectMountSourceField("shmfromhost", "/dev/shm") 2438 c.Assert(err, check.IsNil) 2439 if volPath != "/dev/shm" { 2440 c.Fatalf("volumePath should have been /dev/shm, was %s", volPath) 2441 } 2442 2443 out, _ := dockerCmd(c, "run", "--name", "ipchost", "--ipc", "host", "busybox", "cat", "/dev/shm/test") 2444 if out != "test" { 2445 c.Fatalf("Output of /dev/shm/test expected test but found: %s", out) 2446 } 2447 2448 // Check that the mq was created 2449 if _, err := os.Stat("/dev/mqueue/toto"); err != nil { 2450 c.Fatalf("Failed to confirm '/dev/mqueue/toto' presence on host: %s", err.Error()) 2451 } 2452 } 2453 2454 func (s *DockerSuite) TestContainerNetworkMode(c *check.C) { 2455 // Not applicable on Windows as uses Unix-specific capabilities 2456 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 2457 2458 out, _ := dockerCmd(c, "run", "-d", "busybox", "top") 2459 id := strings.TrimSpace(out) 2460 c.Assert(waitRun(id), check.IsNil) 2461 pid1, err := inspectField(id, "State.Pid") 2462 c.Assert(err, check.IsNil) 2463 2464 parentContainerNet, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/net", pid1)) 2465 if err != nil { 2466 c.Fatal(err) 2467 } 2468 2469 out, _ = dockerCmd(c, "run", fmt.Sprintf("--net=container:%s", id), "busybox", "readlink", "/proc/self/ns/net") 2470 out = strings.Trim(out, "\n") 2471 if parentContainerNet != out { 2472 c.Fatalf("NET different with --net=container:%s %s != %s\n", id, parentContainerNet, out) 2473 } 2474 } 2475 2476 func (s *DockerSuite) TestRunModePidHost(c *check.C) { 2477 // Not applicable on Windows as uses Unix-specific capabilities 2478 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 2479 2480 hostPid, err := os.Readlink("/proc/1/ns/pid") 2481 if err != nil { 2482 c.Fatal(err) 2483 } 2484 2485 out, _ := dockerCmd(c, "run", "--pid=host", "busybox", "readlink", "/proc/self/ns/pid") 2486 out = strings.Trim(out, "\n") 2487 if hostPid != out { 2488 c.Fatalf("PID different with --pid=host %s != %s\n", hostPid, out) 2489 } 2490 2491 out, _ = dockerCmd(c, "run", "busybox", "readlink", "/proc/self/ns/pid") 2492 out = strings.Trim(out, "\n") 2493 if hostPid == out { 2494 c.Fatalf("PID should be different without --pid=host %s == %s\n", hostPid, out) 2495 } 2496 } 2497 2498 func (s *DockerSuite) TestRunModeUTSHost(c *check.C) { 2499 // Not applicable on Windows as uses Unix-specific capabilities 2500 testRequires(c, SameHostDaemon, DaemonIsLinux) 2501 2502 hostUTS, err := os.Readlink("/proc/1/ns/uts") 2503 if err != nil { 2504 c.Fatal(err) 2505 } 2506 2507 out, _ := dockerCmd(c, "run", "--uts=host", "busybox", "readlink", "/proc/self/ns/uts") 2508 out = strings.Trim(out, "\n") 2509 if hostUTS != out { 2510 c.Fatalf("UTS different with --uts=host %s != %s\n", hostUTS, out) 2511 } 2512 2513 out, _ = dockerCmd(c, "run", "busybox", "readlink", "/proc/self/ns/uts") 2514 out = strings.Trim(out, "\n") 2515 if hostUTS == out { 2516 c.Fatalf("UTS should be different without --uts=host %s == %s\n", hostUTS, out) 2517 } 2518 } 2519 2520 func (s *DockerSuite) TestRunTLSverify(c *check.C) { 2521 if out, code, err := dockerCmdWithError("ps"); err != nil || code != 0 { 2522 c.Fatalf("Should have worked: %v:\n%v", err, out) 2523 } 2524 2525 // Regardless of whether we specify true or false we need to 2526 // test to make sure tls is turned on if --tlsverify is specified at all 2527 out, code, err := dockerCmdWithError("--tlsverify=false", "ps") 2528 if err == nil || code == 0 || !strings.Contains(out, "trying to connect") { 2529 c.Fatalf("Should have failed: \net:%v\nout:%v\nerr:%v", code, out, err) 2530 } 2531 2532 out, code, err = dockerCmdWithError("--tlsverify=true", "ps") 2533 if err == nil || code == 0 || !strings.Contains(out, "cert") { 2534 c.Fatalf("Should have failed: \net:%v\nout:%v\nerr:%v", code, out, err) 2535 } 2536 } 2537 2538 func (s *DockerSuite) TestRunPortFromDockerRangeInUse(c *check.C) { 2539 // TODO Windows. Once moved to libnetwork/CNM, this may be able to be 2540 // re-instated. 2541 testRequires(c, DaemonIsLinux) 2542 // first find allocator current position 2543 out, _ := dockerCmd(c, "run", "-d", "-p", ":80", "busybox", "top") 2544 2545 id := strings.TrimSpace(out) 2546 out, _ = dockerCmd(c, "port", id) 2547 2548 out = strings.TrimSpace(out) 2549 if out == "" { 2550 c.Fatal("docker port command output is empty") 2551 } 2552 out = strings.Split(out, ":")[1] 2553 lastPort, err := strconv.Atoi(out) 2554 if err != nil { 2555 c.Fatal(err) 2556 } 2557 port := lastPort + 1 2558 l, err := net.Listen("tcp", ":"+strconv.Itoa(port)) 2559 if err != nil { 2560 c.Fatal(err) 2561 } 2562 defer l.Close() 2563 2564 out, _ = dockerCmd(c, "run", "-d", "-p", ":80", "busybox", "top") 2565 2566 id = strings.TrimSpace(out) 2567 dockerCmd(c, "port", id) 2568 } 2569 2570 func (s *DockerSuite) TestRunTtyWithPipe(c *check.C) { 2571 errChan := make(chan error) 2572 go func() { 2573 defer close(errChan) 2574 2575 cmd := exec.Command(dockerBinary, "run", "-ti", "busybox", "true") 2576 if _, err := cmd.StdinPipe(); err != nil { 2577 errChan <- err 2578 return 2579 } 2580 2581 expected := "cannot enable tty mode" 2582 if out, _, err := runCommandWithOutput(cmd); err == nil { 2583 errChan <- fmt.Errorf("run should have failed") 2584 return 2585 } else if !strings.Contains(out, expected) { 2586 errChan <- fmt.Errorf("run failed with error %q: expected %q", out, expected) 2587 return 2588 } 2589 }() 2590 2591 select { 2592 case err := <-errChan: 2593 c.Assert(err, check.IsNil) 2594 case <-time.After(6 * time.Second): 2595 c.Fatal("container is running but should have failed") 2596 } 2597 } 2598 2599 func (s *DockerSuite) TestRunNonLocalMacAddress(c *check.C) { 2600 addr := "00:16:3E:08:00:50" 2601 cmd := "ifconfig" 2602 image := "busybox" 2603 expected := addr 2604 2605 if daemonPlatform == "windows" { 2606 cmd = "ipconfig /all" 2607 image = WindowsBaseImage 2608 expected = strings.Replace(strings.ToUpper(addr), ":", "-", -1) 2609 2610 } 2611 2612 if out, _ := dockerCmd(c, "run", "--mac-address", addr, image, cmd); !strings.Contains(out, expected) { 2613 c.Fatalf("Output should have contained %q: %s", expected, out) 2614 } 2615 } 2616 2617 func (s *DockerSuite) TestRunNetHost(c *check.C) { 2618 // Not applicable on Windows as uses Unix-specific capabilities 2619 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 2620 2621 hostNet, err := os.Readlink("/proc/1/ns/net") 2622 if err != nil { 2623 c.Fatal(err) 2624 } 2625 2626 out, _ := dockerCmd(c, "run", "--net=host", "busybox", "readlink", "/proc/self/ns/net") 2627 out = strings.Trim(out, "\n") 2628 if hostNet != out { 2629 c.Fatalf("Net namespace different with --net=host %s != %s\n", hostNet, out) 2630 } 2631 2632 out, _ = dockerCmd(c, "run", "busybox", "readlink", "/proc/self/ns/net") 2633 out = strings.Trim(out, "\n") 2634 if hostNet == out { 2635 c.Fatalf("Net namespace should be different without --net=host %s == %s\n", hostNet, out) 2636 } 2637 } 2638 2639 func (s *DockerSuite) TestRunNetHostTwiceSameName(c *check.C) { 2640 // TODO Windows. As Windows networking evolves and converges towards 2641 // CNM, this test may be possible to enable on Windows. 2642 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 2643 2644 dockerCmd(c, "run", "--rm", "--name=thost", "--net=host", "busybox", "true") 2645 dockerCmd(c, "run", "--rm", "--name=thost", "--net=host", "busybox", "true") 2646 } 2647 2648 func (s *DockerSuite) TestRunNetContainerWhichHost(c *check.C) { 2649 // Not applicable on Windows as uses Unix-specific capabilities 2650 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 2651 2652 hostNet, err := os.Readlink("/proc/1/ns/net") 2653 if err != nil { 2654 c.Fatal(err) 2655 } 2656 2657 dockerCmd(c, "run", "-d", "--net=host", "--name=test", "busybox", "top") 2658 2659 out, _ := dockerCmd(c, "run", "--net=container:test", "busybox", "readlink", "/proc/self/ns/net") 2660 out = strings.Trim(out, "\n") 2661 if hostNet != out { 2662 c.Fatalf("Container should have host network namespace") 2663 } 2664 } 2665 2666 func (s *DockerSuite) TestRunAllowPortRangeThroughPublish(c *check.C) { 2667 // TODO Windows. This may be possible to enable in the future. However, 2668 // Windows does not currently support --expose, or populate the network 2669 // settings seen through inspect. 2670 testRequires(c, DaemonIsLinux) 2671 out, _ := dockerCmd(c, "run", "-d", "--expose", "3000-3003", "-p", "3000-3003", "busybox", "top") 2672 2673 id := strings.TrimSpace(out) 2674 portstr, err := inspectFieldJSON(id, "NetworkSettings.Ports") 2675 c.Assert(err, check.IsNil) 2676 2677 var ports nat.PortMap 2678 err = unmarshalJSON([]byte(portstr), &ports) 2679 for port, binding := range ports { 2680 portnum, _ := strconv.Atoi(strings.Split(string(port), "/")[0]) 2681 if portnum < 3000 || portnum > 3003 { 2682 c.Fatalf("Port %d is out of range ", portnum) 2683 } 2684 if binding == nil || len(binding) != 1 || len(binding[0].HostPort) == 0 { 2685 c.Fatal("Port is not mapped for the port "+port, out) 2686 } 2687 } 2688 } 2689 2690 func (s *DockerSuite) TestRunSetDefaultRestartPolicy(c *check.C) { 2691 dockerCmd(c, "run", "-d", "--name", "test", "busybox", "sleep", "30") 2692 out, err := inspectField("test", "HostConfig.RestartPolicy.Name") 2693 c.Assert(err, check.IsNil) 2694 if out != "no" { 2695 c.Fatalf("Set default restart policy failed") 2696 } 2697 } 2698 2699 func (s *DockerSuite) TestRunRestartMaxRetries(c *check.C) { 2700 out, _ := dockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "false") 2701 timeout := 10 * time.Second 2702 if daemonPlatform == "windows" { 2703 timeout = 45 * time.Second 2704 } 2705 2706 id := strings.TrimSpace(string(out)) 2707 if err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", timeout); err != nil { 2708 c.Fatal(err) 2709 } 2710 2711 count, err := inspectField(id, "RestartCount") 2712 c.Assert(err, check.IsNil) 2713 if count != "3" { 2714 c.Fatalf("Container was restarted %s times, expected %d", count, 3) 2715 } 2716 2717 MaximumRetryCount, err := inspectField(id, "HostConfig.RestartPolicy.MaximumRetryCount") 2718 c.Assert(err, check.IsNil) 2719 if MaximumRetryCount != "3" { 2720 c.Fatalf("Container Maximum Retry Count is %s, expected %s", MaximumRetryCount, "3") 2721 } 2722 } 2723 2724 func (s *DockerSuite) TestRunContainerWithWritableRootfs(c *check.C) { 2725 dockerCmd(c, "run", "--rm", "busybox", "touch", "/file") 2726 } 2727 2728 func (s *DockerSuite) TestRunContainerWithReadonlyRootfs(c *check.C) { 2729 // Not applicable on Windows which does not support --read-only 2730 testRequires(c, DaemonIsLinux) 2731 2732 for _, f := range []string{"/file", "/etc/hosts", "/etc/resolv.conf", "/etc/hostname", "/sys/kernel", "/dev/.dont.touch.me"} { 2733 testReadOnlyFile(f, c) 2734 } 2735 } 2736 2737 func (s *DockerSuite) TestPermissionsPtsReadonlyRootfs(c *check.C) { 2738 // Not applicable on Windows due to use of Unix specific functionality, plus 2739 // the use of --read-only which is not supported. 2740 // --read-only + userns has remount issues 2741 testRequires(c, DaemonIsLinux, NotUserNamespace) 2742 2743 // Ensure we have not broken writing /dev/pts 2744 out, status := dockerCmd(c, "run", "--read-only", "--rm", "busybox", "mount") 2745 if status != 0 { 2746 c.Fatal("Could not obtain mounts when checking /dev/pts mntpnt.") 2747 } 2748 expected := "type devpts (rw," 2749 if !strings.Contains(string(out), expected) { 2750 c.Fatalf("expected output to contain %s but contains %s", expected, out) 2751 } 2752 } 2753 2754 func testReadOnlyFile(filename string, c *check.C) { 2755 // Not applicable on Windows which does not support --read-only 2756 testRequires(c, DaemonIsLinux, NotUserNamespace) 2757 2758 out, _, err := dockerCmdWithError("run", "--read-only", "--rm", "busybox", "touch", filename) 2759 if err == nil { 2760 c.Fatal("expected container to error on run with read only error") 2761 } 2762 expected := "Read-only file system" 2763 if !strings.Contains(string(out), expected) { 2764 c.Fatalf("expected output from failure to contain %s but contains %s", expected, out) 2765 } 2766 2767 out, _, err = dockerCmdWithError("run", "--read-only", "--privileged", "--rm", "busybox", "touch", filename) 2768 if err == nil { 2769 c.Fatal("expected container to error on run with read only error") 2770 } 2771 expected = "Read-only file system" 2772 if !strings.Contains(string(out), expected) { 2773 c.Fatalf("expected output from failure to contain %s but contains %s", expected, out) 2774 } 2775 } 2776 2777 func (s *DockerSuite) TestRunContainerWithReadonlyEtcHostsAndLinkedContainer(c *check.C) { 2778 // Not applicable on Windows which does not support --link 2779 // --read-only + userns has remount issues 2780 testRequires(c, DaemonIsLinux, NotUserNamespace) 2781 2782 dockerCmd(c, "run", "-d", "--name", "test-etc-hosts-ro-linked", "busybox", "top") 2783 2784 out, _ := dockerCmd(c, "run", "--read-only", "--link", "test-etc-hosts-ro-linked:testlinked", "busybox", "cat", "/etc/hosts") 2785 if !strings.Contains(string(out), "testlinked") { 2786 c.Fatal("Expected /etc/hosts to be updated even if --read-only enabled") 2787 } 2788 } 2789 2790 func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithDnsFlag(c *check.C) { 2791 // Not applicable on Windows which does not support either --read-only or --dns. 2792 // --read-only + userns has remount issues 2793 testRequires(c, DaemonIsLinux, NotUserNamespace) 2794 2795 out, _ := dockerCmd(c, "run", "--read-only", "--dns", "1.1.1.1", "busybox", "/bin/cat", "/etc/resolv.conf") 2796 if !strings.Contains(string(out), "1.1.1.1") { 2797 c.Fatal("Expected /etc/resolv.conf to be updated even if --read-only enabled and --dns flag used") 2798 } 2799 } 2800 2801 func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithAddHostFlag(c *check.C) { 2802 // Not applicable on Windows which does not support --read-only 2803 // --read-only + userns has remount issues 2804 testRequires(c, DaemonIsLinux, NotUserNamespace) 2805 2806 out, _ := dockerCmd(c, "run", "--read-only", "--add-host", "testreadonly:127.0.0.1", "busybox", "/bin/cat", "/etc/hosts") 2807 if !strings.Contains(string(out), "testreadonly") { 2808 c.Fatal("Expected /etc/hosts to be updated even if --read-only enabled and --add-host flag used") 2809 } 2810 } 2811 2812 func (s *DockerSuite) TestRunVolumesFromRestartAfterRemoved(c *check.C) { 2813 prefix := "" 2814 if daemonPlatform == "windows" { 2815 prefix = "c:" 2816 } 2817 dockerCmd(c, "run", "-d", "--name", "voltest", "-v", prefix+"/foo", "busybox", "sleep", "60") 2818 dockerCmd(c, "run", "-d", "--name", "restarter", "--volumes-from", "voltest", "busybox", "sleep", "60") 2819 2820 // Remove the main volume container and restart the consuming container 2821 dockerCmd(c, "rm", "-f", "voltest") 2822 2823 // This should not fail since the volumes-from were already applied 2824 dockerCmd(c, "restart", "restarter") 2825 } 2826 2827 // run container with --rm should remove container if exit code != 0 2828 func (s *DockerSuite) TestRunContainerWithRmFlagExitCodeNotEqualToZero(c *check.C) { 2829 name := "flowers" 2830 out, _, err := dockerCmdWithError("run", "--name", name, "--rm", "busybox", "ls", "/notexists") 2831 if err == nil { 2832 c.Fatal("Expected docker run to fail", out, err) 2833 } 2834 2835 out, err = getAllContainers() 2836 if err != nil { 2837 c.Fatal(out, err) 2838 } 2839 2840 if out != "" { 2841 c.Fatal("Expected not to have containers", out) 2842 } 2843 } 2844 2845 func (s *DockerSuite) TestRunContainerWithRmFlagCannotStartContainer(c *check.C) { 2846 name := "sparkles" 2847 out, _, err := dockerCmdWithError("run", "--name", name, "--rm", "busybox", "commandNotFound") 2848 if err == nil { 2849 c.Fatal("Expected docker run to fail", out, err) 2850 } 2851 2852 out, err = getAllContainers() 2853 if err != nil { 2854 c.Fatal(out, err) 2855 } 2856 2857 if out != "" { 2858 c.Fatal("Expected not to have containers", out) 2859 } 2860 } 2861 2862 func (s *DockerSuite) TestRunPidHostWithChildIsKillable(c *check.C) { 2863 // Not applicable on Windows as uses Unix specific functionality 2864 testRequires(c, DaemonIsLinux, NotUserNamespace) 2865 name := "ibuildthecloud" 2866 dockerCmd(c, "run", "-d", "--pid=host", "--name", name, "busybox", "sh", "-c", "sleep 30; echo hi") 2867 2868 c.Assert(waitRun(name), check.IsNil) 2869 2870 errchan := make(chan error) 2871 go func() { 2872 if out, _, err := dockerCmdWithError("kill", name); err != nil { 2873 errchan <- fmt.Errorf("%v:\n%s", err, out) 2874 } 2875 close(errchan) 2876 }() 2877 select { 2878 case err := <-errchan: 2879 c.Assert(err, check.IsNil) 2880 case <-time.After(5 * time.Second): 2881 c.Fatal("Kill container timed out") 2882 } 2883 } 2884 2885 func (s *DockerSuite) TestRunWithTooSmallMemoryLimit(c *check.C) { 2886 // TODO Windows. This may be possible to enable once Windows supports 2887 // memory limits on containers 2888 testRequires(c, DaemonIsLinux) 2889 // this memory limit is 1 byte less than the min, which is 4MB 2890 // https://github.com/docker/docker/blob/v1.5.0/daemon/create.go#L22 2891 out, _, err := dockerCmdWithError("run", "-m", "4194303", "busybox") 2892 if err == nil || !strings.Contains(out, "Minimum memory limit allowed is 4MB") { 2893 c.Fatalf("expected run to fail when using too low a memory limit: %q", out) 2894 } 2895 } 2896 2897 func (s *DockerSuite) TestRunWriteToProcAsound(c *check.C) { 2898 // Not applicable on Windows as uses Unix specific functionality 2899 testRequires(c, DaemonIsLinux) 2900 _, code, err := dockerCmdWithError("run", "busybox", "sh", "-c", "echo 111 >> /proc/asound/version") 2901 if err == nil || code == 0 { 2902 c.Fatal("standard container should not be able to write to /proc/asound") 2903 } 2904 } 2905 2906 func (s *DockerSuite) TestRunReadProcTimer(c *check.C) { 2907 // Not applicable on Windows as uses Unix specific functionality 2908 testRequires(c, DaemonIsLinux) 2909 out, code, err := dockerCmdWithError("run", "busybox", "cat", "/proc/timer_stats") 2910 if code != 0 { 2911 return 2912 } 2913 if err != nil { 2914 c.Fatal(err) 2915 } 2916 if strings.Trim(out, "\n ") != "" { 2917 c.Fatalf("expected to receive no output from /proc/timer_stats but received %q", out) 2918 } 2919 } 2920 2921 func (s *DockerSuite) TestRunReadProcLatency(c *check.C) { 2922 // Not applicable on Windows as uses Unix specific functionality 2923 testRequires(c, DaemonIsLinux) 2924 // some kernels don't have this configured so skip the test if this file is not found 2925 // on the host running the tests. 2926 if _, err := os.Stat("/proc/latency_stats"); err != nil { 2927 c.Skip("kernel doesnt have latency_stats configured") 2928 return 2929 } 2930 out, code, err := dockerCmdWithError("run", "busybox", "cat", "/proc/latency_stats") 2931 if code != 0 { 2932 return 2933 } 2934 if err != nil { 2935 c.Fatal(err) 2936 } 2937 if strings.Trim(out, "\n ") != "" { 2938 c.Fatalf("expected to receive no output from /proc/latency_stats but received %q", out) 2939 } 2940 } 2941 2942 func (s *DockerSuite) TestRunReadFilteredProc(c *check.C) { 2943 // Not applicable on Windows as uses Unix specific functionality 2944 testRequires(c, Apparmor, DaemonIsLinux, NotUserNamespace) 2945 2946 testReadPaths := []string{ 2947 "/proc/latency_stats", 2948 "/proc/timer_stats", 2949 "/proc/kcore", 2950 } 2951 for i, filePath := range testReadPaths { 2952 name := fmt.Sprintf("procsieve-%d", i) 2953 shellCmd := fmt.Sprintf("exec 3<%s", filePath) 2954 2955 out, exitCode, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor:docker-default", "--name", name, "busybox", "sh", "-c", shellCmd) 2956 if exitCode != 0 { 2957 return 2958 } 2959 if err != nil { 2960 c.Fatalf("Open FD for read should have failed with permission denied, got: %s, %v", out, err) 2961 } 2962 } 2963 } 2964 2965 func (s *DockerSuite) TestMountIntoProc(c *check.C) { 2966 // Not applicable on Windows as uses Unix specific functionality 2967 testRequires(c, DaemonIsLinux) 2968 _, code, err := dockerCmdWithError("run", "-v", "/proc//sys", "busybox", "true") 2969 if err == nil || code == 0 { 2970 c.Fatal("container should not be able to mount into /proc") 2971 } 2972 } 2973 2974 func (s *DockerSuite) TestMountIntoSys(c *check.C) { 2975 // Not applicable on Windows as uses Unix specific functionality 2976 testRequires(c, DaemonIsLinux) 2977 testRequires(c, NotUserNamespace) 2978 dockerCmd(c, "run", "-v", "/sys/fs/cgroup", "busybox", "true") 2979 } 2980 2981 func (s *DockerSuite) TestRunUnshareProc(c *check.C) { 2982 // Not applicable on Windows as uses Unix specific functionality 2983 testRequires(c, Apparmor, DaemonIsLinux, NotUserNamespace) 2984 2985 name := "acidburn" 2986 out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount") 2987 if err == nil || 2988 !(strings.Contains(strings.ToLower(out), "permission denied") || 2989 strings.Contains(strings.ToLower(out), "operation not permitted")) { 2990 c.Fatalf("unshare with --mount-proc should have failed with 'permission denied' or 'operation not permitted', got: %s, %v", out, err) 2991 } 2992 2993 name = "cereal" 2994 out, _, err = dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc") 2995 if err == nil || 2996 !(strings.Contains(strings.ToLower(out), "mount: cannot mount none") || 2997 strings.Contains(strings.ToLower(out), "permission denied")) { 2998 c.Fatalf("unshare and mount of /proc should have failed with 'mount: cannot mount none' or 'permission denied', got: %s, %v", out, err) 2999 } 3000 3001 /* Ensure still fails if running privileged with the default policy */ 3002 name = "crashoverride" 3003 out, _, err = dockerCmdWithError("run", "--privileged", "--security-opt", "seccomp:unconfined", "--security-opt", "apparmor:docker-default", "--name", name, "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc") 3004 if err == nil || 3005 !(strings.Contains(strings.ToLower(out), "mount: cannot mount none") || 3006 strings.Contains(strings.ToLower(out), "permission denied")) { 3007 c.Fatalf("privileged unshare with apparmor should have failed with 'mount: cannot mount none' or 'permission denied', got: %s, %v", out, err) 3008 } 3009 } 3010 3011 func (s *DockerSuite) TestRunPublishPort(c *check.C) { 3012 // TODO Windows: This may be possible once Windows moves to libnetwork and CNM 3013 testRequires(c, DaemonIsLinux) 3014 dockerCmd(c, "run", "-d", "--name", "test", "--expose", "8080", "busybox", "top") 3015 out, _ := dockerCmd(c, "port", "test") 3016 out = strings.Trim(out, "\r\n") 3017 if out != "" { 3018 c.Fatalf("run without --publish-all should not publish port, out should be nil, but got: %s", out) 3019 } 3020 } 3021 3022 // Issue #10184. 3023 func (s *DockerSuite) TestDevicePermissions(c *check.C) { 3024 // Not applicable on Windows as uses Unix specific functionality 3025 testRequires(c, DaemonIsLinux) 3026 const permissions = "crw-rw-rw-" 3027 out, status := dockerCmd(c, "run", "--device", "/dev/fuse:/dev/fuse:mrw", "busybox:latest", "ls", "-l", "/dev/fuse") 3028 if status != 0 { 3029 c.Fatalf("expected status 0, got %d", status) 3030 } 3031 if !strings.HasPrefix(out, permissions) { 3032 c.Fatalf("output should begin with %q, got %q", permissions, out) 3033 } 3034 } 3035 3036 func (s *DockerSuite) TestRunCapAddCHOWN(c *check.C) { 3037 // Not applicable on Windows as uses Unix specific functionality 3038 testRequires(c, DaemonIsLinux) 3039 out, _ := dockerCmd(c, "run", "--cap-drop=ALL", "--cap-add=CHOWN", "busybox", "sh", "-c", "adduser -D -H newuser && chown newuser /home && echo ok") 3040 3041 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 3042 c.Fatalf("expected output ok received %s", actual) 3043 } 3044 } 3045 3046 // https://github.com/docker/docker/pull/14498 3047 func (s *DockerSuite) TestVolumeFromMixedRWOptions(c *check.C) { 3048 // TODO Windows post TP4. Enable the read-only bits once they are 3049 // supported on the platform. 3050 prefix := "" 3051 slash := `/` 3052 if daemonPlatform == "windows" { 3053 prefix = "c:" 3054 slash = `\` 3055 } 3056 3057 dockerCmd(c, "run", "--name", "parent", "-v", prefix+"/test", "busybox", "true") 3058 if daemonPlatform != "windows" { 3059 dockerCmd(c, "run", "--volumes-from", "parent:ro", "--name", "test-volumes-1", "busybox", "true") 3060 } 3061 dockerCmd(c, "run", "--volumes-from", "parent:rw", "--name", "test-volumes-2", "busybox", "true") 3062 3063 if daemonPlatform != "windows" { 3064 mRO, err := inspectMountPoint("test-volumes-1", prefix+slash+"test") 3065 c.Assert(err, check.IsNil) 3066 if mRO.RW { 3067 c.Fatalf("Expected RO volume was RW") 3068 } 3069 } 3070 3071 mRW, err := inspectMountPoint("test-volumes-2", prefix+slash+"test") 3072 c.Assert(err, check.IsNil) 3073 if !mRW.RW { 3074 c.Fatalf("Expected RW volume was RO") 3075 } 3076 } 3077 3078 func (s *DockerSuite) TestRunWriteFilteredProc(c *check.C) { 3079 // Not applicable on Windows as uses Unix specific functionality 3080 testRequires(c, Apparmor, DaemonIsLinux, NotUserNamespace) 3081 3082 testWritePaths := []string{ 3083 /* modprobe and core_pattern should both be denied by generic 3084 * policy of denials for /proc/sys/kernel. These files have been 3085 * picked to be checked as they are particularly sensitive to writes */ 3086 "/proc/sys/kernel/modprobe", 3087 "/proc/sys/kernel/core_pattern", 3088 "/proc/sysrq-trigger", 3089 "/proc/kcore", 3090 } 3091 for i, filePath := range testWritePaths { 3092 name := fmt.Sprintf("writeprocsieve-%d", i) 3093 3094 shellCmd := fmt.Sprintf("exec 3>%s", filePath) 3095 out, code, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor:docker-default", "--name", name, "busybox", "sh", "-c", shellCmd) 3096 if code != 0 { 3097 return 3098 } 3099 if err != nil { 3100 c.Fatalf("Open FD for write should have failed with permission denied, got: %s, %v", out, err) 3101 } 3102 } 3103 } 3104 3105 func (s *DockerSuite) TestRunNetworkFilesBindMount(c *check.C) { 3106 // Not applicable on Windows as uses Unix specific functionality 3107 testRequires(c, SameHostDaemon, DaemonIsLinux) 3108 3109 expected := "test123" 3110 3111 filename := createTmpFile(c, expected) 3112 defer os.Remove(filename) 3113 3114 nwfiles := []string{"/etc/resolv.conf", "/etc/hosts", "/etc/hostname"} 3115 3116 for i := range nwfiles { 3117 actual, _ := dockerCmd(c, "run", "-v", filename+":"+nwfiles[i], "busybox", "cat", nwfiles[i]) 3118 if actual != expected { 3119 c.Fatalf("expected %s be: %q, but was: %q", nwfiles[i], expected, actual) 3120 } 3121 } 3122 } 3123 3124 func (s *DockerSuite) TestRunNetworkFilesBindMountRO(c *check.C) { 3125 // Not applicable on Windows as uses Unix specific functionality 3126 testRequires(c, SameHostDaemon, DaemonIsLinux) 3127 3128 filename := createTmpFile(c, "test123") 3129 defer os.Remove(filename) 3130 3131 nwfiles := []string{"/etc/resolv.conf", "/etc/hosts", "/etc/hostname"} 3132 3133 for i := range nwfiles { 3134 _, exitCode, err := dockerCmdWithError("run", "-v", filename+":"+nwfiles[i]+":ro", "busybox", "touch", nwfiles[i]) 3135 if err == nil || exitCode == 0 { 3136 c.Fatalf("run should fail because bind mount of %s is ro: exit code %d", nwfiles[i], exitCode) 3137 } 3138 } 3139 } 3140 3141 func (s *DockerSuite) TestRunNetworkFilesBindMountROFilesystem(c *check.C) { 3142 // Not applicable on Windows as uses Unix specific functionality 3143 // --read-only + userns has remount issues 3144 testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) 3145 3146 filename := createTmpFile(c, "test123") 3147 defer os.Remove(filename) 3148 3149 nwfiles := []string{"/etc/resolv.conf", "/etc/hosts", "/etc/hostname"} 3150 3151 for i := range nwfiles { 3152 _, exitCode := dockerCmd(c, "run", "-v", filename+":"+nwfiles[i], "--read-only", "busybox", "touch", nwfiles[i]) 3153 if exitCode != 0 { 3154 c.Fatalf("run should not fail because %s is mounted writable on read-only root filesystem: exit code %d", nwfiles[i], exitCode) 3155 } 3156 } 3157 3158 for i := range nwfiles { 3159 _, exitCode, err := dockerCmdWithError("run", "-v", filename+":"+nwfiles[i]+":ro", "--read-only", "busybox", "touch", nwfiles[i]) 3160 if err == nil || exitCode == 0 { 3161 c.Fatalf("run should fail because %s is mounted read-only on read-only root filesystem: exit code %d", nwfiles[i], exitCode) 3162 } 3163 } 3164 } 3165 3166 func (s *DockerTrustSuite) TestTrustedRun(c *check.C) { 3167 // Windows does not support this functionality 3168 testRequires(c, DaemonIsLinux) 3169 repoName := s.setupTrustedImage(c, "trusted-run") 3170 3171 // Try run 3172 runCmd := exec.Command(dockerBinary, "run", repoName) 3173 s.trustedCmd(runCmd) 3174 out, _, err := runCommandWithOutput(runCmd) 3175 if err != nil { 3176 c.Fatalf("Error running trusted run: %s\n%s\n", err, out) 3177 } 3178 3179 if !strings.Contains(string(out), "Tagging") { 3180 c.Fatalf("Missing expected output on trusted push:\n%s", out) 3181 } 3182 3183 dockerCmd(c, "rmi", repoName) 3184 3185 // Try untrusted run to ensure we pushed the tag to the registry 3186 runCmd = exec.Command(dockerBinary, "run", "--disable-content-trust=true", repoName) 3187 s.trustedCmd(runCmd) 3188 out, _, err = runCommandWithOutput(runCmd) 3189 if err != nil { 3190 c.Fatalf("Error running trusted run: %s\n%s", err, out) 3191 } 3192 3193 if !strings.Contains(string(out), "Status: Downloaded") { 3194 c.Fatalf("Missing expected output on trusted run with --disable-content-trust:\n%s", out) 3195 } 3196 } 3197 3198 func (s *DockerTrustSuite) TestUntrustedRun(c *check.C) { 3199 // Windows does not support this functionality 3200 testRequires(c, DaemonIsLinux) 3201 repoName := fmt.Sprintf("%v/dockercliuntrusted/runtest:latest", privateRegistryURL) 3202 // tag the image and upload it to the private registry 3203 dockerCmd(c, "tag", "busybox", repoName) 3204 dockerCmd(c, "push", repoName) 3205 dockerCmd(c, "rmi", repoName) 3206 3207 // Try trusted run on untrusted tag 3208 runCmd := exec.Command(dockerBinary, "run", repoName) 3209 s.trustedCmd(runCmd) 3210 out, _, err := runCommandWithOutput(runCmd) 3211 if err == nil { 3212 c.Fatalf("Error expected when running trusted run with:\n%s", out) 3213 } 3214 3215 if !strings.Contains(string(out), "does not have trust data for") { 3216 c.Fatalf("Missing expected output on trusted run:\n%s", out) 3217 } 3218 } 3219 3220 func (s *DockerTrustSuite) TestRunWhenCertExpired(c *check.C) { 3221 // Windows does not support this functionality 3222 testRequires(c, DaemonIsLinux) 3223 c.Skip("Currently changes system time, causing instability") 3224 repoName := s.setupTrustedImage(c, "trusted-run-expired") 3225 3226 // Certificates have 10 years of expiration 3227 elevenYearsFromNow := time.Now().Add(time.Hour * 24 * 365 * 11) 3228 3229 runAtDifferentDate(elevenYearsFromNow, func() { 3230 // Try run 3231 runCmd := exec.Command(dockerBinary, "run", repoName) 3232 s.trustedCmd(runCmd) 3233 out, _, err := runCommandWithOutput(runCmd) 3234 if err == nil { 3235 c.Fatalf("Error running trusted run in the distant future: %s\n%s", err, out) 3236 } 3237 3238 if !strings.Contains(string(out), "could not validate the path to a trusted root") { 3239 c.Fatalf("Missing expected output on trusted run in the distant future:\n%s", out) 3240 } 3241 }) 3242 3243 runAtDifferentDate(elevenYearsFromNow, func() { 3244 // Try run 3245 runCmd := exec.Command(dockerBinary, "run", "--disable-content-trust", repoName) 3246 s.trustedCmd(runCmd) 3247 out, _, err := runCommandWithOutput(runCmd) 3248 if err != nil { 3249 c.Fatalf("Error running untrusted run in the distant future: %s\n%s", err, out) 3250 } 3251 3252 if !strings.Contains(string(out), "Status: Downloaded") { 3253 c.Fatalf("Missing expected output on untrusted run in the distant future:\n%s", out) 3254 } 3255 }) 3256 } 3257 3258 func (s *DockerTrustSuite) TestTrustedRunFromBadTrustServer(c *check.C) { 3259 // Windows does not support this functionality 3260 testRequires(c, DaemonIsLinux) 3261 repoName := fmt.Sprintf("%v/dockerclievilrun/trusted:latest", privateRegistryURL) 3262 evilLocalConfigDir, err := ioutil.TempDir("", "evil-local-config-dir") 3263 if err != nil { 3264 c.Fatalf("Failed to create local temp dir") 3265 } 3266 3267 // tag the image and upload it to the private registry 3268 dockerCmd(c, "tag", "busybox", repoName) 3269 3270 pushCmd := exec.Command(dockerBinary, "push", repoName) 3271 s.trustedCmd(pushCmd) 3272 out, _, err := runCommandWithOutput(pushCmd) 3273 if err != nil { 3274 c.Fatalf("Error running trusted push: %s\n%s", err, out) 3275 } 3276 if !strings.Contains(string(out), "Signing and pushing trust metadata") { 3277 c.Fatalf("Missing expected output on trusted push:\n%s", out) 3278 } 3279 3280 dockerCmd(c, "rmi", repoName) 3281 3282 // Try run 3283 runCmd := exec.Command(dockerBinary, "run", repoName) 3284 s.trustedCmd(runCmd) 3285 out, _, err = runCommandWithOutput(runCmd) 3286 if err != nil { 3287 c.Fatalf("Error running trusted run: %s\n%s", err, out) 3288 } 3289 3290 if !strings.Contains(string(out), "Tagging") { 3291 c.Fatalf("Missing expected output on trusted push:\n%s", out) 3292 } 3293 3294 dockerCmd(c, "rmi", repoName) 3295 3296 // Kill the notary server, start a new "evil" one. 3297 s.not.Close() 3298 s.not, err = newTestNotary(c) 3299 if err != nil { 3300 c.Fatalf("Restarting notary server failed.") 3301 } 3302 3303 // In order to make an evil server, lets re-init a client (with a different trust dir) and push new data. 3304 // tag an image and upload it to the private registry 3305 dockerCmd(c, "--config", evilLocalConfigDir, "tag", "busybox", repoName) 3306 3307 // Push up to the new server 3308 pushCmd = exec.Command(dockerBinary, "--config", evilLocalConfigDir, "push", repoName) 3309 s.trustedCmd(pushCmd) 3310 out, _, err = runCommandWithOutput(pushCmd) 3311 if err != nil { 3312 c.Fatalf("Error running trusted push: %s\n%s", err, out) 3313 } 3314 if !strings.Contains(string(out), "Signing and pushing trust metadata") { 3315 c.Fatalf("Missing expected output on trusted push:\n%s", out) 3316 } 3317 3318 // Now, try running with the original client from this new trust server. This should fail. 3319 runCmd = exec.Command(dockerBinary, "run", repoName) 3320 s.trustedCmd(runCmd) 3321 out, _, err = runCommandWithOutput(runCmd) 3322 if err == nil { 3323 c.Fatalf("Expected to fail on this run due to different remote data: %s\n%s", err, out) 3324 } 3325 3326 if !strings.Contains(string(out), "valid signatures did not meet threshold") { 3327 c.Fatalf("Missing expected output on trusted push:\n%s", out) 3328 } 3329 } 3330 3331 func (s *DockerSuite) TestPtraceContainerProcsFromHost(c *check.C) { 3332 // Not applicable on Windows as uses Unix specific functionality 3333 testRequires(c, DaemonIsLinux, SameHostDaemon) 3334 3335 out, _ := dockerCmd(c, "run", "-d", "busybox", "top") 3336 id := strings.TrimSpace(out) 3337 c.Assert(waitRun(id), check.IsNil) 3338 pid1, err := inspectField(id, "State.Pid") 3339 c.Assert(err, check.IsNil) 3340 3341 _, err = os.Readlink(fmt.Sprintf("/proc/%s/ns/net", pid1)) 3342 if err != nil { 3343 c.Fatal(err) 3344 } 3345 } 3346 3347 func (s *DockerSuite) TestAppArmorDeniesPtrace(c *check.C) { 3348 // Not applicable on Windows as uses Unix specific functionality 3349 testRequires(c, SameHostDaemon, Apparmor, DaemonIsLinux, NotGCCGO) 3350 3351 // Run through 'sh' so we are NOT pid 1. Pid 1 may be able to trace 3352 // itself, but pid>1 should not be able to trace pid1. 3353 _, exitCode, _ := dockerCmdWithError("run", "busybox", "sh", "-c", "sh -c readlink /proc/1/ns/net") 3354 if exitCode == 0 { 3355 c.Fatal("ptrace was not successfully restricted by AppArmor") 3356 } 3357 } 3358 3359 func (s *DockerSuite) TestAppArmorTraceSelf(c *check.C) { 3360 // Not applicable on Windows as uses Unix specific functionality 3361 testRequires(c, DaemonIsLinux, SameHostDaemon, Apparmor) 3362 3363 _, exitCode, _ := dockerCmdWithError("run", "busybox", "readlink", "/proc/1/ns/net") 3364 if exitCode != 0 { 3365 c.Fatal("ptrace of self failed.") 3366 } 3367 } 3368 3369 func (s *DockerSuite) TestAppArmorDeniesChmodProc(c *check.C) { 3370 // Not applicable on Windows as uses Unix specific functionality 3371 testRequires(c, SameHostDaemon, Apparmor, DaemonIsLinux, NotUserNamespace) 3372 _, exitCode, _ := dockerCmdWithError("run", "busybox", "chmod", "744", "/proc/cpuinfo") 3373 if exitCode == 0 { 3374 // If our test failed, attempt to repair the host system... 3375 _, exitCode, _ := dockerCmdWithError("run", "busybox", "chmod", "444", "/proc/cpuinfo") 3376 if exitCode == 0 { 3377 c.Fatal("AppArmor was unsuccessful in prohibiting chmod of /proc/* files.") 3378 } 3379 } 3380 } 3381 3382 func (s *DockerSuite) TestRunCapAddSYSTIME(c *check.C) { 3383 // Not applicable on Windows as uses Unix specific functionality 3384 testRequires(c, DaemonIsLinux) 3385 3386 dockerCmd(c, "run", "--cap-drop=ALL", "--cap-add=SYS_TIME", "busybox", "sh", "-c", "grep ^CapEff /proc/self/status | sed 's/^CapEff:\t//' | grep ^0000000002000000$") 3387 } 3388 3389 // run create container failed should clean up the container 3390 func (s *DockerSuite) TestRunCreateContainerFailedCleanUp(c *check.C) { 3391 // TODO Windows. This may be possible to enable once link is supported 3392 testRequires(c, DaemonIsLinux) 3393 name := "unique_name" 3394 _, _, err := dockerCmdWithError("run", "--name", name, "--link", "nothing:nothing", "busybox") 3395 c.Assert(err, check.NotNil, check.Commentf("Expected docker run to fail!")) 3396 3397 containerID, err := inspectField(name, "Id") 3398 c.Assert(containerID, check.Equals, "", check.Commentf("Expected not to have this container: %s!", containerID)) 3399 } 3400 3401 func (s *DockerSuite) TestRunNamedVolume(c *check.C) { 3402 prefix := "" 3403 slash := `/` 3404 if daemonPlatform == "windows" { 3405 prefix = "c:" 3406 slash = `\` 3407 } 3408 testRequires(c, DaemonIsLinux) 3409 dockerCmd(c, "run", "--name=test", "-v", "testing:"+prefix+slash+"foo", "busybox", "sh", "-c", "echo hello > "+prefix+"/foo/bar") 3410 3411 out, _ := dockerCmd(c, "run", "--volumes-from", "test", "busybox", "sh", "-c", "cat "+prefix+"/foo/bar") 3412 c.Assert(strings.TrimSpace(out), check.Equals, "hello") 3413 3414 out, _ = dockerCmd(c, "run", "-v", "testing:"+prefix+slash+"foo", "busybox", "sh", "-c", "cat "+prefix+"/foo/bar") 3415 c.Assert(strings.TrimSpace(out), check.Equals, "hello") 3416 } 3417 3418 func (s *DockerSuite) TestRunWithUlimits(c *check.C) { 3419 // Not applicable on Windows as uses Unix specific functionality 3420 testRequires(c, DaemonIsLinux) 3421 3422 out, _ := dockerCmd(c, "run", "--name=testulimits", "--ulimit", "nofile=42", "busybox", "/bin/sh", "-c", "ulimit -n") 3423 ul := strings.TrimSpace(out) 3424 if ul != "42" { 3425 c.Fatalf("expected `ulimit -n` to be 42, got %s", ul) 3426 } 3427 } 3428 3429 func (s *DockerSuite) TestRunContainerWithCgroupParent(c *check.C) { 3430 // Not applicable on Windows as uses Unix specific functionality 3431 testRequires(c, DaemonIsLinux) 3432 3433 cgroupParent := "test" 3434 name := "cgroup-test" 3435 3436 out, _, err := dockerCmdWithError("run", "--cgroup-parent", cgroupParent, "--name", name, "busybox", "cat", "/proc/self/cgroup") 3437 if err != nil { 3438 c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err) 3439 } 3440 cgroupPaths := parseCgroupPaths(string(out)) 3441 if len(cgroupPaths) == 0 { 3442 c.Fatalf("unexpected output - %q", string(out)) 3443 } 3444 id, err := getIDByName(name) 3445 c.Assert(err, check.IsNil) 3446 expectedCgroup := path.Join(cgroupParent, id) 3447 found := false 3448 for _, path := range cgroupPaths { 3449 if strings.HasSuffix(path, expectedCgroup) { 3450 found = true 3451 break 3452 } 3453 } 3454 if !found { 3455 c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have suffix %q. Cgroup Paths: %v", expectedCgroup, cgroupPaths) 3456 } 3457 } 3458 3459 func (s *DockerSuite) TestRunContainerWithCgroupParentAbsPath(c *check.C) { 3460 // Not applicable on Windows as uses Unix specific functionality 3461 testRequires(c, DaemonIsLinux) 3462 3463 cgroupParent := "/cgroup-parent/test" 3464 name := "cgroup-test" 3465 out, _, err := dockerCmdWithError("run", "--cgroup-parent", cgroupParent, "--name", name, "busybox", "cat", "/proc/self/cgroup") 3466 if err != nil { 3467 c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err) 3468 } 3469 cgroupPaths := parseCgroupPaths(string(out)) 3470 if len(cgroupPaths) == 0 { 3471 c.Fatalf("unexpected output - %q", string(out)) 3472 } 3473 id, err := getIDByName(name) 3474 c.Assert(err, check.IsNil) 3475 expectedCgroup := path.Join(cgroupParent, id) 3476 found := false 3477 for _, path := range cgroupPaths { 3478 if strings.HasSuffix(path, expectedCgroup) { 3479 found = true 3480 break 3481 } 3482 } 3483 if !found { 3484 c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have suffix %q. Cgroup Paths: %v", expectedCgroup, cgroupPaths) 3485 } 3486 } 3487 3488 // TestRunInvalidCgroupParent checks that a specially-crafted cgroup parent doesn't cause Docker to crash or start modifying /. 3489 func (s *DockerSuite) TestRunInvalidCgroupParent(c *check.C) { 3490 // Not applicable on Windows as uses Unix specific functionality 3491 testRequires(c, DaemonIsLinux) 3492 3493 cgroupParent := "../../../../../../../../SHOULD_NOT_EXIST" 3494 cleanCgroupParent := "SHOULD_NOT_EXIST" 3495 name := "cgroup-invalid-test" 3496 3497 out, _, err := dockerCmdWithError("run", "--cgroup-parent", cgroupParent, "--name", name, "busybox", "cat", "/proc/self/cgroup") 3498 if err != nil { 3499 // XXX: This may include a daemon crash. 3500 c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err) 3501 } 3502 3503 // We expect "/SHOULD_NOT_EXIST" to not exist. If not, we have a security issue. 3504 if _, err := os.Stat("/SHOULD_NOT_EXIST"); err == nil || !os.IsNotExist(err) { 3505 c.Fatalf("SECURITY: --cgroup-parent with ../../ relative paths cause files to be created in the host (this is bad) !!") 3506 } 3507 3508 cgroupPaths := parseCgroupPaths(string(out)) 3509 if len(cgroupPaths) == 0 { 3510 c.Fatalf("unexpected output - %q", string(out)) 3511 } 3512 id, err := getIDByName(name) 3513 c.Assert(err, check.IsNil) 3514 expectedCgroup := path.Join(cleanCgroupParent, id) 3515 found := false 3516 for _, path := range cgroupPaths { 3517 if strings.HasSuffix(path, expectedCgroup) { 3518 found = true 3519 break 3520 } 3521 } 3522 if !found { 3523 c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have suffix %q. Cgroup Paths: %v", expectedCgroup, cgroupPaths) 3524 } 3525 } 3526 3527 // TestRunInvalidCgroupParent checks that a specially-crafted cgroup parent doesn't cause Docker to crash or start modifying /. 3528 func (s *DockerSuite) TestRunAbsoluteInvalidCgroupParent(c *check.C) { 3529 // Not applicable on Windows as uses Unix specific functionality 3530 testRequires(c, DaemonIsLinux) 3531 3532 cgroupParent := "/../../../../../../../../SHOULD_NOT_EXIST" 3533 cleanCgroupParent := "/SHOULD_NOT_EXIST" 3534 name := "cgroup-absolute-invalid-test" 3535 3536 out, _, err := dockerCmdWithError("run", "--cgroup-parent", cgroupParent, "--name", name, "busybox", "cat", "/proc/self/cgroup") 3537 if err != nil { 3538 // XXX: This may include a daemon crash. 3539 c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err) 3540 } 3541 3542 // We expect "/SHOULD_NOT_EXIST" to not exist. If not, we have a security issue. 3543 if _, err := os.Stat("/SHOULD_NOT_EXIST"); err == nil || !os.IsNotExist(err) { 3544 c.Fatalf("SECURITY: --cgroup-parent with /../../ garbage paths cause files to be created in the host (this is bad) !!") 3545 } 3546 3547 cgroupPaths := parseCgroupPaths(string(out)) 3548 if len(cgroupPaths) == 0 { 3549 c.Fatalf("unexpected output - %q", string(out)) 3550 } 3551 id, err := getIDByName(name) 3552 c.Assert(err, check.IsNil) 3553 expectedCgroup := path.Join(cleanCgroupParent, id) 3554 found := false 3555 for _, path := range cgroupPaths { 3556 if strings.HasSuffix(path, expectedCgroup) { 3557 found = true 3558 break 3559 } 3560 } 3561 if !found { 3562 c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have suffix %q. Cgroup Paths: %v", expectedCgroup, cgroupPaths) 3563 } 3564 } 3565 3566 func (s *DockerSuite) TestRunContainerWithCgroupMountRO(c *check.C) { 3567 // Not applicable on Windows as uses Unix specific functionality 3568 // --read-only + userns has remount issues 3569 testRequires(c, DaemonIsLinux, NotUserNamespace) 3570 3571 filename := "/sys/fs/cgroup/devices/test123" 3572 out, _, err := dockerCmdWithError("run", "busybox", "touch", filename) 3573 if err == nil { 3574 c.Fatal("expected cgroup mount point to be read-only, touch file should fail") 3575 } 3576 expected := "Read-only file system" 3577 if !strings.Contains(out, expected) { 3578 c.Fatalf("expected output from failure to contain %s but contains %s", expected, out) 3579 } 3580 } 3581 3582 func (s *DockerSuite) TestRunContainerNetworkModeToSelf(c *check.C) { 3583 // Not applicable on Windows which does not support --net=container 3584 testRequires(c, DaemonIsLinux, NotUserNamespace) 3585 out, _, err := dockerCmdWithError("run", "--name=me", "--net=container:me", "busybox", "true") 3586 if err == nil || !strings.Contains(out, "cannot join own network") { 3587 c.Fatalf("using container net mode to self should result in an error\nerr: %q\nout: %s", err, out) 3588 } 3589 } 3590 3591 func (s *DockerSuite) TestRunContainerNetModeWithDnsMacHosts(c *check.C) { 3592 // Not applicable on Windows which does not support --net=container 3593 testRequires(c, DaemonIsLinux, NotUserNamespace) 3594 out, _, err := dockerCmdWithError("run", "-d", "--name", "parent", "busybox", "top") 3595 if err != nil { 3596 c.Fatalf("failed to run container: %v, output: %q", err, out) 3597 } 3598 3599 out, _, err = dockerCmdWithError("run", "--dns", "1.2.3.4", "--net=container:parent", "busybox") 3600 if err == nil || !strings.Contains(out, runconfig.ErrConflictNetworkAndDNS.Error()) { 3601 c.Fatalf("run --net=container with --dns should error out") 3602 } 3603 3604 out, _, err = dockerCmdWithError("run", "--mac-address", "92:d0:c6:0a:29:33", "--net=container:parent", "busybox") 3605 if err == nil || !strings.Contains(out, runconfig.ErrConflictContainerNetworkAndMac.Error()) { 3606 c.Fatalf("run --net=container with --mac-address should error out") 3607 } 3608 3609 out, _, err = dockerCmdWithError("run", "--add-host", "test:192.168.2.109", "--net=container:parent", "busybox") 3610 if err == nil || !strings.Contains(out, runconfig.ErrConflictNetworkHosts.Error()) { 3611 c.Fatalf("run --net=container with --add-host should error out") 3612 } 3613 } 3614 3615 func (s *DockerSuite) TestRunContainerNetModeWithExposePort(c *check.C) { 3616 // Not applicable on Windows which does not support --net=container 3617 testRequires(c, DaemonIsLinux, NotUserNamespace) 3618 dockerCmd(c, "run", "-d", "--name", "parent", "busybox", "top") 3619 3620 out, _, err := dockerCmdWithError("run", "-p", "5000:5000", "--net=container:parent", "busybox") 3621 if err == nil || !strings.Contains(out, runconfig.ErrConflictNetworkPublishPorts.Error()) { 3622 c.Fatalf("run --net=container with -p should error out") 3623 } 3624 3625 out, _, err = dockerCmdWithError("run", "-P", "--net=container:parent", "busybox") 3626 if err == nil || !strings.Contains(out, runconfig.ErrConflictNetworkPublishPorts.Error()) { 3627 c.Fatalf("run --net=container with -P should error out") 3628 } 3629 3630 out, _, err = dockerCmdWithError("run", "--expose", "5000", "--net=container:parent", "busybox") 3631 if err == nil || !strings.Contains(out, runconfig.ErrConflictNetworkExposePorts.Error()) { 3632 c.Fatalf("run --net=container with --expose should error out") 3633 } 3634 } 3635 3636 func (s *DockerSuite) TestRunLinkToContainerNetMode(c *check.C) { 3637 // Not applicable on Windows which does not support --net=container or --link 3638 testRequires(c, DaemonIsLinux, NotUserNamespace) 3639 dockerCmd(c, "run", "--name", "test", "-d", "busybox", "top") 3640 dockerCmd(c, "run", "--name", "parent", "-d", "--net=container:test", "busybox", "top") 3641 dockerCmd(c, "run", "-d", "--link=parent:parent", "busybox", "top") 3642 dockerCmd(c, "run", "--name", "child", "-d", "--net=container:parent", "busybox", "top") 3643 dockerCmd(c, "run", "-d", "--link=child:child", "busybox", "top") 3644 } 3645 3646 func (s *DockerSuite) TestRunLoopbackOnlyExistsWhenNetworkingDisabled(c *check.C) { 3647 // TODO Windows: This may be possible to convert. 3648 testRequires(c, DaemonIsLinux) 3649 out, _ := dockerCmd(c, "run", "--net=none", "busybox", "ip", "-o", "-4", "a", "show", "up") 3650 3651 var ( 3652 count = 0 3653 parts = strings.Split(out, "\n") 3654 ) 3655 3656 for _, l := range parts { 3657 if l != "" { 3658 count++ 3659 } 3660 } 3661 3662 if count != 1 { 3663 c.Fatalf("Wrong interface count in container %d", count) 3664 } 3665 3666 if !strings.HasPrefix(out, "1: lo") { 3667 c.Fatalf("Wrong interface in test container: expected [1: lo], got %s", out) 3668 } 3669 } 3670 3671 // Issue #4681 3672 func (s *DockerSuite) TestRunLoopbackWhenNetworkDisabled(c *check.C) { 3673 if daemonPlatform == "windows" { 3674 dockerCmd(c, "run", "--net=none", WindowsBaseImage, "ping", "-n", "1", "127.0.0.1") 3675 } else { 3676 dockerCmd(c, "run", "--net=none", "busybox", "ping", "-c", "1", "127.0.0.1") 3677 } 3678 } 3679 3680 func (s *DockerSuite) TestRunModeNetContainerHostname(c *check.C) { 3681 // Windows does not support --net=container 3682 testRequires(c, DaemonIsLinux, ExecSupport, NotUserNamespace) 3683 3684 dockerCmd(c, "run", "-i", "-d", "--name", "parent", "busybox", "top") 3685 out, _ := dockerCmd(c, "exec", "parent", "cat", "/etc/hostname") 3686 out1, _ := dockerCmd(c, "run", "--net=container:parent", "busybox", "cat", "/etc/hostname") 3687 3688 if out1 != out { 3689 c.Fatal("containers with shared net namespace should have same hostname") 3690 } 3691 } 3692 3693 func (s *DockerSuite) TestRunNetworkNotInitializedNoneMode(c *check.C) { 3694 // TODO Windows: Network settings are not currently propagated. This may 3695 // be resolved in the future with the move to libnetwork and CNM. 3696 testRequires(c, DaemonIsLinux) 3697 out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top") 3698 id := strings.TrimSpace(out) 3699 res, err := inspectField(id, "NetworkSettings.Networks.none.IPAddress") 3700 c.Assert(err, check.IsNil) 3701 if res != "" { 3702 c.Fatalf("For 'none' mode network must not be initialized, but container got IP: %s", res) 3703 } 3704 } 3705 3706 func (s *DockerSuite) TestTwoContainersInNetHost(c *check.C) { 3707 // Not applicable as Windows does not support --net=host 3708 testRequires(c, DaemonIsLinux, NotUserNamespace, NotUserNamespace) 3709 dockerCmd(c, "run", "-d", "--net=host", "--name=first", "busybox", "top") 3710 dockerCmd(c, "run", "-d", "--net=host", "--name=second", "busybox", "top") 3711 dockerCmd(c, "stop", "first") 3712 dockerCmd(c, "stop", "second") 3713 } 3714 3715 func (s *DockerSuite) TestContainersInUserDefinedNetwork(c *check.C) { 3716 testRequires(c, DaemonIsLinux, NotUserNamespace) 3717 dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork") 3718 dockerCmd(c, "run", "-d", "--net=testnetwork", "--name=first", "busybox", "top") 3719 c.Assert(waitRun("first"), check.IsNil) 3720 dockerCmd(c, "run", "-t", "--net=testnetwork", "--name=second", "busybox", "ping", "-c", "1", "first") 3721 } 3722 3723 func (s *DockerSuite) TestContainersInMultipleNetworks(c *check.C) { 3724 testRequires(c, DaemonIsLinux, NotUserNamespace) 3725 // Create 2 networks using bridge driver 3726 dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") 3727 dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2") 3728 // Run and connect containers to testnetwork1 3729 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") 3730 c.Assert(waitRun("first"), check.IsNil) 3731 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top") 3732 c.Assert(waitRun("second"), check.IsNil) 3733 // Check connectivity between containers in testnetwork2 3734 dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1") 3735 // Connect containers to testnetwork2 3736 dockerCmd(c, "network", "connect", "testnetwork2", "first") 3737 dockerCmd(c, "network", "connect", "testnetwork2", "second") 3738 // Check connectivity between containers 3739 dockerCmd(c, "exec", "second", "ping", "-c", "1", "first.testnetwork2") 3740 } 3741 3742 func (s *DockerSuite) TestContainersNetworkIsolation(c *check.C) { 3743 testRequires(c, DaemonIsLinux, NotUserNamespace) 3744 // Create 2 networks using bridge driver 3745 dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") 3746 dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2") 3747 // Run 1 container in testnetwork1 and another in testnetwork2 3748 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") 3749 c.Assert(waitRun("first"), check.IsNil) 3750 dockerCmd(c, "run", "-d", "--net=testnetwork2", "--name=second", "busybox", "top") 3751 c.Assert(waitRun("second"), check.IsNil) 3752 3753 // Check Isolation between containers : ping must fail 3754 _, _, err := dockerCmdWithError("exec", "first", "ping", "-c", "1", "second") 3755 c.Assert(err, check.NotNil) 3756 // Connect first container to testnetwork2 3757 dockerCmd(c, "network", "connect", "testnetwork2", "first") 3758 // ping must succeed now 3759 _, _, err = dockerCmdWithError("exec", "first", "ping", "-c", "1", "second") 3760 c.Assert(err, check.IsNil) 3761 3762 // Disconnect first container from testnetwork2 3763 dockerCmd(c, "network", "disconnect", "testnetwork2", "first") 3764 // ping must fail again 3765 _, _, err = dockerCmdWithError("exec", "first", "ping", "-c", "1", "second") 3766 c.Assert(err, check.NotNil) 3767 } 3768 3769 func (s *DockerSuite) TestNetworkRmWithActiveContainers(c *check.C) { 3770 testRequires(c, DaemonIsLinux, NotUserNamespace) 3771 // Create 2 networks using bridge driver 3772 dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") 3773 // Run and connect containers to testnetwork1 3774 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") 3775 c.Assert(waitRun("first"), check.IsNil) 3776 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top") 3777 c.Assert(waitRun("second"), check.IsNil) 3778 // Network delete with active containers must fail 3779 _, _, err := dockerCmdWithError("network", "rm", "testnetwork1") 3780 c.Assert(err, check.NotNil) 3781 3782 dockerCmd(c, "stop", "first") 3783 _, _, err = dockerCmdWithError("network", "rm", "testnetwork1") 3784 c.Assert(err, check.NotNil) 3785 } 3786 3787 func (s *DockerSuite) TestContainerRestartInMultipleNetworks(c *check.C) { 3788 testRequires(c, DaemonIsLinux, NotUserNamespace) 3789 // Create 2 networks using bridge driver 3790 dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") 3791 dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2") 3792 3793 // Run and connect containers to testnetwork1 3794 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") 3795 c.Assert(waitRun("first"), check.IsNil) 3796 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top") 3797 c.Assert(waitRun("second"), check.IsNil) 3798 // Check connectivity between containers in testnetwork2 3799 dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1") 3800 // Connect containers to testnetwork2 3801 dockerCmd(c, "network", "connect", "testnetwork2", "first") 3802 dockerCmd(c, "network", "connect", "testnetwork2", "second") 3803 // Check connectivity between containers 3804 dockerCmd(c, "exec", "second", "ping", "-c", "1", "first.testnetwork2") 3805 3806 // Stop second container and test ping failures on both networks 3807 dockerCmd(c, "stop", "second") 3808 _, _, err := dockerCmdWithError("exec", "first", "ping", "-c", "1", "second.testnetwork1") 3809 c.Assert(err, check.NotNil) 3810 _, _, err = dockerCmdWithError("exec", "first", "ping", "-c", "1", "second.testnetwork2") 3811 c.Assert(err, check.NotNil) 3812 3813 // Start second container and connectivity must be restored on both networks 3814 dockerCmd(c, "start", "second") 3815 dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1") 3816 dockerCmd(c, "exec", "second", "ping", "-c", "1", "first.testnetwork2") 3817 } 3818 3819 func (s *DockerSuite) TestContainerWithConflictingHostNetworks(c *check.C) { 3820 testRequires(c, DaemonIsLinux, NotUserNamespace) 3821 // Run a container with --net=host 3822 dockerCmd(c, "run", "-d", "--net=host", "--name=first", "busybox", "top") 3823 c.Assert(waitRun("first"), check.IsNil) 3824 3825 // Create a network using bridge driver 3826 dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") 3827 3828 // Connecting to the user defined network must fail 3829 _, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "first") 3830 c.Assert(err, check.NotNil) 3831 } 3832 3833 func (s *DockerSuite) TestContainerWithConflictingSharedNetwork(c *check.C) { 3834 testRequires(c, DaemonIsLinux, NotUserNamespace) 3835 dockerCmd(c, "run", "-d", "--name=first", "busybox", "top") 3836 c.Assert(waitRun("first"), check.IsNil) 3837 // Run second container in first container's network namespace 3838 dockerCmd(c, "run", "-d", "--net=container:first", "--name=second", "busybox", "top") 3839 c.Assert(waitRun("second"), check.IsNil) 3840 3841 // Create a network using bridge driver 3842 dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") 3843 3844 // Connecting to the user defined network must fail 3845 out, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "second") 3846 c.Assert(err, check.NotNil) 3847 c.Assert(out, checker.Contains, runconfig.ErrConflictSharedNetwork.Error()) 3848 } 3849 3850 func (s *DockerSuite) TestContainerWithConflictingNoneNetwork(c *check.C) { 3851 testRequires(c, DaemonIsLinux, NotUserNamespace) 3852 dockerCmd(c, "run", "-d", "--net=none", "--name=first", "busybox", "top") 3853 c.Assert(waitRun("first"), check.IsNil) 3854 3855 // Create a network using bridge driver 3856 dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") 3857 3858 // Connecting to the user defined network must fail 3859 out, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "first") 3860 c.Assert(err, check.NotNil) 3861 c.Assert(out, checker.Contains, runconfig.ErrConflictNoNetwork.Error()) 3862 3863 // create a container connected to testnetwork1 3864 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top") 3865 c.Assert(waitRun("second"), check.IsNil) 3866 3867 // Connect second container to none network. it must fail as well 3868 _, _, err = dockerCmdWithError("network", "connect", "none", "second") 3869 c.Assert(err, check.NotNil) 3870 } 3871 3872 // #11957 - stdin with no tty does not exit if stdin is not closed even though container exited 3873 func (s *DockerSuite) TestRunStdinBlockedAfterContainerExit(c *check.C) { 3874 cmd := exec.Command(dockerBinary, "run", "-i", "--name=test", "busybox", "true") 3875 in, err := cmd.StdinPipe() 3876 c.Assert(err, check.IsNil) 3877 defer in.Close() 3878 c.Assert(cmd.Start(), check.IsNil) 3879 3880 waitChan := make(chan error) 3881 go func() { 3882 waitChan <- cmd.Wait() 3883 }() 3884 3885 select { 3886 case err := <-waitChan: 3887 c.Assert(err, check.IsNil) 3888 case <-time.After(30 * time.Second): 3889 c.Fatal("timeout waiting for command to exit") 3890 } 3891 } 3892 3893 func (s *DockerSuite) TestRunWrongCpusetCpusFlagValue(c *check.C) { 3894 // TODO Windows: This needs validation (error out) in the daemon. 3895 testRequires(c, DaemonIsLinux) 3896 out, exitCode, err := dockerCmdWithError("run", "--cpuset-cpus", "1-10,11--", "busybox", "true") 3897 c.Assert(err, check.NotNil) 3898 expected := "Error response from daemon: Invalid value 1-10,11-- for cpuset cpus.\n" 3899 if !(strings.Contains(out, expected) || exitCode == 125) { 3900 c.Fatalf("Expected output to contain %q with exitCode 125, got out: %q exitCode: %v", expected, out, exitCode) 3901 } 3902 } 3903 3904 func (s *DockerSuite) TestRunWrongCpusetMemsFlagValue(c *check.C) { 3905 // TODO Windows: This needs validation (error out) in the daemon. 3906 testRequires(c, DaemonIsLinux) 3907 out, exitCode, err := dockerCmdWithError("run", "--cpuset-mems", "1-42--", "busybox", "true") 3908 c.Assert(err, check.NotNil) 3909 expected := "Error response from daemon: Invalid value 1-42-- for cpuset mems.\n" 3910 if !(strings.Contains(out, expected) || exitCode == 125) { 3911 c.Fatalf("Expected output to contain %q with exitCode 125, got out: %q exitCode: %v", expected, out, exitCode) 3912 } 3913 } 3914 3915 // TestRunNonExecutableCmd checks that 'docker run busybox foo' exits with error code 127' 3916 func (s *DockerSuite) TestRunNonExecutableCmd(c *check.C) { 3917 name := "testNonExecutableCmd" 3918 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "foo") 3919 _, exit, _ := runCommandWithOutput(runCmd) 3920 stateExitCode := findContainerExitCode(c, name) 3921 if !(exit == 127 && strings.Contains(stateExitCode, "127")) { 3922 c.Fatalf("Run non-executable command should have errored with exit code 127, but we got exit: %d, State.ExitCode: %s", exit, stateExitCode) 3923 } 3924 } 3925 3926 // TestRunNonExistingCmd checks that 'docker run busybox /bin/foo' exits with code 127. 3927 func (s *DockerSuite) TestRunNonExistingCmd(c *check.C) { 3928 name := "testNonExistingCmd" 3929 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "/bin/foo") 3930 _, exit, _ := runCommandWithOutput(runCmd) 3931 stateExitCode := findContainerExitCode(c, name) 3932 if !(exit == 127 && strings.Contains(stateExitCode, "127")) { 3933 c.Fatalf("Run non-existing command should have errored with exit code 127, but we got exit: %d, State.ExitCode: %s", exit, stateExitCode) 3934 } 3935 } 3936 3937 // TestCmdCannotBeInvoked checks that 'docker run busybox /etc' exits with 126, or 3938 // 127 on Windows. The difference is that in Windows, the container must be started 3939 // as that's when the check is made (and yes, by it's design...) 3940 func (s *DockerSuite) TestCmdCannotBeInvoked(c *check.C) { 3941 expected := 126 3942 if daemonPlatform == "windows" { 3943 expected = 127 3944 } 3945 name := "testCmdCannotBeInvoked" 3946 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "/etc") 3947 _, exit, _ := runCommandWithOutput(runCmd) 3948 stateExitCode := findContainerExitCode(c, name) 3949 if !(exit == expected && strings.Contains(stateExitCode, strconv.Itoa(expected))) { 3950 c.Fatalf("Run cmd that cannot be invoked should have errored with code %d, but we got exit: %d, State.ExitCode: %s", expected, exit, stateExitCode) 3951 } 3952 } 3953 3954 // TestRunNonExistingImage checks that 'docker run foo' exits with error msg 125 and contains 'Unable to find image' 3955 func (s *DockerSuite) TestRunNonExistingImage(c *check.C) { 3956 runCmd := exec.Command(dockerBinary, "run", "foo") 3957 out, exit, err := runCommandWithOutput(runCmd) 3958 if !(err != nil && exit == 125 && strings.Contains(out, "Unable to find image")) { 3959 c.Fatalf("Run non-existing image should have errored with 'Unable to find image' code 125, but we got out: %s, exit: %d, err: %s", out, exit, err) 3960 } 3961 } 3962 3963 // TestDockerFails checks that 'docker run -foo busybox' exits with 125 to signal docker run failed 3964 func (s *DockerSuite) TestDockerFails(c *check.C) { 3965 runCmd := exec.Command(dockerBinary, "run", "-foo", "busybox") 3966 out, exit, err := runCommandWithOutput(runCmd) 3967 if !(err != nil && exit == 125) { 3968 c.Fatalf("Docker run with flag not defined should exit with 125, but we got out: %s, exit: %d, err: %s", out, exit, err) 3969 } 3970 } 3971 3972 // TestRunInvalidReference invokes docker run with a bad reference. 3973 func (s *DockerSuite) TestRunInvalidReference(c *check.C) { 3974 out, exit, _ := dockerCmdWithError("run", "busybox@foo") 3975 if exit == 0 { 3976 c.Fatalf("expected non-zero exist code; received %d", exit) 3977 } 3978 3979 if !strings.Contains(out, "Error parsing reference") { 3980 c.Fatalf(`Expected "Error parsing reference" in output; got: %s`, out) 3981 } 3982 } 3983 3984 // Test fix for issue #17854 3985 func (s *DockerSuite) TestRunInitLayerPathOwnership(c *check.C) { 3986 // Not applicable on Windows as it does not support Linux uid/gid ownership 3987 testRequires(c, DaemonIsLinux) 3988 name := "testetcfileownership" 3989 _, err := buildImage(name, 3990 `FROM busybox 3991 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 3992 RUN echo 'dockerio:x:1001:' >> /etc/group 3993 RUN chown dockerio:dockerio /etc`, 3994 true) 3995 if err != nil { 3996 c.Fatal(err) 3997 } 3998 3999 // Test that dockerio ownership of /etc is retained at runtime 4000 out, _ := dockerCmd(c, "run", "--rm", name, "stat", "-c", "%U:%G", "/etc") 4001 out = strings.TrimSpace(out) 4002 if out != "dockerio:dockerio" { 4003 c.Fatalf("Wrong /etc ownership: expected dockerio:dockerio, got %q", out) 4004 } 4005 } 4006 4007 func (s *DockerSuite) TestRunWithOomScoreAdj(c *check.C) { 4008 testRequires(c, DaemonIsLinux) 4009 4010 expected := "642" 4011 out, _ := dockerCmd(c, "run", "--oom-score-adj", expected, "busybox", "cat", "/proc/self/oom_score_adj") 4012 oomScoreAdj := strings.TrimSpace(out) 4013 if oomScoreAdj != "642" { 4014 c.Fatalf("Expected oom_score_adj set to %q, got %q instead", expected, oomScoreAdj) 4015 } 4016 } 4017 4018 func (s *DockerSuite) TestRunWithOomScoreAdjInvalidRange(c *check.C) { 4019 testRequires(c, DaemonIsLinux) 4020 4021 out, _, err := dockerCmdWithError("run", "--oom-score-adj", "1001", "busybox", "true") 4022 c.Assert(err, check.NotNil) 4023 expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]." 4024 if !strings.Contains(out, expected) { 4025 c.Fatalf("Expected output to contain %q, got %q instead", expected, out) 4026 } 4027 out, _, err = dockerCmdWithError("run", "--oom-score-adj", "-1001", "busybox", "true") 4028 c.Assert(err, check.NotNil) 4029 expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]." 4030 if !strings.Contains(out, expected) { 4031 c.Fatalf("Expected output to contain %q, got %q instead", expected, out) 4032 } 4033 } 4034 4035 func (s *DockerSuite) TestRunVolumesMountedAsShared(c *check.C) { 4036 // Volume propagation is linux only. Also it creates directories for 4037 // bind mounting, so needs to be same host. 4038 testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace) 4039 4040 // Prepare a source directory to bind mount 4041 tmpDir, err := ioutil.TempDir("", "volume-source") 4042 if err != nil { 4043 c.Fatal(err) 4044 } 4045 defer os.RemoveAll(tmpDir) 4046 4047 if err := os.Mkdir(path.Join(tmpDir, "mnt1"), 0755); err != nil { 4048 c.Fatal(err) 4049 } 4050 4051 // Convert this directory into a shared mount point so that we do 4052 // not rely on propagation properties of parent mount. 4053 cmd := exec.Command("mount", "--bind", tmpDir, tmpDir) 4054 if _, err = runCommand(cmd); err != nil { 4055 c.Fatal(err) 4056 } 4057 4058 cmd = exec.Command("mount", "--make-private", "--make-shared", tmpDir) 4059 if _, err = runCommand(cmd); err != nil { 4060 c.Fatal(err) 4061 } 4062 4063 dockerCmd(c, "run", "--privileged", "-v", fmt.Sprintf("%s:/volume-dest:shared", tmpDir), "busybox", "mount", "--bind", "/volume-dest/mnt1", "/volume-dest/mnt1") 4064 4065 // Make sure a bind mount under a shared volume propagated to host. 4066 if mounted, _ := mount.Mounted(path.Join(tmpDir, "mnt1")); !mounted { 4067 c.Fatalf("Bind mount under shared volume did not propagate to host") 4068 } 4069 4070 mount.Unmount(path.Join(tmpDir, "mnt1")) 4071 } 4072 4073 func (s *DockerSuite) TestRunVolumesMountedAsSlave(c *check.C) { 4074 // Volume propagation is linux only. Also it creates directories for 4075 // bind mounting, so needs to be same host. 4076 testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace) 4077 4078 // Prepare a source directory to bind mount 4079 tmpDir, err := ioutil.TempDir("", "volume-source") 4080 if err != nil { 4081 c.Fatal(err) 4082 } 4083 defer os.RemoveAll(tmpDir) 4084 4085 if err := os.Mkdir(path.Join(tmpDir, "mnt1"), 0755); err != nil { 4086 c.Fatal(err) 4087 } 4088 4089 // Prepare a source directory with file in it. We will bind mount this 4090 // direcotry and see if file shows up. 4091 tmpDir2, err := ioutil.TempDir("", "volume-source2") 4092 if err != nil { 4093 c.Fatal(err) 4094 } 4095 defer os.RemoveAll(tmpDir2) 4096 4097 if err := ioutil.WriteFile(path.Join(tmpDir2, "slave-testfile"), []byte("Test"), 0644); err != nil { 4098 c.Fatal(err) 4099 } 4100 4101 // Convert this directory into a shared mount point so that we do 4102 // not rely on propagation properties of parent mount. 4103 cmd := exec.Command("mount", "--bind", tmpDir, tmpDir) 4104 if _, err = runCommand(cmd); err != nil { 4105 c.Fatal(err) 4106 } 4107 4108 cmd = exec.Command("mount", "--make-private", "--make-shared", tmpDir) 4109 if _, err = runCommand(cmd); err != nil { 4110 c.Fatal(err) 4111 } 4112 4113 dockerCmd(c, "run", "-i", "-d", "--name", "parent", "-v", fmt.Sprintf("%s:/volume-dest:slave", tmpDir), "busybox", "top") 4114 4115 // Bind mount tmpDir2/ onto tmpDir/mnt1. If mount propagates inside 4116 // container then contents of tmpDir2/slave-testfile should become 4117 // visible at "/volume-dest/mnt1/slave-testfile" 4118 cmd = exec.Command("mount", "--bind", tmpDir2, path.Join(tmpDir, "mnt1")) 4119 if _, err = runCommand(cmd); err != nil { 4120 c.Fatal(err) 4121 } 4122 4123 out, _ := dockerCmd(c, "exec", "parent", "cat", "/volume-dest/mnt1/slave-testfile") 4124 4125 mount.Unmount(path.Join(tmpDir, "mnt1")) 4126 4127 if out != "Test" { 4128 c.Fatalf("Bind mount under slave volume did not propagate to container") 4129 } 4130 } 4131 4132 func (s *DockerSuite) TestRunNamedVolumesMountedAsShared(c *check.C) { 4133 testRequires(c, DaemonIsLinux, NotUserNamespace) 4134 out, exitcode, _ := dockerCmdWithError("run", "-v", "foo:/test:shared", "busybox", "touch", "/test/somefile") 4135 4136 if exitcode == 0 { 4137 c.Fatalf("expected non-zero exit code; received %d", exitcode) 4138 } 4139 4140 if expected := "Invalid volume specification"; !strings.Contains(out, expected) { 4141 c.Fatalf(`Expected %q in output; got: %s`, expected, out) 4142 } 4143 } 4144 4145 func (s *DockerSuite) TestRunNamedVolumeCopyImageData(c *check.C) { 4146 testRequires(c, DaemonIsLinux) 4147 4148 testImg := "testvolumecopy" 4149 _, err := buildImage(testImg, ` 4150 FROM busybox 4151 RUN mkdir -p /foo && echo hello > /foo/hello 4152 `, true) 4153 c.Assert(err, check.IsNil) 4154 4155 dockerCmd(c, "run", "-v", "foo:/foo", testImg) 4156 out, _ := dockerCmd(c, "run", "-v", "foo:/foo", "busybox", "cat", "/foo/hello") 4157 c.Assert(strings.TrimSpace(out), check.Equals, "hello") 4158 } 4159 4160 func (s *DockerSuite) TestRunNamedVolumeNotRemoved(c *check.C) { 4161 prefix := "" 4162 if daemonPlatform == "windows" { 4163 prefix = "c:" 4164 } 4165 4166 dockerCmd(c, "volume", "create", "--name", "test") 4167 4168 dockerCmd(c, "run", "--rm", "-v", "test:"+prefix+"/foo", "-v", prefix+"/bar", "busybox", "true") 4169 dockerCmd(c, "volume", "inspect", "test") 4170 out, _ := dockerCmd(c, "volume", "ls", "-q") 4171 c.Assert(strings.TrimSpace(out), checker.Equals, "test") 4172 4173 dockerCmd(c, "run", "--name=test", "-v", "test:"+prefix+"/foo", "-v", prefix+"/bar", "busybox", "true") 4174 dockerCmd(c, "rm", "-fv", "test") 4175 dockerCmd(c, "volume", "inspect", "test") 4176 out, _ = dockerCmd(c, "volume", "ls", "-q") 4177 c.Assert(strings.TrimSpace(out), checker.Equals, "test") 4178 } 4179 4180 func (s *DockerSuite) TestRunNamedVolumesFromNotRemoved(c *check.C) { 4181 prefix := "" 4182 if daemonPlatform == "windows" { 4183 prefix = "c:" 4184 } 4185 4186 dockerCmd(c, "volume", "create", "--name", "test") 4187 dockerCmd(c, "run", "--name=parent", "-v", "test:"+prefix+"/foo", "-v", prefix+"/bar", "busybox", "true") 4188 dockerCmd(c, "run", "--name=child", "--volumes-from=parent", "busybox", "true") 4189 4190 // Remove the parent so there are not other references to the volumes 4191 dockerCmd(c, "rm", "-f", "parent") 4192 // now remove the child and ensure the named volume (and only the named volume) still exists 4193 dockerCmd(c, "rm", "-fv", "child") 4194 dockerCmd(c, "volume", "inspect", "test") 4195 out, _ := dockerCmd(c, "volume", "ls", "-q") 4196 c.Assert(strings.TrimSpace(out), checker.Equals, "test") 4197 }