exec.go 3.0 KB

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