github.com/slowteetoe/docker@v1.7.1-rc3/integration-cli/docker_cli_exec_test.go (about) 1 // +build !test_no_exec 2 3 package main 4 5 import ( 6 "bufio" 7 "fmt" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "reflect" 12 "sort" 13 "strings" 14 "sync" 15 "time" 16 17 "github.com/go-check/check" 18 ) 19 20 func (s *DockerSuite) TestExec(c *check.C) { 21 22 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && top") 23 if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil { 24 c.Fatal(out, err) 25 } 26 27 execCmd := exec.Command(dockerBinary, "exec", "testing", "cat", "/tmp/file") 28 out, _, err := runCommandWithOutput(execCmd) 29 if err != nil { 30 c.Fatal(out, err) 31 } 32 33 out = strings.Trim(out, "\r\n") 34 35 if expected := "test"; out != expected { 36 c.Errorf("container exec should've printed %q but printed %q", expected, out) 37 } 38 39 } 40 41 func (s *DockerSuite) TestExecInteractive(c *check.C) { 42 43 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && top") 44 if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil { 45 c.Fatal(out, err) 46 } 47 48 execCmd := exec.Command(dockerBinary, "exec", "-i", "testing", "sh") 49 stdin, err := execCmd.StdinPipe() 50 if err != nil { 51 c.Fatal(err) 52 } 53 stdout, err := execCmd.StdoutPipe() 54 if err != nil { 55 c.Fatal(err) 56 } 57 58 if err := execCmd.Start(); err != nil { 59 c.Fatal(err) 60 } 61 if _, err := stdin.Write([]byte("cat /tmp/file\n")); err != nil { 62 c.Fatal(err) 63 } 64 65 r := bufio.NewReader(stdout) 66 line, err := r.ReadString('\n') 67 if err != nil { 68 c.Fatal(err) 69 } 70 line = strings.TrimSpace(line) 71 if line != "test" { 72 c.Fatalf("Output should be 'test', got '%q'", line) 73 } 74 if err := stdin.Close(); err != nil { 75 c.Fatal(err) 76 } 77 errChan := make(chan error) 78 go func() { 79 errChan <- execCmd.Wait() 80 close(errChan) 81 }() 82 select { 83 case err := <-errChan: 84 c.Assert(err, check.IsNil) 85 case <-time.After(1 * time.Second): 86 c.Fatal("docker exec failed to exit on stdin close") 87 } 88 89 } 90 91 func (s *DockerSuite) TestExecAfterContainerRestart(c *check.C) { 92 93 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 94 out, _, err := runCommandWithOutput(runCmd) 95 if err != nil { 96 c.Fatal(out, err) 97 } 98 99 cleanedContainerID := strings.TrimSpace(out) 100 101 runCmd = exec.Command(dockerBinary, "restart", cleanedContainerID) 102 if out, _, err = runCommandWithOutput(runCmd); err != nil { 103 c.Fatal(out, err) 104 } 105 106 runCmd = exec.Command(dockerBinary, "exec", cleanedContainerID, "echo", "hello") 107 out, _, err = runCommandWithOutput(runCmd) 108 if err != nil { 109 c.Fatal(out, err) 110 } 111 112 outStr := strings.TrimSpace(out) 113 if outStr != "hello" { 114 c.Errorf("container should've printed hello, instead printed %q", outStr) 115 } 116 117 } 118 119 func (s *DockerDaemonSuite) TestExecAfterDaemonRestart(c *check.C) { 120 testRequires(c, SameHostDaemon) 121 122 if err := s.d.StartWithBusybox(); err != nil { 123 c.Fatalf("Could not start daemon with busybox: %v", err) 124 } 125 126 if out, err := s.d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top"); err != nil { 127 c.Fatalf("Could not run top: err=%v\n%s", err, out) 128 } 129 130 if err := s.d.Restart(); err != nil { 131 c.Fatalf("Could not restart daemon: %v", err) 132 } 133 134 if out, err := s.d.Cmd("start", "top"); err != nil { 135 c.Fatalf("Could not start top after daemon restart: err=%v\n%s", err, out) 136 } 137 138 out, err := s.d.Cmd("exec", "top", "echo", "hello") 139 if err != nil { 140 c.Fatalf("Could not exec on container top: err=%v\n%s", err, out) 141 } 142 143 outStr := strings.TrimSpace(string(out)) 144 if outStr != "hello" { 145 c.Errorf("container should've printed hello, instead printed %q", outStr) 146 } 147 } 148 149 // Regression test for #9155, #9044 150 func (s *DockerSuite) TestExecEnv(c *check.C) { 151 152 runCmd := exec.Command(dockerBinary, "run", 153 "-e", "LALA=value1", 154 "-e", "LALA=value2", 155 "-d", "--name", "testing", "busybox", "top") 156 if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil { 157 c.Fatal(out, err) 158 } 159 160 execCmd := exec.Command(dockerBinary, "exec", "testing", "env") 161 out, _, err := runCommandWithOutput(execCmd) 162 if err != nil { 163 c.Fatal(out, err) 164 } 165 166 if strings.Contains(out, "LALA=value1") || 167 !strings.Contains(out, "LALA=value2") || 168 !strings.Contains(out, "HOME=/root") { 169 c.Errorf("exec env(%q), expect %q, %q", out, "LALA=value2", "HOME=/root") 170 } 171 172 } 173 174 func (s *DockerSuite) TestExecExitStatus(c *check.C) { 175 176 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "top", "busybox", "top") 177 if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil { 178 c.Fatal(out, err) 179 } 180 181 // Test normal (non-detached) case first 182 cmd := exec.Command(dockerBinary, "exec", "top", "sh", "-c", "exit 23") 183 ec, _ := runCommand(cmd) 184 185 if ec != 23 { 186 c.Fatalf("Should have had an ExitCode of 23, not: %d", ec) 187 } 188 189 } 190 191 func (s *DockerSuite) TestExecPausedContainer(c *check.C) { 192 defer unpauseAllContainers() 193 194 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top") 195 out, _, err := runCommandWithOutput(runCmd) 196 if err != nil { 197 c.Fatal(out, err) 198 } 199 200 ContainerID := strings.TrimSpace(out) 201 202 pausedCmd := exec.Command(dockerBinary, "pause", "testing") 203 out, _, _, err = runCommandWithStdoutStderr(pausedCmd) 204 if err != nil { 205 c.Fatal(out, err) 206 } 207 208 execCmd := exec.Command(dockerBinary, "exec", "-i", "-t", ContainerID, "echo", "hello") 209 out, _, err = runCommandWithOutput(execCmd) 210 if err == nil { 211 c.Fatal("container should fail to exec new command if it is paused") 212 } 213 214 expected := ContainerID + " is paused, unpause the container before exec" 215 if !strings.Contains(out, expected) { 216 c.Fatal("container should not exec new command if it is paused") 217 } 218 219 } 220 221 // regression test for #9476 222 func (s *DockerSuite) TestExecTtyCloseStdin(c *check.C) { 223 224 cmd := exec.Command(dockerBinary, "run", "-d", "-it", "--name", "exec_tty_stdin", "busybox") 225 if out, _, err := runCommandWithOutput(cmd); err != nil { 226 c.Fatal(out, err) 227 } 228 229 cmd = exec.Command(dockerBinary, "exec", "-i", "exec_tty_stdin", "cat") 230 stdinRw, err := cmd.StdinPipe() 231 if err != nil { 232 c.Fatal(err) 233 } 234 235 stdinRw.Write([]byte("test")) 236 stdinRw.Close() 237 238 if out, _, err := runCommandWithOutput(cmd); err != nil { 239 c.Fatal(out, err) 240 } 241 242 cmd = exec.Command(dockerBinary, "top", "exec_tty_stdin") 243 out, _, err := runCommandWithOutput(cmd) 244 if err != nil { 245 c.Fatal(out, err) 246 } 247 248 outArr := strings.Split(out, "\n") 249 if len(outArr) > 3 || strings.Contains(out, "nsenter-exec") { 250 // This is the really bad part 251 if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "rm", "-f", "exec_tty_stdin")); err != nil { 252 c.Fatal(out, err) 253 } 254 255 c.Fatalf("exec process left running\n\t %s", out) 256 } 257 258 } 259 260 func (s *DockerSuite) TestExecTtyWithoutStdin(c *check.C) { 261 262 cmd := exec.Command(dockerBinary, "run", "-d", "-ti", "busybox") 263 out, _, err := runCommandWithOutput(cmd) 264 if err != nil { 265 c.Fatalf("failed to start container: %v (%v)", out, err) 266 } 267 268 id := strings.TrimSpace(out) 269 if err := waitRun(id); err != nil { 270 c.Fatal(err) 271 } 272 273 defer func() { 274 cmd := exec.Command(dockerBinary, "kill", id) 275 if out, _, err := runCommandWithOutput(cmd); err != nil { 276 c.Fatalf("failed to kill container: %v (%v)", out, err) 277 } 278 }() 279 280 errChan := make(chan error) 281 go func() { 282 defer close(errChan) 283 284 cmd := exec.Command(dockerBinary, "exec", "-ti", id, "true") 285 if _, err := cmd.StdinPipe(); err != nil { 286 errChan <- err 287 return 288 } 289 290 expected := "cannot enable tty mode" 291 if out, _, err := runCommandWithOutput(cmd); err == nil { 292 errChan <- fmt.Errorf("exec should have failed") 293 return 294 } else if !strings.Contains(out, expected) { 295 errChan <- fmt.Errorf("exec failed with error %q: expected %q", out, expected) 296 return 297 } 298 }() 299 300 select { 301 case err := <-errChan: 302 c.Assert(err, check.IsNil) 303 case <-time.After(3 * time.Second): 304 c.Fatal("exec is running but should have failed") 305 } 306 307 } 308 309 func (s *DockerSuite) TestExecParseError(c *check.C) { 310 311 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "top", "busybox", "top") 312 if out, _, err := runCommandWithOutput(runCmd); err != nil { 313 c.Fatal(out, err) 314 } 315 316 // Test normal (non-detached) case first 317 cmd := exec.Command(dockerBinary, "exec", "top") 318 if _, stderr, code, err := runCommandWithStdoutStderr(cmd); err == nil || !strings.Contains(stderr, "See '"+dockerBinary+" exec --help'") || code == 0 { 319 c.Fatalf("Should have thrown error & point to help: %s", stderr) 320 } 321 } 322 323 func (s *DockerSuite) TestExecStopNotHanging(c *check.C) { 324 if out, err := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top").CombinedOutput(); err != nil { 325 c.Fatal(out, err) 326 } 327 328 if err := exec.Command(dockerBinary, "exec", "testing", "top").Start(); err != nil { 329 c.Fatal(err) 330 } 331 332 type dstop struct { 333 out []byte 334 err error 335 } 336 337 ch := make(chan dstop) 338 go func() { 339 out, err := exec.Command(dockerBinary, "stop", "testing").CombinedOutput() 340 ch <- dstop{out, err} 341 close(ch) 342 }() 343 select { 344 case <-time.After(3 * time.Second): 345 c.Fatal("Container stop timed out") 346 case s := <-ch: 347 c.Assert(s.err, check.IsNil) 348 } 349 } 350 351 func (s *DockerSuite) TestExecCgroup(c *check.C) { 352 var cmd *exec.Cmd 353 354 cmd = exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top") 355 _, err := runCommand(cmd) 356 if err != nil { 357 c.Fatal(err) 358 } 359 360 cmd = exec.Command(dockerBinary, "exec", "testing", "cat", "/proc/1/cgroup") 361 out, _, err := runCommandWithOutput(cmd) 362 if err != nil { 363 c.Fatal(out, err) 364 } 365 containerCgroups := sort.StringSlice(strings.Split(string(out), "\n")) 366 367 var wg sync.WaitGroup 368 var mu sync.Mutex 369 execCgroups := []sort.StringSlice{} 370 errChan := make(chan error) 371 // exec a few times concurrently to get consistent failure 372 for i := 0; i < 5; i++ { 373 wg.Add(1) 374 go func() { 375 cmd := exec.Command(dockerBinary, "exec", "testing", "cat", "/proc/self/cgroup") 376 out, _, err := runCommandWithOutput(cmd) 377 if err != nil { 378 errChan <- err 379 return 380 } 381 cg := sort.StringSlice(strings.Split(string(out), "\n")) 382 383 mu.Lock() 384 execCgroups = append(execCgroups, cg) 385 mu.Unlock() 386 wg.Done() 387 }() 388 } 389 wg.Wait() 390 close(errChan) 391 392 for err := range errChan { 393 c.Assert(err, check.IsNil) 394 } 395 396 for _, cg := range execCgroups { 397 if !reflect.DeepEqual(cg, containerCgroups) { 398 fmt.Println("exec cgroups:") 399 for _, name := range cg { 400 fmt.Printf(" %s\n", name) 401 } 402 403 fmt.Println("container cgroups:") 404 for _, name := range containerCgroups { 405 fmt.Printf(" %s\n", name) 406 } 407 c.Fatal("cgroups mismatched") 408 } 409 } 410 411 } 412 413 func (s *DockerSuite) TestInspectExecID(c *check.C) { 414 415 out, exitCode, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "busybox", "top")) 416 if exitCode != 0 || err != nil { 417 c.Fatalf("failed to run container: %s, %v", out, err) 418 } 419 id := strings.TrimSuffix(out, "\n") 420 421 out, err = inspectField(id, "ExecIDs") 422 if err != nil { 423 c.Fatalf("failed to inspect container: %s, %v", out, err) 424 } 425 if out != "[]" { 426 c.Fatalf("ExecIDs should be empty, got: %s", out) 427 } 428 429 exitCode, err = runCommand(exec.Command(dockerBinary, "exec", "-d", id, "ls", "/")) 430 if exitCode != 0 || err != nil { 431 c.Fatalf("failed to exec in container: %s, %v", out, err) 432 } 433 434 out, err = inspectField(id, "ExecIDs") 435 if err != nil { 436 c.Fatalf("failed to inspect container: %s, %v", out, err) 437 } 438 439 out = strings.TrimSuffix(out, "\n") 440 if out == "[]" || out == "<no value>" { 441 c.Fatalf("ExecIDs should not be empty, got: %s", out) 442 } 443 444 } 445 446 func (s *DockerSuite) TestLinksPingLinkedContainersOnRename(c *check.C) { 447 var out string 448 out, _ = dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top") 449 idA := strings.TrimSpace(out) 450 if idA == "" { 451 c.Fatal(out, "id should not be nil") 452 } 453 out, _ = dockerCmd(c, "run", "-d", "--link", "container1:alias1", "--name", "container2", "busybox", "top") 454 idB := strings.TrimSpace(out) 455 if idB == "" { 456 c.Fatal(out, "id should not be nil") 457 } 458 459 execCmd := exec.Command(dockerBinary, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1") 460 out, _, err := runCommandWithOutput(execCmd) 461 if err != nil { 462 c.Fatal(out, err) 463 } 464 465 dockerCmd(c, "rename", "container1", "container_new") 466 467 execCmd = exec.Command(dockerBinary, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1") 468 out, _, err = runCommandWithOutput(execCmd) 469 if err != nil { 470 c.Fatal(out, err) 471 } 472 473 } 474 475 func (s *DockerSuite) TestRunExecDir(c *check.C) { 476 testRequires(c, SameHostDaemon) 477 cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 478 out, _, err := runCommandWithOutput(cmd) 479 if err != nil { 480 c.Fatal(err, out) 481 } 482 id := strings.TrimSpace(out) 483 execDir := filepath.Join(execDriverPath, id) 484 stateFile := filepath.Join(execDir, "state.json") 485 486 { 487 fi, err := os.Stat(execDir) 488 if err != nil { 489 c.Fatal(err) 490 } 491 if !fi.IsDir() { 492 c.Fatalf("%q must be a directory", execDir) 493 } 494 fi, err = os.Stat(stateFile) 495 if err != nil { 496 c.Fatal(err) 497 } 498 } 499 500 stopCmd := exec.Command(dockerBinary, "stop", id) 501 out, _, err = runCommandWithOutput(stopCmd) 502 if err != nil { 503 c.Fatal(err, out) 504 } 505 { 506 _, err := os.Stat(execDir) 507 if err == nil { 508 c.Fatal(err) 509 } 510 if err == nil { 511 c.Fatalf("Exec directory %q exists for removed container!", execDir) 512 } 513 if !os.IsNotExist(err) { 514 c.Fatalf("Error should be about non-existing, got %s", err) 515 } 516 } 517 startCmd := exec.Command(dockerBinary, "start", id) 518 out, _, err = runCommandWithOutput(startCmd) 519 if err != nil { 520 c.Fatal(err, out) 521 } 522 { 523 fi, err := os.Stat(execDir) 524 if err != nil { 525 c.Fatal(err) 526 } 527 if !fi.IsDir() { 528 c.Fatalf("%q must be a directory", execDir) 529 } 530 fi, err = os.Stat(stateFile) 531 if err != nil { 532 c.Fatal(err) 533 } 534 } 535 rmCmd := exec.Command(dockerBinary, "rm", "-f", id) 536 out, _, err = runCommandWithOutput(rmCmd) 537 if err != nil { 538 c.Fatal(err, out) 539 } 540 { 541 _, err := os.Stat(execDir) 542 if err == nil { 543 c.Fatal(err) 544 } 545 if err == nil { 546 c.Fatalf("Exec directory %q is exists for removed container!", execDir) 547 } 548 if !os.IsNotExist(err) { 549 c.Fatalf("Error should be about non-existing, got %s", err) 550 } 551 } 552 553 } 554 555 func (s *DockerSuite) TestRunMutableNetworkFiles(c *check.C) { 556 testRequires(c, SameHostDaemon) 557 558 for _, fn := range []string{"resolv.conf", "hosts"} { 559 deleteAllContainers() 560 561 content, err := runCommandAndReadContainerFile(fn, exec.Command(dockerBinary, "run", "-d", "--name", "c1", "busybox", "sh", "-c", fmt.Sprintf("echo success >/etc/%s && top", fn))) 562 if err != nil { 563 c.Fatal(err) 564 } 565 566 if strings.TrimSpace(string(content)) != "success" { 567 c.Fatal("Content was not what was modified in the container", string(content)) 568 } 569 570 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "c2", "busybox", "top")) 571 if err != nil { 572 c.Fatal(err) 573 } 574 575 contID := strings.TrimSpace(out) 576 577 netFilePath := containerStorageFile(contID, fn) 578 579 f, err := os.OpenFile(netFilePath, os.O_WRONLY|os.O_SYNC|os.O_APPEND, 0644) 580 if err != nil { 581 c.Fatal(err) 582 } 583 584 if _, err := f.Seek(0, 0); err != nil { 585 f.Close() 586 c.Fatal(err) 587 } 588 589 if err := f.Truncate(0); err != nil { 590 f.Close() 591 c.Fatal(err) 592 } 593 594 if _, err := f.Write([]byte("success2\n")); err != nil { 595 f.Close() 596 c.Fatal(err) 597 } 598 f.Close() 599 600 res, err := exec.Command(dockerBinary, "exec", contID, "cat", "/etc/"+fn).CombinedOutput() 601 if err != nil { 602 c.Fatalf("Output: %s, error: %s", res, err) 603 } 604 if string(res) != "success2\n" { 605 c.Fatalf("Expected content of %s: %q, got: %q", fn, "success2\n", res) 606 } 607 } 608 } 609 610 func (s *DockerSuite) TestExecWithUser(c *check.C) { 611 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "parent", "busybox", "top") 612 if out, _, err := runCommandWithOutput(runCmd); err != nil { 613 c.Fatal(out, err) 614 } 615 616 cmd := exec.Command(dockerBinary, "exec", "-u", "1", "parent", "id") 617 out, _, err := runCommandWithOutput(cmd) 618 if err != nil { 619 c.Fatal(err, out) 620 } 621 if !strings.Contains(out, "uid=1(daemon) gid=1(daemon)") { 622 c.Fatalf("exec with user by id expected daemon user got %s", out) 623 } 624 625 cmd = exec.Command(dockerBinary, "exec", "-u", "root", "parent", "id") 626 out, _, err = runCommandWithOutput(cmd) 627 if err != nil { 628 c.Fatal(err, out) 629 } 630 if !strings.Contains(out, "uid=0(root) gid=0(root)") { 631 c.Fatalf("exec with user by root expected root user got %s", out) 632 } 633 634 } 635 636 func (s *DockerSuite) TestExecWithImageUser(c *check.C) { 637 name := "testbuilduser" 638 _, err := buildImage(name, 639 `FROM busybox 640 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 641 USER dockerio`, 642 true) 643 if err != nil { 644 c.Fatalf("Could not build image %s: %v", name, err) 645 } 646 647 dockerCmd(c, "run", "-d", "--name", "dockerioexec", name, "top") 648 649 out, _ := dockerCmd(c, "exec", "dockerioexec", "whoami") 650 if !strings.Contains(out, "dockerio") { 651 c.Fatalf("exec with user by id expected dockerio user got %s", out) 652 } 653 }