github.com/damirazo/docker@v1.9.0/integration-cli/docker_cli_run_unix_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "bufio" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "strconv" 13 "strings" 14 "time" 15 16 "github.com/docker/docker/pkg/integration/checker" 17 "github.com/docker/docker/pkg/mount" 18 "github.com/docker/docker/pkg/parsers" 19 "github.com/docker/docker/pkg/sysinfo" 20 "github.com/docker/docker/pkg/units" 21 "github.com/go-check/check" 22 "github.com/kr/pty" 23 ) 24 25 // #6509 26 func (s *DockerSuite) TestRunRedirectStdout(c *check.C) { 27 checkRedirect := func(command string) { 28 _, tty, err := pty.Open() 29 if err != nil { 30 c.Fatalf("Could not open pty: %v", err) 31 } 32 cmd := exec.Command("sh", "-c", command) 33 cmd.Stdin = tty 34 cmd.Stdout = tty 35 cmd.Stderr = tty 36 if err := cmd.Start(); err != nil { 37 c.Fatalf("start err: %v", err) 38 } 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 if err != nil { 50 c.Fatalf("wait err=%v", err) 51 } 52 } 53 } 54 55 checkRedirect(dockerBinary + " run -i busybox cat /etc/passwd | grep -q root") 56 checkRedirect(dockerBinary + " run busybox cat /etc/passwd | grep -q root") 57 } 58 59 // Test recursive bind mount works by default 60 func (s *DockerSuite) TestRunWithVolumesIsRecursive(c *check.C) { 61 // /tmp gets permission denied 62 testRequires(c, NotUserNamespace) 63 tmpDir, err := ioutil.TempDir("", "docker_recursive_mount_test") 64 if err != nil { 65 c.Fatal(err) 66 } 67 68 defer os.RemoveAll(tmpDir) 69 70 // Create a temporary tmpfs mount. 71 tmpfsDir := filepath.Join(tmpDir, "tmpfs") 72 if err := os.MkdirAll(tmpfsDir, 0777); err != nil { 73 c.Fatalf("failed to mkdir at %s - %s", tmpfsDir, err) 74 } 75 if err := mount.Mount("tmpfs", tmpfsDir, "tmpfs", ""); err != nil { 76 c.Fatalf("failed to create a tmpfs mount at %s - %s", tmpfsDir, err) 77 } 78 79 f, err := ioutil.TempFile(tmpfsDir, "touch-me") 80 if err != nil { 81 c.Fatal(err) 82 } 83 defer f.Close() 84 85 runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", fmt.Sprintf("%s:/tmp:ro", tmpDir), "busybox:latest", "ls", "/tmp/tmpfs") 86 out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd) 87 if err != nil && exitCode != 0 { 88 c.Fatal(out, stderr, err) 89 } 90 if !strings.Contains(out, filepath.Base(f.Name())) { 91 c.Fatal("Recursive bind mount test failed. Expected file not found") 92 } 93 } 94 95 func (s *DockerSuite) TestRunDeviceDirectory(c *check.C) { 96 testRequires(c, NativeExecDriver, NotUserNamespace) 97 if _, err := os.Stat("/dev/snd"); err != nil { 98 c.Skip("Host does not have /dev/snd") 99 } 100 101 out, _ := dockerCmd(c, "run", "--device", "/dev/snd:/dev/snd", "busybox", "sh", "-c", "ls /dev/snd/") 102 if actual := strings.Trim(out, "\r\n"); !strings.Contains(out, "timer") { 103 c.Fatalf("expected output /dev/snd/timer, received %s", actual) 104 } 105 106 out, _ = dockerCmd(c, "run", "--device", "/dev/snd:/dev/othersnd", "busybox", "sh", "-c", "ls /dev/othersnd/") 107 if actual := strings.Trim(out, "\r\n"); !strings.Contains(out, "seq") { 108 c.Fatalf("expected output /dev/othersnd/seq, received %s", actual) 109 } 110 } 111 112 // TestRunDetach checks attaching and detaching with the escape sequence. 113 func (s *DockerSuite) TestRunAttachDetach(c *check.C) { 114 name := "attach-detach" 115 cmd := exec.Command(dockerBinary, "run", "--name", name, "-it", "busybox", "cat") 116 stdout, err := cmd.StdoutPipe() 117 if err != nil { 118 c.Fatal(err) 119 } 120 cpty, tty, err := pty.Open() 121 if err != nil { 122 c.Fatal(err) 123 } 124 defer cpty.Close() 125 cmd.Stdin = tty 126 if err := cmd.Start(); err != nil { 127 c.Fatal(err) 128 } 129 c.Assert(waitRun(name), check.IsNil) 130 131 if _, err := cpty.Write([]byte("hello\n")); err != nil { 132 c.Fatal(err) 133 } 134 135 out, err := bufio.NewReader(stdout).ReadString('\n') 136 if err != nil { 137 c.Fatal(err) 138 } 139 if strings.TrimSpace(out) != "hello" { 140 c.Fatalf("expected 'hello', got %q", out) 141 } 142 143 // escape sequence 144 if _, err := cpty.Write([]byte{16}); err != nil { 145 c.Fatal(err) 146 } 147 time.Sleep(100 * time.Millisecond) 148 if _, err := cpty.Write([]byte{17}); err != nil { 149 c.Fatal(err) 150 } 151 152 ch := make(chan struct{}) 153 go func() { 154 cmd.Wait() 155 ch <- struct{}{} 156 }() 157 158 running, err := inspectField(name, "State.Running") 159 if err != nil { 160 c.Fatal(err) 161 } 162 if running != "true" { 163 c.Fatal("expected container to still be running") 164 } 165 166 go func() { 167 exec.Command(dockerBinary, "kill", name).Run() 168 }() 169 170 select { 171 case <-ch: 172 case <-time.After(10 * time.Millisecond): 173 c.Fatal("timed out waiting for container to exit") 174 } 175 } 176 177 // "test" should be printed 178 func (s *DockerSuite) TestRunEchoStdoutWithCPUQuota(c *check.C) { 179 testRequires(c, cpuCfsQuota) 180 181 out, _, err := dockerCmdWithError("run", "--cpu-quota", "8000", "--name", "test", "busybox", "echo", "test") 182 if err != nil { 183 c.Fatalf("failed to run container: %v, output: %q", err, out) 184 } 185 out = strings.TrimSpace(out) 186 if out != "test" { 187 c.Errorf("container should've printed 'test'") 188 } 189 190 out, err = inspectField("test", "HostConfig.CpuQuota") 191 c.Assert(err, check.IsNil) 192 193 if out != "8000" { 194 c.Fatalf("setting the CPU CFS quota failed") 195 } 196 } 197 198 func (s *DockerSuite) TestRunWithCpuPeriod(c *check.C) { 199 testRequires(c, cpuCfsPeriod) 200 201 if _, _, err := dockerCmdWithError("run", "--cpu-period", "50000", "--name", "test", "busybox", "true"); err != nil { 202 c.Fatalf("failed to run container: %v", err) 203 } 204 205 out, err := inspectField("test", "HostConfig.CpuPeriod") 206 c.Assert(err, check.IsNil) 207 if out != "50000" { 208 c.Fatalf("setting the CPU CFS period failed") 209 } 210 } 211 212 func (s *DockerSuite) TestRunWithKernelMemory(c *check.C) { 213 testRequires(c, kernelMemorySupport) 214 215 dockerCmd(c, "run", "--kernel-memory", "50M", "--name", "test1", "busybox", "true") 216 217 out, err := inspectField("test1", "HostConfig.KernelMemory") 218 c.Assert(err, check.IsNil) 219 c.Assert(out, check.Equals, "52428800") 220 221 out, _, err = dockerCmdWithError("run", "--kernel-memory", "-16m", "--name", "test2", "busybox", "echo", "test") 222 expected := "invalid size" 223 c.Assert(err, check.NotNil) 224 c.Assert(out, checker.Contains, expected) 225 } 226 227 // "test" should be printed 228 func (s *DockerSuite) TestRunEchoStdoutWitCPUShares(c *check.C) { 229 testRequires(c, cpuShare) 230 out, _ := dockerCmd(c, "run", "--cpu-shares", "1000", "busybox", "echo", "test") 231 if out != "test\n" { 232 c.Errorf("container should've printed 'test', got %q instead", out) 233 } 234 } 235 236 // "test" should be printed 237 func (s *DockerSuite) TestRunEchoStdoutWithCPUSharesAndMemoryLimit(c *check.C) { 238 testRequires(c, cpuShare) 239 testRequires(c, memoryLimitSupport) 240 out, _, _ := dockerCmdWithStdoutStderr(c, "run", "--cpu-shares", "1000", "-m", "16m", "busybox", "echo", "test") 241 if out != "test\n" { 242 c.Errorf("container should've printed 'test', got %q instead", out) 243 } 244 } 245 246 func (s *DockerSuite) TestRunWithCpuset(c *check.C) { 247 testRequires(c, cgroupCpuset) 248 if _, code := dockerCmd(c, "run", "--cpuset", "0", "busybox", "true"); code != 0 { 249 c.Fatalf("container should run successfully with cpuset of 0") 250 } 251 } 252 253 func (s *DockerSuite) TestRunWithCpusetCpus(c *check.C) { 254 testRequires(c, cgroupCpuset) 255 if _, code := dockerCmd(c, "run", "--cpuset-cpus", "0", "busybox", "true"); code != 0 { 256 c.Fatalf("container should run successfully with cpuset-cpus of 0") 257 } 258 } 259 260 func (s *DockerSuite) TestRunWithCpusetMems(c *check.C) { 261 testRequires(c, cgroupCpuset) 262 if _, code := dockerCmd(c, "run", "--cpuset-mems", "0", "busybox", "true"); code != 0 { 263 c.Fatalf("container should run successfully with cpuset-mems of 0") 264 } 265 } 266 267 func (s *DockerSuite) TestRunWithBlkioWeight(c *check.C) { 268 testRequires(c, blkioWeight) 269 if _, code := dockerCmd(c, "run", "--blkio-weight", "300", "busybox", "true"); code != 0 { 270 c.Fatalf("container should run successfully with blkio-weight of 300") 271 } 272 } 273 274 func (s *DockerSuite) TestRunWithBlkioInvalidWeight(c *check.C) { 275 testRequires(c, blkioWeight) 276 if _, _, err := dockerCmdWithError("run", "--blkio-weight", "5", "busybox", "true"); err == nil { 277 c.Fatalf("run with invalid blkio-weight should failed") 278 } 279 } 280 281 func (s *DockerSuite) TestRunOOMExitCode(c *check.C) { 282 testRequires(c, oomControl) 283 errChan := make(chan error) 284 go func() { 285 defer close(errChan) 286 //changing memory to 40MB from 4MB due to an issue with GCCGO that test fails to start the container. 287 out, exitCode, _ := dockerCmdWithError("run", "-m", "40MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done") 288 if expected := 137; exitCode != expected { 289 errChan <- fmt.Errorf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out) 290 } 291 }() 292 293 select { 294 case err := <-errChan: 295 c.Assert(err, check.IsNil) 296 case <-time.After(30 * time.Second): 297 c.Fatal("Timeout waiting for container to die on OOM") 298 } 299 } 300 301 // "test" should be printed 302 func (s *DockerSuite) TestRunEchoStdoutWithMemoryLimit(c *check.C) { 303 testRequires(c, memoryLimitSupport) 304 out, _, _ := dockerCmdWithStdoutStderr(c, "run", "-m", "16m", "busybox", "echo", "test") 305 out = strings.Trim(out, "\r\n") 306 307 if expected := "test"; out != expected { 308 c.Fatalf("container should've printed %q but printed %q", expected, out) 309 } 310 } 311 312 // TestRunWithoutMemoryswapLimit sets memory limit and disables swap 313 // memory limit, this means the processes in the container can use 314 // 16M memory and as much swap memory as they need (if the host 315 // supports swap memory). 316 func (s *DockerSuite) TestRunWithoutMemoryswapLimit(c *check.C) { 317 testRequires(c, NativeExecDriver) 318 testRequires(c, memoryLimitSupport) 319 testRequires(c, swapMemorySupport) 320 dockerCmd(c, "run", "-m", "16m", "--memory-swap", "-1", "busybox", "true") 321 } 322 323 func (s *DockerSuite) TestRunWithSwappiness(c *check.C) { 324 testRequires(c, memorySwappinessSupport) 325 dockerCmd(c, "run", "--memory-swappiness", "0", "busybox", "true") 326 } 327 328 func (s *DockerSuite) TestRunWithSwappinessInvalid(c *check.C) { 329 testRequires(c, memorySwappinessSupport) 330 out, _, err := dockerCmdWithError("run", "--memory-swappiness", "101", "busybox", "true") 331 c.Assert(err, check.NotNil) 332 expected := "Valid memory swappiness range is 0-100" 333 c.Assert(out, checker.Contains, expected, check.Commentf("Expected output to contain %q, not %q", out, expected)) 334 335 out, _, err = dockerCmdWithError("run", "--memory-swappiness", "-10", "busybox", "true") 336 c.Assert(err, check.NotNil) 337 c.Assert(out, checker.Contains, expected, check.Commentf("Expected output to contain %q, not %q", out, expected)) 338 } 339 340 func (s *DockerSuite) TestRunWithMemoryReservation(c *check.C) { 341 testRequires(c, memoryReservationSupport) 342 dockerCmd(c, "run", "--memory-reservation", "200M", "busybox", "true") 343 } 344 345 func (s *DockerSuite) TestRunWithMemoryReservationInvalid(c *check.C) { 346 testRequires(c, memoryLimitSupport) 347 testRequires(c, memoryReservationSupport) 348 out, _, err := dockerCmdWithError("run", "-m", "500M", "--memory-reservation", "800M", "busybox", "true") 349 c.Assert(err, check.NotNil) 350 expected := "Minimum memory limit should be larger than memory reservation limit" 351 if !strings.Contains(strings.TrimSpace(out), expected) { 352 c.Fatalf("run container should fail with invalid memory reservation, output: %q", out) 353 } 354 } 355 356 func (s *DockerSuite) TestStopContainerSignal(c *check.C) { 357 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`) 358 containerID := strings.TrimSpace(out) 359 360 if err := waitRun(containerID); err != nil { 361 c.Fatal(err) 362 } 363 364 dockerCmd(c, "stop", containerID) 365 out, _ = dockerCmd(c, "logs", containerID) 366 367 if !strings.Contains(out, "exit trapped") { 368 c.Fatalf("Expected `exit trapped` in the log, got %v", out) 369 } 370 } 371 372 func (s *DockerSuite) TestRunSwapLessThanMemoryLimit(c *check.C) { 373 testRequires(c, memoryLimitSupport) 374 testRequires(c, swapMemorySupport) 375 out, _, err := dockerCmdWithError("run", "-m", "16m", "--memory-swap", "15m", "busybox", "echo", "test") 376 expected := "Minimum memoryswap limit should be larger than memory limit" 377 c.Assert(err, check.NotNil) 378 379 if !strings.Contains(out, expected) { 380 c.Fatalf("Expected output to contain %q, not %q", out, expected) 381 } 382 } 383 384 func (s *DockerSuite) TestRunInvalidCpusetCpusFlagValue(c *check.C) { 385 testRequires(c, cgroupCpuset) 386 387 sysInfo := sysinfo.New(true) 388 cpus, err := parsers.ParseUintList(sysInfo.Cpus) 389 c.Assert(err, check.IsNil) 390 var invalid int 391 for i := 0; i <= len(cpus)+1; i++ { 392 if !cpus[i] { 393 invalid = i 394 break 395 } 396 } 397 out, _, err := dockerCmdWithError("run", "--cpuset-cpus", strconv.Itoa(invalid), "busybox", "true") 398 c.Assert(err, check.NotNil) 399 expected := fmt.Sprintf("Error response from daemon: Requested CPUs are not available - requested %s, available: %s.\n", strconv.Itoa(invalid), sysInfo.Cpus) 400 c.Assert(out, check.Equals, expected, check.Commentf("Expected output to contain %q, got %q", expected, out)) 401 } 402 403 func (s *DockerSuite) TestRunInvalidCpusetMemsFlagValue(c *check.C) { 404 testRequires(c, cgroupCpuset) 405 406 sysInfo := sysinfo.New(true) 407 mems, err := parsers.ParseUintList(sysInfo.Mems) 408 c.Assert(err, check.IsNil) 409 var invalid int 410 for i := 0; i <= len(mems)+1; i++ { 411 if !mems[i] { 412 invalid = i 413 break 414 } 415 } 416 out, _, err := dockerCmdWithError("run", "--cpuset-mems", strconv.Itoa(invalid), "busybox", "true") 417 c.Assert(err, check.NotNil) 418 expected := fmt.Sprintf("Error response from daemon: Requested memory nodes are not available - requested %s, available: %s.\n", strconv.Itoa(invalid), sysInfo.Mems) 419 c.Assert(out, check.Equals, expected, check.Commentf("Expected output to contain %q, got %q", expected, out)) 420 } 421 422 func (s *DockerSuite) TestRunInvalidCPUShares(c *check.C) { 423 testRequires(c, cpuShare, NativeExecDriver) 424 out, _, err := dockerCmdWithError("run", "--cpu-shares", "1", "busybox", "echo", "test") 425 c.Assert(err, check.NotNil, check.Commentf(out)) 426 expected := "The minimum allowed cpu-shares is 2" 427 c.Assert(out, checker.Contains, expected) 428 429 out, _, err = dockerCmdWithError("run", "--cpu-shares", "-1", "busybox", "echo", "test") 430 c.Assert(err, check.NotNil, check.Commentf(out)) 431 expected = "shares: invalid argument" 432 c.Assert(out, checker.Contains, expected) 433 434 out, _, err = dockerCmdWithError("run", "--cpu-shares", "99999999", "busybox", "echo", "test") 435 c.Assert(err, check.NotNil, check.Commentf(out)) 436 expected = "The maximum allowed cpu-shares is" 437 c.Assert(out, checker.Contains, expected) 438 } 439 440 func (s *DockerSuite) TestRunWithCorrectMemorySwapOnLXC(c *check.C) { 441 testRequires(c, memoryLimitSupport) 442 testRequires(c, swapMemorySupport) 443 testRequires(c, SameHostDaemon) 444 445 out, _ := dockerCmd(c, "run", "-d", "-m", "16m", "--memory-swap", "64m", "busybox", "top") 446 if _, err := os.Stat("/sys/fs/cgroup/memory/lxc"); err != nil { 447 c.Skip("Excecution driver must be LXC for this test") 448 } 449 id := strings.TrimSpace(out) 450 memorySwap, err := ioutil.ReadFile(fmt.Sprintf("/sys/fs/cgroup/memory/lxc/%s/memory.memsw.limit_in_bytes", id)) 451 c.Assert(err, check.IsNil) 452 cgSwap, err := strconv.ParseInt(strings.TrimSpace(string(memorySwap)), 10, 64) 453 c.Assert(err, check.IsNil) 454 swap, err := units.RAMInBytes("64m") 455 c.Assert(err, check.IsNil) 456 c.Assert(cgSwap, check.Equals, swap) 457 }