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

     1  // Package executor is used to invoke child processes across various operating
     2  // systems in a way that provides the following features:
     3  //
     4  // - Least privilege
     5  // - Resource constraints
     6  // - Process isolation
     7  //
     8  // An operating system may be something like "windows" or "linux with systemd".
     9  // Executors allow drivers like `exec` and `java` to share an implementation
    10  // for isolation capabilities on a particular operating system.
    11  //
    12  // For example:
    13  //
    14  // - `exec` and `java` on Linux use a cgroups executor
    15  // - `exec` and `java` on FreeBSD use a jails executor
    16  //
    17  // However, drivers that provide their own isolation should not use executors.
    18  // For example, using an executor to start QEMU means that the QEMU call is
    19  // run inside a chroot+cgroup, even though the VM already provides isolation for
    20  // the task running inside it. This is an extraneous level of indirection.
    21  package executor
    22  
    23  import (
    24  	"fmt"
    25  	"os/exec"
    26  	"path/filepath"
    27  
    28  	"github.com/hashicorp/nomad/client/allocdir"
    29  	"github.com/hashicorp/nomad/nomad/structs"
    30  
    31  	cstructs "github.com/hashicorp/nomad/client/driver/structs"
    32  )
    33  
    34  var errNoResources = fmt.Errorf("No resources are associated with this task")
    35  
    36  // Executor is an interface that any platform- or capability-specific exec
    37  // wrapper must implement. You should not need to implement a Java executor.
    38  // Rather, you would implement a cgroups executor that the Java driver will use.
    39  type Executor interface {
    40  	// Limit must be called before Start and restricts the amount of resources
    41  	// the process can use. Note that an error may be returned ONLY IF the
    42  	// executor implements resource limiting. Otherwise Limit is ignored.
    43  	Limit(*structs.Resources) error
    44  
    45  	// ConfigureTaskDir must be called before Start and ensures that the tasks
    46  	// directory is properly configured.
    47  	ConfigureTaskDir(taskName string, alloc *allocdir.AllocDir) error
    48  
    49  	// Start the process. This may wrap the actual process in another command,
    50  	// depending on the capabilities in this environment. Errors that arise from
    51  	// Limits or Runas may bubble through Start()
    52  	Start() error
    53  
    54  	// Open should be called to restore a previous execution. This might be needed if
    55  	// nomad is restarted.
    56  	Open(string) error
    57  
    58  	// Wait waits till the user's command is completed.
    59  	Wait() *cstructs.WaitResult
    60  
    61  	// Returns a handle that is executor specific for use in reopening.
    62  	ID() (string, error)
    63  
    64  	// Shutdown should use a graceful stop mechanism so the application can
    65  	// perform checkpointing or cleanup, if such a mechanism is available.
    66  	// If such a mechanism is not available, Shutdown() should call ForceStop().
    67  	Shutdown() error
    68  
    69  	// ForceStop will terminate the process without waiting for cleanup. Every
    70  	// implementations must provide this.
    71  	ForceStop() error
    72  
    73  	// Command provides access the underlying Cmd struct in case the Executor
    74  	// interface doesn't expose the functionality you need.
    75  	Command() *exec.Cmd
    76  }
    77  
    78  // Command is a mirror of exec.Command that returns a platform-specific Executor
    79  func Command(name string, args ...string) Executor {
    80  	executor := NewExecutor()
    81  	SetCommand(executor, name, args)
    82  	return executor
    83  }
    84  
    85  func SetCommand(e Executor, name string, args []string) {
    86  	cmd := e.Command()
    87  	cmd.Path = name
    88  	cmd.Args = append([]string{name}, args...)
    89  
    90  	if filepath.Base(name) == name {
    91  		if lp, err := exec.LookPath(name); err != nil {
    92  			// cmd.lookPathErr = err
    93  		} else {
    94  			cmd.Path = lp
    95  		}
    96  	}
    97  }
    98  
    99  // OpenId is similar to executor.Command but will attempt to reopen with the
   100  // passed ID.
   101  func OpenId(id string) (Executor, error) {
   102  	executor := NewExecutor()
   103  	err := executor.Open(id)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	return executor, nil
   108  }