github.com/jmitchell/nomad@v0.1.3-0.20151007230021-7ab84c2862d8/client/executor/exec.go (about)

     1  // Package exec is used to invoke child processes across various platforms to
     2  // provide the following features:
     3  //
     4  // - Least privilege
     5  // - Resource constraints
     6  // - Process isolation
     7  //
     8  // A "platform" may be defined as coarsely as "Windows" or as specifically as
     9  // "linux 3.20 with systemd". This allows Nomad to use best-effort, best-
    10  // available capabilities of each platform to provide resource constraints,
    11  // process isolation, and security features, or otherwise take advantage of
    12  // features that are unique to that platform.
    13  //
    14  // The `semantics of any particular instance are left up to the implementation.
    15  // However, these should be completely transparent to the calling context. In
    16  // other words, the Java driver should be able to call exec for any platform and
    17  // just work.
    18  package executor
    19  
    20  import (
    21  	"fmt"
    22  	"os/exec"
    23  	"path/filepath"
    24  
    25  	"github.com/hashicorp/nomad/client/allocdir"
    26  	"github.com/hashicorp/nomad/nomad/structs"
    27  )
    28  
    29  var errNoResources = fmt.Errorf("No resources are associated with this task")
    30  
    31  // Executor is an interface that any platform- or capability-specific exec
    32  // wrapper must implement. You should not need to implement a Java executor.
    33  // Rather, you would implement a cgroups executor that the Java driver will use.
    34  type Executor interface {
    35  	// Limit must be called before Start and restricts the amount of resources
    36  	// the process can use. Note that an error may be returned ONLY IF the
    37  	// executor implements resource limiting. Otherwise Limit is ignored.
    38  	Limit(*structs.Resources) error
    39  
    40  	// ConfigureTaskDir must be called before Start and ensures that the tasks
    41  	// directory is properly configured.
    42  	ConfigureTaskDir(taskName string, alloc *allocdir.AllocDir) error
    43  
    44  	// Start the process. This may wrap the actual process in another command,
    45  	// depending on the capabilities in this environment. Errors that arise from
    46  	// Limits or Runas may bubble through Start()
    47  	Start() error
    48  
    49  	// Open should be called to restore a previous execution. This might be needed if
    50  	// nomad is restarted.
    51  	Open(string) error
    52  
    53  	// Wait waits till the user's command is completed.
    54  	Wait() error
    55  
    56  	// Returns a handle that is executor specific for use in reopening.
    57  	ID() (string, error)
    58  
    59  	// Shutdown should use a graceful stop mechanism so the application can
    60  	// perform checkpointing or cleanup, if such a mechanism is available.
    61  	// If such a mechanism is not available, Shutdown() should call ForceStop().
    62  	Shutdown() error
    63  
    64  	// ForceStop will terminate the process without waiting for cleanup. Every
    65  	// implementations must provide this.
    66  	ForceStop() error
    67  
    68  	// Command provides access the underlying Cmd struct in case the Executor
    69  	// interface doesn't expose the functionality you need.
    70  	Command() *cmd
    71  }
    72  
    73  // Command is a mirror of exec.Command that returns a platform-specific Executor
    74  func Command(name string, arg ...string) Executor {
    75  	executor := NewExecutor()
    76  	cmd := executor.Command()
    77  	cmd.Path = name
    78  	cmd.Args = append([]string{name}, arg...)
    79  
    80  	if filepath.Base(name) == name {
    81  		if lp, err := exec.LookPath(name); err != nil {
    82  			// cmd.lookPathErr = err
    83  		} else {
    84  			cmd.Path = lp
    85  		}
    86  	}
    87  	return executor
    88  }
    89  
    90  // OpenId is similar to executor.Command but will attempt to reopen with the
    91  // passed ID.
    92  func OpenId(id string) (Executor, error) {
    93  	executor := NewExecutor()
    94  	err := executor.Open(id)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	return executor, nil
    99  }
   100  
   101  // Cmd is an extension of exec.Cmd that incorporates functionality for
   102  // re-attaching to processes, dropping priviledges, etc., based on platform-
   103  // specific implementations.
   104  type cmd struct {
   105  	exec.Cmd
   106  
   107  	// Resources is used to limit CPU and RAM used by the process, by way of
   108  	// cgroups or a similar mechanism.
   109  	Resources structs.Resources
   110  
   111  	// RunAs may be a username or Uid. The implementation will decide how to use it.
   112  	RunAs string
   113  }