github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/daemon/execdriver/windows/exec.go (about)

     1  // +build windows
     2  
     3  package windows
     4  
     5  import (
     6  	"fmt"
     7  
     8  	"github.com/Sirupsen/logrus"
     9  	"github.com/docker/docker/daemon/execdriver"
    10  	"github.com/microsoft/hcsshim"
    11  )
    12  
    13  // Exec implements the exec driver Driver interface.
    14  func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
    15  
    16  	var (
    17  		term     execdriver.Terminal
    18  		err      error
    19  		exitCode int32
    20  		errno    uint32
    21  	)
    22  
    23  	active := d.activeContainers[c.ID]
    24  	if active == nil {
    25  		return -1, fmt.Errorf("Exec - No active container exists with ID %s", c.ID)
    26  	}
    27  
    28  	createProcessParms := hcsshim.CreateProcessParams{
    29  		EmulateConsole:   processConfig.Tty, // Note NOT c.ProcessConfig.Tty
    30  		WorkingDirectory: c.WorkingDir,
    31  	}
    32  
    33  	// Configure the environment for the process // Note NOT c.ProcessConfig.Env
    34  	createProcessParms.Environment = setupEnvironmentVariables(processConfig.Env)
    35  
    36  	// Create the commandline for the process // Note NOT c.ProcessConfig
    37  	createProcessParms.CommandLine, err = createCommandLine(processConfig, false)
    38  
    39  	if err != nil {
    40  		return -1, err
    41  	}
    42  
    43  	// Start the command running in the container.
    44  	pid, stdin, stdout, stderr, rc, err := hcsshim.CreateProcessInComputeSystem(c.ID, pipes.Stdin != nil, true, !processConfig.Tty, createProcessParms)
    45  	if err != nil {
    46  		// TODO Windows: TP4 Workaround. In Hyper-V containers, there is a limitation
    47  		// of one exec per container. This should be fixed post TP4. CreateProcessInComputeSystem
    48  		// will return a specific error which we handle here to give a good error message
    49  		// back to the user instead of an inactionable "An invalid argument was supplied"
    50  		if rc == hcsshim.Win32InvalidArgument {
    51  			return -1, fmt.Errorf("The limit of docker execs per Hyper-V container has been exceeded")
    52  		}
    53  		logrus.Errorf("CreateProcessInComputeSystem() failed %s", err)
    54  		return -1, err
    55  	}
    56  
    57  	// Now that the process has been launched, begin copying data to and from
    58  	// the named pipes for the std handles.
    59  	setupPipes(stdin, stdout, stderr, pipes)
    60  
    61  	// Note NOT c.ProcessConfig.Tty
    62  	if processConfig.Tty {
    63  		term = NewTtyConsole(c.ID, pid)
    64  	} else {
    65  		term = NewStdConsole()
    66  	}
    67  	processConfig.Terminal = term
    68  
    69  	// Invoke the start callback
    70  	if hooks.Start != nil {
    71  		// A closed channel for OOM is returned here as it will be
    72  		// non-blocking and return the correct result when read.
    73  		chOOM := make(chan struct{})
    74  		close(chOOM)
    75  		hooks.Start(&c.ProcessConfig, int(pid), chOOM)
    76  	}
    77  
    78  	if exitCode, errno, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid, hcsshim.TimeoutInfinite); err != nil {
    79  		if errno == hcsshim.Win32PipeHasBeenEnded {
    80  			logrus.Debugf("Exiting Run() after WaitForProcessInComputeSystem failed with recognised error 0x%X", errno)
    81  			return hcsshim.WaitErrExecFailed, nil
    82  		}
    83  		logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): 0x%X %s", errno, err)
    84  		return -1, err
    85  	}
    86  
    87  	logrus.Debugln("Exiting Run()", c.ID)
    88  	return int(exitCode), nil
    89  }