github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/client/driver/exec.go (about) 1 package driver 2 3 import ( 4 "fmt" 5 "runtime" 6 "syscall" 7 "time" 8 9 "github.com/hashicorp/nomad/client/config" 10 "github.com/hashicorp/nomad/client/executor" 11 "github.com/hashicorp/nomad/nomad/structs" 12 ) 13 14 // ExecDriver fork/execs tasks using as many of the underlying OS's isolation 15 // features. 16 type ExecDriver struct { 17 DriverContext 18 } 19 20 // execHandle is returned from Start/Open as a handle to the PID 21 type execHandle struct { 22 cmd executor.Executor 23 waitCh chan error 24 doneCh chan struct{} 25 } 26 27 // NewExecDriver is used to create a new exec driver 28 func NewExecDriver(ctx *DriverContext) Driver { 29 return &ExecDriver{*ctx} 30 } 31 32 func (d *ExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) { 33 // Only enable if we are root when running on non-windows systems. 34 if runtime.GOOS != "windows" && syscall.Geteuid() != 0 { 35 d.logger.Printf("[DEBUG] driver.exec: must run as root user, disabling") 36 return false, nil 37 } 38 39 node.Attributes["driver.exec"] = "1" 40 return true, nil 41 } 42 43 func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) { 44 // Get the command 45 command, ok := task.Config["command"] 46 if !ok || command == "" { 47 return nil, fmt.Errorf("missing command for exec driver") 48 } 49 50 // Get the environment variables. 51 envVars := TaskEnvironmentVariables(ctx, task) 52 53 // Look for arguments 54 var args []string 55 if argRaw, ok := task.Config["args"]; ok { 56 args = append(args, argRaw) 57 } 58 59 // Setup the command 60 cmd := executor.Command(command, args...) 61 if err := cmd.Limit(task.Resources); err != nil { 62 return nil, fmt.Errorf("failed to constrain resources: %s", err) 63 } 64 65 // Populate environment variables 66 cmd.Command().Env = envVars.List() 67 68 if err := cmd.ConfigureTaskDir(d.taskName, ctx.AllocDir); err != nil { 69 return nil, fmt.Errorf("failed to configure task directory: %v", err) 70 } 71 72 if err := cmd.Start(); err != nil { 73 return nil, fmt.Errorf("failed to start command: %v", err) 74 } 75 76 // Return a driver handle 77 h := &execHandle{ 78 cmd: cmd, 79 doneCh: make(chan struct{}), 80 waitCh: make(chan error, 1), 81 } 82 go h.run() 83 return h, nil 84 } 85 86 func (d *ExecDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) { 87 // Find the process 88 cmd, err := executor.OpenId(handleID) 89 if err != nil { 90 return nil, fmt.Errorf("failed to open ID %v: %v", handleID, err) 91 } 92 93 // Return a driver handle 94 h := &execHandle{ 95 cmd: cmd, 96 doneCh: make(chan struct{}), 97 waitCh: make(chan error, 1), 98 } 99 go h.run() 100 return h, nil 101 } 102 103 func (h *execHandle) ID() string { 104 id, _ := h.cmd.ID() 105 return id 106 } 107 108 func (h *execHandle) WaitCh() chan error { 109 return h.waitCh 110 } 111 112 func (h *execHandle) Update(task *structs.Task) error { 113 // Update is not possible 114 return nil 115 } 116 117 func (h *execHandle) Kill() error { 118 h.cmd.Shutdown() 119 select { 120 case <-h.doneCh: 121 return nil 122 case <-time.After(5 * time.Second): 123 return h.cmd.ForceStop() 124 } 125 } 126 127 func (h *execHandle) run() { 128 err := h.cmd.Wait() 129 close(h.doneCh) 130 if err != nil { 131 h.waitCh <- err 132 } 133 close(h.waitCh) 134 }