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