1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- // +build windows
- package windows
- import (
- "fmt"
- "syscall"
- "github.com/Microsoft/hcsshim"
- "github.com/Sirupsen/logrus"
- "github.com/docker/docker/daemon/execdriver"
- )
- // Exec implements the exec driver Driver interface.
- func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
- var (
- term execdriver.Terminal
- err error
- exitCode int32
- )
- active := d.activeContainers[c.ID]
- if active == nil {
- return -1, fmt.Errorf("Exec - No active container exists with ID %s", c.ID)
- }
- createProcessParms := hcsshim.CreateProcessParams{
- EmulateConsole: processConfig.Tty, // Note NOT c.ProcessConfig.Tty
- WorkingDirectory: c.WorkingDir,
- }
- // Configure the environment for the process // Note NOT c.ProcessConfig.Env
- createProcessParms.Environment = setupEnvironmentVariables(processConfig.Env)
- // Create the commandline for the process // Note NOT c.ProcessConfig
- createProcessParms.CommandLine, err = createCommandLine(processConfig, false)
- if err != nil {
- return -1, err
- }
- // Start the command running in the container.
- pid, stdin, stdout, stderr, err := hcsshim.CreateProcessInComputeSystem(c.ID, pipes.Stdin != nil, true, !processConfig.Tty, createProcessParms)
- if err != nil {
- // TODO Windows: TP4 Workaround. In Hyper-V containers, there is a limitation
- // of one exec per container. This should be fixed post TP4. CreateProcessInComputeSystem
- // will return a specific error which we handle here to give a good error message
- // back to the user instead of an inactionable "An invalid argument was supplied"
- if herr, ok := err.(*hcsshim.HcsError); ok && herr.Err == hcsshim.WSAEINVAL {
- return -1, fmt.Errorf("The limit of docker execs per Hyper-V container has been exceeded")
- }
- logrus.Errorf("CreateProcessInComputeSystem() failed %s", err)
- return -1, err
- }
- // Now that the process has been launched, begin copying data to and from
- // the named pipes for the std handles.
- setupPipes(stdin, stdout, stderr, pipes)
- // Note NOT c.ProcessConfig.Tty
- if processConfig.Tty {
- term = NewTtyConsole(c.ID, pid)
- } else {
- term = NewStdConsole()
- }
- processConfig.Terminal = term
- // Invoke the start callback
- if hooks.Start != nil {
- // A closed channel for OOM is returned here as it will be
- // non-blocking and return the correct result when read.
- chOOM := make(chan struct{})
- close(chOOM)
- hooks.Start(&c.ProcessConfig, int(pid), chOOM)
- }
- if exitCode, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid, hcsshim.TimeoutInfinite); err != nil {
- if herr, ok := err.(*hcsshim.HcsError); ok && herr.Err == syscall.ERROR_BROKEN_PIPE {
- logrus.Debugf("Exiting Run() after WaitForProcessInComputeSystem failed with recognised error %s", err)
- return hcsshim.WaitErrExecFailed, nil
- }
- logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): %s", err)
- return -1, err
- }
- logrus.Debugln("Exiting Run()", c.ID)
- return int(exitCode), nil
- }
|