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