start.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package client
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "strings"
  7. "github.com/Sirupsen/logrus"
  8. "github.com/docker/docker/api/types"
  9. Cli "github.com/docker/docker/cli"
  10. flag "github.com/docker/docker/pkg/mflag"
  11. "github.com/docker/docker/pkg/promise"
  12. "github.com/docker/docker/pkg/signal"
  13. )
  14. func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
  15. sigc := make(chan os.Signal, 128)
  16. signal.CatchAll(sigc)
  17. go func() {
  18. for s := range sigc {
  19. if s == signal.SIGCHLD {
  20. continue
  21. }
  22. var sig string
  23. for sigStr, sigN := range signal.SignalMap {
  24. if sigN == s {
  25. sig = sigStr
  26. break
  27. }
  28. }
  29. if sig == "" {
  30. fmt.Fprintf(cli.err, "Unsupported signal: %v. Discarding.\n", s)
  31. continue
  32. }
  33. if err := cli.client.ContainerKill(cid, sig); err != nil {
  34. logrus.Debugf("Error sending signal: %s", err)
  35. }
  36. }
  37. }()
  38. return sigc
  39. }
  40. // CmdStart starts one or more containers.
  41. //
  42. // Usage: docker start [OPTIONS] CONTAINER [CONTAINER...]
  43. func (cli *DockerCli) CmdStart(args ...string) error {
  44. cmd := Cli.Subcmd("start", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["start"].Description, true)
  45. attach := cmd.Bool([]string{"a", "-attach"}, false, "Attach STDOUT/STDERR and forward signals")
  46. openStdin := cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
  47. cmd.Require(flag.Min, 1)
  48. cmd.ParseFlags(args, true)
  49. if *attach || *openStdin {
  50. // We're going to attach to a container.
  51. // 1. Ensure we only have one container.
  52. if cmd.NArg() > 1 {
  53. return fmt.Errorf("You cannot start and attach multiple containers at once.")
  54. }
  55. // 2. Attach to the container.
  56. containerID := cmd.Arg(0)
  57. c, err := cli.client.ContainerInspect(containerID)
  58. if err != nil {
  59. return err
  60. }
  61. if !c.Config.Tty {
  62. sigc := cli.forwardAllSignals(containerID)
  63. defer signal.StopCatch(sigc)
  64. }
  65. options := types.ContainerAttachOptions{
  66. ContainerID: containerID,
  67. Stream: true,
  68. Stdin: *openStdin && c.Config.OpenStdin,
  69. Stdout: true,
  70. Stderr: true,
  71. }
  72. var in io.ReadCloser
  73. if options.Stdin {
  74. in = cli.in
  75. }
  76. resp, err := cli.client.ContainerAttach(options)
  77. if err != nil {
  78. return err
  79. }
  80. defer resp.Close()
  81. cErr := promise.Go(func() error {
  82. return cli.holdHijackedConnection(c.Config.Tty, in, cli.out, cli.err, resp)
  83. })
  84. // 3. Start the container.
  85. if err := cli.client.ContainerStart(containerID); err != nil {
  86. return err
  87. }
  88. // 4. Wait for attachment to break.
  89. if c.Config.Tty && cli.isTerminalOut {
  90. if err := cli.monitorTtySize(containerID, false); err != nil {
  91. fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
  92. }
  93. }
  94. if attchErr := <-cErr; attchErr != nil {
  95. return attchErr
  96. }
  97. _, status, err := getExitCode(cli, containerID)
  98. if err != nil {
  99. return err
  100. }
  101. if status != 0 {
  102. return Cli.StatusError{StatusCode: status}
  103. }
  104. } else {
  105. // We're not going to attach to anything.
  106. // Start as many containers as we want.
  107. return cli.startContainersWithoutAttachments(cmd.Args())
  108. }
  109. return nil
  110. }
  111. func (cli *DockerCli) startContainersWithoutAttachments(containerIDs []string) error {
  112. var failedContainers []string
  113. for _, containerID := range containerIDs {
  114. if err := cli.client.ContainerStart(containerID); err != nil {
  115. fmt.Fprintf(cli.err, "%s\n", err)
  116. failedContainers = append(failedContainers, containerID)
  117. } else {
  118. fmt.Fprintf(cli.out, "%s\n", containerID)
  119. }
  120. }
  121. if len(failedContainers) > 0 {
  122. return fmt.Errorf("Error: failed to start containers: %v", strings.Join(failedContainers, ", "))
  123. }
  124. return nil
  125. }