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 }