Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux executor with cgroup isolation support #68

Merged
merged 7 commits into from
Sep 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions client/alloc_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ func TestAllocRunner_Update(t *testing.T) {
}
}

/*
TODO: This test is disabled til a follow-up api changes the restore state interface.
The driver/executor interface will be changed from Open to Cleanup, in which
clean-up tears down previous allocs.

func TestAllocRunner_SaveRestoreState(t *testing.T) {
upd, ar := testAllocRunner()

Expand Down Expand Up @@ -155,3 +160,4 @@ func TestAllocRunner_SaveRestoreState(t *testing.T) {
t.Fatalf("took too long to terminate")
}
}
*/
26 changes: 7 additions & 19 deletions client/driver/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package driver

import (
"fmt"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -52,12 +51,11 @@ func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,

// Setup the command
cmd := executor.Command(command, args...)
err := cmd.Limit(task.Resources)
if err != nil {
if err := cmd.Limit(task.Resources); err != nil {
return nil, fmt.Errorf("failed to constrain resources: %s", err)
}
err = cmd.Start()
if err != nil {

if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("failed to start command: %v", err)
}

Expand All @@ -72,17 +70,10 @@ func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,
}

func (d *ExecDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) {
// Split the handle
pidStr := strings.TrimPrefix(handleID, "PID:")
pid, err := strconv.Atoi(pidStr)
if err != nil {
return nil, fmt.Errorf("failed to parse handle '%s': %v", handleID, err)
}

// Find the process
cmd, err := executor.OpenPid(pid)
cmd, err := executor.OpenId(handleID)
if err != nil {
return nil, fmt.Errorf("failed to find PID %d: %v", pid, err)
return nil, fmt.Errorf("failed to open ID %v: %v", handleID, err)
}

// Return a driver handle
Expand All @@ -96,9 +87,8 @@ func (d *ExecDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, erro
}

func (h *execHandle) ID() string {
// Return a handle to the PID
pid, _ := h.cmd.Pid()
return fmt.Sprintf("PID:%d", pid)
id, _ := h.cmd.ID()
return id
}

func (h *execHandle) WaitCh() chan error {
Expand All @@ -125,8 +115,6 @@ func (h *execHandle) run() {
close(h.doneCh)
if err != nil {
h.waitCh <- err
} else if !h.cmd.Command().ProcessState.Success() {
h.waitCh <- fmt.Errorf("task exited with error")
}
close(h.waitCh)
}
8 changes: 7 additions & 1 deletion client/driver/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,15 @@ func TestExecDriver_StartOpen_Wait(t *testing.T) {
task := &structs.Task{
Config: map[string]string{
"command": "/bin/sleep",
"args": "1",
"args": "5",
},
}
if task.Resources == nil {
task.Resources = &structs.Resources{}
}
task.Resources.CPU = 2048
task.Resources.MemoryMB = 2

handle, err := d.Start(ctx, task)
if err != nil {
t.Fatalf("err: %v", err)
Expand Down
17 changes: 4 additions & 13 deletions client/driver/java.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"os/exec"
"path"
"path/filepath"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -150,17 +149,10 @@ func (d *JavaDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,
}

func (d *JavaDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) {
// Split the handle
pidStr := strings.TrimPrefix(handleID, "PID:")
pid, err := strconv.Atoi(pidStr)
if err != nil {
return nil, fmt.Errorf("failed to parse handle '%s': %v", handleID, err)
}

// Find the process
cmd, err := executor.OpenPid(pid)
cmd, err := executor.OpenId(handleID)
if err != nil {
return nil, fmt.Errorf("failed to find PID %d: %v", pid, err)
return nil, fmt.Errorf("failed to open ID %v: %v", handleID, err)
}

// Return a driver handle
Expand All @@ -175,9 +167,8 @@ func (d *JavaDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, erro
}

func (h *javaHandle) ID() string {
// Return a handle to the PID
pid, _ := h.cmd.Pid()
return fmt.Sprintf("PID:%d", pid)
id, _ := h.cmd.ID()
return id
}

func (h *javaHandle) WaitCh() chan error {
Expand Down
Binary file not shown.
26 changes: 10 additions & 16 deletions client/executor/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,20 @@ type Executor interface {
// executor implements resource limiting. Otherwise Limit is ignored.
Limit(*structs.Resources) error

// RunAs sets the user we should use to run this command. This may be set as
// a username, uid, or other identifier. The implementation will decide what
// to do with it, if anything. Note that an error may be returned ONLY IF
// the executor implements user lookups. Otherwise RunAs is ignored.
RunAs(string) error

// Start the process. This may wrap the actual process in another command,
// depending on the capabilities in this environment. Errors that arise from
// Limits or Runas may bubble through Start()
Start() error

// Open should be called to restore a previous pid. This might be needed if
// nomad is restarted. This sets os.Process internally.
Open(int) error
// Open should be called to restore a previous execution. This might be needed if
// nomad is restarted.
Open(string) error

// This is a convenience wrapper around Command().Wait()
// Wait waits till the user's command is completed.
Wait() error

// This is a convenience wrapper around Command().Process.Pid
Pid() (int, error)
// Returns a handle that is executor specific for use in reopening.
ID() (string, error)

// Shutdown should use a graceful stop mechanism so the application can
// perform checkpointing or cleanup, if such a mechanism is available.
Expand Down Expand Up @@ -85,11 +79,11 @@ func Command(name string, arg ...string) Executor {
return executor
}

// OpenPid is similar to executor.Command but will initialize executor.Cmd with
// the Pid set to the one specified.
func OpenPid(pid int) (Executor, error) {
// OpenId is similar to executor.Command but will attempt to reopen with the
// passed ID.
func OpenId(id string) (Executor, error) {
executor := NewExecutor()
err := executor.Open(pid)
err := executor.Open(id)
if err != nil {
return nil, err
}
Expand Down
Loading