github.com/ncdc/docker@v0.10.1-0.20160129113957-6c6729ef5b74/api/client/start.go (about)

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