github.com/hamo/docker@v1.11.1/api/client/start.go (about)

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