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