github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/integration-cli/docker_cli_run_unix_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "bufio" 7 "encoding/json" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "regexp" 14 "strconv" 15 "strings" 16 "sync" 17 "syscall" 18 "time" 19 20 "github.com/docker/docker/pkg/homedir" 21 "github.com/docker/docker/pkg/integration/checker" 22 "github.com/docker/docker/pkg/mount" 23 "github.com/docker/docker/pkg/parsers" 24 "github.com/docker/docker/pkg/sysinfo" 25 "github.com/go-check/check" 26 "github.com/kr/pty" 27 ) 28 29 // #6509 30 func (s *DockerSuite) TestRunRedirectStdout(c *check.C) { 31 checkRedirect := func(command string) { 32 _, tty, err := pty.Open() 33 c.Assert(err, checker.IsNil, check.Commentf("Could not open pty")) 34 cmd := exec.Command("sh", "-c", command) 35 cmd.Stdin = tty 36 cmd.Stdout = tty 37 cmd.Stderr = tty 38 c.Assert(cmd.Start(), checker.IsNil) 39 ch := make(chan error) 40 go func() { 41 ch <- cmd.Wait() 42 close(ch) 43 }() 44 45 select { 46 case <-time.After(10 * time.Second): 47 c.Fatal("command timeout") 48 case err := <-ch: 49 c.Assert(err, checker.IsNil, check.Commentf("wait err")) 50 } 51 } 52 53 checkRedirect(dockerBinary + " run -i busybox cat /etc/passwd | grep -q root") 54 checkRedirect(dockerBinary + " run busybox cat /etc/passwd | grep -q root") 55 } 56 57 // Test recursive bind mount works by default 58 func (s *DockerSuite) TestRunWithVolumesIsRecursive(c *check.C) { 59 // /tmp gets permission denied 60 testRequires(c, NotUserNamespace, SameHostDaemon) 61 tmpDir, err := ioutil.TempDir("", "docker_recursive_mount_test") 62 c.Assert(err, checker.IsNil) 63 64 defer os.RemoveAll(tmpDir) 65 66 // Create a temporary tmpfs mount. 67 tmpfsDir := filepath.Join(tmpDir, "tmpfs") 68 c.Assert(os.MkdirAll(tmpfsDir, 0777), checker.IsNil, check.Commentf("failed to mkdir at %s", tmpfsDir)) 69 c.Assert(mount.Mount("tmpfs", tmpfsDir, "tmpfs", ""), checker.IsNil, check.Commentf("failed to create a tmpfs mount at %s", tmpfsDir)) 70 71 f, err := ioutil.TempFile(tmpfsDir, "touch-me") 72 c.Assert(err, checker.IsNil) 73 defer f.Close() 74 75 runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", fmt.Sprintf("%s:/tmp:ro", tmpDir), "busybox:latest", "ls", "/tmp/tmpfs") 76 out, _, _, err := runCommandWithStdoutStderr(runCmd) 77 c.Assert(err, checker.IsNil) 78 c.Assert(out, checker.Contains, filepath.Base(f.Name()), check.Commentf("Recursive bind mount test failed. Expected file not found")) 79 } 80 81 func (s *DockerSuite) TestRunDeviceDirectory(c *check.C) { 82 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) 83 if _, err := os.Stat("/dev/snd"); err != nil { 84 c.Skip("Host does not have /dev/snd") 85 } 86 87 out, _ := dockerCmd(c, "run", "--device", "/dev/snd:/dev/snd", "busybox", "sh", "-c", "ls /dev/snd/") 88 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "timer", check.Commentf("expected output /dev/snd/timer")) 89 90 out, _ = dockerCmd(c, "run", "--device", "/dev/snd:/dev/othersnd", "busybox", "sh", "-c", "ls /dev/othersnd/") 91 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "seq", check.Commentf("expected output /dev/othersnd/seq")) 92 } 93 94 // TestRunDetach checks attaching and detaching with the default escape sequence. 95 func (s *DockerSuite) TestRunAttachDetach(c *check.C) { 96 name := "attach-detach" 97 98 dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat") 99 100 cmd := exec.Command(dockerBinary, "attach", name) 101 stdout, err := cmd.StdoutPipe() 102 c.Assert(err, checker.IsNil) 103 cpty, tty, err := pty.Open() 104 c.Assert(err, checker.IsNil) 105 defer cpty.Close() 106 cmd.Stdin = tty 107 c.Assert(cmd.Start(), checker.IsNil) 108 c.Assert(waitRun(name), check.IsNil) 109 110 _, err = cpty.Write([]byte("hello\n")) 111 c.Assert(err, checker.IsNil) 112 113 out, err := bufio.NewReader(stdout).ReadString('\n') 114 c.Assert(err, checker.IsNil) 115 c.Assert(strings.TrimSpace(out), checker.Equals, "hello") 116 117 // escape sequence 118 _, err = cpty.Write([]byte{16}) 119 c.Assert(err, checker.IsNil) 120 time.Sleep(100 * time.Millisecond) 121 _, err = cpty.Write([]byte{17}) 122 c.Assert(err, checker.IsNil) 123 124 ch := make(chan struct{}) 125 go func() { 126 cmd.Wait() 127 ch <- struct{}{} 128 }() 129 130 select { 131 case <-ch: 132 case <-time.After(10 * time.Second): 133 c.Fatal("timed out waiting for container to exit") 134 } 135 136 running := inspectField(c, name, "State.Running") 137 c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running")) 138 } 139 140 // TestRunDetach checks attaching and detaching with the escape sequence specified via flags. 141 func (s *DockerSuite) TestRunAttachDetachFromFlag(c *check.C) { 142 name := "attach-detach" 143 keyCtrlA := []byte{1} 144 keyA := []byte{97} 145 146 dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat") 147 148 cmd := exec.Command(dockerBinary, "attach", "--detach-keys='ctrl-a,a'", name) 149 stdout, err := cmd.StdoutPipe() 150 if err != nil { 151 c.Fatal(err) 152 } 153 cpty, tty, err := pty.Open() 154 if err != nil { 155 c.Fatal(err) 156 } 157 defer cpty.Close() 158 cmd.Stdin = tty 159 if err := cmd.Start(); err != nil { 160 c.Fatal(err) 161 } 162 c.Assert(waitRun(name), check.IsNil) 163 164 if _, err := cpty.Write([]byte("hello\n")); err != nil { 165 c.Fatal(err) 166 } 167 168 out, err := bufio.NewReader(stdout).ReadString('\n') 169 if err != nil { 170 c.Fatal(err) 171 } 172 if strings.TrimSpace(out) != "hello" { 173 c.Fatalf("expected 'hello', got %q", out) 174 } 175 176 // escape sequence 177 if _, err := cpty.Write(keyCtrlA); err != nil { 178 c.Fatal(err) 179 } 180 time.Sleep(100 * time.Millisecond) 181 if _, err := cpty.Write(keyA); err != nil { 182 c.Fatal(err) 183 } 184 185 ch := make(chan struct{}) 186 go func() { 187 cmd.Wait() 188 ch <- struct{}{} 189 }() 190 191 select { 192 case <-ch: 193 case <-time.After(10 * time.Second): 194 c.Fatal("timed out waiting for container to exit") 195 } 196 197 running := inspectField(c, name, "State.Running") 198 c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running")) 199 } 200 201 // TestRunDetach checks attaching and detaching with the escape sequence specified via flags. 202 func (s *DockerSuite) TestRunAttachDetachFromInvalidFlag(c *check.C) { 203 name := "attach-detach" 204 dockerCmd(c, "run", "--name", name, "-itd", "busybox", "top") 205 c.Assert(waitRun(name), check.IsNil) 206 207 // specify an invalid detach key, container will ignore it and use default 208 cmd := exec.Command(dockerBinary, "attach", "--detach-keys='ctrl-A,a'", name) 209 stdout, err := cmd.StdoutPipe() 210 if err != nil { 211 c.Fatal(err) 212 } 213 cpty, tty, err := pty.Open() 214 if err != nil { 215 c.Fatal(err) 216 } 217 defer cpty.Close() 218 cmd.Stdin = tty 219 if err := cmd.Start(); err != nil { 220 c.Fatal(err) 221 } 222 223 bufReader := bufio.NewReader(stdout) 224 out, err := bufReader.ReadString('\n') 225 if err != nil { 226 c.Fatal(err) 227 } 228 // it should print a warning to indicate the detach key flag is invalid 229 errStr := "Invalid escape keys (ctrl-A,a) provided" 230 c.Assert(strings.TrimSpace(out), checker.Equals, errStr) 231 } 232 233 // TestRunDetach checks attaching and detaching with the escape sequence specified via config file. 234 func (s *DockerSuite) TestRunAttachDetachFromConfig(c *check.C) { 235 keyCtrlA := []byte{1} 236 keyA := []byte{97} 237 238 // Setup config 239 homeKey := homedir.Key() 240 homeVal := homedir.Get() 241 tmpDir, err := ioutil.TempDir("", "fake-home") 242 c.Assert(err, checker.IsNil) 243 defer os.RemoveAll(tmpDir) 244 245 dotDocker := filepath.Join(tmpDir, ".docker") 246 os.Mkdir(dotDocker, 0600) 247 tmpCfg := filepath.Join(dotDocker, "config.json") 248 249 defer func() { os.Setenv(homeKey, homeVal) }() 250 os.Setenv(homeKey, tmpDir) 251 252 data := `{ 253 "detachKeys": "ctrl-a,a" 254 }` 255 256 err = ioutil.WriteFile(tmpCfg, []byte(data), 0600) 257 c.Assert(err, checker.IsNil) 258 259 // Then do the work 260 name := "attach-detach" 261 dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat") 262 263 cmd := exec.Command(dockerBinary, "attach", name) 264 stdout, err := cmd.StdoutPipe() 265 if err != nil { 266 c.Fatal(err) 267 } 268 cpty, tty, err := pty.Open() 269 if err != nil { 270 c.Fatal(err) 271 } 272 defer cpty.Close() 273 cmd.Stdin = tty 274 if err := cmd.Start(); err != nil { 275 c.Fatal(err) 276 } 277 c.Assert(waitRun(name), check.IsNil) 278 279 if _, err := cpty.Write([]byte("hello\n")); err != nil { 280 c.Fatal(err) 281 } 282 283 out, err := bufio.NewReader(stdout).ReadString('\n') 284 if err != nil { 285 c.Fatal(err) 286 } 287 if strings.TrimSpace(out) != "hello" { 288 c.Fatalf("expected 'hello', got %q", out) 289 } 290 291 // escape sequence 292 if _, err := cpty.Write(keyCtrlA); err != nil { 293 c.Fatal(err) 294 } 295 time.Sleep(100 * time.Millisecond) 296 if _, err := cpty.Write(keyA); err != nil { 297 c.Fatal(err) 298 } 299 300 ch := make(chan struct{}) 301 go func() { 302 cmd.Wait() 303 ch <- struct{}{} 304 }() 305 306 select { 307 case <-ch: 308 case <-time.After(10 * time.Second): 309 c.Fatal("timed out waiting for container to exit") 310 } 311 312 running := inspectField(c, name, "State.Running") 313 c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running")) 314 } 315 316 // TestRunDetach checks attaching and detaching with the detach flags, making sure it overrides config file 317 func (s *DockerSuite) TestRunAttachDetachKeysOverrideConfig(c *check.C) { 318 keyCtrlA := []byte{1} 319 keyA := []byte{97} 320 321 // Setup config 322 homeKey := homedir.Key() 323 homeVal := homedir.Get() 324 tmpDir, err := ioutil.TempDir("", "fake-home") 325 c.Assert(err, checker.IsNil) 326 defer os.RemoveAll(tmpDir) 327 328 dotDocker := filepath.Join(tmpDir, ".docker") 329 os.Mkdir(dotDocker, 0600) 330 tmpCfg := filepath.Join(dotDocker, "config.json") 331 332 defer func() { os.Setenv(homeKey, homeVal) }() 333 os.Setenv(homeKey, tmpDir) 334 335 data := `{ 336 "detachKeys": "ctrl-e,e" 337 }` 338 339 err = ioutil.WriteFile(tmpCfg, []byte(data), 0600) 340 c.Assert(err, checker.IsNil) 341 342 // Then do the work 343 name := "attach-detach" 344 dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat") 345 346 cmd := exec.Command(dockerBinary, "attach", "--detach-keys='ctrl-a,a'", name) 347 stdout, err := cmd.StdoutPipe() 348 if err != nil { 349 c.Fatal(err) 350 } 351 cpty, tty, err := pty.Open() 352 if err != nil { 353 c.Fatal(err) 354 } 355 defer cpty.Close() 356 cmd.Stdin = tty 357 if err := cmd.Start(); err != nil { 358 c.Fatal(err) 359 } 360 c.Assert(waitRun(name), check.IsNil) 361 362 if _, err := cpty.Write([]byte("hello\n")); err != nil { 363 c.Fatal(err) 364 } 365 366 out, err := bufio.NewReader(stdout).ReadString('\n') 367 if err != nil { 368 c.Fatal(err) 369 } 370 if strings.TrimSpace(out) != "hello" { 371 c.Fatalf("expected 'hello', got %q", out) 372 } 373 374 // escape sequence 375 if _, err := cpty.Write(keyCtrlA); err != nil { 376 c.Fatal(err) 377 } 378 time.Sleep(100 * time.Millisecond) 379 if _, err := cpty.Write(keyA); err != nil { 380 c.Fatal(err) 381 } 382 383 ch := make(chan struct{}) 384 go func() { 385 cmd.Wait() 386 ch <- struct{}{} 387 }() 388 389 select { 390 case <-ch: 391 case <-time.After(10 * time.Second): 392 c.Fatal("timed out waiting for container to exit") 393 } 394 395 running := inspectField(c, name, "State.Running") 396 c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running")) 397 } 398 399 // "test" should be printed 400 func (s *DockerSuite) TestRunWithCPUQuota(c *check.C) { 401 testRequires(c, cpuCfsQuota) 402 403 file := "/sys/fs/cgroup/cpu/cpu.cfs_quota_us" 404 out, _ := dockerCmd(c, "run", "--cpu-quota", "8000", "--name", "test", "busybox", "cat", file) 405 c.Assert(strings.TrimSpace(out), checker.Equals, "8000") 406 407 out = inspectField(c, "test", "HostConfig.CpuQuota") 408 c.Assert(out, checker.Equals, "8000", check.Commentf("setting the CPU CFS quota failed")) 409 } 410 411 func (s *DockerSuite) TestRunWithCpuPeriod(c *check.C) { 412 testRequires(c, cpuCfsPeriod) 413 414 file := "/sys/fs/cgroup/cpu/cpu.cfs_period_us" 415 out, _ := dockerCmd(c, "run", "--cpu-period", "50000", "--name", "test", "busybox", "cat", file) 416 c.Assert(strings.TrimSpace(out), checker.Equals, "50000") 417 418 out = inspectField(c, "test", "HostConfig.CpuPeriod") 419 c.Assert(out, checker.Equals, "50000", check.Commentf("setting the CPU CFS period failed")) 420 } 421 422 func (s *DockerSuite) TestRunWithKernelMemory(c *check.C) { 423 testRequires(c, kernelMemorySupport) 424 425 file := "/sys/fs/cgroup/memory/memory.kmem.limit_in_bytes" 426 stdout, _, _ := dockerCmdWithStdoutStderr(c, "run", "--kernel-memory", "50M", "--name", "test1", "busybox", "cat", file) 427 c.Assert(strings.TrimSpace(stdout), checker.Equals, "52428800") 428 429 out := inspectField(c, "test1", "HostConfig.KernelMemory") 430 c.Assert(out, check.Equals, "52428800") 431 } 432 433 func (s *DockerSuite) TestRunWithInvalidKernelMemory(c *check.C) { 434 testRequires(c, kernelMemorySupport) 435 436 out, _, err := dockerCmdWithError("run", "--kernel-memory", "2M", "busybox", "true") 437 c.Assert(err, check.NotNil) 438 expected := "Minimum kernel memory limit allowed is 4MB" 439 c.Assert(out, checker.Contains, expected) 440 441 out, _, err = dockerCmdWithError("run", "--kernel-memory", "-16m", "--name", "test2", "busybox", "echo", "test") 442 c.Assert(err, check.NotNil) 443 expected = "invalid size" 444 c.Assert(out, checker.Contains, expected) 445 } 446 447 func (s *DockerSuite) TestRunWithCPUShares(c *check.C) { 448 testRequires(c, cpuShare) 449 450 file := "/sys/fs/cgroup/cpu/cpu.shares" 451 out, _ := dockerCmd(c, "run", "--cpu-shares", "1000", "--name", "test", "busybox", "cat", file) 452 c.Assert(strings.TrimSpace(out), checker.Equals, "1000") 453 454 out = inspectField(c, "test", "HostConfig.CPUShares") 455 c.Assert(out, check.Equals, "1000") 456 } 457 458 // "test" should be printed 459 func (s *DockerSuite) TestRunEchoStdoutWithCPUSharesAndMemoryLimit(c *check.C) { 460 testRequires(c, cpuShare) 461 testRequires(c, memoryLimitSupport) 462 out, _, _ := dockerCmdWithStdoutStderr(c, "run", "--cpu-shares", "1000", "-m", "32m", "busybox", "echo", "test") 463 c.Assert(out, checker.Equals, "test\n", check.Commentf("container should've printed 'test'")) 464 } 465 466 func (s *DockerSuite) TestRunWithCpusetCpus(c *check.C) { 467 testRequires(c, cgroupCpuset) 468 469 file := "/sys/fs/cgroup/cpuset/cpuset.cpus" 470 out, _ := dockerCmd(c, "run", "--cpuset-cpus", "0", "--name", "test", "busybox", "cat", file) 471 c.Assert(strings.TrimSpace(out), checker.Equals, "0") 472 473 out = inspectField(c, "test", "HostConfig.CpusetCpus") 474 c.Assert(out, check.Equals, "0") 475 } 476 477 func (s *DockerSuite) TestRunWithCpusetMems(c *check.C) { 478 testRequires(c, cgroupCpuset) 479 480 file := "/sys/fs/cgroup/cpuset/cpuset.mems" 481 out, _ := dockerCmd(c, "run", "--cpuset-mems", "0", "--name", "test", "busybox", "cat", file) 482 c.Assert(strings.TrimSpace(out), checker.Equals, "0") 483 484 out = inspectField(c, "test", "HostConfig.CpusetMems") 485 c.Assert(out, check.Equals, "0") 486 } 487 488 func (s *DockerSuite) TestRunWithBlkioWeight(c *check.C) { 489 testRequires(c, blkioWeight) 490 491 file := "/sys/fs/cgroup/blkio/blkio.weight" 492 out, _ := dockerCmd(c, "run", "--blkio-weight", "300", "--name", "test", "busybox", "cat", file) 493 c.Assert(strings.TrimSpace(out), checker.Equals, "300") 494 495 out = inspectField(c, "test", "HostConfig.BlkioWeight") 496 c.Assert(out, check.Equals, "300") 497 } 498 499 func (s *DockerSuite) TestRunWithInvalidBlkioWeight(c *check.C) { 500 testRequires(c, blkioWeight) 501 out, _, err := dockerCmdWithError("run", "--blkio-weight", "5", "busybox", "true") 502 c.Assert(err, check.NotNil, check.Commentf(out)) 503 expected := "Range of blkio weight is from 10 to 1000" 504 c.Assert(out, checker.Contains, expected) 505 } 506 507 func (s *DockerSuite) TestRunWithInvalidPathforBlkioWeightDevice(c *check.C) { 508 testRequires(c, blkioWeight) 509 out, _, err := dockerCmdWithError("run", "--blkio-weight-device", "/dev/sdX:100", "busybox", "true") 510 c.Assert(err, check.NotNil, check.Commentf(out)) 511 } 512 513 func (s *DockerSuite) TestRunWithInvalidPathforBlkioDeviceReadBps(c *check.C) { 514 testRequires(c, blkioWeight) 515 out, _, err := dockerCmdWithError("run", "--device-read-bps", "/dev/sdX:500", "busybox", "true") 516 c.Assert(err, check.NotNil, check.Commentf(out)) 517 } 518 519 func (s *DockerSuite) TestRunWithInvalidPathforBlkioDeviceWriteBps(c *check.C) { 520 testRequires(c, blkioWeight) 521 out, _, err := dockerCmdWithError("run", "--device-write-bps", "/dev/sdX:500", "busybox", "true") 522 c.Assert(err, check.NotNil, check.Commentf(out)) 523 } 524 525 func (s *DockerSuite) TestRunWithInvalidPathforBlkioDeviceReadIOps(c *check.C) { 526 testRequires(c, blkioWeight) 527 out, _, err := dockerCmdWithError("run", "--device-read-iops", "/dev/sdX:500", "busybox", "true") 528 c.Assert(err, check.NotNil, check.Commentf(out)) 529 } 530 531 func (s *DockerSuite) TestRunWithInvalidPathforBlkioDeviceWriteIOps(c *check.C) { 532 testRequires(c, blkioWeight) 533 out, _, err := dockerCmdWithError("run", "--device-write-iops", "/dev/sdX:500", "busybox", "true") 534 c.Assert(err, check.NotNil, check.Commentf(out)) 535 } 536 537 func (s *DockerSuite) TestRunOOMExitCode(c *check.C) { 538 testRequires(c, oomControl) 539 errChan := make(chan error) 540 go func() { 541 defer close(errChan) 542 //changing memory to 40MB from 4MB due to an issue with GCCGO that test fails to start the container. 543 out, exitCode, _ := dockerCmdWithError("run", "-m", "40MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done") 544 if expected := 137; exitCode != expected { 545 errChan <- fmt.Errorf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out) 546 } 547 }() 548 549 select { 550 case err := <-errChan: 551 c.Assert(err, check.IsNil) 552 case <-time.After(600 * time.Second): 553 c.Fatal("Timeout waiting for container to die on OOM") 554 } 555 } 556 557 func (s *DockerSuite) TestRunWithMemoryLimit(c *check.C) { 558 testRequires(c, memoryLimitSupport) 559 560 file := "/sys/fs/cgroup/memory/memory.limit_in_bytes" 561 stdout, _, _ := dockerCmdWithStdoutStderr(c, "run", "-m", "32M", "--name", "test", "busybox", "cat", file) 562 c.Assert(strings.TrimSpace(stdout), checker.Equals, "33554432") 563 564 out := inspectField(c, "test", "HostConfig.Memory") 565 c.Assert(out, check.Equals, "33554432") 566 } 567 568 // TestRunWithoutMemoryswapLimit sets memory limit and disables swap 569 // memory limit, this means the processes in the container can use 570 // 16M memory and as much swap memory as they need (if the host 571 // supports swap memory). 572 func (s *DockerSuite) TestRunWithoutMemoryswapLimit(c *check.C) { 573 testRequires(c, DaemonIsLinux) 574 testRequires(c, memoryLimitSupport) 575 testRequires(c, swapMemorySupport) 576 dockerCmd(c, "run", "-m", "32m", "--memory-swap", "-1", "busybox", "true") 577 } 578 579 func (s *DockerSuite) TestRunWithSwappiness(c *check.C) { 580 testRequires(c, memorySwappinessSupport) 581 file := "/sys/fs/cgroup/memory/memory.swappiness" 582 out, _ := dockerCmd(c, "run", "--memory-swappiness", "0", "--name", "test", "busybox", "cat", file) 583 c.Assert(strings.TrimSpace(out), checker.Equals, "0") 584 585 out = inspectField(c, "test", "HostConfig.MemorySwappiness") 586 c.Assert(out, check.Equals, "0") 587 } 588 589 func (s *DockerSuite) TestRunWithSwappinessInvalid(c *check.C) { 590 testRequires(c, memorySwappinessSupport) 591 out, _, err := dockerCmdWithError("run", "--memory-swappiness", "101", "busybox", "true") 592 c.Assert(err, check.NotNil) 593 expected := "Valid memory swappiness range is 0-100" 594 c.Assert(out, checker.Contains, expected, check.Commentf("Expected output to contain %q, not %q", out, expected)) 595 596 out, _, err = dockerCmdWithError("run", "--memory-swappiness", "-10", "busybox", "true") 597 c.Assert(err, check.NotNil) 598 c.Assert(out, checker.Contains, expected, check.Commentf("Expected output to contain %q, not %q", out, expected)) 599 } 600 601 func (s *DockerSuite) TestRunWithMemoryReservation(c *check.C) { 602 testRequires(c, memoryReservationSupport) 603 604 file := "/sys/fs/cgroup/memory/memory.soft_limit_in_bytes" 605 out, _ := dockerCmd(c, "run", "--memory-reservation", "200M", "--name", "test", "busybox", "cat", file) 606 c.Assert(strings.TrimSpace(out), checker.Equals, "209715200") 607 608 out = inspectField(c, "test", "HostConfig.MemoryReservation") 609 c.Assert(out, check.Equals, "209715200") 610 } 611 612 func (s *DockerSuite) TestRunWithMemoryReservationInvalid(c *check.C) { 613 testRequires(c, memoryLimitSupport) 614 testRequires(c, memoryReservationSupport) 615 out, _, err := dockerCmdWithError("run", "-m", "500M", "--memory-reservation", "800M", "busybox", "true") 616 c.Assert(err, check.NotNil) 617 expected := "Minimum memory limit should be larger than memory reservation limit" 618 c.Assert(strings.TrimSpace(out), checker.Contains, expected, check.Commentf("run container should fail with invalid memory reservation")) 619 620 out, _, err = dockerCmdWithError("run", "--memory-reservation", "1k", "busybox", "true") 621 c.Assert(err, check.NotNil) 622 expected = "Minimum memory reservation allowed is 4MB" 623 c.Assert(strings.TrimSpace(out), checker.Contains, expected, check.Commentf("run container should fail with invalid memory reservation")) 624 } 625 626 func (s *DockerSuite) TestStopContainerSignal(c *check.C) { 627 out, _ := dockerCmd(c, "run", "--stop-signal", "SIGUSR1", "-d", "busybox", "/bin/sh", "-c", `trap 'echo "exit trapped"; exit 0' USR1; while true; do sleep 1; done`) 628 containerID := strings.TrimSpace(out) 629 630 c.Assert(waitRun(containerID), checker.IsNil) 631 632 dockerCmd(c, "stop", containerID) 633 out, _ = dockerCmd(c, "logs", containerID) 634 635 c.Assert(out, checker.Contains, "exit trapped", check.Commentf("Expected `exit trapped` in the log")) 636 } 637 638 func (s *DockerSuite) TestRunSwapLessThanMemoryLimit(c *check.C) { 639 testRequires(c, memoryLimitSupport) 640 testRequires(c, swapMemorySupport) 641 out, _, err := dockerCmdWithError("run", "-m", "16m", "--memory-swap", "15m", "busybox", "echo", "test") 642 expected := "Minimum memoryswap limit should be larger than memory limit" 643 c.Assert(err, check.NotNil) 644 645 c.Assert(out, checker.Contains, expected) 646 } 647 648 func (s *DockerSuite) TestRunInvalidCpusetCpusFlagValue(c *check.C) { 649 testRequires(c, cgroupCpuset, SameHostDaemon) 650 651 sysInfo := sysinfo.New(true) 652 cpus, err := parsers.ParseUintList(sysInfo.Cpus) 653 c.Assert(err, check.IsNil) 654 var invalid int 655 for i := 0; i <= len(cpus)+1; i++ { 656 if !cpus[i] { 657 invalid = i 658 break 659 } 660 } 661 out, _, err := dockerCmdWithError("run", "--cpuset-cpus", strconv.Itoa(invalid), "busybox", "true") 662 c.Assert(err, check.NotNil) 663 expected := fmt.Sprintf("Error response from daemon: Requested CPUs are not available - requested %s, available: %s", strconv.Itoa(invalid), sysInfo.Cpus) 664 c.Assert(out, checker.Contains, expected) 665 } 666 667 func (s *DockerSuite) TestRunInvalidCpusetMemsFlagValue(c *check.C) { 668 testRequires(c, cgroupCpuset) 669 670 sysInfo := sysinfo.New(true) 671 mems, err := parsers.ParseUintList(sysInfo.Mems) 672 c.Assert(err, check.IsNil) 673 var invalid int 674 for i := 0; i <= len(mems)+1; i++ { 675 if !mems[i] { 676 invalid = i 677 break 678 } 679 } 680 out, _, err := dockerCmdWithError("run", "--cpuset-mems", strconv.Itoa(invalid), "busybox", "true") 681 c.Assert(err, check.NotNil) 682 expected := fmt.Sprintf("Error response from daemon: Requested memory nodes are not available - requested %s, available: %s", strconv.Itoa(invalid), sysInfo.Mems) 683 c.Assert(out, checker.Contains, expected) 684 } 685 686 func (s *DockerSuite) TestRunInvalidCPUShares(c *check.C) { 687 testRequires(c, cpuShare, DaemonIsLinux) 688 out, _, err := dockerCmdWithError("run", "--cpu-shares", "1", "busybox", "echo", "test") 689 c.Assert(err, check.NotNil, check.Commentf(out)) 690 expected := "The minimum allowed cpu-shares is 2" 691 c.Assert(out, checker.Contains, expected) 692 693 out, _, err = dockerCmdWithError("run", "--cpu-shares", "-1", "busybox", "echo", "test") 694 c.Assert(err, check.NotNil, check.Commentf(out)) 695 expected = "shares: invalid argument" 696 c.Assert(out, checker.Contains, expected) 697 698 out, _, err = dockerCmdWithError("run", "--cpu-shares", "99999999", "busybox", "echo", "test") 699 c.Assert(err, check.NotNil, check.Commentf(out)) 700 expected = "The maximum allowed cpu-shares is" 701 c.Assert(out, checker.Contains, expected) 702 } 703 704 func (s *DockerSuite) TestRunWithDefaultShmSize(c *check.C) { 705 testRequires(c, DaemonIsLinux) 706 707 name := "shm-default" 708 out, _ := dockerCmd(c, "run", "--name", name, "busybox", "mount") 709 shmRegex := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=65536k`) 710 if !shmRegex.MatchString(out) { 711 c.Fatalf("Expected shm of 64MB in mount command, got %v", out) 712 } 713 shmSize := inspectField(c, name, "HostConfig.ShmSize") 714 c.Assert(shmSize, check.Equals, "67108864") 715 } 716 717 func (s *DockerSuite) TestRunWithShmSize(c *check.C) { 718 testRequires(c, DaemonIsLinux) 719 720 name := "shm" 721 out, _ := dockerCmd(c, "run", "--name", name, "--shm-size=1G", "busybox", "mount") 722 shmRegex := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=1048576k`) 723 if !shmRegex.MatchString(out) { 724 c.Fatalf("Expected shm of 1GB in mount command, got %v", out) 725 } 726 shmSize := inspectField(c, name, "HostConfig.ShmSize") 727 c.Assert(shmSize, check.Equals, "1073741824") 728 } 729 730 func (s *DockerSuite) TestRunTmpfsMounts(c *check.C) { 731 // TODO Windows (Post TP5): This test cannot run on a Windows daemon as 732 // Windows does not support tmpfs mounts. 733 testRequires(c, DaemonIsLinux) 734 if out, _, err := dockerCmdWithError("run", "--tmpfs", "/run", "busybox", "touch", "/run/somefile"); err != nil { 735 c.Fatalf("/run directory not mounted on tmpfs %q %s", err, out) 736 } 737 if out, _, err := dockerCmdWithError("run", "--tmpfs", "/run:noexec", "busybox", "touch", "/run/somefile"); err != nil { 738 c.Fatalf("/run directory not mounted on tmpfs %q %s", err, out) 739 } 740 if out, _, err := dockerCmdWithError("run", "--tmpfs", "/run:noexec,nosuid,rw,size=5k,mode=700", "busybox", "touch", "/run/somefile"); err != nil { 741 c.Fatalf("/run failed to mount on tmpfs with valid options %q %s", err, out) 742 } 743 if _, _, err := dockerCmdWithError("run", "--tmpfs", "/run:foobar", "busybox", "touch", "/run/somefile"); err == nil { 744 c.Fatalf("/run mounted on tmpfs when it should have vailed within invalid mount option") 745 } 746 if _, _, err := dockerCmdWithError("run", "--tmpfs", "/run", "-v", "/run:/run", "busybox", "touch", "/run/somefile"); err == nil { 747 c.Fatalf("Should have generated an error saying Duplicate mount points") 748 } 749 } 750 751 func (s *DockerSuite) TestRunSysctls(c *check.C) { 752 753 testRequires(c, DaemonIsLinux) 754 var err error 755 756 out, _ := dockerCmd(c, "run", "--sysctl", "net.ipv4.ip_forward=1", "--name", "test", "busybox", "cat", "/proc/sys/net/ipv4/ip_forward") 757 c.Assert(strings.TrimSpace(out), check.Equals, "1") 758 759 out = inspectFieldJSON(c, "test", "HostConfig.Sysctls") 760 761 sysctls := make(map[string]string) 762 err = json.Unmarshal([]byte(out), &sysctls) 763 c.Assert(err, check.IsNil) 764 c.Assert(sysctls["net.ipv4.ip_forward"], check.Equals, "1") 765 766 out, _ = dockerCmd(c, "run", "--sysctl", "net.ipv4.ip_forward=0", "--name", "test1", "busybox", "cat", "/proc/sys/net/ipv4/ip_forward") 767 c.Assert(strings.TrimSpace(out), check.Equals, "0") 768 769 out = inspectFieldJSON(c, "test1", "HostConfig.Sysctls") 770 771 err = json.Unmarshal([]byte(out), &sysctls) 772 c.Assert(err, check.IsNil) 773 c.Assert(sysctls["net.ipv4.ip_forward"], check.Equals, "0") 774 775 runCmd := exec.Command(dockerBinary, "run", "--sysctl", "kernel.foobar=1", "--name", "test2", "busybox", "cat", "/proc/sys/kernel/foobar") 776 out, _, _ = runCommandWithOutput(runCmd) 777 if !strings.Contains(out, "invalid value") { 778 c.Fatalf("expected --sysctl to fail, got %s", out) 779 } 780 } 781 782 // TestRunSeccompProfileDenyUnshare checks that 'docker run --security-opt seccomp=/tmp/profile.json debian:jessie unshare' exits with operation not permitted. 783 func (s *DockerSuite) TestRunSeccompProfileDenyUnshare(c *check.C) { 784 testRequires(c, SameHostDaemon, seccompEnabled, NotArm, Apparmor) 785 jsonData := `{ 786 "defaultAction": "SCMP_ACT_ALLOW", 787 "syscalls": [ 788 { 789 "name": "unshare", 790 "action": "SCMP_ACT_ERRNO" 791 } 792 ] 793 }` 794 tmpFile, err := ioutil.TempFile("", "profile.json") 795 defer tmpFile.Close() 796 if err != nil { 797 c.Fatal(err) 798 } 799 800 if _, err := tmpFile.Write([]byte(jsonData)); err != nil { 801 c.Fatal(err) 802 } 803 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor=unconfined", "--security-opt", "seccomp="+tmpFile.Name(), "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc") 804 out, _, _ := runCommandWithOutput(runCmd) 805 if !strings.Contains(out, "Operation not permitted") { 806 c.Fatalf("expected unshare with seccomp profile denied to fail, got %s", out) 807 } 808 } 809 810 // TestRunSeccompProfileDenyChmod checks that 'docker run --security-opt seccomp=/tmp/profile.json busybox chmod 400 /etc/hostname' exits with operation not permitted. 811 func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) { 812 testRequires(c, SameHostDaemon, seccompEnabled) 813 jsonData := `{ 814 "defaultAction": "SCMP_ACT_ALLOW", 815 "syscalls": [ 816 { 817 "name": "chmod", 818 "action": "SCMP_ACT_ERRNO" 819 } 820 ] 821 }` 822 tmpFile, err := ioutil.TempFile("", "profile.json") 823 defer tmpFile.Close() 824 if err != nil { 825 c.Fatal(err) 826 } 827 828 if _, err := tmpFile.Write([]byte(jsonData)); err != nil { 829 c.Fatal(err) 830 } 831 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp="+tmpFile.Name(), "busybox", "chmod", "400", "/etc/hostname") 832 out, _, _ := runCommandWithOutput(runCmd) 833 if !strings.Contains(out, "Operation not permitted") { 834 c.Fatalf("expected chmod with seccomp profile denied to fail, got %s", out) 835 } 836 } 837 838 // TestRunSeccompProfileDenyUnshareUserns checks that 'docker run debian:jessie unshare --map-root-user --user sh -c whoami' with a specific profile to 839 // deny unhare of a userns exits with operation not permitted. 840 func (s *DockerSuite) TestRunSeccompProfileDenyUnshareUserns(c *check.C) { 841 testRequires(c, SameHostDaemon, seccompEnabled, NotArm, Apparmor) 842 // from sched.h 843 jsonData := fmt.Sprintf(`{ 844 "defaultAction": "SCMP_ACT_ALLOW", 845 "syscalls": [ 846 { 847 "name": "unshare", 848 "action": "SCMP_ACT_ERRNO", 849 "args": [ 850 { 851 "index": 0, 852 "value": %d, 853 "op": "SCMP_CMP_EQ" 854 } 855 ] 856 } 857 ] 858 }`, uint64(0x10000000)) 859 tmpFile, err := ioutil.TempFile("", "profile.json") 860 defer tmpFile.Close() 861 if err != nil { 862 c.Fatal(err) 863 } 864 865 if _, err := tmpFile.Write([]byte(jsonData)); err != nil { 866 c.Fatal(err) 867 } 868 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor=unconfined", "--security-opt", "seccomp="+tmpFile.Name(), "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami") 869 out, _, _ := runCommandWithOutput(runCmd) 870 if !strings.Contains(out, "Operation not permitted") { 871 c.Fatalf("expected unshare userns with seccomp profile denied to fail, got %s", out) 872 } 873 } 874 875 // TestRunSeccompProfileDenyCloneUserns checks that 'docker run syscall-test' 876 // with a the default seccomp profile exits with operation not permitted. 877 func (s *DockerSuite) TestRunSeccompProfileDenyCloneUserns(c *check.C) { 878 testRequires(c, SameHostDaemon, seccompEnabled) 879 880 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "userns-test", "id") 881 out, _, err := runCommandWithOutput(runCmd) 882 if err == nil || !strings.Contains(out, "clone failed: Operation not permitted") { 883 c.Fatalf("expected clone userns with default seccomp profile denied to fail, got %s: %v", out, err) 884 } 885 } 886 887 // TestRunSeccompUnconfinedCloneUserns checks that 888 // 'docker run --security-opt seccomp=unconfined syscall-test' allows creating a userns. 889 func (s *DockerSuite) TestRunSeccompUnconfinedCloneUserns(c *check.C) { 890 testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace) 891 892 // make sure running w privileged is ok 893 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "syscall-test", "userns-test", "id") 894 if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") { 895 c.Fatalf("expected clone userns with --security-opt seccomp=unconfined to succeed, got %s: %v", out, err) 896 } 897 } 898 899 // TestRunSeccompAllowPrivCloneUserns checks that 'docker run --privileged syscall-test' 900 // allows creating a userns. 901 func (s *DockerSuite) TestRunSeccompAllowPrivCloneUserns(c *check.C) { 902 testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace) 903 904 // make sure running w privileged is ok 905 runCmd := exec.Command(dockerBinary, "run", "--privileged", "syscall-test", "userns-test", "id") 906 if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") { 907 c.Fatalf("expected clone userns with --privileged to succeed, got %s: %v", out, err) 908 } 909 } 910 911 // TestRunSeccompAllowSetrlimit checks that 'docker run debian:jessie ulimit -v 1048510' succeeds. 912 func (s *DockerSuite) TestRunSeccompAllowSetrlimit(c *check.C) { 913 testRequires(c, SameHostDaemon, seccompEnabled) 914 915 // ulimit uses setrlimit, so we want to make sure we don't break it 916 runCmd := exec.Command(dockerBinary, "run", "debian:jessie", "bash", "-c", "ulimit -v 1048510") 917 if out, _, err := runCommandWithOutput(runCmd); err != nil { 918 c.Fatalf("expected ulimit with seccomp to succeed, got %s: %v", out, err) 919 } 920 } 921 922 func (s *DockerSuite) TestRunSeccompDefaultProfile(c *check.C) { 923 testRequires(c, SameHostDaemon, seccompEnabled, NotUserNamespace) 924 925 var group sync.WaitGroup 926 group.Add(4) 927 errChan := make(chan error, 4) 928 go func() { 929 out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "syscall-test", "acct-test") 930 if err == nil || !strings.Contains(out, "Operation not permitted") { 931 errChan <- fmt.Errorf("expected Operation not permitted, got: %s", out) 932 } 933 group.Done() 934 }() 935 936 go func() { 937 out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "syscall-test", "ns-test", "echo", "hello") 938 if err == nil || !strings.Contains(out, "Operation not permitted") { 939 errChan <- fmt.Errorf("expected Operation not permitted, got: %s", out) 940 } 941 group.Done() 942 }() 943 944 go func() { 945 out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "acct-test") 946 if err == nil || !strings.Contains(out, "No such file or directory") { 947 errChan <- fmt.Errorf("expected No such file or directory, got: %s", out) 948 } 949 group.Done() 950 }() 951 952 go func() { 953 out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "ns-test", "echo", "hello") 954 if err != nil || !strings.Contains(out, "hello") { 955 errChan <- fmt.Errorf("expected hello, got: %s, %v", out, err) 956 } 957 group.Done() 958 }() 959 960 group.Wait() 961 close(errChan) 962 963 for err := range errChan { 964 c.Assert(err, checker.IsNil) 965 } 966 } 967 968 // TestRunNoNewPrivSetuid checks that --security-opt=no-new-privileges prevents 969 // effective uid transtions on executing setuid binaries. 970 func (s *DockerSuite) TestRunNoNewPrivSetuid(c *check.C) { 971 testRequires(c, DaemonIsLinux, NotUserNamespace, SameHostDaemon) 972 973 // test that running a setuid binary results in no effective uid transition 974 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "no-new-privileges", "--user", "1000", "nnp-test", "/usr/bin/nnp-test") 975 if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "EUID=1000") { 976 c.Fatalf("expected output to contain EUID=1000, got %s: %v", out, err) 977 } 978 } 979 980 func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) { 981 testRequires(c, SameHostDaemon, Apparmor) 982 983 // running w seccomp unconfined tests the apparmor profile 984 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/cgroup") 985 if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) { 986 c.Fatalf("expected chmod 777 /proc/1/cgroup to fail, got %s: %v", out, err) 987 } 988 989 runCmd = exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/attr/current") 990 if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) { 991 c.Fatalf("expected chmod 777 /proc/1/attr/current to fail, got %s: %v", out, err) 992 } 993 } 994 995 // make sure the default profile can be successfully parsed (using unshare as it is 996 // something which we know is blocked in the default profile) 997 func (s *DockerSuite) TestRunSeccompWithDefaultProfile(c *check.C) { 998 testRequires(c, SameHostDaemon, seccompEnabled) 999 1000 out, _, err := dockerCmdWithError("run", "--security-opt", "seccomp=../profiles/seccomp/default.json", "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami") 1001 c.Assert(err, checker.NotNil, check.Commentf(out)) 1002 c.Assert(strings.TrimSpace(out), checker.Equals, "unshare: unshare failed: Operation not permitted") 1003 } 1004 1005 // TestRunDeviceSymlink checks run with device that follows symlink (#13840) 1006 func (s *DockerSuite) TestRunDeviceSymlink(c *check.C) { 1007 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm, SameHostDaemon) 1008 if _, err := os.Stat("/dev/zero"); err != nil { 1009 c.Skip("Host does not have /dev/zero") 1010 } 1011 1012 // Create a temporary directory to create symlink 1013 tmpDir, err := ioutil.TempDir("", "docker_device_follow_symlink_tests") 1014 c.Assert(err, checker.IsNil) 1015 1016 defer os.RemoveAll(tmpDir) 1017 1018 // Create a symbolic link to /dev/zero 1019 symZero := filepath.Join(tmpDir, "zero") 1020 err = os.Symlink("/dev/zero", symZero) 1021 c.Assert(err, checker.IsNil) 1022 1023 // Create a temporary file "temp" inside tmpDir, write some data to "tmpDir/temp", 1024 // then create a symlink "tmpDir/file" to the temporary file "tmpDir/temp". 1025 tmpFile := filepath.Join(tmpDir, "temp") 1026 err = ioutil.WriteFile(tmpFile, []byte("temp"), 0666) 1027 c.Assert(err, checker.IsNil) 1028 symFile := filepath.Join(tmpDir, "file") 1029 err = os.Symlink(tmpFile, symFile) 1030 c.Assert(err, checker.IsNil) 1031 1032 // md5sum of 'dd if=/dev/zero bs=4K count=8' is bb7df04e1b0a2570657527a7e108ae23 1033 out, _ := dockerCmd(c, "run", "--device", symZero+":/dev/symzero", "busybox", "sh", "-c", "dd if=/dev/symzero bs=4K count=8 | md5sum") 1034 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "bb7df04e1b0a2570657527a7e108ae23", check.Commentf("expected output bb7df04e1b0a2570657527a7e108ae23")) 1035 1036 // symlink "tmpDir/file" to a file "tmpDir/temp" will result in an error as it is not a device. 1037 out, _, err = dockerCmdWithError("run", "--device", symFile+":/dev/symzero", "busybox", "sh", "-c", "dd if=/dev/symzero bs=4K count=8 | md5sum") 1038 c.Assert(err, check.NotNil) 1039 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "not a device node", check.Commentf("expected output 'not a device node'")) 1040 } 1041 1042 // TestRunPidsLimit makes sure the pids cgroup is set with --pids-limit 1043 func (s *DockerSuite) TestRunPidsLimit(c *check.C) { 1044 testRequires(c, pidsLimit) 1045 1046 file := "/sys/fs/cgroup/pids/pids.max" 1047 out, _ := dockerCmd(c, "run", "--name", "skittles", "--pids-limit", "2", "busybox", "cat", file) 1048 c.Assert(strings.TrimSpace(out), checker.Equals, "2") 1049 1050 out = inspectField(c, "skittles", "HostConfig.PidsLimit") 1051 c.Assert(out, checker.Equals, "2", check.Commentf("setting the pids limit failed")) 1052 } 1053 1054 func (s *DockerSuite) TestRunPrivilegedAllowedDevices(c *check.C) { 1055 testRequires(c, DaemonIsLinux, NotUserNamespace) 1056 1057 file := "/sys/fs/cgroup/devices/devices.list" 1058 out, _ := dockerCmd(c, "run", "--privileged", "busybox", "cat", file) 1059 c.Logf("out: %q", out) 1060 c.Assert(strings.TrimSpace(out), checker.Equals, "a *:* rwm") 1061 } 1062 1063 func (s *DockerSuite) TestRunUserDeviceAllowed(c *check.C) { 1064 testRequires(c, DaemonIsLinux) 1065 1066 fi, err := os.Stat("/dev/snd/timer") 1067 if err != nil { 1068 c.Skip("Host does not have /dev/snd/timer") 1069 } 1070 stat, ok := fi.Sys().(*syscall.Stat_t) 1071 if !ok { 1072 c.Skip("Could not stat /dev/snd/timer") 1073 } 1074 1075 file := "/sys/fs/cgroup/devices/devices.list" 1076 out, _ := dockerCmd(c, "run", "--device", "/dev/snd/timer:w", "busybox", "cat", file) 1077 c.Assert(out, checker.Contains, fmt.Sprintf("c %d:%d w", stat.Rdev/256, stat.Rdev%256)) 1078 }