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