open-nomad/client/driver/raw_exec.go

171 lines
4.4 KiB
Go
Raw Normal View History

2015-10-08 18:36:22 +00:00
package driver
import (
"fmt"
"path/filepath"
"strconv"
"time"
"github.com/hashicorp/nomad/client/allocdir"
"github.com/hashicorp/nomad/client/config"
2015-11-06 18:42:49 +00:00
"github.com/hashicorp/nomad/client/driver/executor"
2015-11-17 00:23:03 +00:00
cstructs "github.com/hashicorp/nomad/client/driver/structs"
2015-11-05 21:46:02 +00:00
"github.com/hashicorp/nomad/client/fingerprint"
"github.com/hashicorp/nomad/client/getter"
2015-10-08 18:36:22 +00:00
"github.com/hashicorp/nomad/nomad/structs"
"github.com/mitchellh/mapstructure"
2015-10-08 18:36:22 +00:00
)
const (
// The option that enables this driver in the Config.Options map.
rawExecConfigOption = "driver.raw_exec.enable"
)
// The RawExecDriver is a privileged version of the exec driver. It provides no
// resource isolation and just fork/execs. The Exec driver should be preferred
// and this should only be used when explicitly needed.
type RawExecDriver struct {
DriverContext
2015-11-05 21:46:02 +00:00
fingerprint.StaticFingerprinter
2015-10-08 18:36:22 +00:00
}
// rawExecHandle is returned from Start/Open as a handle to the PID
type rawExecHandle struct {
2015-11-06 18:42:49 +00:00
cmd executor.Executor
waitCh chan *cstructs.WaitResult
2015-10-08 18:36:22 +00:00
doneCh chan struct{}
}
// NewRawExecDriver is used to create a new raw exec driver
func NewRawExecDriver(ctx *DriverContext) Driver {
2015-11-05 21:46:02 +00:00
return &RawExecDriver{DriverContext: *ctx}
2015-10-08 18:36:22 +00:00
}
func (d *RawExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
// Check that the user has explicitly enabled this executor.
enabled, err := strconv.ParseBool(cfg.ReadDefault(rawExecConfigOption, "false"))
if err != nil {
return false, fmt.Errorf("Failed to parse %v option: %v", rawExecConfigOption, err)
}
if enabled {
2015-10-08 18:36:22 +00:00
d.logger.Printf("[WARN] driver.raw_exec: raw exec is enabled. Only enable if needed")
node.Attributes["driver.raw_exec"] = "1"
return true, nil
}
return false, nil
}
func (d *RawExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
2015-11-14 04:22:49 +00:00
var driverConfig ExecDriverConfig
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
return nil, err
}
2015-10-08 18:36:22 +00:00
// Get the tasks local directory.
taskName := d.DriverContext.taskName
taskDir, ok := ctx.AllocDir.TaskDirs[taskName]
if !ok {
return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName)
}
// Get the command to be ran
command := driverConfig.Command
if command == "" {
return nil, fmt.Errorf("missing command for Raw Exec driver")
}
// Check if an artificat is specified and attempt to download it
source, ok := task.Config["artifact_source"]
if ok && source != "" {
// Proceed to download an artifact to be executed.
_, err := getter.GetArtifact(
filepath.Join(taskDir, allocdir.TaskLocal),
driverConfig.ArtifactSource,
driverConfig.Checksum,
d.logger,
)
if err != nil {
return nil, err
}
}
2015-10-08 18:36:22 +00:00
// Get the environment variables.
envVars := TaskEnvironmentVariables(ctx, task)
// Setup the command
2015-11-06 18:42:49 +00:00
cmd := executor.NewBasicExecutor()
executor.SetCommand(cmd, command, driverConfig.Args)
2015-11-06 18:42:49 +00:00
if err := cmd.Limit(task.Resources); err != nil {
return nil, fmt.Errorf("failed to constrain resources: %s", err)
2015-10-08 18:36:22 +00:00
}
2015-11-06 18:42:49 +00:00
// Populate environment variables
cmd.Command().Env = envVars.List()
2015-10-08 18:36:22 +00:00
2015-11-06 18:42:49 +00:00
if err := cmd.ConfigureTaskDir(d.taskName, ctx.AllocDir); err != nil {
return nil, fmt.Errorf("failed to configure task directory: %v", err)
2015-10-08 18:36:22 +00:00
}
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("failed to start command: %v", err)
}
// Return a driver handle
2015-11-06 18:42:49 +00:00
h := &execHandle{
cmd: cmd,
2015-10-08 18:36:22 +00:00
doneCh: make(chan struct{}),
waitCh: make(chan *cstructs.WaitResult, 1),
2015-10-08 18:36:22 +00:00
}
go h.run()
return h, nil
}
func (d *RawExecDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) {
// Find the process
2015-11-06 18:42:49 +00:00
cmd := executor.NewBasicExecutor()
if err := cmd.Open(handleID); err != nil {
return nil, fmt.Errorf("failed to open ID %v: %v", handleID, err)
2015-10-08 18:36:22 +00:00
}
// Return a driver handle
2015-11-06 18:42:49 +00:00
h := &execHandle{
cmd: cmd,
2015-10-08 18:36:22 +00:00
doneCh: make(chan struct{}),
waitCh: make(chan *cstructs.WaitResult, 1),
2015-10-08 18:36:22 +00:00
}
go h.run()
return h, nil
}
func (h *rawExecHandle) ID() string {
2015-11-06 18:42:49 +00:00
id, _ := h.cmd.ID()
return id
2015-10-08 18:36:22 +00:00
}
func (h *rawExecHandle) WaitCh() chan *cstructs.WaitResult {
2015-10-08 18:36:22 +00:00
return h.waitCh
}
func (h *rawExecHandle) Update(task *structs.Task) error {
// Update is not possible
return nil
}
func (h *rawExecHandle) Kill() error {
2015-11-06 18:42:49 +00:00
h.cmd.Shutdown()
2015-10-08 18:36:22 +00:00
select {
case <-h.doneCh:
return nil
case <-time.After(5 * time.Second):
2015-11-06 18:42:49 +00:00
return h.cmd.ForceStop()
2015-10-08 18:36:22 +00:00
}
}
func (h *rawExecHandle) run() {
res := h.cmd.Wait()
2015-10-08 18:36:22 +00:00
close(h.doneCh)
h.waitCh <- res
2015-10-08 18:36:22 +00:00
close(h.waitCh)
}