github.com/squaremo/docker@v1.3.2-0.20150516120342-42cfc9554972/api/client/start.go (about) 1 package client 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "net/url" 8 "os" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/api/types" 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 } 35 if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, nil)); err != nil { 36 logrus.Debugf("Error sending signal: %s", err) 37 } 38 } 39 }() 40 return sigc 41 } 42 43 // CmdStart starts one or more stopped containers. 44 // 45 // Usage: docker start [OPTIONS] CONTAINER [CONTAINER...] 46 func (cli *DockerCli) CmdStart(args ...string) error { 47 var ( 48 cErr chan error 49 tty bool 50 51 cmd = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Start one or more stopped containers", 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 ) 55 56 cmd.Require(flag.Min, 1) 57 cmd.ParseFlags(args, true) 58 59 if *attach || *openStdin { 60 if cmd.NArg() > 1 { 61 return fmt.Errorf("You cannot start and attach multiple containers at once.") 62 } 63 64 stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil) 65 if err != nil { 66 return err 67 } 68 69 var c types.ContainerJSON 70 if err := json.NewDecoder(stream).Decode(&c); err != nil { 71 return err 72 } 73 74 tty = c.Config.Tty 75 76 if !tty { 77 sigc := cli.forwardAllSignals(cmd.Arg(0)) 78 defer signal.StopCatch(sigc) 79 } 80 81 var in io.ReadCloser 82 83 v := url.Values{} 84 v.Set("stream", "1") 85 86 if *openStdin && c.Config.OpenStdin { 87 v.Set("stdin", "1") 88 in = cli.in 89 } 90 91 v.Set("stdout", "1") 92 v.Set("stderr", "1") 93 94 hijacked := make(chan io.Closer) 95 // Block the return until the chan gets closed 96 defer func() { 97 logrus.Debugf("CmdStart() returned, defer waiting for hijack to finish.") 98 if _, ok := <-hijacked; ok { 99 fmt.Fprintln(cli.err, "Hijack did not finish (chan still open)") 100 } 101 cli.in.Close() 102 }() 103 cErr = promise.Go(func() error { 104 return cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), tty, in, cli.out, cli.err, hijacked, nil) 105 }) 106 107 // Acknowledge the hijack before starting 108 select { 109 case closer := <-hijacked: 110 // Make sure that the hijack gets closed when returning (results 111 // in closing the hijack chan and freeing server's goroutines) 112 if closer != nil { 113 defer closer.Close() 114 } 115 case err := <-cErr: 116 if err != nil { 117 return err 118 } 119 } 120 } 121 122 var encounteredError error 123 var errNames []string 124 for _, name := range cmd.Args() { 125 _, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, nil)) 126 if err != nil { 127 if !*attach && !*openStdin { 128 // attach and openStdin is false means it could be starting multiple containers 129 // when a container start failed, show the error message and start next 130 fmt.Fprintf(cli.err, "%s\n", err) 131 errNames = append(errNames, name) 132 } else { 133 encounteredError = err 134 } 135 } else { 136 if !*attach && !*openStdin { 137 fmt.Fprintf(cli.out, "%s\n", name) 138 } 139 } 140 } 141 142 if len(errNames) > 0 { 143 encounteredError = fmt.Errorf("Error: failed to start containers: %v", errNames) 144 } 145 if encounteredError != nil { 146 return encounteredError 147 } 148 149 if *openStdin || *attach { 150 if tty && cli.isTerminalOut { 151 if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil { 152 fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err) 153 } 154 } 155 if attchErr := <-cErr; attchErr != nil { 156 return attchErr 157 } 158 _, status, err := getExitCode(cli, cmd.Arg(0)) 159 if err != nil { 160 return err 161 } 162 if status != 0 { 163 return StatusError{StatusCode: status} 164 } 165 } 166 return nil 167 }