github.com/nalind/docker@v1.5.0/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 "testing" 20 "time" 21 22 "github.com/docker/docker/nat" 23 "github.com/docker/docker/pkg/networkfs/resolvconf" 24 ) 25 26 // "test123" should be printed by docker run 27 func TestRunEchoStdout(t *testing.T) { 28 runCmd := exec.Command(dockerBinary, "run", "busybox", "echo", "test123") 29 out, _, _, err := runCommandWithStdoutStderr(runCmd) 30 if err != nil { 31 t.Fatalf("failed to run container: %v, output: %q", err, out) 32 } 33 34 if out != "test123\n" { 35 t.Errorf("container should've printed 'test123'") 36 } 37 38 deleteAllContainers() 39 40 logDone("run - echo test123") 41 } 42 43 // "test" should be printed 44 func TestRunEchoStdoutWithMemoryLimit(t *testing.T) { 45 runCmd := exec.Command(dockerBinary, "run", "-m", "16m", "busybox", "echo", "test") 46 out, _, _, err := runCommandWithStdoutStderr(runCmd) 47 if err != nil { 48 t.Fatalf("failed to run container: %v, output: %q", err, out) 49 } 50 51 out = strings.Trim(out, "\r\n") 52 53 if expected := "test"; out != expected { 54 t.Errorf("container should've printed %q but printed %q", expected, out) 55 56 } 57 58 deleteAllContainers() 59 60 logDone("run - echo with memory limit") 61 } 62 63 // "test" should be printed 64 func TestRunEchoStdoutWitCPULimit(t *testing.T) { 65 runCmd := exec.Command(dockerBinary, "run", "-c", "1000", "busybox", "echo", "test") 66 out, _, _, err := runCommandWithStdoutStderr(runCmd) 67 if err != nil { 68 t.Fatalf("failed to run container: %v, output: %q", err, out) 69 } 70 71 if out != "test\n" { 72 t.Errorf("container should've printed 'test'") 73 } 74 75 deleteAllContainers() 76 77 logDone("run - echo with CPU limit") 78 } 79 80 // "test" should be printed 81 func TestRunEchoStdoutWithCPUAndMemoryLimit(t *testing.T) { 82 runCmd := exec.Command(dockerBinary, "run", "-c", "1000", "-m", "16m", "busybox", "echo", "test") 83 out, _, _, err := runCommandWithStdoutStderr(runCmd) 84 if err != nil { 85 t.Fatalf("failed to run container: %v, output: %q", err, out) 86 } 87 88 if out != "test\n" { 89 t.Errorf("container should've printed 'test', got %q instead", out) 90 } 91 92 deleteAllContainers() 93 94 logDone("run - echo with CPU and memory limit") 95 } 96 97 // "test" should be printed 98 func TestRunEchoNamedContainer(t *testing.T) { 99 runCmd := exec.Command(dockerBinary, "run", "--name", "testfoonamedcontainer", "busybox", "echo", "test") 100 out, _, _, err := runCommandWithStdoutStderr(runCmd) 101 if err != nil { 102 t.Fatalf("failed to run container: %v, output: %q", err, out) 103 } 104 105 if out != "test\n" { 106 t.Errorf("container should've printed 'test'") 107 } 108 109 if err := deleteContainer("testfoonamedcontainer"); err != nil { 110 t.Errorf("failed to remove the named container: %v", err) 111 } 112 113 deleteAllContainers() 114 115 logDone("run - echo with named container") 116 } 117 118 // docker run should not leak file descriptors 119 func TestRunLeakyFileDescriptors(t *testing.T) { 120 runCmd := exec.Command(dockerBinary, "run", "busybox", "ls", "-C", "/proc/self/fd") 121 out, _, _, err := runCommandWithStdoutStderr(runCmd) 122 if err != nil { 123 t.Fatalf("failed to run container: %v, output: %q", err, out) 124 } 125 126 // normally, we should only get 0, 1, and 2, but 3 gets created by "ls" when it does "opendir" on the "fd" directory 127 if out != "0 1 2 3\n" { 128 t.Errorf("container should've printed '0 1 2 3', not: %s", out) 129 } 130 131 deleteAllContainers() 132 133 logDone("run - check file descriptor leakage") 134 } 135 136 // it should be possible to ping Google DNS resolver 137 // this will fail when Internet access is unavailable 138 func TestRunPingGoogle(t *testing.T) { 139 runCmd := exec.Command(dockerBinary, "run", "busybox", "ping", "-c", "1", "8.8.8.8") 140 out, _, _, err := runCommandWithStdoutStderr(runCmd) 141 if err != nil { 142 t.Fatalf("failed to run container: %v, output: %q", err, out) 143 } 144 145 deleteAllContainers() 146 147 logDone("run - ping 8.8.8.8") 148 } 149 150 // the exit code should be 0 151 // some versions of lxc might make this test fail 152 func TestRunExitCodeZero(t *testing.T) { 153 runCmd := exec.Command(dockerBinary, "run", "busybox", "true") 154 if out, _, err := runCommandWithOutput(runCmd); err != nil { 155 t.Errorf("container should've exited with exit code 0: %s, %v", out, err) 156 } 157 158 deleteAllContainers() 159 160 logDone("run - exit with 0") 161 } 162 163 // the exit code should be 1 164 // some versions of lxc might make this test fail 165 func TestRunExitCodeOne(t *testing.T) { 166 runCmd := exec.Command(dockerBinary, "run", "busybox", "false") 167 exitCode, err := runCommand(runCmd) 168 if err != nil && !strings.Contains("exit status 1", fmt.Sprintf("%s", err)) { 169 t.Fatal(err) 170 } 171 if exitCode != 1 { 172 t.Errorf("container should've exited with exit code 1") 173 } 174 175 deleteAllContainers() 176 177 logDone("run - exit with 1") 178 } 179 180 // it should be possible to pipe in data via stdin to a process running in a container 181 // some versions of lxc might make this test fail 182 func TestRunStdinPipe(t *testing.T) { 183 runCmd := exec.Command("bash", "-c", `echo "blahblah" | docker run -i -a stdin busybox cat`) 184 out, _, _, err := runCommandWithStdoutStderr(runCmd) 185 if err != nil { 186 t.Fatalf("failed to run container: %v, output: %q", err, out) 187 } 188 189 out = stripTrailingCharacters(out) 190 191 inspectCmd := exec.Command(dockerBinary, "inspect", out) 192 if out, _, err := runCommandWithOutput(inspectCmd); err != nil { 193 t.Fatalf("out should've been a container id: %s %v", out, err) 194 } 195 196 waitCmd := exec.Command(dockerBinary, "wait", out) 197 if waitOut, _, err := runCommandWithOutput(waitCmd); err != nil { 198 t.Fatalf("error thrown while waiting for container: %s, %v", waitOut, err) 199 } 200 201 logsCmd := exec.Command(dockerBinary, "logs", out) 202 logsOut, _, err := runCommandWithOutput(logsCmd) 203 if err != nil { 204 t.Fatalf("error thrown while trying to get container logs: %s, %v", logsOut, err) 205 } 206 207 containerLogs := stripTrailingCharacters(logsOut) 208 209 if containerLogs != "blahblah" { 210 t.Errorf("logs didn't print the container's logs %s", containerLogs) 211 } 212 213 rmCmd := exec.Command(dockerBinary, "rm", out) 214 if out, _, err = runCommandWithOutput(rmCmd); err != nil { 215 t.Fatalf("rm failed to remove container: %s, %v", out, err) 216 } 217 218 deleteAllContainers() 219 220 logDone("run - pipe in with -i -a stdin") 221 } 222 223 // the container's ID should be printed when starting a container in detached mode 224 func TestRunDetachedContainerIDPrinting(t *testing.T) { 225 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true") 226 out, _, _, err := runCommandWithStdoutStderr(runCmd) 227 if err != nil { 228 t.Fatalf("failed to run container: %v, output: %q", err, out) 229 } 230 231 out = stripTrailingCharacters(out) 232 233 inspectCmd := exec.Command(dockerBinary, "inspect", out) 234 if inspectOut, _, err := runCommandWithOutput(inspectCmd); err != nil { 235 t.Fatalf("out should've been a container id: %s %v", inspectOut, err) 236 } 237 238 waitCmd := exec.Command(dockerBinary, "wait", out) 239 if waitOut, _, err := runCommandWithOutput(waitCmd); err != nil { 240 t.Fatalf("error thrown while waiting for container: %s, %v", waitOut, err) 241 } 242 243 rmCmd := exec.Command(dockerBinary, "rm", out) 244 rmOut, _, err := runCommandWithOutput(rmCmd) 245 if err != nil { 246 t.Fatalf("rm failed to remove container: %s, %v", rmOut, err) 247 } 248 249 rmOut = stripTrailingCharacters(rmOut) 250 if rmOut != out { 251 t.Errorf("rm didn't print the container ID %s %s", out, rmOut) 252 } 253 254 deleteAllContainers() 255 256 logDone("run - print container ID in detached mode") 257 } 258 259 // the working directory should be set correctly 260 func TestRunWorkingDirectory(t *testing.T) { 261 runCmd := exec.Command(dockerBinary, "run", "-w", "/root", "busybox", "pwd") 262 out, _, _, err := runCommandWithStdoutStderr(runCmd) 263 if err != nil { 264 t.Fatalf("failed to run container: %v, output: %q", err, out) 265 } 266 267 out = stripTrailingCharacters(out) 268 269 if out != "/root" { 270 t.Errorf("-w failed to set working directory") 271 } 272 273 runCmd = exec.Command(dockerBinary, "run", "--workdir", "/root", "busybox", "pwd") 274 out, _, _, err = runCommandWithStdoutStderr(runCmd) 275 if err != nil { 276 t.Fatal(out, err) 277 } 278 279 out = stripTrailingCharacters(out) 280 281 if out != "/root" { 282 t.Errorf("--workdir failed to set working directory") 283 } 284 285 deleteAllContainers() 286 287 logDone("run - run with working directory set by -w") 288 logDone("run - run with working directory set by --workdir") 289 } 290 291 // pinging Google's DNS resolver should fail when we disable the networking 292 func TestRunWithoutNetworking(t *testing.T) { 293 runCmd := exec.Command(dockerBinary, "run", "--net=none", "busybox", "ping", "-c", "1", "8.8.8.8") 294 out, _, exitCode, err := runCommandWithStdoutStderr(runCmd) 295 if err != nil && exitCode != 1 { 296 t.Fatal(out, err) 297 } 298 if exitCode != 1 { 299 t.Errorf("--net=none should've disabled the network; the container shouldn't have been able to ping 8.8.8.8") 300 } 301 302 runCmd = exec.Command(dockerBinary, "run", "-n=false", "busybox", "ping", "-c", "1", "8.8.8.8") 303 out, _, exitCode, err = runCommandWithStdoutStderr(runCmd) 304 if err != nil && exitCode != 1 { 305 t.Fatal(out, err) 306 } 307 if exitCode != 1 { 308 t.Errorf("-n=false should've disabled the network; the container shouldn't have been able to ping 8.8.8.8") 309 } 310 311 deleteAllContainers() 312 313 logDone("run - disable networking with --net=none") 314 logDone("run - disable networking with -n=false") 315 } 316 317 //test --link use container name to link target 318 func TestRunLinksContainerWithContainerName(t *testing.T) { 319 cmd := exec.Command(dockerBinary, "run", "-i", "-t", "-d", "--name", "parent", "busybox") 320 out, _, _, err := runCommandWithStdoutStderr(cmd) 321 if err != nil { 322 t.Fatalf("failed to run container: %v, output: %q", err, out) 323 } 324 cmd = exec.Command(dockerBinary, "inspect", "-f", "{{.NetworkSettings.IPAddress}}", "parent") 325 ip, _, _, err := runCommandWithStdoutStderr(cmd) 326 if err != nil { 327 t.Fatalf("failed to inspect container: %v, output: %q", err, ip) 328 } 329 ip = strings.TrimSpace(ip) 330 cmd = exec.Command(dockerBinary, "run", "--link", "parent:test", "busybox", "/bin/cat", "/etc/hosts") 331 out, _, err = runCommandWithOutput(cmd) 332 if err != nil { 333 t.Fatalf("failed to run container: %v, output: %q", err, out) 334 } 335 if !strings.Contains(out, ip+" test") { 336 t.Fatalf("use a container name to link target failed") 337 } 338 deleteAllContainers() 339 340 logDone("run - use a container name to link target work") 341 } 342 343 //test --link use container id to link target 344 func TestRunLinksContainerWithContainerId(t *testing.T) { 345 cmd := exec.Command(dockerBinary, "run", "-i", "-t", "-d", "busybox") 346 cID, _, _, err := runCommandWithStdoutStderr(cmd) 347 if err != nil { 348 t.Fatalf("failed to run container: %v, output: %q", err, cID) 349 } 350 cID = strings.TrimSpace(cID) 351 cmd = exec.Command(dockerBinary, "inspect", "-f", "{{.NetworkSettings.IPAddress}}", cID) 352 ip, _, _, err := runCommandWithStdoutStderr(cmd) 353 if err != nil { 354 t.Fatalf("faild to inspect container: %v, output: %q", err, ip) 355 } 356 ip = strings.TrimSpace(ip) 357 cmd = exec.Command(dockerBinary, "run", "--link", cID+":test", "busybox", "/bin/cat", "/etc/hosts") 358 out, _, err := runCommandWithOutput(cmd) 359 if err != nil { 360 t.Fatalf("failed to run container: %v, output: %q", err, out) 361 } 362 if !strings.Contains(out, ip+" test") { 363 t.Fatalf("use a container id to link target failed") 364 } 365 366 deleteAllContainers() 367 368 logDone("run - use a container id to link target work") 369 } 370 371 // Regression test for #4741 372 func TestRunWithVolumesAsFiles(t *testing.T) { 373 runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", "/etc/hosts:/target-file", "busybox", "true") 374 out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd) 375 if err != nil && exitCode != 0 { 376 t.Fatal("1", out, stderr, err) 377 } 378 379 runCmd = exec.Command(dockerBinary, "run", "--volumes-from", "test-data", "busybox", "cat", "/target-file") 380 out, stderr, exitCode, err = runCommandWithStdoutStderr(runCmd) 381 if err != nil && exitCode != 0 { 382 t.Fatal("2", out, stderr, err) 383 } 384 deleteAllContainers() 385 386 logDone("run - regression test for #4741 - volumes from as files") 387 } 388 389 // Regression test for #4979 390 func TestRunWithVolumesFromExited(t *testing.T) { 391 runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", "/some/dir", "busybox", "touch", "/some/dir/file") 392 out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd) 393 if err != nil && exitCode != 0 { 394 t.Fatal("1", out, stderr, err) 395 } 396 397 runCmd = exec.Command(dockerBinary, "run", "--volumes-from", "test-data", "busybox", "cat", "/some/dir/file") 398 out, stderr, exitCode, err = runCommandWithStdoutStderr(runCmd) 399 if err != nil && exitCode != 0 { 400 t.Fatal("2", out, stderr, err) 401 } 402 deleteAllContainers() 403 404 logDone("run - regression test for #4979 - volumes-from on exited container") 405 } 406 407 // Regression test for #4830 408 func TestRunWithRelativePath(t *testing.T) { 409 runCmd := exec.Command(dockerBinary, "run", "-v", "tmp:/other-tmp", "busybox", "true") 410 if _, _, _, err := runCommandWithStdoutStderr(runCmd); err == nil { 411 t.Fatalf("relative path should result in an error") 412 } 413 414 deleteAllContainers() 415 416 logDone("run - volume with relative path") 417 } 418 419 func TestRunVolumesMountedAsReadonly(t *testing.T) { 420 cmd := exec.Command(dockerBinary, "run", "-v", "/test:/test:ro", "busybox", "touch", "/test/somefile") 421 if code, err := runCommand(cmd); err == nil || code == 0 { 422 t.Fatalf("run should fail because volume is ro: exit code %d", code) 423 } 424 425 deleteAllContainers() 426 427 logDone("run - volumes as readonly mount") 428 } 429 430 func TestRunVolumesFromInReadonlyMode(t *testing.T) { 431 defer deleteAllContainers() 432 cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "true") 433 if _, err := runCommand(cmd); err != nil { 434 t.Fatal(err) 435 } 436 437 cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent:ro", "busybox", "touch", "/test/file") 438 if code, err := runCommand(cmd); err == nil || code == 0 { 439 t.Fatalf("run should fail because volume is ro: exit code %d", code) 440 } 441 442 logDone("run - volumes from as readonly mount") 443 } 444 445 // Regression test for #1201 446 func TestRunVolumesFromInReadWriteMode(t *testing.T) { 447 defer deleteAllContainers() 448 cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "true") 449 if _, err := runCommand(cmd); err != nil { 450 t.Fatal(err) 451 } 452 453 cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent:rw", "busybox", "touch", "/test/file") 454 if out, _, err := runCommandWithOutput(cmd); err != nil { 455 t.Fatalf("running --volumes-from parent:rw failed with output: %q\nerror: %v", out, err) 456 } 457 458 cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent:bar", "busybox", "touch", "/test/file") 459 if out, _, err := runCommandWithOutput(cmd); err == nil || !strings.Contains(out, "invalid mode for volumes-from: bar") { 460 t.Fatalf("running --volumes-from foo:bar should have failed with invalid mount mode: %q", out) 461 } 462 463 cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent", "busybox", "touch", "/test/file") 464 if out, _, err := runCommandWithOutput(cmd); err != nil { 465 t.Fatalf("running --volumes-from parent failed with output: %q\nerror: %v", out, err) 466 } 467 468 logDone("run - volumes from as read write mount") 469 } 470 471 func TestVolumesFromGetsProperMode(t *testing.T) { 472 defer deleteAllContainers() 473 cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test:/test:ro", "busybox", "true") 474 if _, err := runCommand(cmd); err != nil { 475 t.Fatal(err) 476 } 477 // Expect this "rw" mode to be be ignored since the inheritted volume is "ro" 478 cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent:rw", "busybox", "touch", "/test/file") 479 if _, err := runCommand(cmd); err == nil { 480 t.Fatal("Expected volumes-from to inherit read-only volume even when passing in `rw`") 481 } 482 483 cmd = exec.Command(dockerBinary, "run", "--name", "parent2", "-v", "/test:/test:ro", "busybox", "true") 484 if _, err := runCommand(cmd); err != nil { 485 t.Fatal(err) 486 } 487 // Expect this to be read-only since both are "ro" 488 cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent2:ro", "busybox", "touch", "/test/file") 489 if _, err := runCommand(cmd); err == nil { 490 t.Fatal("Expected volumes-from to inherit read-only volume even when passing in `ro`") 491 } 492 493 logDone("run - volumes from ignores `rw` if inherrited volume is `ro`") 494 } 495 496 // Test for #1351 497 func TestRunApplyVolumesFromBeforeVolumes(t *testing.T) { 498 cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "touch", "/test/foo") 499 if _, err := runCommand(cmd); err != nil { 500 t.Fatal(err) 501 } 502 503 cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent", "-v", "/test", "busybox", "cat", "/test/foo") 504 if out, _, err := runCommandWithOutput(cmd); err != nil { 505 t.Fatal(out, err) 506 } 507 508 deleteAllContainers() 509 510 logDone("run - volumes from mounted first") 511 } 512 513 func TestRunMultipleVolumesFrom(t *testing.T) { 514 cmd := exec.Command(dockerBinary, "run", "--name", "parent1", "-v", "/test", "busybox", "touch", "/test/foo") 515 if _, err := runCommand(cmd); err != nil { 516 t.Fatal(err) 517 } 518 519 cmd = exec.Command(dockerBinary, "run", "--name", "parent2", "-v", "/other", "busybox", "touch", "/other/bar") 520 if _, err := runCommand(cmd); err != nil { 521 t.Fatal(err) 522 } 523 524 cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent1", "--volumes-from", "parent2", 525 "busybox", "sh", "-c", "cat /test/foo && cat /other/bar") 526 if _, err := runCommand(cmd); err != nil { 527 t.Fatal(err) 528 } 529 530 deleteAllContainers() 531 532 logDone("run - multiple volumes from") 533 } 534 535 // this tests verifies the ID format for the container 536 func TestRunVerifyContainerID(t *testing.T) { 537 cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true") 538 out, exit, err := runCommandWithOutput(cmd) 539 if err != nil { 540 t.Fatal(err) 541 } 542 if exit != 0 { 543 t.Fatalf("expected exit code 0 received %d", exit) 544 } 545 match, err := regexp.MatchString("^[0-9a-f]{64}$", strings.TrimSuffix(out, "\n")) 546 if err != nil { 547 t.Fatal(err) 548 } 549 if !match { 550 t.Fatalf("Invalid container ID: %s", out) 551 } 552 553 deleteAllContainers() 554 555 logDone("run - verify container ID") 556 } 557 558 // Test that creating a container with a volume doesn't crash. Regression test for #995. 559 func TestRunCreateVolume(t *testing.T) { 560 cmd := exec.Command(dockerBinary, "run", "-v", "/var/lib/data", "busybox", "true") 561 if _, err := runCommand(cmd); err != nil { 562 t.Fatal(err) 563 } 564 565 deleteAllContainers() 566 567 logDone("run - create docker managed volume") 568 } 569 570 // Test that creating a volume with a symlink in its path works correctly. Test for #5152. 571 // Note that this bug happens only with symlinks with a target that starts with '/'. 572 func TestRunCreateVolumeWithSymlink(t *testing.T) { 573 buildCmd := exec.Command(dockerBinary, "build", "-t", "docker-test-createvolumewithsymlink", "-") 574 buildCmd.Stdin = strings.NewReader(`FROM busybox 575 RUN mkdir /foo && ln -s /foo /bar`) 576 buildCmd.Dir = workingDirectory 577 err := buildCmd.Run() 578 if err != nil { 579 t.Fatalf("could not build 'docker-test-createvolumewithsymlink': %v", err) 580 } 581 582 cmd := exec.Command(dockerBinary, "run", "-v", "/bar/foo", "--name", "test-createvolumewithsymlink", "docker-test-createvolumewithsymlink", "sh", "-c", "mount | grep -q /foo/foo") 583 exitCode, err := runCommand(cmd) 584 if err != nil || exitCode != 0 { 585 t.Fatalf("[run] err: %v, exitcode: %d", err, exitCode) 586 } 587 588 var volPath string 589 cmd = exec.Command(dockerBinary, "inspect", "-f", "{{range .Volumes}}{{.}}{{end}}", "test-createvolumewithsymlink") 590 volPath, exitCode, err = runCommandWithOutput(cmd) 591 if err != nil || exitCode != 0 { 592 t.Fatalf("[inspect] err: %v, exitcode: %d", err, exitCode) 593 } 594 595 cmd = exec.Command(dockerBinary, "rm", "-v", "test-createvolumewithsymlink") 596 exitCode, err = runCommand(cmd) 597 if err != nil || exitCode != 0 { 598 t.Fatalf("[rm] err: %v, exitcode: %d", err, exitCode) 599 } 600 601 f, err := os.Open(volPath) 602 defer f.Close() 603 if !os.IsNotExist(err) { 604 t.Fatalf("[open] (expecting 'file does not exist' error) err: %v, volPath: %s", err, volPath) 605 } 606 607 deleteImages("docker-test-createvolumewithsymlink") 608 deleteAllContainers() 609 610 logDone("run - create volume with symlink") 611 } 612 613 // Tests that a volume path that has a symlink exists in a container mounting it with `--volumes-from`. 614 func TestRunVolumesFromSymlinkPath(t *testing.T) { 615 name := "docker-test-volumesfromsymlinkpath" 616 buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-") 617 buildCmd.Stdin = strings.NewReader(`FROM busybox 618 RUN mkdir /baz && ln -s /baz /foo 619 VOLUME ["/foo/bar"]`) 620 buildCmd.Dir = workingDirectory 621 err := buildCmd.Run() 622 if err != nil { 623 t.Fatalf("could not build 'docker-test-volumesfromsymlinkpath': %v", err) 624 } 625 626 cmd := exec.Command(dockerBinary, "run", "--name", "test-volumesfromsymlinkpath", name) 627 exitCode, err := runCommand(cmd) 628 if err != nil || exitCode != 0 { 629 t.Fatalf("[run] (volume) err: %v, exitcode: %d", err, exitCode) 630 } 631 632 cmd = exec.Command(dockerBinary, "run", "--volumes-from", "test-volumesfromsymlinkpath", "busybox", "sh", "-c", "ls /foo | grep -q bar") 633 exitCode, err = runCommand(cmd) 634 if err != nil || exitCode != 0 { 635 t.Fatalf("[run] err: %v, exitcode: %d", err, exitCode) 636 } 637 638 deleteAllContainers() 639 deleteImages(name) 640 641 logDone("run - volumes-from symlink path") 642 } 643 644 func TestRunExitCode(t *testing.T) { 645 cmd := exec.Command(dockerBinary, "run", "busybox", "/bin/sh", "-c", "exit 72") 646 647 exit, err := runCommand(cmd) 648 if err == nil { 649 t.Fatal("should not have a non nil error") 650 } 651 if exit != 72 { 652 t.Fatalf("expected exit code 72 received %d", exit) 653 } 654 655 deleteAllContainers() 656 657 logDone("run - correct exit code") 658 } 659 660 func TestRunUserDefaultsToRoot(t *testing.T) { 661 cmd := exec.Command(dockerBinary, "run", "busybox", "id") 662 663 out, _, err := runCommandWithOutput(cmd) 664 if err != nil { 665 t.Fatal(err, out) 666 } 667 if !strings.Contains(out, "uid=0(root) gid=0(root)") { 668 t.Fatalf("expected root user got %s", out) 669 } 670 deleteAllContainers() 671 672 logDone("run - default user") 673 } 674 675 func TestRunUserByName(t *testing.T) { 676 cmd := exec.Command(dockerBinary, "run", "-u", "root", "busybox", "id") 677 678 out, _, err := runCommandWithOutput(cmd) 679 if err != nil { 680 t.Fatal(err, out) 681 } 682 if !strings.Contains(out, "uid=0(root) gid=0(root)") { 683 t.Fatalf("expected root user got %s", out) 684 } 685 deleteAllContainers() 686 687 logDone("run - user by name") 688 } 689 690 func TestRunUserByID(t *testing.T) { 691 cmd := exec.Command(dockerBinary, "run", "-u", "1", "busybox", "id") 692 693 out, _, err := runCommandWithOutput(cmd) 694 if err != nil { 695 t.Fatal(err, out) 696 } 697 if !strings.Contains(out, "uid=1(daemon) gid=1(daemon)") { 698 t.Fatalf("expected daemon user got %s", out) 699 } 700 deleteAllContainers() 701 702 logDone("run - user by id") 703 } 704 705 func TestRunUserByIDBig(t *testing.T) { 706 cmd := exec.Command(dockerBinary, "run", "-u", "2147483648", "busybox", "id") 707 708 out, _, err := runCommandWithOutput(cmd) 709 if err == nil { 710 t.Fatal("No error, but must be.", out) 711 } 712 if !strings.Contains(out, "Uids and gids must be in range") { 713 t.Fatalf("expected error about uids range, got %s", out) 714 } 715 deleteAllContainers() 716 717 logDone("run - user by id, id too big") 718 } 719 720 func TestRunUserByIDNegative(t *testing.T) { 721 cmd := exec.Command(dockerBinary, "run", "-u", "-1", "busybox", "id") 722 723 out, _, err := runCommandWithOutput(cmd) 724 if err == nil { 725 t.Fatal("No error, but must be.", out) 726 } 727 if !strings.Contains(out, "Uids and gids must be in range") { 728 t.Fatalf("expected error about uids range, got %s", out) 729 } 730 deleteAllContainers() 731 732 logDone("run - user by id, id negative") 733 } 734 735 func TestRunUserByIDZero(t *testing.T) { 736 cmd := exec.Command(dockerBinary, "run", "-u", "0", "busybox", "id") 737 738 out, _, err := runCommandWithOutput(cmd) 739 if err != nil { 740 t.Fatal(err, out) 741 } 742 if !strings.Contains(out, "uid=0(root) gid=0(root) groups=10(wheel)") { 743 t.Fatalf("expected daemon user got %s", out) 744 } 745 deleteAllContainers() 746 747 logDone("run - user by id, zero uid") 748 } 749 750 func TestRunUserNotFound(t *testing.T) { 751 cmd := exec.Command(dockerBinary, "run", "-u", "notme", "busybox", "id") 752 753 _, err := runCommand(cmd) 754 if err == nil { 755 t.Fatal("unknown user should cause container to fail") 756 } 757 deleteAllContainers() 758 759 logDone("run - user not found") 760 } 761 762 func TestRunTwoConcurrentContainers(t *testing.T) { 763 group := sync.WaitGroup{} 764 group.Add(2) 765 766 for i := 0; i < 2; i++ { 767 go func() { 768 defer group.Done() 769 cmd := exec.Command(dockerBinary, "run", "busybox", "sleep", "2") 770 if _, err := runCommand(cmd); err != nil { 771 t.Fatal(err) 772 } 773 }() 774 } 775 776 group.Wait() 777 778 deleteAllContainers() 779 780 logDone("run - two concurrent containers") 781 } 782 783 func TestRunEnvironment(t *testing.T) { 784 cmd := exec.Command(dockerBinary, "run", "-h", "testing", "-e=FALSE=true", "-e=TRUE", "-e=TRICKY", "-e=HOME=", "busybox", "env") 785 cmd.Env = append(os.Environ(), 786 "TRUE=false", 787 "TRICKY=tri\ncky\n", 788 ) 789 790 out, _, err := runCommandWithOutput(cmd) 791 if err != nil { 792 t.Fatal(err, out) 793 } 794 795 actualEnv := strings.Split(strings.TrimSpace(out), "\n") 796 sort.Strings(actualEnv) 797 798 goodEnv := []string{ 799 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 800 "HOSTNAME=testing", 801 "FALSE=true", 802 "TRUE=false", 803 "TRICKY=tri", 804 "cky", 805 "", 806 "HOME=/root", 807 } 808 sort.Strings(goodEnv) 809 if len(goodEnv) != len(actualEnv) { 810 t.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", ")) 811 } 812 for i := range goodEnv { 813 if actualEnv[i] != goodEnv[i] { 814 t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i]) 815 } 816 } 817 818 deleteAllContainers() 819 820 logDone("run - verify environment") 821 } 822 823 func TestRunEnvironmentErase(t *testing.T) { 824 // Test to make sure that when we use -e on env vars that are 825 // not set in our local env that they're removed (if present) in 826 // the container 827 cmd := exec.Command(dockerBinary, "run", "-e", "FOO", "-e", "HOSTNAME", "busybox", "env") 828 cmd.Env = []string{} 829 out, _, err := runCommandWithOutput(cmd) 830 if err != nil { 831 t.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=/root", 840 } 841 sort.Strings(goodEnv) 842 if len(goodEnv) != len(actualEnv) { 843 t.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", ")) 844 } 845 for i := range goodEnv { 846 if actualEnv[i] != goodEnv[i] { 847 t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i]) 848 } 849 } 850 851 deleteAllContainers() 852 853 logDone("run - verify environment erase") 854 } 855 856 func TestRunEnvironmentOverride(t *testing.T) { 857 // Test to make sure that when we use -e on env vars that are 858 // already in the env that we're overriding them 859 cmd := exec.Command(dockerBinary, "run", "-e", "HOSTNAME", "-e", "HOME=/root2", "busybox", "env") 860 cmd.Env = []string{"HOSTNAME=bar"} 861 out, _, err := runCommandWithOutput(cmd) 862 if err != nil { 863 t.Fatal(err, out) 864 } 865 866 actualEnv := strings.Split(strings.TrimSpace(out), "\n") 867 sort.Strings(actualEnv) 868 869 goodEnv := []string{ 870 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 871 "HOME=/root2", 872 "HOSTNAME=bar", 873 } 874 sort.Strings(goodEnv) 875 if len(goodEnv) != len(actualEnv) { 876 t.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", ")) 877 } 878 for i := range goodEnv { 879 if actualEnv[i] != goodEnv[i] { 880 t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i]) 881 } 882 } 883 884 deleteAllContainers() 885 886 logDone("run - verify environment override") 887 } 888 889 func TestRunContainerNetwork(t *testing.T) { 890 cmd := exec.Command(dockerBinary, "run", "busybox", "ping", "-c", "1", "127.0.0.1") 891 if _, err := runCommand(cmd); err != nil { 892 t.Fatal(err) 893 } 894 895 deleteAllContainers() 896 897 logDone("run - test container network via ping") 898 } 899 900 // Issue #4681 901 func TestRunLoopbackWhenNetworkDisabled(t *testing.T) { 902 cmd := exec.Command(dockerBinary, "run", "--net=none", "busybox", "ping", "-c", "1", "127.0.0.1") 903 if _, err := runCommand(cmd); err != nil { 904 t.Fatal(err) 905 } 906 907 deleteAllContainers() 908 909 logDone("run - test container loopback when networking disabled") 910 } 911 912 func TestRunNetHostNotAllowedWithLinks(t *testing.T) { 913 _, _, err := dockerCmd(t, "run", "--name", "linked", "busybox", "true") 914 915 cmd := exec.Command(dockerBinary, "run", "--net=host", "--link", "linked:linked", "busybox", "true") 916 _, _, err = runCommandWithOutput(cmd) 917 if err == nil { 918 t.Fatal("Expected error") 919 } 920 921 deleteAllContainers() 922 923 logDone("run - don't allow --net=host to be used with links") 924 } 925 926 func TestRunLoopbackOnlyExistsWhenNetworkingDisabled(t *testing.T) { 927 cmd := exec.Command(dockerBinary, "run", "--net=none", "busybox", "ip", "-o", "-4", "a", "show", "up") 928 out, _, err := runCommandWithOutput(cmd) 929 if err != nil { 930 t.Fatal(err, out) 931 } 932 933 var ( 934 count = 0 935 parts = strings.Split(out, "\n") 936 ) 937 938 for _, l := range parts { 939 if l != "" { 940 count++ 941 } 942 } 943 944 if count != 1 { 945 t.Fatalf("Wrong interface count in container %d", count) 946 } 947 948 if !strings.HasPrefix(out, "1: lo") { 949 t.Fatalf("Wrong interface in test container: expected [1: lo], got %s", out) 950 } 951 952 deleteAllContainers() 953 954 logDone("run - test loopback only exists when networking disabled") 955 } 956 957 // #7851 hostname outside container shows FQDN, inside only shortname 958 // For testing purposes it is not required to set host's hostname directly 959 // and use "--net=host" (as the original issue submitter did), as the same 960 // codepath is executed with "docker run -h <hostname>". Both were manually 961 // tested, but this testcase takes the simpler path of using "run -h .." 962 func TestRunFullHostnameSet(t *testing.T) { 963 cmd := exec.Command(dockerBinary, "run", "-h", "foo.bar.baz", "busybox", "hostname") 964 out, _, err := runCommandWithOutput(cmd) 965 if err != nil { 966 t.Fatal(err, out) 967 } 968 969 if actual := strings.Trim(out, "\r\n"); actual != "foo.bar.baz" { 970 t.Fatalf("expected hostname 'foo.bar.baz', received %s", actual) 971 } 972 deleteAllContainers() 973 974 logDone("run - test fully qualified hostname set with -h") 975 } 976 977 func TestRunPrivilegedCanMknod(t *testing.T) { 978 cmd := exec.Command(dockerBinary, "run", "--privileged", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 979 out, _, err := runCommandWithOutput(cmd) 980 if err != nil { 981 t.Fatal(err) 982 } 983 984 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 985 t.Fatalf("expected output ok received %s", actual) 986 } 987 deleteAllContainers() 988 989 logDone("run - test privileged can mknod") 990 } 991 992 func TestRunUnPrivilegedCanMknod(t *testing.T) { 993 cmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 994 out, _, err := runCommandWithOutput(cmd) 995 if err != nil { 996 t.Fatal(err) 997 } 998 999 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 1000 t.Fatalf("expected output ok received %s", actual) 1001 } 1002 deleteAllContainers() 1003 1004 logDone("run - test un-privileged can mknod") 1005 } 1006 1007 func TestRunCapDropInvalid(t *testing.T) { 1008 defer deleteAllContainers() 1009 cmd := exec.Command(dockerBinary, "run", "--cap-drop=CHPASS", "busybox", "ls") 1010 out, _, err := runCommandWithOutput(cmd) 1011 if err == nil { 1012 t.Fatal(err, out) 1013 } 1014 1015 logDone("run - test --cap-drop=CHPASS invalid") 1016 } 1017 1018 func TestRunCapDropCannotMknod(t *testing.T) { 1019 cmd := exec.Command(dockerBinary, "run", "--cap-drop=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 1020 out, _, err := runCommandWithOutput(cmd) 1021 if err == nil { 1022 t.Fatal(err, out) 1023 } 1024 1025 if actual := strings.Trim(out, "\r\n"); actual == "ok" { 1026 t.Fatalf("expected output not ok received %s", actual) 1027 } 1028 deleteAllContainers() 1029 1030 logDone("run - test --cap-drop=MKNOD cannot mknod") 1031 } 1032 1033 func TestRunCapDropCannotMknodLowerCase(t *testing.T) { 1034 cmd := exec.Command(dockerBinary, "run", "--cap-drop=mknod", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 1035 out, _, err := runCommandWithOutput(cmd) 1036 if err == nil { 1037 t.Fatal(err, out) 1038 } 1039 1040 if actual := strings.Trim(out, "\r\n"); actual == "ok" { 1041 t.Fatalf("expected output not ok received %s", actual) 1042 } 1043 deleteAllContainers() 1044 1045 logDone("run - test --cap-drop=mknod cannot mknod lowercase") 1046 } 1047 1048 func TestRunCapDropALLCannotMknod(t *testing.T) { 1049 cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL", "--cap-add=SETGID", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 1050 out, _, err := runCommandWithOutput(cmd) 1051 if err == nil { 1052 t.Fatal(err, out) 1053 } 1054 1055 if actual := strings.Trim(out, "\r\n"); actual == "ok" { 1056 t.Fatalf("expected output not ok received %s", actual) 1057 } 1058 deleteAllContainers() 1059 1060 logDone("run - test --cap-drop=ALL cannot mknod") 1061 } 1062 1063 func TestRunCapDropALLAddMknodCanMknod(t *testing.T) { 1064 cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL", "--cap-add=MKNOD", "--cap-add=SETGID", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") 1065 out, _, err := runCommandWithOutput(cmd) 1066 if err != nil { 1067 t.Fatal(err, out) 1068 } 1069 1070 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 1071 t.Fatalf("expected output ok received %s", actual) 1072 } 1073 deleteAllContainers() 1074 1075 logDone("run - test --cap-drop=ALL --cap-add=MKNOD can mknod") 1076 } 1077 1078 func TestRunCapAddInvalid(t *testing.T) { 1079 defer deleteAllContainers() 1080 1081 cmd := exec.Command(dockerBinary, "run", "--cap-add=CHPASS", "busybox", "ls") 1082 out, _, err := runCommandWithOutput(cmd) 1083 if err == nil { 1084 t.Fatal(err, out) 1085 } 1086 1087 logDone("run - test --cap-add=CHPASS invalid") 1088 } 1089 1090 func TestRunCapAddCanDownInterface(t *testing.T) { 1091 cmd := exec.Command(dockerBinary, "run", "--cap-add=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") 1092 out, _, err := runCommandWithOutput(cmd) 1093 if err != nil { 1094 t.Fatal(err, out) 1095 } 1096 1097 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 1098 t.Fatalf("expected output ok received %s", actual) 1099 } 1100 deleteAllContainers() 1101 1102 logDone("run - test --cap-add=NET_ADMIN can set eth0 down") 1103 } 1104 1105 func TestRunCapAddALLCanDownInterface(t *testing.T) { 1106 cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") 1107 out, _, err := runCommandWithOutput(cmd) 1108 if err != nil { 1109 t.Fatal(err, out) 1110 } 1111 1112 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 1113 t.Fatalf("expected output ok received %s", actual) 1114 } 1115 deleteAllContainers() 1116 1117 logDone("run - test --cap-add=ALL can set eth0 down") 1118 } 1119 1120 func TestRunCapAddALLDropNetAdminCanDownInterface(t *testing.T) { 1121 cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL", "--cap-drop=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") 1122 out, _, err := runCommandWithOutput(cmd) 1123 if err == nil { 1124 t.Fatal(err, out) 1125 } 1126 1127 if actual := strings.Trim(out, "\r\n"); actual == "ok" { 1128 t.Fatalf("expected output not ok received %s", actual) 1129 } 1130 deleteAllContainers() 1131 1132 logDone("run - test --cap-add=ALL --cap-drop=NET_ADMIN cannot set eth0 down") 1133 } 1134 1135 func TestRunPrivilegedCanMount(t *testing.T) { 1136 cmd := exec.Command(dockerBinary, "run", "--privileged", "busybox", "sh", "-c", "mount -t tmpfs none /tmp && echo ok") 1137 1138 out, _, err := runCommandWithOutput(cmd) 1139 if err != nil { 1140 t.Fatal(err) 1141 } 1142 1143 if actual := strings.Trim(out, "\r\n"); actual != "ok" { 1144 t.Fatalf("expected output ok received %s", actual) 1145 } 1146 deleteAllContainers() 1147 1148 logDone("run - test privileged can mount") 1149 } 1150 1151 func TestRunUnPrivilegedCannotMount(t *testing.T) { 1152 cmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "mount -t tmpfs none /tmp && echo ok") 1153 1154 out, _, err := runCommandWithOutput(cmd) 1155 if err == nil { 1156 t.Fatal(err, out) 1157 } 1158 1159 if actual := strings.Trim(out, "\r\n"); actual == "ok" { 1160 t.Fatalf("expected output not ok received %s", actual) 1161 } 1162 deleteAllContainers() 1163 1164 logDone("run - test un-privileged cannot mount") 1165 } 1166 1167 func TestRunSysNotWritableInNonPrivilegedContainers(t *testing.T) { 1168 cmd := exec.Command(dockerBinary, "run", "busybox", "touch", "/sys/kernel/profiling") 1169 if code, err := runCommand(cmd); err == nil || code == 0 { 1170 t.Fatal("sys should not be writable in a non privileged container") 1171 } 1172 1173 deleteAllContainers() 1174 1175 logDone("run - sys not writable in non privileged container") 1176 } 1177 1178 func TestRunSysWritableInPrivilegedContainers(t *testing.T) { 1179 cmd := exec.Command(dockerBinary, "run", "--privileged", "busybox", "touch", "/sys/kernel/profiling") 1180 if code, err := runCommand(cmd); err != nil || code != 0 { 1181 t.Fatalf("sys should be writable in privileged container") 1182 } 1183 1184 deleteAllContainers() 1185 1186 logDone("run - sys writable in privileged container") 1187 } 1188 1189 func TestRunProcNotWritableInNonPrivilegedContainers(t *testing.T) { 1190 cmd := exec.Command(dockerBinary, "run", "busybox", "touch", "/proc/sysrq-trigger") 1191 if code, err := runCommand(cmd); err == nil || code == 0 { 1192 t.Fatal("proc should not be writable in a non privileged container") 1193 } 1194 1195 deleteAllContainers() 1196 1197 logDone("run - proc not writable in non privileged container") 1198 } 1199 1200 func TestRunProcWritableInPrivilegedContainers(t *testing.T) { 1201 cmd := exec.Command(dockerBinary, "run", "--privileged", "busybox", "touch", "/proc/sysrq-trigger") 1202 if code, err := runCommand(cmd); err != nil || code != 0 { 1203 t.Fatalf("proc should be writable in privileged container") 1204 } 1205 1206 deleteAllContainers() 1207 1208 logDone("run - proc writable in privileged container") 1209 } 1210 1211 func TestRunWithCpuset(t *testing.T) { 1212 cmd := exec.Command(dockerBinary, "run", "--cpuset", "0", "busybox", "true") 1213 if code, err := runCommand(cmd); err != nil || code != 0 { 1214 t.Fatalf("container should run successfuly with cpuset of 0: %s", err) 1215 } 1216 1217 deleteAllContainers() 1218 1219 logDone("run - cpuset 0") 1220 } 1221 1222 func TestRunDeviceNumbers(t *testing.T) { 1223 cmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "ls -l /dev/null") 1224 1225 out, _, err := runCommandWithOutput(cmd) 1226 if err != nil { 1227 t.Fatal(err, out) 1228 } 1229 deviceLineFields := strings.Fields(out) 1230 deviceLineFields[6] = "" 1231 deviceLineFields[7] = "" 1232 deviceLineFields[8] = "" 1233 expected := []string{"crw-rw-rw-", "1", "root", "root", "1,", "3", "", "", "", "/dev/null"} 1234 1235 if !(reflect.DeepEqual(deviceLineFields, expected)) { 1236 t.Fatalf("expected output\ncrw-rw-rw- 1 root root 1, 3 May 24 13:29 /dev/null\n received\n %s\n", out) 1237 } 1238 deleteAllContainers() 1239 1240 logDone("run - test device numbers") 1241 } 1242 1243 func TestRunThatCharacterDevicesActLikeCharacterDevices(t *testing.T) { 1244 cmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "dd if=/dev/zero of=/zero bs=1k count=5 2> /dev/null ; du -h /zero") 1245 1246 out, _, err := runCommandWithOutput(cmd) 1247 if err != nil { 1248 t.Fatal(err, out) 1249 } 1250 1251 if actual := strings.Trim(out, "\r\n"); actual[0] == '0' { 1252 t.Fatalf("expected a new file called /zero to be create that is greater than 0 bytes long, but du says: %s", actual) 1253 } 1254 deleteAllContainers() 1255 1256 logDone("run - test that character devices work.") 1257 } 1258 1259 func TestRunUnprivilegedWithChroot(t *testing.T) { 1260 cmd := exec.Command(dockerBinary, "run", "busybox", "chroot", "/", "true") 1261 1262 if _, err := runCommand(cmd); err != nil { 1263 t.Fatal(err) 1264 } 1265 1266 deleteAllContainers() 1267 1268 logDone("run - unprivileged with chroot") 1269 } 1270 1271 func TestRunAddingOptionalDevices(t *testing.T) { 1272 cmd := exec.Command(dockerBinary, "run", "--device", "/dev/zero:/dev/nulo", "busybox", "sh", "-c", "ls /dev/nulo") 1273 1274 out, _, err := runCommandWithOutput(cmd) 1275 if err != nil { 1276 t.Fatal(err, out) 1277 } 1278 1279 if actual := strings.Trim(out, "\r\n"); actual != "/dev/nulo" { 1280 t.Fatalf("expected output /dev/nulo, received %s", actual) 1281 } 1282 deleteAllContainers() 1283 1284 logDone("run - test --device argument") 1285 } 1286 1287 func TestRunModeHostname(t *testing.T) { 1288 cmd := exec.Command(dockerBinary, "run", "-h=testhostname", "busybox", "cat", "/etc/hostname") 1289 1290 out, _, err := runCommandWithOutput(cmd) 1291 if err != nil { 1292 t.Fatal(err, out) 1293 } 1294 1295 if actual := strings.Trim(out, "\r\n"); actual != "testhostname" { 1296 t.Fatalf("expected 'testhostname', but says: %q", actual) 1297 } 1298 1299 cmd = exec.Command(dockerBinary, "run", "--net=host", "busybox", "cat", "/etc/hostname") 1300 1301 out, _, err = runCommandWithOutput(cmd) 1302 if err != nil { 1303 t.Fatal(err, out) 1304 } 1305 hostname, err := os.Hostname() 1306 if err != nil { 1307 t.Fatal(err) 1308 } 1309 if actual := strings.Trim(out, "\r\n"); actual != hostname { 1310 t.Fatalf("expected %q, but says: %q", hostname, actual) 1311 } 1312 1313 deleteAllContainers() 1314 1315 logDone("run - hostname and several network modes") 1316 } 1317 1318 func TestRunRootWorkdir(t *testing.T) { 1319 s, _, err := dockerCmd(t, "run", "--workdir", "/", "busybox", "pwd") 1320 if err != nil { 1321 t.Fatal(s, err) 1322 } 1323 if s != "/\n" { 1324 t.Fatalf("pwd returned %q (expected /\\n)", s) 1325 } 1326 1327 deleteAllContainers() 1328 1329 logDone("run - workdir /") 1330 } 1331 1332 func TestRunAllowBindMountingRoot(t *testing.T) { 1333 s, _, err := dockerCmd(t, "run", "-v", "/:/host", "busybox", "ls", "/host") 1334 if err != nil { 1335 t.Fatal(s, err) 1336 } 1337 1338 deleteAllContainers() 1339 1340 logDone("run - bind mount / as volume") 1341 } 1342 1343 func TestRunDisallowBindMountingRootToRoot(t *testing.T) { 1344 cmd := exec.Command(dockerBinary, "run", "-v", "/:/", "busybox", "ls", "/host") 1345 out, _, err := runCommandWithOutput(cmd) 1346 if err == nil { 1347 t.Fatal(out, err) 1348 } 1349 1350 deleteAllContainers() 1351 1352 logDone("run - bind mount /:/ as volume should fail") 1353 } 1354 1355 // Verify that a container gets default DNS when only localhost resolvers exist 1356 func TestRunDnsDefaultOptions(t *testing.T) { 1357 1358 // preserve original resolv.conf for restoring after test 1359 origResolvConf, err := ioutil.ReadFile("/etc/resolv.conf") 1360 if os.IsNotExist(err) { 1361 t.Fatalf("/etc/resolv.conf does not exist") 1362 } 1363 // defer restored original conf 1364 defer func() { 1365 if err := ioutil.WriteFile("/etc/resolv.conf", origResolvConf, 0644); err != nil { 1366 t.Fatal(err) 1367 } 1368 }() 1369 1370 // test 3 cases: standard IPv4 localhost, commented out localhost, and IPv6 localhost 1371 // 2 are removed from the file at container start, and the 3rd (commented out) one is ignored by 1372 // GetNameservers(), leading to a replacement of nameservers with the default set 1373 tmpResolvConf := []byte("nameserver 127.0.0.1\n#nameserver 127.0.2.1\nnameserver ::1") 1374 if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil { 1375 t.Fatal(err) 1376 } 1377 1378 cmd := exec.Command(dockerBinary, "run", "busybox", "cat", "/etc/resolv.conf") 1379 1380 actual, _, err := runCommandWithOutput(cmd) 1381 if err != nil { 1382 t.Fatal(err, actual) 1383 } 1384 1385 // check that the actual defaults are appended to the commented out 1386 // localhost resolver (which should be preserved) 1387 // NOTE: if we ever change the defaults from google dns, this will break 1388 expected := "#nameserver 127.0.2.1\n\nnameserver 8.8.8.8\nnameserver 8.8.4.4" 1389 if actual != expected { 1390 t.Fatalf("expected resolv.conf be: %q, but was: %q", expected, actual) 1391 } 1392 1393 deleteAllContainers() 1394 1395 logDone("run - dns default options") 1396 } 1397 1398 func TestRunDnsOptions(t *testing.T) { 1399 cmd := exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "--dns-search=mydomain", "busybox", "cat", "/etc/resolv.conf") 1400 1401 out, _, err := runCommandWithOutput(cmd) 1402 if err != nil { 1403 t.Fatal(err, out) 1404 } 1405 1406 actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1) 1407 if actual != "nameserver 127.0.0.1 search mydomain" { 1408 t.Fatalf("expected 'nameserver 127.0.0.1 search mydomain', but says: %q", actual) 1409 } 1410 1411 cmd = exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "--dns-search=.", "busybox", "cat", "/etc/resolv.conf") 1412 1413 out, _, err = runCommandWithOutput(cmd) 1414 if err != nil { 1415 t.Fatal(err, out) 1416 } 1417 1418 actual = strings.Replace(strings.Trim(strings.Trim(out, "\r\n"), " "), "\n", " ", -1) 1419 if actual != "nameserver 127.0.0.1" { 1420 t.Fatalf("expected 'nameserver 127.0.0.1', but says: %q", actual) 1421 } 1422 1423 logDone("run - dns options") 1424 } 1425 1426 func TestRunDnsOptionsBasedOnHostResolvConf(t *testing.T) { 1427 var out string 1428 1429 origResolvConf, err := ioutil.ReadFile("/etc/resolv.conf") 1430 if os.IsNotExist(err) { 1431 t.Fatalf("/etc/resolv.conf does not exist") 1432 } 1433 1434 hostNamservers := resolvconf.GetNameservers(origResolvConf) 1435 hostSearch := resolvconf.GetSearchDomains(origResolvConf) 1436 1437 cmd := exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "busybox", "cat", "/etc/resolv.conf") 1438 1439 if out, _, err = runCommandWithOutput(cmd); err != nil { 1440 t.Fatal(err, out) 1441 } 1442 1443 if actualNameservers := resolvconf.GetNameservers([]byte(out)); string(actualNameservers[0]) != "127.0.0.1" { 1444 t.Fatalf("expected '127.0.0.1', but says: %q", string(actualNameservers[0])) 1445 } 1446 1447 actualSearch := resolvconf.GetSearchDomains([]byte(out)) 1448 if len(actualSearch) != len(hostSearch) { 1449 t.Fatalf("expected %q search domain(s), but it has: %q", len(hostSearch), len(actualSearch)) 1450 } 1451 for i := range actualSearch { 1452 if actualSearch[i] != hostSearch[i] { 1453 t.Fatalf("expected %q domain, but says: %q", actualSearch[i], hostSearch[i]) 1454 } 1455 } 1456 1457 cmd = exec.Command(dockerBinary, "run", "--dns-search=mydomain", "busybox", "cat", "/etc/resolv.conf") 1458 1459 if out, _, err = runCommandWithOutput(cmd); err != nil { 1460 t.Fatal(err, out) 1461 } 1462 1463 actualNameservers := resolvconf.GetNameservers([]byte(out)) 1464 if len(actualNameservers) != len(hostNamservers) { 1465 t.Fatalf("expected %q nameserver(s), but it has: %q", len(hostNamservers), len(actualNameservers)) 1466 } 1467 for i := range actualNameservers { 1468 if actualNameservers[i] != hostNamservers[i] { 1469 t.Fatalf("expected %q nameserver, but says: %q", actualNameservers[i], hostNamservers[i]) 1470 } 1471 } 1472 1473 if actualSearch = resolvconf.GetSearchDomains([]byte(out)); string(actualSearch[0]) != "mydomain" { 1474 t.Fatalf("expected 'mydomain', but says: %q", string(actualSearch[0])) 1475 } 1476 1477 // test with file 1478 tmpResolvConf := []byte("search example.com\nnameserver 12.34.56.78\nnameserver 127.0.0.1") 1479 if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil { 1480 t.Fatal(err) 1481 } 1482 // put the old resolvconf back 1483 defer func() { 1484 if err := ioutil.WriteFile("/etc/resolv.conf", origResolvConf, 0644); err != nil { 1485 t.Fatal(err) 1486 } 1487 }() 1488 1489 resolvConf, err := ioutil.ReadFile("/etc/resolv.conf") 1490 if os.IsNotExist(err) { 1491 t.Fatalf("/etc/resolv.conf does not exist") 1492 } 1493 1494 hostNamservers = resolvconf.GetNameservers(resolvConf) 1495 hostSearch = resolvconf.GetSearchDomains(resolvConf) 1496 1497 cmd = exec.Command(dockerBinary, "run", "busybox", "cat", "/etc/resolv.conf") 1498 1499 if out, _, err = runCommandWithOutput(cmd); err != nil { 1500 t.Fatal(err, out) 1501 } 1502 1503 if actualNameservers = resolvconf.GetNameservers([]byte(out)); string(actualNameservers[0]) != "12.34.56.78" || len(actualNameservers) != 1 { 1504 t.Fatalf("expected '12.34.56.78', but has: %v", actualNameservers) 1505 } 1506 1507 actualSearch = resolvconf.GetSearchDomains([]byte(out)) 1508 if len(actualSearch) != len(hostSearch) { 1509 t.Fatalf("expected %q search domain(s), but it has: %q", len(hostSearch), len(actualSearch)) 1510 } 1511 for i := range actualSearch { 1512 if actualSearch[i] != hostSearch[i] { 1513 t.Fatalf("expected %q domain, but says: %q", actualSearch[i], hostSearch[i]) 1514 } 1515 } 1516 1517 deleteAllContainers() 1518 1519 logDone("run - dns options based on host resolv.conf") 1520 } 1521 1522 // Test the file watch notifier on docker host's /etc/resolv.conf 1523 // A go-routine is responsible for auto-updating containers which are 1524 // stopped and have an unmodified copy of resolv.conf, as well as 1525 // marking running containers as requiring an update on next restart 1526 func TestRunResolvconfUpdater(t *testing.T) { 1527 1528 tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78") 1529 tmpLocalhostResolvConf := []byte("nameserver 127.0.0.1") 1530 1531 //take a copy of resolv.conf for restoring after test completes 1532 resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf") 1533 if err != nil { 1534 t.Fatal(err) 1535 } 1536 1537 //cleanup 1538 defer func() { 1539 deleteAllContainers() 1540 if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { 1541 t.Fatal(err) 1542 } 1543 }() 1544 1545 //1. test that a non-running container gets an updated resolv.conf 1546 cmd := exec.Command(dockerBinary, "run", "--name='first'", "busybox", "true") 1547 if _, err := runCommand(cmd); err != nil { 1548 t.Fatal(err) 1549 } 1550 containerID1, err := getIDByName("first") 1551 if err != nil { 1552 t.Fatal(err) 1553 } 1554 1555 // replace resolv.conf with our temporary copy 1556 bytesResolvConf := []byte(tmpResolvConf) 1557 if err := ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil { 1558 t.Fatal(err) 1559 } 1560 1561 time.Sleep(time.Second / 2) 1562 // check for update in container 1563 containerResolv, err := readContainerFile(containerID1, "resolv.conf") 1564 if err != nil { 1565 t.Fatal(err) 1566 } 1567 if !bytes.Equal(containerResolv, bytesResolvConf) { 1568 t.Fatalf("Stopped container does not have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv)) 1569 } 1570 1571 //2. test that a non-running container does not receive resolv.conf updates 1572 // if it modified the container copy of the starting point resolv.conf 1573 cmd = exec.Command(dockerBinary, "run", "--name='second'", "busybox", "sh", "-c", "echo 'search mylittlepony.com' >>/etc/resolv.conf") 1574 if _, err = runCommand(cmd); err != nil { 1575 t.Fatal(err) 1576 } 1577 containerID2, err := getIDByName("second") 1578 if err != nil { 1579 t.Fatal(err) 1580 } 1581 containerResolvHashBefore, err := readContainerFile(containerID2, "resolv.conf.hash") 1582 if err != nil { 1583 t.Fatal(err) 1584 } 1585 1586 //make a change to resolv.conf (in this case replacing our tmp copy with orig copy) 1587 if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { 1588 t.Fatal(err) 1589 } 1590 1591 time.Sleep(time.Second / 2) 1592 containerResolvHashAfter, err := readContainerFile(containerID2, "resolv.conf.hash") 1593 if err != nil { 1594 t.Fatal(err) 1595 } 1596 1597 if !bytes.Equal(containerResolvHashBefore, containerResolvHashAfter) { 1598 t.Fatalf("Stopped container with modified resolv.conf should not have been updated; expected hash: %v, new hash: %v", containerResolvHashBefore, containerResolvHashAfter) 1599 } 1600 1601 //3. test that a running container's resolv.conf is not modified while running 1602 cmd = exec.Command(dockerBinary, "run", "-d", "busybox", "top") 1603 out, _, err := runCommandWithOutput(cmd) 1604 if err != nil { 1605 t.Fatal(err) 1606 } 1607 runningContainerID := strings.TrimSpace(out) 1608 1609 containerResolvHashBefore, err = readContainerFile(runningContainerID, "resolv.conf.hash") 1610 if err != nil { 1611 t.Fatal(err) 1612 } 1613 1614 // replace resolv.conf 1615 if err := ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil { 1616 t.Fatal(err) 1617 } 1618 1619 // make sure the updater has time to run to validate we really aren't 1620 // getting updated 1621 time.Sleep(time.Second / 2) 1622 containerResolvHashAfter, err = readContainerFile(runningContainerID, "resolv.conf.hash") 1623 if err != nil { 1624 t.Fatal(err) 1625 } 1626 1627 if !bytes.Equal(containerResolvHashBefore, containerResolvHashAfter) { 1628 t.Fatalf("Running container's resolv.conf should not be updated; expected hash: %v, new hash: %v", containerResolvHashBefore, containerResolvHashAfter) 1629 } 1630 1631 //4. test that a running container's resolv.conf is updated upon restart 1632 // (the above container is still running..) 1633 cmd = exec.Command(dockerBinary, "restart", runningContainerID) 1634 if _, err = runCommand(cmd); err != nil { 1635 t.Fatal(err) 1636 } 1637 1638 // check for update in container 1639 containerResolv, err = readContainerFile(runningContainerID, "resolv.conf") 1640 if err != nil { 1641 t.Fatal(err) 1642 } 1643 if !bytes.Equal(containerResolv, bytesResolvConf) { 1644 t.Fatalf("Restarted container should have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv)) 1645 } 1646 1647 //5. test that additions of a localhost resolver are cleaned from 1648 // host resolv.conf before updating container's resolv.conf copies 1649 1650 // replace resolv.conf with a localhost-only nameserver copy 1651 bytesResolvConf = []byte(tmpLocalhostResolvConf) 1652 if err = ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil { 1653 t.Fatal(err) 1654 } 1655 1656 time.Sleep(time.Second / 2) 1657 // our first exited container ID should have been updated, but with default DNS 1658 // after the cleanup of resolv.conf found only a localhost nameserver: 1659 containerResolv, err = readContainerFile(containerID1, "resolv.conf") 1660 if err != nil { 1661 t.Fatal(err) 1662 } 1663 1664 expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4" 1665 if !bytes.Equal(containerResolv, []byte(expected)) { 1666 t.Fatalf("Container does not have cleaned/replaced DNS in resolv.conf; expected %q, got %q", expected, string(containerResolv)) 1667 } 1668 1669 //cleanup, restore original resolv.conf happens in defer func() 1670 logDone("run - resolv.conf updater") 1671 } 1672 1673 func TestRunAddHost(t *testing.T) { 1674 defer deleteAllContainers() 1675 cmd := exec.Command(dockerBinary, "run", "--add-host=extra:86.75.30.9", "busybox", "grep", "extra", "/etc/hosts") 1676 1677 out, _, err := runCommandWithOutput(cmd) 1678 if err != nil { 1679 t.Fatal(err, out) 1680 } 1681 1682 actual := strings.Trim(out, "\r\n") 1683 if actual != "86.75.30.9\textra" { 1684 t.Fatalf("expected '86.75.30.9\textra', but says: %q", actual) 1685 } 1686 1687 logDone("run - add-host option") 1688 } 1689 1690 // Regression test for #6983 1691 func TestRunAttachStdErrOnlyTTYMode(t *testing.T) { 1692 cmd := exec.Command(dockerBinary, "run", "-t", "-a", "stderr", "busybox", "true") 1693 1694 exitCode, err := runCommand(cmd) 1695 if err != nil { 1696 t.Fatal(err) 1697 } else if exitCode != 0 { 1698 t.Fatalf("Container should have exited with error code 0") 1699 } 1700 1701 deleteAllContainers() 1702 1703 logDone("run - Attach stderr only with -t") 1704 } 1705 1706 // Regression test for #6983 1707 func TestRunAttachStdOutOnlyTTYMode(t *testing.T) { 1708 cmd := exec.Command(dockerBinary, "run", "-t", "-a", "stdout", "busybox", "true") 1709 1710 exitCode, err := runCommand(cmd) 1711 if err != nil { 1712 t.Fatal(err) 1713 } else if exitCode != 0 { 1714 t.Fatalf("Container should have exited with error code 0") 1715 } 1716 1717 deleteAllContainers() 1718 1719 logDone("run - Attach stdout only with -t") 1720 } 1721 1722 // Regression test for #6983 1723 func TestRunAttachStdOutAndErrTTYMode(t *testing.T) { 1724 cmd := exec.Command(dockerBinary, "run", "-t", "-a", "stdout", "-a", "stderr", "busybox", "true") 1725 1726 exitCode, err := runCommand(cmd) 1727 if err != nil { 1728 t.Fatal(err) 1729 } else if exitCode != 0 { 1730 t.Fatalf("Container should have exited with error code 0") 1731 } 1732 1733 deleteAllContainers() 1734 1735 logDone("run - Attach stderr and stdout with -t") 1736 } 1737 1738 func TestRunState(t *testing.T) { 1739 defer deleteAllContainers() 1740 cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 1741 1742 out, _, err := runCommandWithOutput(cmd) 1743 if err != nil { 1744 t.Fatal(err, out) 1745 } 1746 id := strings.TrimSpace(out) 1747 state, err := inspectField(id, "State.Running") 1748 if err != nil { 1749 t.Fatal(err) 1750 } 1751 if state != "true" { 1752 t.Fatal("Container state is 'not running'") 1753 } 1754 pid1, err := inspectField(id, "State.Pid") 1755 if err != nil { 1756 t.Fatal(err) 1757 } 1758 if pid1 == "0" { 1759 t.Fatal("Container state Pid 0") 1760 } 1761 1762 cmd = exec.Command(dockerBinary, "stop", id) 1763 out, _, err = runCommandWithOutput(cmd) 1764 if err != nil { 1765 t.Fatal(err, out) 1766 } 1767 state, err = inspectField(id, "State.Running") 1768 if err != nil { 1769 t.Fatal(err) 1770 } 1771 if state != "false" { 1772 t.Fatal("Container state is 'running'") 1773 } 1774 pid2, err := inspectField(id, "State.Pid") 1775 if err != nil { 1776 t.Fatal(err) 1777 } 1778 if pid2 == pid1 { 1779 t.Fatalf("Container state Pid %s, but expected %s", pid2, pid1) 1780 } 1781 1782 cmd = exec.Command(dockerBinary, "start", id) 1783 out, _, err = runCommandWithOutput(cmd) 1784 if err != nil { 1785 t.Fatal(err, out) 1786 } 1787 state, err = inspectField(id, "State.Running") 1788 if err != nil { 1789 t.Fatal(err) 1790 } 1791 if state != "true" { 1792 t.Fatal("Container state is 'not running'") 1793 } 1794 pid3, err := inspectField(id, "State.Pid") 1795 if err != nil { 1796 t.Fatal(err) 1797 } 1798 if pid3 == pid1 { 1799 t.Fatalf("Container state Pid %s, but expected %s", pid2, pid1) 1800 } 1801 logDone("run - test container state.") 1802 } 1803 1804 // Test for #1737 1805 func TestRunCopyVolumeUidGid(t *testing.T) { 1806 name := "testrunvolumesuidgid" 1807 defer deleteImages(name) 1808 defer deleteAllContainers() 1809 _, err := buildImage(name, 1810 `FROM busybox 1811 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1812 RUN echo 'dockerio:x:1001:' >> /etc/group 1813 RUN mkdir -p /hello && touch /hello/test && chown dockerio.dockerio /hello`, 1814 true) 1815 if err != nil { 1816 t.Fatal(err) 1817 } 1818 1819 // Test that the uid and gid is copied from the image to the volume 1820 cmd := exec.Command(dockerBinary, "run", "--rm", "-v", "/hello", name, "sh", "-c", "ls -l / | grep hello | awk '{print $3\":\"$4}'") 1821 out, _, err := runCommandWithOutput(cmd) 1822 if err != nil { 1823 t.Fatal(err, out) 1824 } 1825 out = strings.TrimSpace(out) 1826 if out != "dockerio:dockerio" { 1827 t.Fatalf("Wrong /hello ownership: %s, expected dockerio:dockerio", out) 1828 } 1829 1830 logDone("run - copy uid/gid for volume") 1831 } 1832 1833 // Test for #1582 1834 func TestRunCopyVolumeContent(t *testing.T) { 1835 name := "testruncopyvolumecontent" 1836 defer deleteImages(name) 1837 defer deleteAllContainers() 1838 _, err := buildImage(name, 1839 `FROM busybox 1840 RUN mkdir -p /hello/local && echo hello > /hello/local/world`, 1841 true) 1842 if err != nil { 1843 t.Fatal(err) 1844 } 1845 1846 // Test that the content is copied from the image to the volume 1847 cmd := exec.Command(dockerBinary, "run", "--rm", "-v", "/hello", name, "find", "/hello") 1848 out, _, err := runCommandWithOutput(cmd) 1849 if err != nil { 1850 t.Fatal(err, out) 1851 } 1852 if !(strings.Contains(out, "/hello/local/world") && strings.Contains(out, "/hello/local")) { 1853 t.Fatal("Container failed to transfer content to volume") 1854 } 1855 logDone("run - copy volume content") 1856 } 1857 1858 func TestRunCleanupCmdOnEntrypoint(t *testing.T) { 1859 name := "testrunmdcleanuponentrypoint" 1860 defer deleteImages(name) 1861 defer deleteAllContainers() 1862 if _, err := buildImage(name, 1863 `FROM busybox 1864 ENTRYPOINT ["echo"] 1865 CMD ["testingpoint"]`, 1866 true); err != nil { 1867 t.Fatal(err) 1868 } 1869 runCmd := exec.Command(dockerBinary, "run", "--entrypoint", "whoami", name) 1870 out, exit, err := runCommandWithOutput(runCmd) 1871 if err != nil { 1872 t.Fatalf("Error: %v, out: %q", err, out) 1873 } 1874 if exit != 0 { 1875 t.Fatalf("expected exit code 0 received %d, out: %q", exit, out) 1876 } 1877 out = strings.TrimSpace(out) 1878 if out != "root" { 1879 t.Fatalf("Expected output root, got %q", out) 1880 } 1881 logDone("run - cleanup cmd on --entrypoint") 1882 } 1883 1884 // TestRunWorkdirExistsAndIsFile checks that if 'docker run -w' with existing file can be detected 1885 func TestRunWorkdirExistsAndIsFile(t *testing.T) { 1886 defer deleteAllContainers() 1887 runCmd := exec.Command(dockerBinary, "run", "-w", "/bin/cat", "busybox") 1888 out, exit, err := runCommandWithOutput(runCmd) 1889 if !(err != nil && exit == 1 && strings.Contains(out, "Cannot mkdir: /bin/cat is not a directory")) { 1890 t.Fatalf("Docker must complains about making dir, but we got out: %s, exit: %d, err: %s", out, exit, err) 1891 } 1892 logDone("run - error on existing file for workdir") 1893 } 1894 1895 func TestRunExitOnStdinClose(t *testing.T) { 1896 name := "testrunexitonstdinclose" 1897 defer deleteAllContainers() 1898 runCmd := exec.Command(dockerBinary, "run", "--name", name, "-i", "busybox", "/bin/cat") 1899 1900 stdin, err := runCmd.StdinPipe() 1901 if err != nil { 1902 t.Fatal(err) 1903 } 1904 stdout, err := runCmd.StdoutPipe() 1905 if err != nil { 1906 t.Fatal(err) 1907 } 1908 1909 if err := runCmd.Start(); err != nil { 1910 t.Fatal(err) 1911 } 1912 if _, err := stdin.Write([]byte("hello\n")); err != nil { 1913 t.Fatal(err) 1914 } 1915 1916 r := bufio.NewReader(stdout) 1917 line, err := r.ReadString('\n') 1918 if err != nil { 1919 t.Fatal(err) 1920 } 1921 line = strings.TrimSpace(line) 1922 if line != "hello" { 1923 t.Fatalf("Output should be 'hello', got '%q'", line) 1924 } 1925 if err := stdin.Close(); err != nil { 1926 t.Fatal(err) 1927 } 1928 finish := make(chan struct{}) 1929 go func() { 1930 if err := runCmd.Wait(); err != nil { 1931 t.Fatal(err) 1932 } 1933 close(finish) 1934 }() 1935 select { 1936 case <-finish: 1937 case <-time.After(1 * time.Second): 1938 t.Fatal("docker run failed to exit on stdin close") 1939 } 1940 state, err := inspectField(name, "State.Running") 1941 if err != nil { 1942 t.Fatal(err) 1943 } 1944 if state != "false" { 1945 t.Fatal("Container must be stopped after stdin closing") 1946 } 1947 logDone("run - exit on stdin closing") 1948 } 1949 1950 // Test for #2267 1951 func TestRunWriteHostsFileAndNotCommit(t *testing.T) { 1952 defer deleteAllContainers() 1953 1954 name := "writehosts" 1955 cmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "sh", "-c", "echo test2267 >> /etc/hosts && cat /etc/hosts") 1956 out, _, err := runCommandWithOutput(cmd) 1957 if err != nil { 1958 t.Fatal(err, out) 1959 } 1960 if !strings.Contains(out, "test2267") { 1961 t.Fatal("/etc/hosts should contain 'test2267'") 1962 } 1963 1964 cmd = exec.Command(dockerBinary, "diff", name) 1965 if err != nil { 1966 t.Fatal(err, out) 1967 } 1968 out, _, err = runCommandWithOutput(cmd) 1969 if err != nil { 1970 t.Fatal(err, out) 1971 } 1972 if len(strings.Trim(out, "\r\n")) != 0 { 1973 t.Fatal("diff should be empty") 1974 } 1975 1976 logDone("run - write to /etc/hosts and not commited") 1977 } 1978 1979 // Test for #2267 1980 func TestRunWriteHostnameFileAndNotCommit(t *testing.T) { 1981 defer deleteAllContainers() 1982 1983 name := "writehostname" 1984 cmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "sh", "-c", "echo test2267 >> /etc/hostname && cat /etc/hostname") 1985 out, _, err := runCommandWithOutput(cmd) 1986 if err != nil { 1987 t.Fatal(err, out) 1988 } 1989 if !strings.Contains(out, "test2267") { 1990 t.Fatal("/etc/hostname should contain 'test2267'") 1991 } 1992 1993 cmd = exec.Command(dockerBinary, "diff", name) 1994 if err != nil { 1995 t.Fatal(err, out) 1996 } 1997 out, _, err = runCommandWithOutput(cmd) 1998 if err != nil { 1999 t.Fatal(err, out) 2000 } 2001 if len(strings.Trim(out, "\r\n")) != 0 { 2002 t.Fatal("diff should be empty") 2003 } 2004 2005 logDone("run - write to /etc/hostname and not commited") 2006 } 2007 2008 // Test for #2267 2009 func TestRunWriteResolvFileAndNotCommit(t *testing.T) { 2010 defer deleteAllContainers() 2011 2012 name := "writeresolv" 2013 cmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "sh", "-c", "echo test2267 >> /etc/resolv.conf && cat /etc/resolv.conf") 2014 out, _, err := runCommandWithOutput(cmd) 2015 if err != nil { 2016 t.Fatal(err, out) 2017 } 2018 if !strings.Contains(out, "test2267") { 2019 t.Fatal("/etc/resolv.conf should contain 'test2267'") 2020 } 2021 2022 cmd = exec.Command(dockerBinary, "diff", name) 2023 if err != nil { 2024 t.Fatal(err, out) 2025 } 2026 out, _, err = runCommandWithOutput(cmd) 2027 if err != nil { 2028 t.Fatal(err, out) 2029 } 2030 if len(strings.Trim(out, "\r\n")) != 0 { 2031 t.Fatal("diff should be empty") 2032 } 2033 2034 logDone("run - write to /etc/resolv.conf and not commited") 2035 } 2036 2037 func TestRunWithBadDevice(t *testing.T) { 2038 defer deleteAllContainers() 2039 2040 name := "baddevice" 2041 cmd := exec.Command(dockerBinary, "run", "--name", name, "--device", "/etc", "busybox", "true") 2042 out, _, err := runCommandWithOutput(cmd) 2043 if err == nil { 2044 t.Fatal("Run should fail with bad device") 2045 } 2046 expected := `\"/etc\": not a device node` 2047 if !strings.Contains(out, expected) { 2048 t.Fatalf("Output should contain %q, actual out: %q", expected, out) 2049 } 2050 logDone("run - error with bad device") 2051 } 2052 2053 func TestRunEntrypoint(t *testing.T) { 2054 defer deleteAllContainers() 2055 2056 name := "entrypoint" 2057 cmd := exec.Command(dockerBinary, "run", "--name", name, "--entrypoint", "/bin/echo", "busybox", "-n", "foobar") 2058 out, _, err := runCommandWithOutput(cmd) 2059 if err != nil { 2060 t.Fatal(err, out) 2061 } 2062 expected := "foobar" 2063 if out != expected { 2064 t.Fatalf("Output should be %q, actual out: %q", expected, out) 2065 } 2066 logDone("run - entrypoint") 2067 } 2068 2069 func TestRunBindMounts(t *testing.T) { 2070 defer deleteAllContainers() 2071 2072 tmpDir, err := ioutil.TempDir("", "docker-test-container") 2073 if err != nil { 2074 t.Fatal(err) 2075 } 2076 2077 defer os.RemoveAll(tmpDir) 2078 writeFile(path.Join(tmpDir, "touch-me"), "", t) 2079 2080 // Test reading from a read-only bind mount 2081 cmd := exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp:ro", tmpDir), "busybox", "ls", "/tmp") 2082 out, _, err := runCommandWithOutput(cmd) 2083 if err != nil { 2084 t.Fatal(err, out) 2085 } 2086 if !strings.Contains(out, "touch-me") { 2087 t.Fatal("Container failed to read from bind mount") 2088 } 2089 2090 // test writing to bind mount 2091 cmd = exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "busybox", "touch", "/tmp/holla") 2092 out, _, err = runCommandWithOutput(cmd) 2093 if err != nil { 2094 t.Fatal(err, out) 2095 } 2096 readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist 2097 2098 // test mounting to an illegal destination directory 2099 cmd = exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:.", tmpDir), "busybox", "ls", ".") 2100 _, err = runCommand(cmd) 2101 if err == nil { 2102 t.Fatal("Container bind mounted illegal directory") 2103 } 2104 2105 // test mount a file 2106 cmd = exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s/holla:/tmp/holla:rw", tmpDir), "busybox", "sh", "-c", "echo -n 'yotta' > /tmp/holla") 2107 _, err = runCommand(cmd) 2108 if err != nil { 2109 t.Fatal(err, out) 2110 } 2111 content := readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist 2112 expected := "yotta" 2113 if content != expected { 2114 t.Fatalf("Output should be %q, actual out: %q", expected, content) 2115 } 2116 2117 logDone("run - bind mounts") 2118 } 2119 2120 func TestRunMutableNetworkFiles(t *testing.T) { 2121 defer deleteAllContainers() 2122 2123 for _, fn := range []string{"resolv.conf", "hosts"} { 2124 deleteAllContainers() 2125 2126 content, err := runCommandAndReadContainerFile(fn, exec.Command(dockerBinary, "run", "-d", "--name", "c1", "busybox", "sh", "-c", fmt.Sprintf("echo success >/etc/%s && top", fn))) 2127 if err != nil { 2128 t.Fatal(err) 2129 } 2130 2131 if strings.TrimSpace(string(content)) != "success" { 2132 t.Fatal("Content was not what was modified in the container", string(content)) 2133 } 2134 2135 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "c2", "busybox", "top")) 2136 if err != nil { 2137 t.Fatal(err) 2138 } 2139 2140 contID := strings.TrimSpace(out) 2141 2142 netFilePath := containerStorageFile(contID, fn) 2143 2144 f, err := os.OpenFile(netFilePath, os.O_WRONLY|os.O_SYNC|os.O_APPEND, 0644) 2145 if err != nil { 2146 t.Fatal(err) 2147 } 2148 2149 if _, err := f.Seek(0, 0); err != nil { 2150 f.Close() 2151 t.Fatal(err) 2152 } 2153 2154 if err := f.Truncate(0); err != nil { 2155 f.Close() 2156 t.Fatal(err) 2157 } 2158 2159 if _, err := f.Write([]byte("success2\n")); err != nil { 2160 f.Close() 2161 t.Fatal(err) 2162 } 2163 f.Close() 2164 2165 res, err := exec.Command(dockerBinary, "exec", contID, "cat", "/etc/"+fn).CombinedOutput() 2166 if err != nil { 2167 t.Fatalf("Output: %s, error: %s", res, err) 2168 } 2169 if string(res) != "success2\n" { 2170 t.Fatalf("Expected content of %s: %q, got: %q", fn, "success2\n", res) 2171 } 2172 } 2173 logDone("run - mutable network files") 2174 } 2175 2176 // Ensure that CIDFile gets deleted if it's empty 2177 // Perform this test by making `docker run` fail 2178 func TestRunCidFileCleanupIfEmpty(t *testing.T) { 2179 tmpDir, err := ioutil.TempDir("", "TestRunCidFile") 2180 if err != nil { 2181 t.Fatal(err) 2182 } 2183 defer os.RemoveAll(tmpDir) 2184 tmpCidFile := path.Join(tmpDir, "cid") 2185 cmd := exec.Command(dockerBinary, "run", "--cidfile", tmpCidFile, "scratch") 2186 out, _, err := runCommandWithOutput(cmd) 2187 t.Log(out) 2188 if err == nil { 2189 t.Fatal("Run without command must fail") 2190 } 2191 2192 if _, err := os.Stat(tmpCidFile); err == nil { 2193 t.Fatalf("empty CIDFile %q should've been deleted", tmpCidFile) 2194 } 2195 deleteAllContainers() 2196 logDone("run - cleanup empty cidfile on fail") 2197 } 2198 2199 // #2098 - Docker cidFiles only contain short version of the containerId 2200 //sudo docker run --cidfile /tmp/docker_test.cid ubuntu echo "test" 2201 // TestRunCidFile tests that run --cidfile returns the longid 2202 func TestRunCidFileCheckIDLength(t *testing.T) { 2203 tmpDir, err := ioutil.TempDir("", "TestRunCidFile") 2204 if err != nil { 2205 t.Fatal(err) 2206 } 2207 tmpCidFile := path.Join(tmpDir, "cid") 2208 defer os.RemoveAll(tmpDir) 2209 cmd := exec.Command(dockerBinary, "run", "-d", "--cidfile", tmpCidFile, "busybox", "true") 2210 out, _, err := runCommandWithOutput(cmd) 2211 if err != nil { 2212 t.Fatal(err) 2213 } 2214 id := strings.TrimSpace(out) 2215 buffer, err := ioutil.ReadFile(tmpCidFile) 2216 if err != nil { 2217 t.Fatal(err) 2218 } 2219 cid := string(buffer) 2220 if len(cid) != 64 { 2221 t.Fatalf("--cidfile should be a long id, not %q", id) 2222 } 2223 if cid != id { 2224 t.Fatalf("cid must be equal to %s, got %s", id, cid) 2225 } 2226 deleteAllContainers() 2227 logDone("run - cidfile contains long id") 2228 } 2229 2230 func TestRunNetworkNotInitializedNoneMode(t *testing.T) { 2231 cmd := exec.Command(dockerBinary, "run", "-d", "--net=none", "busybox", "top") 2232 out, _, err := runCommandWithOutput(cmd) 2233 if err != nil { 2234 t.Fatal(err) 2235 } 2236 id := strings.TrimSpace(out) 2237 res, err := inspectField(id, "NetworkSettings.IPAddress") 2238 if err != nil { 2239 t.Fatal(err) 2240 } 2241 if res != "" { 2242 t.Fatalf("For 'none' mode network must not be initialized, but container got IP: %s", res) 2243 } 2244 deleteAllContainers() 2245 logDone("run - network must not be initialized in 'none' mode") 2246 } 2247 2248 func TestRunSetMacAddress(t *testing.T) { 2249 mac := "12:34:56:78:9a:bc" 2250 cmd := exec.Command("/bin/bash", "-c", dockerBinary+` run -i --rm --mac-address=`+mac+` busybox /bin/sh -c "ip link show eth0 | tail -1 | awk '{ print \$2 }'"`) 2251 out, _, err := runCommandWithOutput(cmd) 2252 if err != nil { 2253 t.Fatal(err) 2254 } 2255 actualMac := strings.TrimSpace(out) 2256 if actualMac != mac { 2257 t.Fatalf("Set MAC address with --mac-address failed. The container has an incorrect MAC address: %q, expected: %q", actualMac, mac) 2258 } 2259 2260 deleteAllContainers() 2261 logDone("run - setting MAC address with --mac-address") 2262 } 2263 2264 func TestRunInspectMacAddress(t *testing.T) { 2265 mac := "12:34:56:78:9a:bc" 2266 cmd := exec.Command(dockerBinary, "run", "-d", "--mac-address="+mac, "busybox", "top") 2267 out, _, err := runCommandWithOutput(cmd) 2268 if err != nil { 2269 t.Fatal(err) 2270 } 2271 id := strings.TrimSpace(out) 2272 inspectedMac, err := inspectField(id, "NetworkSettings.MacAddress") 2273 if err != nil { 2274 t.Fatal(err) 2275 } 2276 if inspectedMac != mac { 2277 t.Fatalf("docker inspect outputs wrong MAC address: %q, should be: %q", inspectedMac, mac) 2278 } 2279 deleteAllContainers() 2280 logDone("run - inspecting MAC address") 2281 } 2282 2283 func TestRunDeallocatePortOnMissingIptablesRule(t *testing.T) { 2284 cmd := exec.Command(dockerBinary, "run", "-d", "-p", "23:23", "busybox", "top") 2285 out, _, err := runCommandWithOutput(cmd) 2286 if err != nil { 2287 t.Fatal(err) 2288 } 2289 id := strings.TrimSpace(out) 2290 ip, err := inspectField(id, "NetworkSettings.IPAddress") 2291 if err != nil { 2292 t.Fatal(err) 2293 } 2294 iptCmd := exec.Command("iptables", "-D", "DOCKER", "-d", fmt.Sprintf("%s/32", ip), 2295 "!", "-i", "docker0", "-o", "docker0", "-p", "tcp", "-m", "tcp", "--dport", "23", "-j", "ACCEPT") 2296 out, _, err = runCommandWithOutput(iptCmd) 2297 if err != nil { 2298 t.Fatal(err, out) 2299 } 2300 if err := deleteContainer(id); err != nil { 2301 t.Fatal(err) 2302 } 2303 cmd = exec.Command(dockerBinary, "run", "-d", "-p", "23:23", "busybox", "top") 2304 out, _, err = runCommandWithOutput(cmd) 2305 if err != nil { 2306 t.Fatal(err, out) 2307 } 2308 deleteAllContainers() 2309 logDone("run - port should be deallocated even on iptables error") 2310 } 2311 2312 func TestRunPortInUse(t *testing.T) { 2313 port := "1234" 2314 l, err := net.Listen("tcp", ":"+port) 2315 if err != nil { 2316 t.Fatal(err) 2317 } 2318 defer l.Close() 2319 cmd := exec.Command(dockerBinary, "run", "-d", "-p", port+":80", "busybox", "top") 2320 out, _, err := runCommandWithOutput(cmd) 2321 if err == nil { 2322 t.Fatalf("Binding on used port must fail") 2323 } 2324 if !strings.Contains(out, "address already in use") { 2325 t.Fatalf("Out must be about \"address already in use\", got %s", out) 2326 } 2327 2328 deleteAllContainers() 2329 logDone("run - fail if port already in use") 2330 } 2331 2332 // https://github.com/docker/docker/issues/8428 2333 func TestRunPortProxy(t *testing.T) { 2334 defer deleteAllContainers() 2335 2336 port := "12345" 2337 cmd := exec.Command(dockerBinary, "run", "-d", "-p", port+":80", "busybox", "top") 2338 2339 out, _, err := runCommandWithOutput(cmd) 2340 if err != nil { 2341 t.Fatalf("Failed to run and bind port %s, output: %s, error: %s", port, out, err) 2342 } 2343 2344 // connect for 10 times here. This will trigger 10 EPIPES in the child 2345 // process and kill it when it writes to a closed stdout/stderr 2346 for i := 0; i < 10; i++ { 2347 net.Dial("tcp", fmt.Sprintf("0.0.0.0:%s", port)) 2348 } 2349 2350 listPs := exec.Command("sh", "-c", "ps ax | grep docker") 2351 out, _, err = runCommandWithOutput(listPs) 2352 if err != nil { 2353 t.Errorf("list docker process failed with output %s, error %s", out, err) 2354 } 2355 if strings.Contains(out, "docker <defunct>") { 2356 t.Errorf("Unexpected defunct docker process") 2357 } 2358 if !strings.Contains(out, "docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 12345") { 2359 t.Errorf("Failed to find docker-proxy process, got %s", out) 2360 } 2361 2362 logDone("run - proxy should work with unavailable port") 2363 } 2364 2365 // Regression test for #7792 2366 func TestRunMountOrdering(t *testing.T) { 2367 tmpDir, err := ioutil.TempDir("", "docker_nested_mount_test") 2368 if err != nil { 2369 t.Fatal(err) 2370 } 2371 defer os.RemoveAll(tmpDir) 2372 2373 tmpDir2, err := ioutil.TempDir("", "docker_nested_mount_test2") 2374 if err != nil { 2375 t.Fatal(err) 2376 } 2377 defer os.RemoveAll(tmpDir2) 2378 2379 // Create a temporary tmpfs mount. 2380 fooDir := filepath.Join(tmpDir, "foo") 2381 if err := os.MkdirAll(filepath.Join(tmpDir, "foo"), 0755); err != nil { 2382 t.Fatalf("failed to mkdir at %s - %s", fooDir, err) 2383 } 2384 2385 if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", fooDir), []byte{}, 0644); err != nil { 2386 t.Fatal(err) 2387 } 2388 2389 if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", tmpDir), []byte{}, 0644); err != nil { 2390 t.Fatal(err) 2391 } 2392 2393 if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", tmpDir2), []byte{}, 0644); err != nil { 2394 t.Fatal(err) 2395 } 2396 2397 cmd := exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp", tmpDir), "-v", fmt.Sprintf("%s:/tmp/foo", fooDir), "-v", fmt.Sprintf("%s:/tmp/tmp2", tmpDir2), "-v", fmt.Sprintf("%s:/tmp/tmp2/foo", fooDir), "busybox:latest", "sh", "-c", "ls /tmp/touch-me && ls /tmp/foo/touch-me && ls /tmp/tmp2/touch-me && ls /tmp/tmp2/foo/touch-me") 2398 out, _, err := runCommandWithOutput(cmd) 2399 if err != nil { 2400 t.Fatal(out, err) 2401 } 2402 2403 deleteAllContainers() 2404 logDone("run - volumes are mounted in the correct order") 2405 } 2406 2407 func TestRunExecDir(t *testing.T) { 2408 cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 2409 out, _, err := runCommandWithOutput(cmd) 2410 if err != nil { 2411 t.Fatal(err, out) 2412 } 2413 id := strings.TrimSpace(out) 2414 execDir := filepath.Join(execDriverPath, id) 2415 stateFile := filepath.Join(execDir, "state.json") 2416 contFile := filepath.Join(execDir, "container.json") 2417 2418 { 2419 fi, err := os.Stat(execDir) 2420 if err != nil { 2421 t.Fatal(err) 2422 } 2423 if !fi.IsDir() { 2424 t.Fatalf("%q must be a directory", execDir) 2425 } 2426 fi, err = os.Stat(stateFile) 2427 if err != nil { 2428 t.Fatal(err) 2429 } 2430 fi, err = os.Stat(contFile) 2431 if err != nil { 2432 t.Fatal(err) 2433 } 2434 } 2435 2436 stopCmd := exec.Command(dockerBinary, "stop", id) 2437 out, _, err = runCommandWithOutput(stopCmd) 2438 if err != nil { 2439 t.Fatal(err, out) 2440 } 2441 { 2442 fi, err := os.Stat(execDir) 2443 if err != nil { 2444 t.Fatal(err) 2445 } 2446 if !fi.IsDir() { 2447 t.Fatalf("%q must be a directory", execDir) 2448 } 2449 fi, err = os.Stat(stateFile) 2450 if err == nil { 2451 t.Fatalf("Statefile %q is exists for stopped container!", stateFile) 2452 } 2453 if !os.IsNotExist(err) { 2454 t.Fatalf("Error should be about non-existing, got %s", err) 2455 } 2456 fi, err = os.Stat(contFile) 2457 if err == nil { 2458 t.Fatalf("Container file %q is exists for stopped container!", contFile) 2459 } 2460 if !os.IsNotExist(err) { 2461 t.Fatalf("Error should be about non-existing, got %s", err) 2462 } 2463 } 2464 startCmd := exec.Command(dockerBinary, "start", id) 2465 out, _, err = runCommandWithOutput(startCmd) 2466 if err != nil { 2467 t.Fatal(err, out) 2468 } 2469 { 2470 fi, err := os.Stat(execDir) 2471 if err != nil { 2472 t.Fatal(err) 2473 } 2474 if !fi.IsDir() { 2475 t.Fatalf("%q must be a directory", execDir) 2476 } 2477 fi, err = os.Stat(stateFile) 2478 if err != nil { 2479 t.Fatal(err) 2480 } 2481 fi, err = os.Stat(contFile) 2482 if err != nil { 2483 t.Fatal(err) 2484 } 2485 } 2486 rmCmd := exec.Command(dockerBinary, "rm", "-f", id) 2487 out, _, err = runCommandWithOutput(rmCmd) 2488 if err != nil { 2489 t.Fatal(err, out) 2490 } 2491 { 2492 _, err := os.Stat(execDir) 2493 if err == nil { 2494 t.Fatal(err) 2495 } 2496 if err == nil { 2497 t.Fatalf("Exec directory %q is exists for removed container!", execDir) 2498 } 2499 if !os.IsNotExist(err) { 2500 t.Fatalf("Error should be about non-existing, got %s", err) 2501 } 2502 } 2503 2504 logDone("run - check execdriver dir behavior") 2505 } 2506 2507 // Regression test for https://github.com/docker/docker/issues/8259 2508 func TestRunReuseBindVolumeThatIsSymlink(t *testing.T) { 2509 tmpDir, err := ioutil.TempDir(os.TempDir(), "testlink") 2510 if err != nil { 2511 t.Fatal(err) 2512 } 2513 defer os.RemoveAll(tmpDir) 2514 2515 linkPath := os.TempDir() + "/testlink2" 2516 if err := os.Symlink(tmpDir, linkPath); err != nil { 2517 t.Fatal(err) 2518 } 2519 defer os.RemoveAll(linkPath) 2520 2521 // Create first container 2522 cmd := exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp/test", linkPath), "busybox", "ls", "-lh", "/tmp/test") 2523 if _, err := runCommand(cmd); err != nil { 2524 t.Fatal(err) 2525 } 2526 2527 // Create second container with same symlinked path 2528 // This will fail if the referenced issue is hit with a "Volume exists" error 2529 cmd = exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp/test", linkPath), "busybox", "ls", "-lh", "/tmp/test") 2530 if out, _, err := runCommandWithOutput(cmd); err != nil { 2531 t.Fatal(err, out) 2532 } 2533 2534 deleteAllContainers() 2535 logDone("run - can remount old bindmount volume") 2536 } 2537 2538 func TestVolumesNoCopyData(t *testing.T) { 2539 defer deleteImages("dataimage") 2540 defer deleteAllContainers() 2541 if _, err := buildImage("dataimage", 2542 `FROM busybox 2543 RUN mkdir -p /foo 2544 RUN touch /foo/bar`, 2545 true); err != nil { 2546 t.Fatal(err) 2547 } 2548 2549 cmd := exec.Command(dockerBinary, "run", "--name", "test", "-v", "/foo", "busybox") 2550 if _, err := runCommand(cmd); err != nil { 2551 t.Fatal(err) 2552 } 2553 2554 cmd = exec.Command(dockerBinary, "run", "--volumes-from", "test", "dataimage", "ls", "-lh", "/foo/bar") 2555 if out, _, err := runCommandWithOutput(cmd); err == nil || !strings.Contains(out, "No such file or directory") { 2556 t.Fatalf("Data was copied on volumes-from but shouldn't be:\n%q", out) 2557 } 2558 2559 tmpDir, err := ioutil.TempDir("", "docker_test_bind_mount_copy_data") 2560 if err != nil { 2561 t.Fatal(err) 2562 } 2563 2564 defer os.RemoveAll(tmpDir) 2565 2566 cmd = exec.Command(dockerBinary, "run", "-v", tmpDir+":/foo", "dataimage", "ls", "-lh", "/foo/bar") 2567 if out, _, err := runCommandWithOutput(cmd); err == nil || !strings.Contains(out, "No such file or directory") { 2568 t.Fatalf("Data was copied on bind-mount but shouldn't be:\n%q", out) 2569 } 2570 2571 logDone("run - volumes do not copy data for volumes-from and bindmounts") 2572 } 2573 2574 func TestRunVolumesNotRecreatedOnStart(t *testing.T) { 2575 // Clear out any remnants from other tests 2576 deleteAllContainers() 2577 info, err := ioutil.ReadDir(volumesConfigPath) 2578 if err != nil { 2579 t.Fatal(err) 2580 } 2581 if len(info) > 0 { 2582 for _, f := range info { 2583 if err := os.RemoveAll(volumesConfigPath + "/" + f.Name()); err != nil { 2584 t.Fatal(err) 2585 } 2586 } 2587 } 2588 2589 defer deleteAllContainers() 2590 cmd := exec.Command(dockerBinary, "run", "-v", "/foo", "--name", "lone_starr", "busybox") 2591 if _, err := runCommand(cmd); err != nil { 2592 t.Fatal(err) 2593 } 2594 2595 cmd = exec.Command(dockerBinary, "start", "lone_starr") 2596 if _, err := runCommand(cmd); err != nil { 2597 t.Fatal(err) 2598 } 2599 2600 info, err = ioutil.ReadDir(volumesConfigPath) 2601 if err != nil { 2602 t.Fatal(err) 2603 } 2604 if len(info) != 1 { 2605 t.Fatalf("Expected only 1 volume have %v", len(info)) 2606 } 2607 2608 logDone("run - volumes not recreated on start") 2609 } 2610 2611 func TestRunNoOutputFromPullInStdout(t *testing.T) { 2612 defer deleteAllContainers() 2613 // just run with unknown image 2614 cmd := exec.Command(dockerBinary, "run", "asdfsg") 2615 stdout := bytes.NewBuffer(nil) 2616 cmd.Stdout = stdout 2617 if err := cmd.Run(); err == nil { 2618 t.Fatal("Run with unknown image should fail") 2619 } 2620 if stdout.Len() != 0 { 2621 t.Fatalf("Stdout contains output from pull: %s", stdout) 2622 } 2623 logDone("run - no output from pull in stdout") 2624 } 2625 2626 func TestRunVolumesCleanPaths(t *testing.T) { 2627 if _, err := buildImage("run_volumes_clean_paths", 2628 `FROM busybox 2629 VOLUME /foo/`, 2630 true); err != nil { 2631 t.Fatal(err) 2632 } 2633 defer deleteImages("run_volumes_clean_paths") 2634 defer deleteAllContainers() 2635 2636 cmd := exec.Command(dockerBinary, "run", "-v", "/foo", "-v", "/bar/", "--name", "dark_helmet", "run_volumes_clean_paths") 2637 if out, _, err := runCommandWithOutput(cmd); err != nil { 2638 t.Fatal(err, out) 2639 } 2640 2641 out, err := inspectFieldMap("dark_helmet", "Volumes", "/foo/") 2642 if err != nil { 2643 t.Fatal(err) 2644 } 2645 if out != "<no value>" { 2646 t.Fatalf("Found unexpected volume entry for '/foo/' in volumes\n%q", out) 2647 } 2648 2649 out, err = inspectFieldMap("dark_helmet", "Volumes", "/foo") 2650 if err != nil { 2651 t.Fatal(err) 2652 } 2653 if !strings.Contains(out, volumesStoragePath) { 2654 t.Fatalf("Volume was not defined for /foo\n%q", out) 2655 } 2656 2657 out, err = inspectFieldMap("dark_helmet", "Volumes", "/bar/") 2658 if err != nil { 2659 t.Fatal(err) 2660 } 2661 if out != "<no value>" { 2662 t.Fatalf("Found unexpected volume entry for '/bar/' in volumes\n%q", out) 2663 } 2664 out, err = inspectFieldMap("dark_helmet", "Volumes", "/bar") 2665 if err != nil { 2666 t.Fatal(err) 2667 } 2668 if !strings.Contains(out, volumesStoragePath) { 2669 t.Fatalf("Volume was not defined for /bar\n%q", out) 2670 } 2671 2672 logDone("run - volume paths are cleaned") 2673 } 2674 2675 // Regression test for #3631 2676 func TestRunSlowStdoutConsumer(t *testing.T) { 2677 defer deleteAllContainers() 2678 2679 c := exec.Command("/bin/bash", "-c", dockerBinary+` run --rm -i busybox /bin/sh -c "dd if=/dev/zero of=/foo bs=1024 count=2000 &>/dev/null; catv /foo"`) 2680 2681 stdout, err := c.StdoutPipe() 2682 if err != nil { 2683 t.Fatal(err) 2684 } 2685 2686 if err := c.Start(); err != nil { 2687 t.Fatal(err) 2688 } 2689 n, err := consumeWithSpeed(stdout, 10000, 5*time.Millisecond, nil) 2690 if err != nil { 2691 t.Fatal(err) 2692 } 2693 2694 expected := 2 * 1024 * 2000 2695 if n != expected { 2696 t.Fatalf("Expected %d, got %d", expected, n) 2697 } 2698 2699 logDone("run - slow consumer") 2700 } 2701 2702 func TestRunAllowPortRangeThroughExpose(t *testing.T) { 2703 cmd := exec.Command(dockerBinary, "run", "-d", "--expose", "3000-3003", "-P", "busybox", "top") 2704 out, _, err := runCommandWithOutput(cmd) 2705 if err != nil { 2706 t.Fatal(err) 2707 } 2708 id := strings.TrimSpace(out) 2709 portstr, err := inspectFieldJSON(id, "NetworkSettings.Ports") 2710 if err != nil { 2711 t.Fatal(err) 2712 } 2713 var ports nat.PortMap 2714 err = unmarshalJSON([]byte(portstr), &ports) 2715 for port, binding := range ports { 2716 portnum, _ := strconv.Atoi(strings.Split(string(port), "/")[0]) 2717 if portnum < 3000 || portnum > 3003 { 2718 t.Fatalf("Port is out of range ", portnum, binding, out) 2719 } 2720 if binding == nil || len(binding) != 1 || len(binding[0].HostPort) == 0 { 2721 t.Fatal("Port is not mapped for the port "+port, out) 2722 } 2723 } 2724 if err := deleteContainer(id); err != nil { 2725 t.Fatal(err) 2726 } 2727 logDone("run - allow port range through --expose flag") 2728 } 2729 2730 func TestRunUnknownCommand(t *testing.T) { 2731 defer deleteAllContainers() 2732 runCmd := exec.Command(dockerBinary, "create", "busybox", "/bin/nada") 2733 cID, _, _, err := runCommandWithStdoutStderr(runCmd) 2734 if err != nil { 2735 t.Fatalf("Failed to create container: %v, output: %q", err, cID) 2736 } 2737 cID = strings.TrimSpace(cID) 2738 2739 runCmd = exec.Command(dockerBinary, "start", cID) 2740 _, _, _, err = runCommandWithStdoutStderr(runCmd) 2741 if err == nil { 2742 t.Fatalf("Container should not have been able to start!") 2743 } 2744 2745 runCmd = exec.Command(dockerBinary, "inspect", "--format={{.State.ExitCode}}", cID) 2746 rc, _, _, err2 := runCommandWithStdoutStderr(runCmd) 2747 rc = strings.TrimSpace(rc) 2748 2749 if err2 != nil { 2750 t.Fatalf("Error getting status of container: %v", err2) 2751 } 2752 2753 if rc != "-1" { 2754 t.Fatalf("ExitCode(%v) was supposed to be -1", rc) 2755 } 2756 2757 logDone("run - Unknown Command") 2758 } 2759 2760 func TestRunModeIpcHost(t *testing.T) { 2761 hostIpc, err := os.Readlink("/proc/1/ns/ipc") 2762 if err != nil { 2763 t.Fatal(err) 2764 } 2765 2766 cmd := exec.Command(dockerBinary, "run", "--ipc=host", "busybox", "readlink", "/proc/self/ns/ipc") 2767 out2, _, err := runCommandWithOutput(cmd) 2768 if err != nil { 2769 t.Fatal(err, out2) 2770 } 2771 2772 out2 = strings.Trim(out2, "\n") 2773 if hostIpc != out2 { 2774 t.Fatalf("IPC different with --ipc=host %s != %s\n", hostIpc, out2) 2775 } 2776 2777 cmd = exec.Command(dockerBinary, "run", "busybox", "readlink", "/proc/self/ns/ipc") 2778 out2, _, err = runCommandWithOutput(cmd) 2779 if err != nil { 2780 t.Fatal(err, out2) 2781 } 2782 2783 out2 = strings.Trim(out2, "\n") 2784 if hostIpc == out2 { 2785 t.Fatalf("IPC should be different without --ipc=host %s == %s\n", hostIpc, out2) 2786 } 2787 deleteAllContainers() 2788 2789 logDone("run - ipc host mode") 2790 } 2791 2792 func TestRunModeIpcContainer(t *testing.T) { 2793 cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 2794 out, _, err := runCommandWithOutput(cmd) 2795 if err != nil { 2796 t.Fatal(err, out) 2797 } 2798 id := strings.TrimSpace(out) 2799 state, err := inspectField(id, "State.Running") 2800 if err != nil { 2801 t.Fatal(err) 2802 } 2803 if state != "true" { 2804 t.Fatal("Container state is 'not running'") 2805 } 2806 pid1, err := inspectField(id, "State.Pid") 2807 if err != nil { 2808 t.Fatal(err) 2809 } 2810 2811 parentContainerIpc, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/ipc", pid1)) 2812 if err != nil { 2813 t.Fatal(err) 2814 } 2815 cmd = exec.Command(dockerBinary, "run", fmt.Sprintf("--ipc=container:%s", id), "busybox", "readlink", "/proc/self/ns/ipc") 2816 out2, _, err := runCommandWithOutput(cmd) 2817 if err != nil { 2818 t.Fatal(err, out2) 2819 } 2820 2821 out2 = strings.Trim(out2, "\n") 2822 if parentContainerIpc != out2 { 2823 t.Fatalf("IPC different with --ipc=container:%s %s != %s\n", id, parentContainerIpc, out2) 2824 } 2825 deleteAllContainers() 2826 2827 logDone("run - ipc container mode") 2828 } 2829 2830 func TestContainerNetworkMode(t *testing.T) { 2831 cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 2832 out, _, err := runCommandWithOutput(cmd) 2833 if err != nil { 2834 t.Fatal(err, out) 2835 } 2836 id := strings.TrimSpace(out) 2837 if err := waitRun(id); err != nil { 2838 t.Fatal(err) 2839 } 2840 pid1, err := inspectField(id, "State.Pid") 2841 if err != nil { 2842 t.Fatal(err) 2843 } 2844 2845 parentContainerNet, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/net", pid1)) 2846 if err != nil { 2847 t.Fatal(err) 2848 } 2849 cmd = exec.Command(dockerBinary, "run", fmt.Sprintf("--net=container:%s", id), "busybox", "readlink", "/proc/self/ns/net") 2850 out2, _, err := runCommandWithOutput(cmd) 2851 if err != nil { 2852 t.Fatal(err, out2) 2853 } 2854 2855 out2 = strings.Trim(out2, "\n") 2856 if parentContainerNet != out2 { 2857 t.Fatalf("NET different with --net=container:%s %s != %s\n", id, parentContainerNet, out2) 2858 } 2859 deleteAllContainers() 2860 2861 logDone("run - container shared network namespace") 2862 } 2863 2864 func TestRunModePidHost(t *testing.T) { 2865 hostPid, err := os.Readlink("/proc/1/ns/pid") 2866 if err != nil { 2867 t.Fatal(err) 2868 } 2869 2870 cmd := exec.Command(dockerBinary, "run", "--pid=host", "busybox", "readlink", "/proc/self/ns/pid") 2871 out2, _, err := runCommandWithOutput(cmd) 2872 if err != nil { 2873 t.Fatal(err, out2) 2874 } 2875 2876 out2 = strings.Trim(out2, "\n") 2877 if hostPid != out2 { 2878 t.Fatalf("PID different with --pid=host %s != %s\n", hostPid, out2) 2879 } 2880 2881 cmd = exec.Command(dockerBinary, "run", "busybox", "readlink", "/proc/self/ns/pid") 2882 out2, _, err = runCommandWithOutput(cmd) 2883 if err != nil { 2884 t.Fatal(err, out2) 2885 } 2886 2887 out2 = strings.Trim(out2, "\n") 2888 if hostPid == out2 { 2889 t.Fatalf("PID should be different without --pid=host %s == %s\n", hostPid, out2) 2890 } 2891 deleteAllContainers() 2892 2893 logDone("run - pid host mode") 2894 } 2895 2896 func TestRunTLSverify(t *testing.T) { 2897 cmd := exec.Command(dockerBinary, "ps") 2898 out, ec, err := runCommandWithOutput(cmd) 2899 if err != nil || ec != 0 { 2900 t.Fatalf("Should have worked: %v:\n%v", err, out) 2901 } 2902 2903 // Regardless of whether we specify true or false we need to 2904 // test to make sure tls is turned on if --tlsverify is specified at all 2905 2906 cmd = exec.Command(dockerBinary, "--tlsverify=false", "ps") 2907 out, ec, err = runCommandWithOutput(cmd) 2908 if err == nil || ec == 0 || !strings.Contains(out, "trying to connect") { 2909 t.Fatalf("Should have failed: \nec:%v\nout:%v\nerr:%v", ec, out, err) 2910 } 2911 2912 cmd = exec.Command(dockerBinary, "--tlsverify=true", "ps") 2913 out, ec, err = runCommandWithOutput(cmd) 2914 if err == nil || ec == 0 || !strings.Contains(out, "cert") { 2915 t.Fatalf("Should have failed: \nec:%v\nout:%v\nerr:%v", ec, out, err) 2916 } 2917 2918 logDone("run - verify tls is set for --tlsverify") 2919 } 2920 2921 func TestRunPortFromDockerRangeInUse(t *testing.T) { 2922 defer deleteAllContainers() 2923 // first find allocator current position 2924 cmd := exec.Command(dockerBinary, "run", "-d", "-p", ":80", "busybox", "top") 2925 out, _, err := runCommandWithOutput(cmd) 2926 if err != nil { 2927 t.Fatal(out, err) 2928 } 2929 id := strings.TrimSpace(out) 2930 cmd = exec.Command(dockerBinary, "port", id) 2931 out, _, err = runCommandWithOutput(cmd) 2932 if err != nil { 2933 t.Fatal(out, err) 2934 } 2935 out = strings.TrimSpace(out) 2936 out = strings.Split(out, ":")[1] 2937 lastPort, err := strconv.Atoi(out) 2938 if err != nil { 2939 t.Fatal(err) 2940 } 2941 port := lastPort + 1 2942 l, err := net.Listen("tcp", ":"+strconv.Itoa(port)) 2943 if err != nil { 2944 t.Fatal(err) 2945 } 2946 defer l.Close() 2947 cmd = exec.Command(dockerBinary, "run", "-d", "-p", ":80", "busybox", "top") 2948 out, _, err = runCommandWithOutput(cmd) 2949 if err != nil { 2950 t.Fatalf(out, err) 2951 } 2952 id = strings.TrimSpace(out) 2953 cmd = exec.Command(dockerBinary, "port", id) 2954 out, _, err = runCommandWithOutput(cmd) 2955 if err != nil { 2956 t.Fatal(out, err) 2957 } 2958 2959 logDone("run - find another port if port from autorange already bound") 2960 } 2961 2962 func TestRunTtyWithPipe(t *testing.T) { 2963 defer deleteAllContainers() 2964 2965 done := make(chan struct{}) 2966 go func() { 2967 defer close(done) 2968 2969 cmd := exec.Command(dockerBinary, "run", "-ti", "busybox", "true") 2970 if _, err := cmd.StdinPipe(); err != nil { 2971 t.Fatal(err) 2972 } 2973 2974 expected := "cannot enable tty mode" 2975 if out, _, err := runCommandWithOutput(cmd); err == nil { 2976 t.Fatal("run should have failed") 2977 } else if !strings.Contains(out, expected) { 2978 t.Fatalf("run failed with error %q: expected %q", out, expected) 2979 } 2980 }() 2981 2982 select { 2983 case <-done: 2984 case <-time.After(3 * time.Second): 2985 t.Fatal("container is running but should have failed") 2986 } 2987 2988 logDone("run - forbid piped stdin with tty") 2989 } 2990 2991 func TestRunNonLocalMacAddress(t *testing.T) { 2992 defer deleteAllContainers() 2993 addr := "00:16:3E:08:00:50" 2994 2995 cmd := exec.Command(dockerBinary, "run", "--mac-address", addr, "busybox", "ifconfig") 2996 if out, _, err := runCommandWithOutput(cmd); err != nil || !strings.Contains(out, addr) { 2997 t.Fatalf("Output should have contained %q: %s, %v", addr, out, err) 2998 } 2999 3000 logDone("run - use non-local mac-address") 3001 } 3002 3003 func TestRunNetHost(t *testing.T) { 3004 defer deleteAllContainers() 3005 hostNet, err := os.Readlink("/proc/1/ns/net") 3006 if err != nil { 3007 t.Fatal(err) 3008 } 3009 3010 cmd := exec.Command(dockerBinary, "run", "--net=host", "busybox", "readlink", "/proc/self/ns/net") 3011 out2, _, err := runCommandWithOutput(cmd) 3012 if err != nil { 3013 t.Fatal(err, out2) 3014 } 3015 3016 out2 = strings.Trim(out2, "\n") 3017 if hostNet != out2 { 3018 t.Fatalf("Net namespace different with --net=host %s != %s\n", hostNet, out2) 3019 } 3020 3021 cmd = exec.Command(dockerBinary, "run", "busybox", "readlink", "/proc/self/ns/net") 3022 out2, _, err = runCommandWithOutput(cmd) 3023 if err != nil { 3024 t.Fatal(err, out2) 3025 } 3026 3027 out2 = strings.Trim(out2, "\n") 3028 if hostNet == out2 { 3029 t.Fatalf("Net namespace should be different without --net=host %s == %s\n", hostNet, out2) 3030 } 3031 3032 logDone("run - net host mode") 3033 } 3034 3035 func TestRunAllowPortRangeThroughPublish(t *testing.T) { 3036 cmd := exec.Command(dockerBinary, "run", "-d", "--expose", "3000-3003", "-p", "3000-3003", "busybox", "top") 3037 out, _, err := runCommandWithOutput(cmd) 3038 defer deleteAllContainers() 3039 3040 id := strings.TrimSpace(out) 3041 portstr, err := inspectFieldJSON(id, "NetworkSettings.Ports") 3042 if err != nil { 3043 t.Fatal(err) 3044 } 3045 var ports nat.PortMap 3046 err = unmarshalJSON([]byte(portstr), &ports) 3047 for port, binding := range ports { 3048 portnum, _ := strconv.Atoi(strings.Split(string(port), "/")[0]) 3049 if portnum < 3000 || portnum > 3003 { 3050 t.Fatalf("Port is out of range ", portnum, binding, out) 3051 } 3052 if binding == nil || len(binding) != 1 || len(binding[0].HostPort) == 0 { 3053 t.Fatal("Port is not mapped for the port "+port, out) 3054 } 3055 } 3056 logDone("run - allow port range through --expose flag") 3057 } 3058 3059 func TestRunOOMExitCode(t *testing.T) { 3060 defer deleteAllContainers() 3061 3062 done := make(chan struct{}) 3063 go func() { 3064 defer close(done) 3065 3066 runCmd := exec.Command(dockerBinary, "run", "-m", "4MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x; done") 3067 out, exitCode, _ := runCommandWithOutput(runCmd) 3068 if expected := 137; exitCode != expected { 3069 t.Fatalf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out) 3070 } 3071 }() 3072 3073 select { 3074 case <-done: 3075 case <-time.After(3 * time.Second): 3076 t.Fatal("Timeout waiting for container to die on OOM") 3077 } 3078 3079 logDone("run - exit code on oom") 3080 } 3081 3082 func TestRunRestartMaxRetries(t *testing.T) { 3083 defer deleteAllContainers() 3084 out, err := exec.Command(dockerBinary, "run", "-d", "--restart=on-failure:3", "busybox", "false").CombinedOutput() 3085 if err != nil { 3086 t.Fatal(string(out), err) 3087 } 3088 id := strings.TrimSpace(string(out)) 3089 if err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", 5); err != nil { 3090 t.Fatal(err) 3091 } 3092 count, err := inspectField(id, "RestartCount") 3093 if err != nil { 3094 t.Fatal(err) 3095 } 3096 if count != "3" { 3097 t.Fatalf("Container was restarted %s times, expected %d", count, 3) 3098 } 3099 logDone("run - test max-retries for --restart") 3100 } 3101 3102 func TestRunContainerWithWritableRootfs(t *testing.T) { 3103 defer deleteAllContainers() 3104 out, err := exec.Command(dockerBinary, "run", "--rm", "busybox", "touch", "/file").CombinedOutput() 3105 if err != nil { 3106 t.Fatal(string(out), err) 3107 } 3108 logDone("run - writable rootfs") 3109 } 3110 3111 func TestRunContainerWithReadonlyRootfs(t *testing.T) { 3112 defer deleteAllContainers() 3113 out, err := exec.Command(dockerBinary, "run", "--read-only", "--rm", "busybox", "touch", "/file").CombinedOutput() 3114 if err == nil { 3115 t.Fatal("expected container to error on run with read only error") 3116 } 3117 expected := "Read-only file system" 3118 if !strings.Contains(string(out), expected) { 3119 t.Fatalf("expected output from failure to contain %s but contains %s", expected, out) 3120 } 3121 logDone("run - read only rootfs") 3122 } 3123 3124 func TestRunVolumesFromRestartAfterRemoved(t *testing.T) { 3125 defer deleteAllContainers() 3126 3127 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "voltest", "-v", "/foo", "busybox")) 3128 if err != nil { 3129 t.Fatal(out, err) 3130 } 3131 3132 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "restarter", "--volumes-from", "voltest", "busybox", "top")) 3133 if err != nil { 3134 t.Fatal(out, err) 3135 } 3136 3137 // Remove the main volume container and restart the consuming container 3138 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "rm", "-f", "voltest")) 3139 if err != nil { 3140 t.Fatal(out, err) 3141 } 3142 3143 // This should not fail since the volumes-from were already applied 3144 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "restart", "restarter")) 3145 if err != nil { 3146 t.Fatalf("expected container to restart successfully: %v\n%s", err, out) 3147 } 3148 3149 logDone("run - can restart a volumes-from container after producer is removed") 3150 }