github.com/ncdc/docker@v0.10.1-0.20160129113957-6c6729ef5b74/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 Cli "github.com/docker/docker/cli" 11 flag "github.com/docker/docker/pkg/mflag" 12 "github.com/docker/docker/pkg/promise" 13 "github.com/docker/docker/pkg/signal" 14 "github.com/docker/engine-api/types" 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 detachKeys := cmd.String([]string{"-detach-keys"}, "", "Override the key sequence for detaching a container") 53 cmd.Require(flag.Min, 1) 54 55 cmd.ParseFlags(args, true) 56 57 if *attach || *openStdin { 58 // We're going to attach to a container. 59 // 1. Ensure we only have one container. 60 if cmd.NArg() > 1 { 61 return fmt.Errorf("You cannot start and attach multiple containers at once.") 62 } 63 64 // 2. Attach to the container. 65 containerID := cmd.Arg(0) 66 c, err := cli.client.ContainerInspect(containerID) 67 if err != nil { 68 return err 69 } 70 71 if !c.Config.Tty { 72 sigc := cli.forwardAllSignals(containerID) 73 defer signal.StopCatch(sigc) 74 } 75 76 if *detachKeys != "" { 77 cli.configFile.DetachKeys = *detachKeys 78 } 79 80 options := types.ContainerAttachOptions{ 81 ContainerID: containerID, 82 Stream: true, 83 Stdin: *openStdin && c.Config.OpenStdin, 84 Stdout: true, 85 Stderr: true, 86 DetachKeys: cli.configFile.DetachKeys, 87 } 88 89 var in io.ReadCloser 90 if options.Stdin { 91 in = cli.in 92 } 93 94 resp, err := cli.client.ContainerAttach(options) 95 if err != nil { 96 return err 97 } 98 defer resp.Close() 99 if in != nil && c.Config.Tty { 100 if err := cli.setRawTerminal(); err != nil { 101 return err 102 } 103 defer cli.restoreTerminal(in) 104 } 105 106 cErr := promise.Go(func() error { 107 return cli.holdHijackedConnection(c.Config.Tty, in, cli.out, cli.err, resp) 108 }) 109 110 // 3. Start the container. 111 if err := cli.client.ContainerStart(containerID); err != nil { 112 return err 113 } 114 115 // 4. Wait for attachment to break. 116 if c.Config.Tty && cli.isTerminalOut { 117 if err := cli.monitorTtySize(containerID, false); err != nil { 118 fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err) 119 } 120 } 121 if attchErr := <-cErr; attchErr != nil { 122 return attchErr 123 } 124 _, status, err := getExitCode(cli, containerID) 125 if err != nil { 126 return err 127 } 128 if status != 0 { 129 return Cli.StatusError{StatusCode: status} 130 } 131 } else { 132 // We're not going to attach to anything. 133 // Start as many containers as we want. 134 return cli.startContainersWithoutAttachments(cmd.Args()) 135 } 136 137 return nil 138 } 139 140 func (cli *DockerCli) startContainersWithoutAttachments(containerIDs []string) error { 141 var failedContainers []string 142 for _, containerID := range containerIDs { 143 if err := cli.client.ContainerStart(containerID); err != nil { 144 fmt.Fprintf(cli.err, "%s\n", err) 145 failedContainers = append(failedContainers, containerID) 146 } else { 147 fmt.Fprintf(cli.out, "%s\n", containerID) 148 } 149 } 150 151 if len(failedContainers) > 0 { 152 return fmt.Errorf("Error: failed to start containers: %v", strings.Join(failedContainers, ", ")) 153 } 154 return nil 155 }