github.com/huiliang/nomad@v0.2.1-0.20151124023127-7a8b664699ff/client/driver/raw_exec.go (about)

     1  package driver
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/hashicorp/nomad/client/allocdir"
    10  	"github.com/hashicorp/nomad/client/config"
    11  	"github.com/hashicorp/nomad/client/driver/executor"
    12  	cstructs "github.com/hashicorp/nomad/client/driver/structs"
    13  	"github.com/hashicorp/nomad/client/fingerprint"
    14  	"github.com/hashicorp/nomad/client/getter"
    15  	"github.com/hashicorp/nomad/nomad/structs"
    16  	"github.com/mitchellh/mapstructure"
    17  )
    18  
    19  const (
    20  	// The option that enables this driver in the Config.Options map.
    21  	rawExecConfigOption = "driver.raw_exec.enable"
    22  )
    23  
    24  // The RawExecDriver is a privileged version of the exec driver. It provides no
    25  // resource isolation and just fork/execs. The Exec driver should be preferred
    26  // and this should only be used when explicitly needed.
    27  type RawExecDriver struct {
    28  	DriverContext
    29  	fingerprint.StaticFingerprinter
    30  }
    31  
    32  // rawExecHandle is returned from Start/Open as a handle to the PID
    33  type rawExecHandle struct {
    34  	cmd    executor.Executor
    35  	waitCh chan *cstructs.WaitResult
    36  	doneCh chan struct{}
    37  }
    38  
    39  // NewRawExecDriver is used to create a new raw exec driver
    40  func NewRawExecDriver(ctx *DriverContext) Driver {
    41  	return &RawExecDriver{DriverContext: *ctx}
    42  }
    43  
    44  func (d *RawExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
    45  	// Check that the user has explicitly enabled this executor.
    46  	enabled, err := strconv.ParseBool(cfg.ReadDefault(rawExecConfigOption, "false"))
    47  	if err != nil {
    48  		return false, fmt.Errorf("Failed to parse %v option: %v", rawExecConfigOption, err)
    49  	}
    50  
    51  	if enabled {
    52  		d.logger.Printf("[WARN] driver.raw_exec: raw exec is enabled. Only enable if needed")
    53  		node.Attributes["driver.raw_exec"] = "1"
    54  		return true, nil
    55  	}
    56  
    57  	return false, nil
    58  }
    59  
    60  func (d *RawExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
    61  	var driverConfig ExecDriverConfig
    62  	if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
    63  		return nil, err
    64  	}
    65  	// Get the tasks local directory.
    66  	taskName := d.DriverContext.taskName
    67  	taskDir, ok := ctx.AllocDir.TaskDirs[taskName]
    68  	if !ok {
    69  		return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName)
    70  	}
    71  
    72  	// Get the command to be ran
    73  	command := driverConfig.Command
    74  	if command == "" {
    75  		return nil, fmt.Errorf("missing command for Raw Exec driver")
    76  	}
    77  
    78  	// Check if an artificat is specified and attempt to download it
    79  	source, ok := task.Config["artifact_source"]
    80  	if ok && source != "" {
    81  		// Proceed to download an artifact to be executed.
    82  		_, err := getter.GetArtifact(
    83  			filepath.Join(taskDir, allocdir.TaskLocal),
    84  			driverConfig.ArtifactSource,
    85  			driverConfig.Checksum,
    86  			d.logger,
    87  		)
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  	}
    92  
    93  	// Get the environment variables.
    94  	envVars := TaskEnvironmentVariables(ctx, task)
    95  
    96  	// Setup the command
    97  	cmd := executor.NewBasicExecutor()
    98  	executor.SetCommand(cmd, command, driverConfig.Args)
    99  	if err := cmd.Limit(task.Resources); err != nil {
   100  		return nil, fmt.Errorf("failed to constrain resources: %s", err)
   101  	}
   102  
   103  	// Populate environment variables
   104  	cmd.Command().Env = envVars.List()
   105  
   106  	if err := cmd.ConfigureTaskDir(d.taskName, ctx.AllocDir); err != nil {
   107  		return nil, fmt.Errorf("failed to configure task directory: %v", err)
   108  	}
   109  
   110  	if err := cmd.Start(); err != nil {
   111  		return nil, fmt.Errorf("failed to start command: %v", err)
   112  	}
   113  
   114  	// Return a driver handle
   115  	h := &execHandle{
   116  		cmd:    cmd,
   117  		doneCh: make(chan struct{}),
   118  		waitCh: make(chan *cstructs.WaitResult, 1),
   119  	}
   120  	go h.run()
   121  	return h, nil
   122  }
   123  
   124  func (d *RawExecDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) {
   125  	// Find the process
   126  	cmd := executor.NewBasicExecutor()
   127  	if err := cmd.Open(handleID); err != nil {
   128  		return nil, fmt.Errorf("failed to open ID %v: %v", handleID, err)
   129  	}
   130  
   131  	// Return a driver handle
   132  	h := &execHandle{
   133  		cmd:    cmd,
   134  		doneCh: make(chan struct{}),
   135  		waitCh: make(chan *cstructs.WaitResult, 1),
   136  	}
   137  	go h.run()
   138  	return h, nil
   139  }
   140  
   141  func (h *rawExecHandle) ID() string {
   142  	id, _ := h.cmd.ID()
   143  	return id
   144  }
   145  
   146  func (h *rawExecHandle) WaitCh() chan *cstructs.WaitResult {
   147  	return h.waitCh
   148  }
   149  
   150  func (h *rawExecHandle) Update(task *structs.Task) error {
   151  	// Update is not possible
   152  	return nil
   153  }
   154  
   155  func (h *rawExecHandle) Kill() error {
   156  	h.cmd.Shutdown()
   157  	select {
   158  	case <-h.doneCh:
   159  		return nil
   160  	case <-time.After(5 * time.Second):
   161  		return h.cmd.ForceStop()
   162  	}
   163  }
   164  
   165  func (h *rawExecHandle) run() {
   166  	res := h.cmd.Wait()
   167  	close(h.doneCh)
   168  	h.waitCh <- res
   169  	close(h.waitCh)
   170  }