github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/client/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 32 var errNoResources = fmt.Errorf("No resources are associated with this task") 33 34 // Executor is an interface that any platform- or capability-specific exec 35 // wrapper must implement. You should not need to implement a Java executor. 36 // Rather, you would implement a cgroups executor that the Java driver will use. 37 type Executor interface { 38 // Limit must be called before Start and restricts the amount of resources 39 // the process can use. Note that an error may be returned ONLY IF the 40 // executor implements resource limiting. Otherwise Limit is ignored. 41 Limit(*structs.Resources) error 42 43 // ConfigureTaskDir must be called before Start and ensures that the tasks 44 // directory is properly configured. 45 ConfigureTaskDir(taskName string, alloc *allocdir.AllocDir) error 46 47 // Start the process. This may wrap the actual process in another command, 48 // depending on the capabilities in this environment. Errors that arise from 49 // Limits or Runas may bubble through Start() 50 Start() error 51 52 // Open should be called to restore a previous execution. This might be needed if 53 // nomad is restarted. 54 Open(string) error 55 56 // Wait waits till the user's command is completed. 57 Wait() error 58 59 // Returns a handle that is executor specific for use in reopening. 60 ID() (string, error) 61 62 // Shutdown should use a graceful stop mechanism so the application can 63 // perform checkpointing or cleanup, if such a mechanism is available. 64 // If such a mechanism is not available, Shutdown() should call ForceStop(). 65 Shutdown() error 66 67 // ForceStop will terminate the process without waiting for cleanup. Every 68 // implementations must provide this. 69 ForceStop() error 70 71 // Command provides access the underlying Cmd struct in case the Executor 72 // interface doesn't expose the functionality you need. 73 Command() *cmd 74 } 75 76 // Command is a mirror of exec.Command that returns a platform-specific Executor 77 func Command(name string, arg ...string) Executor { 78 executor := NewExecutor() 79 cmd := executor.Command() 80 cmd.Path = name 81 cmd.Args = append([]string{name}, arg...) 82 83 if filepath.Base(name) == name { 84 if lp, err := exec.LookPath(name); err != nil { 85 // cmd.lookPathErr = err 86 } else { 87 cmd.Path = lp 88 } 89 } 90 return executor 91 } 92 93 // OpenId is similar to executor.Command but will attempt to reopen with the 94 // passed ID. 95 func OpenId(id string) (Executor, error) { 96 executor := NewExecutor() 97 err := executor.Open(id) 98 if err != nil { 99 return nil, err 100 } 101 return executor, nil 102 } 103 104 // Cmd is an extension of exec.Cmd that incorporates functionality for 105 // re-attaching to processes, dropping priviledges, etc., based on platform- 106 // specific implementations. 107 type cmd struct { 108 exec.Cmd 109 110 // Resources is used to limit CPU and RAM used by the process, by way of 111 // cgroups or a similar mechanism. 112 Resources structs.Resources 113 114 // RunAs may be a username or Uid. The implementation will decide how to use it. 115 RunAs string 116 }