github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/api/client/exec.go (about)

     1  package client
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/Sirupsen/logrus"
     8  	"github.com/docker/docker/api/types"
     9  	Cli "github.com/docker/docker/cli"
    10  	"github.com/docker/docker/pkg/promise"
    11  	"github.com/docker/docker/runconfig"
    12  )
    13  
    14  // CmdExec runs a command in a running container.
    15  //
    16  // Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
    17  func (cli *DockerCli) CmdExec(args ...string) error {
    18  	cmd := Cli.Subcmd("exec", []string{"CONTAINER COMMAND [ARG...]"}, Cli.DockerCommands["exec"].Description, true)
    19  
    20  	execConfig, err := runconfig.ParseExec(cmd, args)
    21  	// just in case the ParseExec does not exit
    22  	if execConfig.Container == "" || err != nil {
    23  		return Cli.StatusError{StatusCode: 1}
    24  	}
    25  
    26  	response, err := cli.client.ContainerExecCreate(*execConfig)
    27  	if err != nil {
    28  		return err
    29  	}
    30  
    31  	execID := response.ID
    32  	if execID == "" {
    33  		fmt.Fprintf(cli.out, "exec ID empty")
    34  		return nil
    35  	}
    36  
    37  	//Temp struct for execStart so that we don't need to transfer all the execConfig
    38  	if !execConfig.Detach {
    39  		if err := cli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil {
    40  			return err
    41  		}
    42  	} else {
    43  		execStartCheck := types.ExecStartCheck{
    44  			Detach: execConfig.Detach,
    45  			Tty:    execConfig.Tty,
    46  		}
    47  
    48  		if err := cli.client.ContainerExecStart(execID, execStartCheck); err != nil {
    49  			return err
    50  		}
    51  		// For now don't print this - wait for when we support exec wait()
    52  		// fmt.Fprintf(cli.out, "%s\n", execID)
    53  		return nil
    54  	}
    55  
    56  	// Interactive exec requested.
    57  	var (
    58  		out, stderr io.Writer
    59  		in          io.ReadCloser
    60  		errCh       chan error
    61  	)
    62  
    63  	if execConfig.AttachStdin {
    64  		in = cli.in
    65  	}
    66  	if execConfig.AttachStdout {
    67  		out = cli.out
    68  	}
    69  	if execConfig.AttachStderr {
    70  		if execConfig.Tty {
    71  			stderr = cli.out
    72  		} else {
    73  			stderr = cli.err
    74  		}
    75  	}
    76  
    77  	resp, err := cli.client.ContainerExecAttach(execID, *execConfig)
    78  	if err != nil {
    79  		return err
    80  	}
    81  	defer resp.Close()
    82  	errCh = promise.Go(func() error {
    83  		return cli.holdHijackedConnection(execConfig.Tty, in, out, stderr, resp)
    84  	})
    85  
    86  	if execConfig.Tty && cli.isTerminalIn {
    87  		if err := cli.monitorTtySize(execID, true); err != nil {
    88  			fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
    89  		}
    90  	}
    91  
    92  	if err := <-errCh; err != nil {
    93  		logrus.Debugf("Error hijack: %s", err)
    94  		return err
    95  	}
    96  
    97  	var status int
    98  	if _, status, err = getExecExitCode(cli, execID); err != nil {
    99  		return err
   100  	}
   101  
   102  	if status != 0 {
   103  		return Cli.StatusError{StatusCode: status}
   104  	}
   105  
   106  	return nil
   107  }