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  }