github.com/ryanslade/nomad@v0.2.4-0.20160128061903-fc95782f2089/client/driver/executor/exec_basic.go (about) 1 package executor 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "runtime" 11 "strings" 12 13 "github.com/hashicorp/nomad/client/allocdir" 14 "github.com/hashicorp/nomad/client/driver/spawn" 15 "github.com/hashicorp/nomad/nomad/structs" 16 17 cstructs "github.com/hashicorp/nomad/client/driver/structs" 18 ) 19 20 // BasicExecutor should work everywhere, and as a result does not include 21 // any resource restrictions or runas capabilities. 22 type BasicExecutor struct { 23 *ExecutorContext 24 cmd exec.Cmd 25 spawn *spawn.Spawner 26 taskName string 27 taskDir string 28 allocDir string 29 } 30 31 func NewBasicExecutor(ctx *ExecutorContext) Executor { 32 return &BasicExecutor{ExecutorContext: ctx} 33 } 34 35 func (e *BasicExecutor) Limit(resources *structs.Resources) error { 36 if resources == nil { 37 return errNoResources 38 } 39 return nil 40 } 41 42 func (e *BasicExecutor) ConfigureTaskDir(taskName string, alloc *allocdir.AllocDir) error { 43 taskDir, ok := alloc.TaskDirs[taskName] 44 if !ok { 45 return fmt.Errorf("Couldn't find task directory for task %v", taskName) 46 } 47 e.cmd.Dir = taskDir 48 49 e.taskDir = taskDir 50 e.taskName = taskName 51 e.allocDir = alloc.AllocDir 52 return nil 53 } 54 55 func (e *BasicExecutor) Start() error { 56 // Parse the commands arguments and replace instances of Nomad environment 57 // variables. 58 e.cmd.Path = e.taskEnv.ReplaceEnv(e.cmd.Path) 59 e.cmd.Args = e.taskEnv.ParseAndReplace(e.cmd.Args) 60 e.cmd.Env = e.taskEnv.Build().EnvList() 61 62 spawnState := filepath.Join(e.allocDir, fmt.Sprintf("%s_%s", e.taskName, "exit_status")) 63 e.spawn = spawn.NewSpawner(spawnState) 64 e.spawn.SetCommand(&e.cmd) 65 e.spawn.SetLogs(&spawn.Logs{ 66 Stdout: filepath.Join(e.taskDir, allocdir.TaskLocal, fmt.Sprintf("%v.stdout", e.taskName)), 67 Stderr: filepath.Join(e.taskDir, allocdir.TaskLocal, fmt.Sprintf("%v.stderr", e.taskName)), 68 Stdin: os.DevNull, 69 }) 70 71 return e.spawn.Spawn(nil) 72 } 73 74 func (e *BasicExecutor) Open(id string) error { 75 var spawn spawn.Spawner 76 dec := json.NewDecoder(strings.NewReader(id)) 77 if err := dec.Decode(&spawn); err != nil { 78 return fmt.Errorf("Failed to parse id: %v", err) 79 } 80 81 // Setup the executor. 82 e.spawn = &spawn 83 return e.spawn.Valid() 84 } 85 86 func (e *BasicExecutor) Wait() *cstructs.WaitResult { 87 return e.spawn.Wait() 88 } 89 90 func (e *BasicExecutor) ID() (string, error) { 91 if e.spawn == nil { 92 return "", fmt.Errorf("Process was never started") 93 } 94 95 var buffer bytes.Buffer 96 enc := json.NewEncoder(&buffer) 97 if err := enc.Encode(e.spawn); err != nil { 98 return "", fmt.Errorf("Failed to serialize id: %v", err) 99 } 100 101 return buffer.String(), nil 102 } 103 104 func (e *BasicExecutor) Shutdown() error { 105 proc, err := os.FindProcess(e.spawn.UserPid) 106 if err != nil { 107 return fmt.Errorf("Failed to find user processes %v: %v", e.spawn.UserPid, err) 108 } 109 110 if runtime.GOOS == "windows" { 111 return proc.Kill() 112 } 113 114 return proc.Signal(os.Interrupt) 115 } 116 117 func (e *BasicExecutor) ForceStop() error { 118 proc, err := os.FindProcess(e.spawn.UserPid) 119 if err != nil { 120 return fmt.Errorf("Failed to find user processes %v: %v", e.spawn.UserPid, err) 121 } 122 123 if err := proc.Kill(); err != nil && err.Error() != "os: process already finished" { 124 return err 125 } 126 return nil 127 } 128 129 func (e *BasicExecutor) Command() *exec.Cmd { 130 return &e.cmd 131 }