github.com/rentongzhang/docker@v1.8.2-rc1/daemon/execdriver/windows/exec.go (about) 1 // +build windows 2 3 package windows 4 5 import ( 6 "errors" 7 "fmt" 8 9 "github.com/Sirupsen/logrus" 10 "github.com/docker/docker/daemon/execdriver" 11 "github.com/docker/docker/pkg/stringid" 12 "github.com/microsoft/hcsshim" 13 "github.com/natefinch/npipe" 14 ) 15 16 func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) { 17 18 var ( 19 inListen, outListen, errListen *npipe.PipeListener 20 term execdriver.Terminal 21 err error 22 randomID string = stringid.GenerateRandomID() 23 serverPipeFormat, clientPipeFormat string 24 pid uint32 25 exitCode int32 26 ) 27 28 active := d.activeContainers[c.ID] 29 if active == nil { 30 return -1, fmt.Errorf("Exec - No active container exists with ID %s", c.ID) 31 } 32 33 createProcessParms := hcsshim.CreateProcessParams{ 34 EmulateConsole: processConfig.Tty, // Note NOT c.ProcessConfig.Tty 35 WorkingDirectory: c.WorkingDir, 36 } 37 38 // Configure the environment for the process // Note NOT c.ProcessConfig.Tty 39 createProcessParms.Environment = setupEnvironmentVariables(processConfig.Env) 40 41 // We use another unique ID here for each exec instance otherwise it 42 // may conflict with the pipe name being used by RUN. 43 44 // We use a different pipe name between real and dummy mode in the HCS 45 if dummyMode { 46 clientPipeFormat = `\\.\pipe\docker-exec-%[1]s-%[2]s-%[3]s` 47 serverPipeFormat = clientPipeFormat 48 } else { 49 clientPipeFormat = `\\.\pipe\docker-exec-%[2]s-%[3]s` 50 serverPipeFormat = `\\.\Containers\%[1]s\Device\NamedPipe\docker-exec-%[2]s-%[3]s` 51 } 52 53 // Connect stdin 54 if pipes.Stdin != nil { 55 stdInPipe := fmt.Sprintf(serverPipeFormat, c.ID, randomID, "stdin") 56 createProcessParms.StdInPipe = fmt.Sprintf(clientPipeFormat, c.ID, randomID, "stdin") 57 58 // Listen on the named pipe 59 inListen, err = npipe.Listen(stdInPipe) 60 if err != nil { 61 logrus.Errorf("stdin failed to listen on %s %s ", stdInPipe, err) 62 return -1, err 63 } 64 defer inListen.Close() 65 66 // Launch a goroutine to do the accept. We do this so that we can 67 // cause an otherwise blocking goroutine to gracefully close when 68 // the caller (us) closes the listener 69 go stdinAccept(inListen, stdInPipe, pipes.Stdin) 70 } 71 72 // Connect stdout 73 stdOutPipe := fmt.Sprintf(serverPipeFormat, c.ID, randomID, "stdout") 74 createProcessParms.StdOutPipe = fmt.Sprintf(clientPipeFormat, c.ID, randomID, "stdout") 75 76 outListen, err = npipe.Listen(stdOutPipe) 77 if err != nil { 78 logrus.Errorf("stdout failed to listen on %s %s", stdOutPipe, err) 79 return -1, err 80 } 81 defer outListen.Close() 82 go stdouterrAccept(outListen, stdOutPipe, pipes.Stdout) 83 84 // No stderr on TTY. Note NOT c.ProcessConfig.Tty 85 if !processConfig.Tty { 86 // Connect stderr 87 stdErrPipe := fmt.Sprintf(serverPipeFormat, c.ID, randomID, "stderr") 88 createProcessParms.StdErrPipe = fmt.Sprintf(clientPipeFormat, c.ID, randomID, "stderr") 89 90 errListen, err = npipe.Listen(stdErrPipe) 91 if err != nil { 92 logrus.Errorf("Stderr failed to listen on %s %s", stdErrPipe, err) 93 return -1, err 94 } 95 defer errListen.Close() 96 go stdouterrAccept(errListen, stdErrPipe, pipes.Stderr) 97 } 98 99 // While this should get caught earlier, just in case, validate that we 100 // have something to run. 101 if processConfig.Entrypoint == "" { 102 err = errors.New("No entrypoint specified") 103 logrus.Error(err) 104 return -1, err 105 } 106 107 // Build the command line of the process 108 createProcessParms.CommandLine = processConfig.Entrypoint 109 for _, arg := range processConfig.Arguments { 110 logrus.Debugln("appending ", arg) 111 createProcessParms.CommandLine += " " + arg 112 } 113 logrus.Debugln("commandLine: ", createProcessParms.CommandLine) 114 115 // Start the command running in the container. 116 pid, err = hcsshim.CreateProcessInComputeSystem(c.ID, createProcessParms) 117 118 if err != nil { 119 logrus.Errorf("CreateProcessInComputeSystem() failed %s", err) 120 return -1, err 121 } 122 123 // Note NOT c.ProcessConfig.Tty 124 if processConfig.Tty { 125 term = NewTtyConsole(c.ID, pid) 126 } else { 127 term = NewStdConsole() 128 } 129 processConfig.Terminal = term 130 131 // Invoke the start callback 132 if startCallback != nil { 133 startCallback(&c.ProcessConfig, int(pid)) 134 } 135 136 if exitCode, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid); err != nil { 137 logrus.Errorf("Failed to WaitForProcessInComputeSystem %s", err) 138 return -1, err 139 } 140 141 // TODO Windows - Do something with this exit code 142 logrus.Debugln("Exiting Run() with ExitCode 0", c.ID) 143 return int(exitCode), nil 144 }