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