2015-11-03 20:47:48 +00:00
|
|
|
package executor
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
2015-11-05 01:20:52 +00:00
|
|
|
"os/exec"
|
2015-11-03 20:47:48 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/hashicorp/nomad/client/allocdir"
|
|
|
|
"github.com/hashicorp/nomad/client/driver/args"
|
|
|
|
"github.com/hashicorp/nomad/client/driver/environment"
|
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
)
|
|
|
|
|
|
|
|
// BasicExecutor should work everywhere, and as a result does not include
|
|
|
|
// any resource restrictions or runas capabilities.
|
|
|
|
type BasicExecutor struct {
|
2015-11-05 01:20:52 +00:00
|
|
|
cmd exec.Cmd
|
2015-11-03 20:47:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Have raw_exec use this as well.
|
|
|
|
func NewBasicExecutor() Executor {
|
|
|
|
return &BasicExecutor{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *BasicExecutor) Limit(resources *structs.Resources) error {
|
|
|
|
if resources == nil {
|
|
|
|
return errNoResources
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *BasicExecutor) ConfigureTaskDir(taskName string, alloc *allocdir.AllocDir) error {
|
|
|
|
taskDir, ok := alloc.TaskDirs[taskName]
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("Error finding task dir for (%s)", taskName)
|
|
|
|
}
|
2015-11-05 01:20:52 +00:00
|
|
|
e.cmd.Dir = taskDir
|
2015-11-03 20:47:48 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *BasicExecutor) Start() error {
|
|
|
|
// Parse the commands arguments and replace instances of Nomad environment
|
|
|
|
// variables.
|
|
|
|
envVars, err := environment.ParseFromList(e.cmd.Env)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
parsedPath, err := args.ParseAndReplace(e.cmd.Path, envVars.Map())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
} else if len(parsedPath) != 1 {
|
|
|
|
return fmt.Errorf("couldn't properly parse command path: %v", e.cmd.Path)
|
|
|
|
}
|
|
|
|
|
|
|
|
e.cmd.Path = parsedPath[0]
|
|
|
|
combined := strings.Join(e.cmd.Args, " ")
|
|
|
|
parsed, err := args.ParseAndReplace(combined, envVars.Map())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-11-05 01:20:52 +00:00
|
|
|
e.cmd.Args = parsed
|
2015-11-03 20:47:48 +00:00
|
|
|
|
|
|
|
// We don't want to call ourself. We want to call Start on our embedded Cmd
|
|
|
|
return e.cmd.Start()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *BasicExecutor) Open(pid string) error {
|
|
|
|
pidNum, err := strconv.Atoi(pid)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to parse pid %v: %v", pid, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
process, err := os.FindProcess(pidNum)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to reopen pid %d: %v", pidNum, err)
|
|
|
|
}
|
2015-11-05 01:20:52 +00:00
|
|
|
e.cmd.Process = process
|
2015-11-03 20:47:48 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *BasicExecutor) Wait() error {
|
|
|
|
// We don't want to call ourself. We want to call Start on our embedded Cmd
|
|
|
|
return e.cmd.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *BasicExecutor) ID() (string, error) {
|
|
|
|
if e.cmd.Process != nil {
|
|
|
|
return strconv.Itoa(e.cmd.Process.Pid), nil
|
|
|
|
} else {
|
|
|
|
return "", fmt.Errorf("Process has finished or was never started")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *BasicExecutor) Shutdown() error {
|
|
|
|
return e.ForceStop()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *BasicExecutor) ForceStop() error {
|
2015-11-05 01:20:52 +00:00
|
|
|
return e.cmd.Process.Kill()
|
2015-11-03 20:47:48 +00:00
|
|
|
}
|
|
|
|
|
2015-11-05 01:20:52 +00:00
|
|
|
func (e *BasicExecutor) Command() *exec.Cmd {
|
2015-11-03 20:47:48 +00:00
|
|
|
return &e.cmd
|
|
|
|
}
|