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