exec.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package client
  2. import (
  3. "fmt"
  4. "io"
  5. "github.com/Sirupsen/logrus"
  6. "github.com/docker/docker/api/types"
  7. Cli "github.com/docker/docker/cli"
  8. "github.com/docker/docker/pkg/promise"
  9. "github.com/docker/docker/runconfig"
  10. )
  11. // CmdExec runs a command in a running container.
  12. //
  13. // Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
  14. func (cli *DockerCli) CmdExec(args ...string) error {
  15. cmd := Cli.Subcmd("exec", []string{"CONTAINER COMMAND [ARG...]"}, Cli.DockerCommands["exec"].Description, true)
  16. execConfig, err := runconfig.ParseExec(cmd, args)
  17. // just in case the ParseExec does not exit
  18. if execConfig.Container == "" || err != nil {
  19. return Cli.StatusError{StatusCode: 1}
  20. }
  21. response, err := cli.client.ContainerExecCreate(*execConfig)
  22. if err != nil {
  23. return err
  24. }
  25. execID := response.ID
  26. if execID == "" {
  27. fmt.Fprintf(cli.out, "exec ID empty")
  28. return nil
  29. }
  30. //Temp struct for execStart so that we don't need to transfer all the execConfig
  31. if !execConfig.Detach {
  32. if err := cli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil {
  33. return err
  34. }
  35. } else {
  36. execStartCheck := types.ExecStartCheck{
  37. Detach: execConfig.Detach,
  38. Tty: execConfig.Tty,
  39. }
  40. if err := cli.client.ContainerExecStart(execID, execStartCheck); err != nil {
  41. return err
  42. }
  43. // For now don't print this - wait for when we support exec wait()
  44. // fmt.Fprintf(cli.out, "%s\n", execID)
  45. return nil
  46. }
  47. // Interactive exec requested.
  48. var (
  49. out, stderr io.Writer
  50. in io.ReadCloser
  51. errCh chan error
  52. )
  53. if execConfig.AttachStdin {
  54. in = cli.in
  55. }
  56. if execConfig.AttachStdout {
  57. out = cli.out
  58. }
  59. if execConfig.AttachStderr {
  60. if execConfig.Tty {
  61. stderr = cli.out
  62. } else {
  63. stderr = cli.err
  64. }
  65. }
  66. resp, err := cli.client.ContainerExecAttach(execID, *execConfig)
  67. if err != nil {
  68. return err
  69. }
  70. defer resp.Close()
  71. errCh = promise.Go(func() error {
  72. return cli.holdHijackedConnection(execConfig.Tty, in, out, stderr, resp)
  73. })
  74. if execConfig.Tty && cli.isTerminalIn {
  75. if err := cli.monitorTtySize(execID, true); err != nil {
  76. fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
  77. }
  78. }
  79. if err := <-errCh; err != nil {
  80. logrus.Debugf("Error hijack: %s", err)
  81. return err
  82. }
  83. var status int
  84. if _, status, err = getExecExitCode(cli, execID); err != nil {
  85. return err
  86. }
  87. if status != 0 {
  88. return Cli.StatusError{StatusCode: status}
  89. }
  90. return nil
  91. }