github.com/slene/docker@v1.8.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"
    12  	"path/filepath"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/docker/docker/pkg/mount"
    17  	"github.com/go-check/check"
    18  	"github.com/kr/pty"
    19  )
    20  
    21  // #6509
    22  func (s *DockerSuite) TestRunRedirectStdout(c *check.C) {
    23  	checkRedirect := func(command string) {
    24  		_, tty, err := pty.Open()
    25  		if err != nil {
    26  			c.Fatalf("Could not open pty: %v", err)
    27  		}
    28  		cmd := exec.Command("sh", "-c", command)
    29  		cmd.Stdin = tty
    30  		cmd.Stdout = tty
    31  		cmd.Stderr = tty
    32  		if err := cmd.Start(); err != nil {
    33  			c.Fatalf("start err: %v", err)
    34  		}
    35  		ch := make(chan error)
    36  		go func() {
    37  			ch <- cmd.Wait()
    38  			close(ch)
    39  		}()
    40  
    41  		select {
    42  		case <-time.After(10 * time.Second):
    43  			c.Fatal("command timeout")
    44  		case err := <-ch:
    45  			if err != nil {
    46  				c.Fatalf("wait err=%v", err)
    47  			}
    48  		}
    49  	}
    50  
    51  	checkRedirect(dockerBinary + " run -i busybox cat /etc/passwd | grep -q root")
    52  	checkRedirect(dockerBinary + " run busybox cat /etc/passwd | grep -q root")
    53  }
    54  
    55  // Test recursive bind mount works by default
    56  func (s *DockerSuite) TestRunWithVolumesIsRecursive(c *check.C) {
    57  	tmpDir, err := ioutil.TempDir("", "docker_recursive_mount_test")
    58  	if err != nil {
    59  		c.Fatal(err)
    60  	}
    61  
    62  	defer os.RemoveAll(tmpDir)
    63  
    64  	// Create a temporary tmpfs mount.
    65  	tmpfsDir := filepath.Join(tmpDir, "tmpfs")
    66  	if err := os.MkdirAll(tmpfsDir, 0777); err != nil {
    67  		c.Fatalf("failed to mkdir at %s - %s", tmpfsDir, err)
    68  	}
    69  	if err := mount.Mount("tmpfs", tmpfsDir, "tmpfs", ""); err != nil {
    70  		c.Fatalf("failed to create a tmpfs mount at %s - %s", tmpfsDir, err)
    71  	}
    72  
    73  	f, err := ioutil.TempFile(tmpfsDir, "touch-me")
    74  	if err != nil {
    75  		c.Fatal(err)
    76  	}
    77  	defer f.Close()
    78  
    79  	runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", fmt.Sprintf("%s:/tmp:ro", tmpDir), "busybox:latest", "ls", "/tmp/tmpfs")
    80  	out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd)
    81  	if err != nil && exitCode != 0 {
    82  		c.Fatal(out, stderr, err)
    83  	}
    84  	if !strings.Contains(out, filepath.Base(f.Name())) {
    85  		c.Fatal("Recursive bind mount test failed. Expected file not found")
    86  	}
    87  }
    88  
    89  func (s *DockerSuite) TestRunWithUlimits(c *check.C) {
    90  	testRequires(c, NativeExecDriver)
    91  
    92  	out, _ := dockerCmd(c, "run", "--name=testulimits", "--ulimit", "nofile=42", "busybox", "/bin/sh", "-c", "ulimit -n")
    93  	ul := strings.TrimSpace(out)
    94  	if ul != "42" {
    95  		c.Fatalf("expected `ulimit -n` to be 42, got %s", ul)
    96  	}
    97  }
    98  
    99  func (s *DockerSuite) TestRunContainerWithCgroupParent(c *check.C) {
   100  	testRequires(c, NativeExecDriver)
   101  
   102  	cgroupParent := "test"
   103  	name := "cgroup-test"
   104  
   105  	out, _, err := dockerCmdWithError(c, "run", "--cgroup-parent", cgroupParent, "--name", name, "busybox", "cat", "/proc/self/cgroup")
   106  	if err != nil {
   107  		c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err)
   108  	}
   109  	cgroupPaths := parseCgroupPaths(string(out))
   110  	if len(cgroupPaths) == 0 {
   111  		c.Fatalf("unexpected output - %q", string(out))
   112  	}
   113  	id, err := getIDByName(name)
   114  	c.Assert(err, check.IsNil)
   115  	expectedCgroup := path.Join(cgroupParent, id)
   116  	found := false
   117  	for _, path := range cgroupPaths {
   118  		if strings.HasSuffix(path, expectedCgroup) {
   119  			found = true
   120  			break
   121  		}
   122  	}
   123  	if !found {
   124  		c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have suffix %q. Cgroup Paths: %v", expectedCgroup, cgroupPaths)
   125  	}
   126  }
   127  
   128  func (s *DockerSuite) TestRunContainerWithCgroupParentAbsPath(c *check.C) {
   129  	testRequires(c, NativeExecDriver)
   130  
   131  	cgroupParent := "/cgroup-parent/test"
   132  	name := "cgroup-test"
   133  	out, _, err := dockerCmdWithError(c, "run", "--cgroup-parent", cgroupParent, "--name", name, "busybox", "cat", "/proc/self/cgroup")
   134  	if err != nil {
   135  		c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err)
   136  	}
   137  	cgroupPaths := parseCgroupPaths(string(out))
   138  	if len(cgroupPaths) == 0 {
   139  		c.Fatalf("unexpected output - %q", string(out))
   140  	}
   141  	id, err := getIDByName(name)
   142  	c.Assert(err, check.IsNil)
   143  	expectedCgroup := path.Join(cgroupParent, id)
   144  	found := false
   145  	for _, path := range cgroupPaths {
   146  		if strings.HasSuffix(path, expectedCgroup) {
   147  			found = true
   148  			break
   149  		}
   150  	}
   151  	if !found {
   152  		c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have suffix %q. Cgroup Paths: %v", expectedCgroup, cgroupPaths)
   153  	}
   154  }
   155  
   156  func (s *DockerSuite) TestRunContainerWithCgroupMountRO(c *check.C) {
   157  	testRequires(c, NativeExecDriver)
   158  
   159  	filename := "/sys/fs/cgroup/devices/test123"
   160  	out, _, err := dockerCmdWithError(c, "run", "busybox", "touch", filename)
   161  	if err == nil {
   162  		c.Fatal("expected cgroup mount point to be read-only, touch file should fail")
   163  	}
   164  	expected := "Read-only file system"
   165  	if !strings.Contains(out, expected) {
   166  		c.Fatalf("expected output from failure to contain %s but contains %s", expected, out)
   167  	}
   168  }
   169  
   170  func (s *DockerSuite) TestRunDeviceDirectory(c *check.C) {
   171  	testRequires(c, NativeExecDriver)
   172  
   173  	out, _ := dockerCmd(c, "run", "--device", "/dev/snd:/dev/snd", "busybox", "sh", "-c", "ls /dev/snd/")
   174  	if actual := strings.Trim(out, "\r\n"); !strings.Contains(out, "timer") {
   175  		c.Fatalf("expected output /dev/snd/timer, received %s", actual)
   176  	}
   177  
   178  	out, _ = dockerCmd(c, "run", "--device", "/dev/snd:/dev/othersnd", "busybox", "sh", "-c", "ls /dev/othersnd/")
   179  	if actual := strings.Trim(out, "\r\n"); !strings.Contains(out, "seq") {
   180  		c.Fatalf("expected output /dev/othersnd/seq, received %s", actual)
   181  	}
   182  }
   183  
   184  // TestRunDetach checks attaching and detaching with the escape sequence.
   185  func (s *DockerSuite) TestRunAttachDetach(c *check.C) {
   186  	name := "attach-detach"
   187  	cmd := exec.Command(dockerBinary, "run", "--name", name, "-it", "busybox", "cat")
   188  	stdout, err := cmd.StdoutPipe()
   189  	if err != nil {
   190  		c.Fatal(err)
   191  	}
   192  	cpty, tty, err := pty.Open()
   193  	if err != nil {
   194  		c.Fatal(err)
   195  	}
   196  	defer cpty.Close()
   197  	cmd.Stdin = tty
   198  	if err := cmd.Start(); err != nil {
   199  		c.Fatal(err)
   200  	}
   201  	if err := waitRun(name); err != nil {
   202  		c.Fatal(err)
   203  	}
   204  
   205  	if _, err := cpty.Write([]byte("hello\n")); err != nil {
   206  		c.Fatal(err)
   207  	}
   208  
   209  	out, err := bufio.NewReader(stdout).ReadString('\n')
   210  	if err != nil {
   211  		c.Fatal(err)
   212  	}
   213  	if strings.TrimSpace(out) != "hello" {
   214  		c.Fatalf("expected 'hello', got %q", out)
   215  	}
   216  
   217  	// escape sequence
   218  	if _, err := cpty.Write([]byte{16}); err != nil {
   219  		c.Fatal(err)
   220  	}
   221  	time.Sleep(100 * time.Millisecond)
   222  	if _, err := cpty.Write([]byte{17}); err != nil {
   223  		c.Fatal(err)
   224  	}
   225  
   226  	ch := make(chan struct{})
   227  	go func() {
   228  		cmd.Wait()
   229  		ch <- struct{}{}
   230  	}()
   231  
   232  	running, err := inspectField(name, "State.Running")
   233  	if err != nil {
   234  		c.Fatal(err)
   235  	}
   236  	if running != "true" {
   237  		c.Fatal("expected container to still be running")
   238  	}
   239  
   240  	go func() {
   241  		exec.Command(dockerBinary, "kill", name).Run()
   242  	}()
   243  
   244  	select {
   245  	case <-ch:
   246  	case <-time.After(10 * time.Millisecond):
   247  		c.Fatal("timed out waiting for container to exit")
   248  	}
   249  }
   250  
   251  // "test" should be printed
   252  func (s *DockerSuite) TestRunEchoStdoutWithCPUQuota(c *check.C) {
   253  	testRequires(c, cpuCfsQuota)
   254  
   255  	out, _, err := dockerCmdWithError(c, "run", "--cpu-quota", "8000", "--name", "test", "busybox", "echo", "test")
   256  	if err != nil {
   257  		c.Fatalf("failed to run container: %v, output: %q", err, out)
   258  	}
   259  	out = strings.TrimSpace(out)
   260  	if out != "test" {
   261  		c.Errorf("container should've printed 'test'")
   262  	}
   263  
   264  	out, err = inspectField("test", "HostConfig.CpuQuota")
   265  	c.Assert(err, check.IsNil)
   266  
   267  	if out != "8000" {
   268  		c.Fatalf("setting the CPU CFS quota failed")
   269  	}
   270  }
   271  
   272  func (s *DockerSuite) TestRunWithCpuPeriod(c *check.C) {
   273  	testRequires(c, cpuCfsPeriod)
   274  
   275  	if _, _, err := dockerCmdWithError(c, "run", "--cpu-period", "50000", "--name", "test", "busybox", "true"); err != nil {
   276  		c.Fatalf("failed to run container: %v", err)
   277  	}
   278  
   279  	out, err := inspectField("test", "HostConfig.CpuPeriod")
   280  	c.Assert(err, check.IsNil)
   281  	if out != "50000" {
   282  		c.Fatalf("setting the CPU CFS period failed")
   283  	}
   284  }
   285  
   286  func (s *DockerSuite) TestRunOOMExitCode(c *check.C) {
   287  	testRequires(c, oomControl)
   288  	errChan := make(chan error)
   289  	go func() {
   290  		defer close(errChan)
   291  		out, exitCode, _ := dockerCmdWithError(c, "run", "-m", "4MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done")
   292  		if expected := 137; exitCode != expected {
   293  			errChan <- fmt.Errorf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out)
   294  		}
   295  	}()
   296  
   297  	select {
   298  	case err := <-errChan:
   299  		c.Assert(err, check.IsNil)
   300  	case <-time.After(30 * time.Second):
   301  		c.Fatal("Timeout waiting for container to die on OOM")
   302  	}
   303  }
   304  
   305  func (s *DockerSuite) TestContainerNetworkModeToSelf(c *check.C) {
   306  	out, _, err := dockerCmdWithError(c, "run", "--name=me", "--net=container:me", "busybox", "true")
   307  	if err == nil || !strings.Contains(out, "cannot join own network") {
   308  		c.Fatalf("using container net mode to self should result in an error")
   309  	}
   310  }
   311  
   312  func (s *DockerSuite) TestRunContainerNetModeWithDnsMacHosts(c *check.C) {
   313  	out, _, err := dockerCmdWithError(c, "run", "-d", "--name", "parent", "busybox", "top")
   314  	if err != nil {
   315  		c.Fatalf("failed to run container: %v, output: %q", err, out)
   316  	}
   317  
   318  	out, _, err = dockerCmdWithError(c, "run", "--dns", "1.2.3.4", "--net=container:parent", "busybox")
   319  	if err == nil || !strings.Contains(out, "Conflicting options: --dns and the network mode") {
   320  		c.Fatalf("run --net=container with --dns should error out")
   321  	}
   322  
   323  	out, _, err = dockerCmdWithError(c, "run", "--mac-address", "92:d0:c6:0a:29:33", "--net=container:parent", "busybox")
   324  	if err == nil || !strings.Contains(out, "--mac-address and the network mode") {
   325  		c.Fatalf("run --net=container with --mac-address should error out")
   326  	}
   327  
   328  	out, _, err = dockerCmdWithError(c, "run", "--add-host", "test:192.168.2.109", "--net=container:parent", "busybox")
   329  	if err == nil || !strings.Contains(out, "--add-host and the network mode") {
   330  		c.Fatalf("run --net=container with --add-host should error out")
   331  	}
   332  }
   333  
   334  func (s *DockerSuite) TestRunContainerNetModeWithExposePort(c *check.C) {
   335  	dockerCmd(c, "run", "-d", "--name", "parent", "busybox", "top")
   336  
   337  	out, _, err := dockerCmdWithError(c, "run", "-p", "5000:5000", "--net=container:parent", "busybox")
   338  	if err == nil || !strings.Contains(out, "Conflicting options: -p, -P, --publish-all, --publish and the network mode (--net)") {
   339  		c.Fatalf("run --net=container with -p should error out")
   340  	}
   341  
   342  	out, _, err = dockerCmdWithError(c, "run", "-P", "--net=container:parent", "busybox")
   343  	if err == nil || !strings.Contains(out, "Conflicting options: -p, -P, --publish-all, --publish and the network mode (--net)") {
   344  		c.Fatalf("run --net=container with -P should error out")
   345  	}
   346  
   347  	out, _, err = dockerCmdWithError(c, "run", "--expose", "5000", "--net=container:parent", "busybox")
   348  	if err == nil || !strings.Contains(out, "Conflicting options: --expose and the network mode (--expose)") {
   349  		c.Fatalf("run --net=container with --expose should error out")
   350  	}
   351  }
   352  
   353  func (s *DockerSuite) TestRunLinkToContainerNetMode(c *check.C) {
   354  	dockerCmd(c, "run", "--name", "test", "-d", "busybox", "top")
   355  	dockerCmd(c, "run", "--name", "parent", "-d", "--net=container:test", "busybox", "top")
   356  	dockerCmd(c, "run", "-d", "--link=parent:parent", "busybox", "top")
   357  	dockerCmd(c, "run", "--name", "child", "-d", "--net=container:parent", "busybox", "top")
   358  	dockerCmd(c, "run", "-d", "--link=child:child", "busybox", "top")
   359  }
   360  
   361  func (s *DockerSuite) TestRunLoopbackOnlyExistsWhenNetworkingDisabled(c *check.C) {
   362  	out, _ := dockerCmd(c, "run", "--net=none", "busybox", "ip", "-o", "-4", "a", "show", "up")
   363  
   364  	var (
   365  		count = 0
   366  		parts = strings.Split(out, "\n")
   367  	)
   368  
   369  	for _, l := range parts {
   370  		if l != "" {
   371  			count++
   372  		}
   373  	}
   374  
   375  	if count != 1 {
   376  		c.Fatalf("Wrong interface count in container %d", count)
   377  	}
   378  
   379  	if !strings.HasPrefix(out, "1: lo") {
   380  		c.Fatalf("Wrong interface in test container: expected [1: lo], got %s", out)
   381  	}
   382  }
   383  
   384  // Issue #4681
   385  func (s *DockerSuite) TestRunLoopbackWhenNetworkDisabled(c *check.C) {
   386  	dockerCmd(c, "run", "--net=none", "busybox", "ping", "-c", "1", "127.0.0.1")
   387  }
   388  
   389  func (s *DockerSuite) TestRunModeNetContainerHostname(c *check.C) {
   390  	testRequires(c, ExecSupport)
   391  
   392  	dockerCmd(c, "run", "-i", "-d", "--name", "parent", "busybox", "top")
   393  	out, _ := dockerCmd(c, "exec", "parent", "cat", "/etc/hostname")
   394  	out1, _ := dockerCmd(c, "run", "--net=container:parent", "busybox", "cat", "/etc/hostname")
   395  
   396  	if out1 != out {
   397  		c.Fatal("containers with shared net namespace should have same hostname")
   398  	}
   399  }
   400  
   401  func (s *DockerSuite) TestRunNetworkNotInitializedNoneMode(c *check.C) {
   402  	out, _, err := dockerCmdWithError(c, "run", "-d", "--net=none", "busybox", "top")
   403  	id := strings.TrimSpace(out)
   404  	res, err := inspectField(id, "NetworkSettings.IPAddress")
   405  	c.Assert(err, check.IsNil)
   406  	if res != "" {
   407  		c.Fatalf("For 'none' mode network must not be initialized, but container got IP: %s", res)
   408  	}
   409  }
   410  
   411  func (s *DockerSuite) TestTwoContainersInNetHost(c *check.C) {
   412  	dockerCmd(c, "run", "-d", "--net=host", "--name=first", "busybox", "top")
   413  	dockerCmd(c, "run", "-d", "--net=host", "--name=second", "busybox", "top")
   414  	dockerCmd(c, "stop", "first")
   415  	dockerCmd(c, "stop", "second")
   416  }