From 2bcf7105e88bca3cf1ca2253c686b7d6b9db1699 Mon Sep 17 00:00:00 2001 From: Chris Bednarski Date: Mon, 14 Sep 2015 19:38:21 -0700 Subject: [PATCH] Use Linux on Linux --- client/exec/exec.go | 24 +++++++++++++++++++++++- client/exec/exec_linux.go | 25 +++++++++++++++---------- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/client/exec/exec.go b/client/exec/exec.go index 8f67768ce..dcad3098c 100644 --- a/client/exec/exec.go +++ b/client/exec/exec.go @@ -30,6 +30,11 @@ import ( // wrapper must implement. You should not need to implement a Java executor. // Rather, you would implement a cgroups executor that the Java driver will use. type Executor interface { + // Available should return true or false based on whether the current platform + // can run this type of executor, based on capability testing. Returning + // true does not guarantee that this executor will be used. + Available() bool + // Limit must be called before Start and restricts the amount of resources // the process can use. Note that an error may be returned ONLY IF the // executor implements resource limiting. Otherwise Limit is ignored. @@ -107,7 +112,20 @@ func OpenPid(int) Executor { // This is a simplistic strategy pattern. We can potentially improve this by // using a decorator pattern instead. func AutoselectExecutor() Executor { - // TODO platform switching + // These will be IN ORDER and the first available will be used, so preferred + // ones should be at the top and fallbacks at the bottom. + // TODO refactor this to be more lightweight. + executors := []Executor{ + &LinuxExecutor{}, + } + + for _, executor := range executors { + if executor.Available() { + return executor + } + } + + // Always return something, even if we don't have advanced capabilities. return &UniversalExecutor{} } @@ -117,6 +135,10 @@ type UniversalExecutor struct { cmd } +func (e *UniversalExecutor) Available() bool { + return true +} + func (e *UniversalExecutor) Limit(resources structs.Resources) error { // No-op return nil diff --git a/client/exec/exec_linux.go b/client/exec/exec_linux.go index ea5d4cb48..1d6a79413 100644 --- a/client/exec/exec_linux.go +++ b/client/exec/exec_linux.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "os/user" + "runtime" "strconv" "syscall" @@ -11,13 +12,6 @@ import ( "github.com/hashicorp/nomad/nomad/structs" ) -// Linux executor is designed to run on linux kernel 2.8+. It will fork/exec as -// a user you specify and limit resources using rlimit. -type LinuxExecutor struct { - cmd - user *user.User -} - // SetUID changes the Uid for this command (must be set before starting) func SetUID(command *cmd, userid string) error { uid, err := strconv.ParseUint(userid, 10, 32) @@ -50,8 +44,19 @@ func SetGID(command *cmd, groupid string) error { return nil } +// Linux executor is designed to run on linux kernel 2.8+. It will fork/exec as +// a user you specify and limit resources using rlimit. +type LinuxExecutor struct { + cmd + user *user.User +} + +func (e *LinuxExecutor) Available() bool { + return runtime.GOOS == "linux" +} + func (e *LinuxExecutor) Limit(resources structs.Resources) error { - // TODO rlimit + // TODO limit some things return nil } @@ -76,7 +81,7 @@ func (e *LinuxExecutor) RunAs(userid string) error { errs = multierror.Append(errs, err) } - // If we got here we failed to looking based on id and username, so we'll + // If we got here we failed to lookup based on id and username, so we'll // return those errors. return fmt.Errorf("Failed to identify user to run as: %s", errs) } @@ -109,7 +114,7 @@ func (e *LinuxExecutor) Open(pid int) error { // On linux FindProcess() will return a pid but doesn't actually check to // see whether that process is running. We'll send signal 0 to see if the // process is alive. - err := process.Signal(syscall.Signal(0)) + err = process.Signal(syscall.Signal(0)) if err != nil { return fmt.Errorf("Unable to signal pid %d: %s", err) }