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  }