github.com/squaremo/docker@v1.3.2-0.20150516120342-42cfc9554972/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 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--name=testulimits", "--ulimit", "nofile=42", "busybox", "/bin/sh", "-c", "ulimit -n")) 92 if err != nil { 93 c.Fatal(err, out) 94 } 95 96 ul := strings.TrimSpace(out) 97 if ul != "42" { 98 c.Fatalf("expected `ulimit -n` to be 42, got %s", ul) 99 } 100 } 101 102 func (s *DockerSuite) TestRunContainerWithCgroupParent(c *check.C) { 103 testRequires(c, NativeExecDriver) 104 105 cgroupParent := "test" 106 data, err := ioutil.ReadFile("/proc/self/cgroup") 107 if err != nil { 108 c.Fatalf("failed to read '/proc/self/cgroup - %v", err) 109 } 110 selfCgroupPaths := parseCgroupPaths(string(data)) 111 selfCpuCgroup, found := selfCgroupPaths["memory"] 112 if !found { 113 c.Fatalf("unable to find self cpu cgroup path. CgroupsPath: %v", selfCgroupPaths) 114 } 115 116 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--cgroup-parent", cgroupParent, "--rm", "busybox", "cat", "/proc/self/cgroup")) 117 if err != nil { 118 c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err) 119 } 120 cgroupPaths := parseCgroupPaths(string(out)) 121 if len(cgroupPaths) == 0 { 122 c.Fatalf("unexpected output - %q", string(out)) 123 } 124 found = false 125 expectedCgroupPrefix := path.Join(selfCpuCgroup, cgroupParent) 126 for _, path := range cgroupPaths { 127 if strings.HasPrefix(path, expectedCgroupPrefix) { 128 found = true 129 break 130 } 131 } 132 if !found { 133 c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have prefix %q. Cgroup Paths: %v", expectedCgroupPrefix, cgroupPaths) 134 } 135 } 136 137 func (s *DockerSuite) TestRunContainerWithCgroupParentAbsPath(c *check.C) { 138 testRequires(c, NativeExecDriver) 139 140 cgroupParent := "/cgroup-parent/test" 141 142 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--cgroup-parent", cgroupParent, "--rm", "busybox", "cat", "/proc/self/cgroup")) 143 if err != nil { 144 c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err) 145 } 146 cgroupPaths := parseCgroupPaths(string(out)) 147 if len(cgroupPaths) == 0 { 148 c.Fatalf("unexpected output - %q", string(out)) 149 } 150 found := false 151 for _, path := range cgroupPaths { 152 if strings.HasPrefix(path, cgroupParent) { 153 found = true 154 break 155 } 156 } 157 if !found { 158 c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have prefix %q. Cgroup Paths: %v", cgroupParent, cgroupPaths) 159 } 160 } 161 162 func (s *DockerSuite) TestRunDeviceDirectory(c *check.C) { 163 testRequires(c, NativeExecDriver) 164 cmd := exec.Command(dockerBinary, "run", "--device", "/dev/snd:/dev/snd", "busybox", "sh", "-c", "ls /dev/snd/") 165 166 out, _, err := runCommandWithOutput(cmd) 167 if err != nil { 168 c.Fatal(err, out) 169 } 170 171 if actual := strings.Trim(out, "\r\n"); !strings.Contains(out, "timer") { 172 c.Fatalf("expected output /dev/snd/timer, received %s", actual) 173 } 174 175 cmd = exec.Command(dockerBinary, "run", "--device", "/dev/snd:/dev/othersnd", "busybox", "sh", "-c", "ls /dev/othersnd/") 176 177 out, _, err = runCommandWithOutput(cmd) 178 if err != nil { 179 c.Fatal(err, out) 180 } 181 182 if actual := strings.Trim(out, "\r\n"); !strings.Contains(out, "seq") { 183 c.Fatalf("expected output /dev/othersnd/seq, received %s", actual) 184 } 185 } 186 187 // TestRunDetach checks attaching and detaching with the escape sequence. 188 func (s *DockerSuite) TestRunAttachDetach(c *check.C) { 189 name := "attach-detach" 190 cmd := exec.Command(dockerBinary, "run", "--name", name, "-it", "busybox", "cat") 191 stdout, err := cmd.StdoutPipe() 192 if err != nil { 193 c.Fatal(err) 194 } 195 cpty, tty, err := pty.Open() 196 if err != nil { 197 c.Fatal(err) 198 } 199 defer cpty.Close() 200 cmd.Stdin = tty 201 if err := cmd.Start(); err != nil { 202 c.Fatal(err) 203 } 204 if err := waitRun(name); err != nil { 205 c.Fatal(err) 206 } 207 208 if _, err := cpty.Write([]byte("hello\n")); err != nil { 209 c.Fatal(err) 210 } 211 212 out, err := bufio.NewReader(stdout).ReadString('\n') 213 if err != nil { 214 c.Fatal(err) 215 } 216 if strings.TrimSpace(out) != "hello" { 217 c.Fatalf("expected 'hello', got %q", out) 218 } 219 220 // escape sequence 221 if _, err := cpty.Write([]byte{16}); err != nil { 222 c.Fatal(err) 223 } 224 time.Sleep(100 * time.Millisecond) 225 if _, err := cpty.Write([]byte{17}); err != nil { 226 c.Fatal(err) 227 } 228 229 ch := make(chan struct{}) 230 go func() { 231 cmd.Wait() 232 ch <- struct{}{} 233 }() 234 235 running, err := inspectField(name, "State.Running") 236 if err != nil { 237 c.Fatal(err) 238 } 239 if running != "true" { 240 c.Fatal("expected container to still be running") 241 } 242 243 go func() { 244 exec.Command(dockerBinary, "kill", name).Run() 245 }() 246 247 select { 248 case <-ch: 249 case <-time.After(10 * time.Millisecond): 250 c.Fatal("timed out waiting for container to exit") 251 } 252 }