github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/client/driver/exec.go (about)

     1  package driver
     2  
     3  import (
     4  	"fmt"
     5  	"runtime"
     6  	"syscall"
     7  	"time"
     8  
     9  	"github.com/hashicorp/nomad/client/config"
    10  	"github.com/hashicorp/nomad/client/executor"
    11  	"github.com/hashicorp/nomad/nomad/structs"
    12  )
    13  
    14  // ExecDriver fork/execs tasks using as many of the underlying OS's isolation
    15  // features.
    16  type ExecDriver struct {
    17  	DriverContext
    18  }
    19  
    20  // execHandle is returned from Start/Open as a handle to the PID
    21  type execHandle struct {
    22  	cmd    executor.Executor
    23  	waitCh chan error
    24  	doneCh chan struct{}
    25  }
    26  
    27  // NewExecDriver is used to create a new exec driver
    28  func NewExecDriver(ctx *DriverContext) Driver {
    29  	return &ExecDriver{*ctx}
    30  }
    31  
    32  func (d *ExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
    33  	// Only enable if we are root when running on non-windows systems.
    34  	if runtime.GOOS != "windows" && syscall.Geteuid() != 0 {
    35  		d.logger.Printf("[DEBUG] driver.exec: must run as root user, disabling")
    36  		return false, nil
    37  	}
    38  
    39  	node.Attributes["driver.exec"] = "1"
    40  	return true, nil
    41  }
    42  
    43  func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
    44  	// Get the command
    45  	command, ok := task.Config["command"]
    46  	if !ok || command == "" {
    47  		return nil, fmt.Errorf("missing command for exec driver")
    48  	}
    49  
    50  	// Get the environment variables.
    51  	envVars := TaskEnvironmentVariables(ctx, task)
    52  
    53  	// Look for arguments
    54  	var args []string
    55  	if argRaw, ok := task.Config["args"]; ok {
    56  		args = append(args, argRaw)
    57  	}
    58  
    59  	// Setup the command
    60  	cmd := executor.Command(command, args...)
    61  	if err := cmd.Limit(task.Resources); err != nil {
    62  		return nil, fmt.Errorf("failed to constrain resources: %s", err)
    63  	}
    64  
    65  	// Populate environment variables
    66  	cmd.Command().Env = envVars.List()
    67  
    68  	if err := cmd.ConfigureTaskDir(d.taskName, ctx.AllocDir); err != nil {
    69  		return nil, fmt.Errorf("failed to configure task directory: %v", err)
    70  	}
    71  
    72  	if err := cmd.Start(); err != nil {
    73  		return nil, fmt.Errorf("failed to start command: %v", err)
    74  	}
    75  
    76  	// Return a driver handle
    77  	h := &execHandle{
    78  		cmd:    cmd,
    79  		doneCh: make(chan struct{}),
    80  		waitCh: make(chan error, 1),
    81  	}
    82  	go h.run()
    83  	return h, nil
    84  }
    85  
    86  func (d *ExecDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) {
    87  	// Find the process
    88  	cmd, err := executor.OpenId(handleID)
    89  	if err != nil {
    90  		return nil, fmt.Errorf("failed to open ID %v: %v", handleID, err)
    91  	}
    92  
    93  	// Return a driver handle
    94  	h := &execHandle{
    95  		cmd:    cmd,
    96  		doneCh: make(chan struct{}),
    97  		waitCh: make(chan error, 1),
    98  	}
    99  	go h.run()
   100  	return h, nil
   101  }
   102  
   103  func (h *execHandle) ID() string {
   104  	id, _ := h.cmd.ID()
   105  	return id
   106  }
   107  
   108  func (h *execHandle) WaitCh() chan error {
   109  	return h.waitCh
   110  }
   111  
   112  func (h *execHandle) Update(task *structs.Task) error {
   113  	// Update is not possible
   114  	return nil
   115  }
   116  
   117  func (h *execHandle) Kill() error {
   118  	h.cmd.Shutdown()
   119  	select {
   120  	case <-h.doneCh:
   121  		return nil
   122  	case <-time.After(5 * time.Second):
   123  		return h.cmd.ForceStop()
   124  	}
   125  }
   126  
   127  func (h *execHandle) run() {
   128  	err := h.cmd.Wait()
   129  	close(h.doneCh)
   130  	if err != nil {
   131  		h.waitCh <- err
   132  	}
   133  	close(h.waitCh)
   134  }