github.com/iamlotus/docker@v1.8.1/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 }