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  }