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