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