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