open-nomad/client/driver/exec.go

135 lines
2.9 KiB
Go
Raw Normal View History

2015-08-20 23:50:28 +00:00
package driver
import (
2015-08-29 23:20:07 +00:00
"fmt"
"runtime"
"syscall"
2015-08-29 23:20:07 +00:00
"time"
2015-08-20 23:50:28 +00:00
"github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/client/executor"
2015-08-20 23:50:28 +00:00
"github.com/hashicorp/nomad/nomad/structs"
)
2015-09-25 23:49:14 +00:00
// ExecDriver fork/execs tasks using as many of the underlying OS's isolation
// features.
2015-08-20 23:50:28 +00:00
type ExecDriver struct {
DriverContext
2015-08-20 23:50:28 +00:00
}
2015-08-23 23:49:48 +00:00
// execHandle is returned from Start/Open as a handle to the PID
type execHandle struct {
cmd executor.Executor
2015-08-23 23:49:48 +00:00
waitCh chan error
2015-08-29 23:20:07 +00:00
doneCh chan struct{}
2015-08-23 23:49:48 +00:00
}
2015-08-20 23:50:28 +00:00
// NewExecDriver is used to create a new exec driver
func NewExecDriver(ctx *DriverContext) Driver {
return &ExecDriver{*ctx}
2015-08-20 23:50:28 +00:00
}
func (d *ExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
// Only enable if we are root when running on non-windows systems.
if runtime.GOOS != "windows" && syscall.Geteuid() != 0 {
d.logger.Printf("[DEBUG] driver.exec: must run as root user, disabling")
return false, nil
}
2015-08-20 23:53:43 +00:00
node.Attributes["driver.exec"] = "1"
2015-08-20 23:50:28 +00:00
return true, nil
}
2015-08-23 23:49:48 +00:00
func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
2015-08-29 23:20:07 +00:00
// Get the command
command, ok := task.Config["command"]
if !ok || command == "" {
return nil, fmt.Errorf("missing command for exec driver")
}
2015-09-26 22:37:48 +00:00
// Get the environment variables.
envVars := TaskEnvironmentVariables(ctx, task)
2015-08-29 23:20:07 +00:00
// Look for arguments
var args []string
2015-09-26 22:37:48 +00:00
if argRaw, ok := task.Config["args"]; ok {
args = append(args, argRaw)
2015-08-29 23:20:07 +00:00
}
// Setup the command
cmd := executor.Command(command, args...)
if err := cmd.Limit(task.Resources); err != nil {
return nil, fmt.Errorf("failed to constrain resources: %s", err)
}
2015-09-16 14:13:54 +00:00
2015-09-23 05:36:10 +00:00
// Populate environment variables
cmd.Command().Env = envVars.List()
2015-09-25 23:49:14 +00:00
if err := cmd.ConfigureTaskDir(d.taskName, ctx.AllocDir); err != nil {
return nil, fmt.Errorf("failed to configure task directory: %v", err)
}
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("failed to start command: %v", err)
2015-08-29 23:20:07 +00:00
}
// Return a driver handle
h := &execHandle{
cmd: cmd,
2015-08-29 23:20:07 +00:00
doneCh: make(chan struct{}),
waitCh: make(chan error, 1),
}
go h.run()
return h, nil
2015-08-23 23:49:48 +00:00
}
func (d *ExecDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) {
2015-08-29 23:20:07 +00:00
// Find the process
cmd, err := executor.OpenId(handleID)
2015-09-15 20:45:48 +00:00
if err != nil {
return nil, fmt.Errorf("failed to open ID %v: %v", handleID, err)
2015-08-29 23:20:07 +00:00
}
// Return a driver handle
h := &execHandle{
cmd: cmd,
2015-08-29 23:20:07 +00:00
doneCh: make(chan struct{}),
waitCh: make(chan error, 1),
}
go h.run()
return h, nil
2015-08-23 23:49:48 +00:00
}
func (h *execHandle) ID() string {
id, _ := h.cmd.ID()
return id
2015-08-23 23:49:48 +00:00
}
func (h *execHandle) WaitCh() chan error {
return h.waitCh
}
2015-08-29 23:20:07 +00:00
func (h *execHandle) Update(task *structs.Task) error {
// Update is not possible
2015-08-23 23:49:48 +00:00
return nil
}
2015-08-29 23:20:07 +00:00
func (h *execHandle) Kill() error {
h.cmd.Shutdown()
2015-08-29 23:20:07 +00:00
select {
case <-h.doneCh:
return nil
case <-time.After(5 * time.Second):
return h.cmd.ForceStop()
2015-08-29 23:20:07 +00:00
}
}
func (h *execHandle) run() {
err := h.cmd.Wait()
2015-08-29 23:20:07 +00:00
close(h.doneCh)
if err != nil {
h.waitCh <- err
}
close(h.waitCh)
}