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