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  }