github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/client/driver/driver.go (about) 1 package driver 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "path/filepath" 8 9 "github.com/hashicorp/nomad/client/allocdir" 10 "github.com/hashicorp/nomad/client/config" 11 "github.com/hashicorp/nomad/client/driver/env" 12 "github.com/hashicorp/nomad/client/fingerprint" 13 "github.com/hashicorp/nomad/nomad/structs" 14 15 dstructs "github.com/hashicorp/nomad/client/driver/structs" 16 cstructs "github.com/hashicorp/nomad/client/structs" 17 ) 18 19 // BuiltinDrivers contains the built in registered drivers 20 // which are available for allocation handling 21 var BuiltinDrivers = map[string]Factory{ 22 "docker": NewDockerDriver, 23 "exec": NewExecDriver, 24 "raw_exec": NewRawExecDriver, 25 "java": NewJavaDriver, 26 "qemu": NewQemuDriver, 27 "rkt": NewRktDriver, 28 } 29 30 // NewDriver is used to instantiate and return a new driver 31 // given the name and a logger 32 func NewDriver(name string, ctx *DriverContext) (Driver, error) { 33 // Lookup the factory function 34 factory, ok := BuiltinDrivers[name] 35 if !ok { 36 return nil, fmt.Errorf("unknown driver '%s'", name) 37 } 38 39 // Instantiate the driver 40 f := factory(ctx) 41 return f, nil 42 } 43 44 // Factory is used to instantiate a new Driver 45 type Factory func(*DriverContext) Driver 46 47 // Driver is used for execution of tasks. This allows Nomad 48 // to support many pluggable implementations of task drivers. 49 // Examples could include LXC, Docker, Qemu, etc. 50 type Driver interface { 51 // Drivers must support the fingerprint interface for detection 52 fingerprint.Fingerprint 53 54 // Start is used to being task execution 55 Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) 56 57 // Open is used to re-open a handle to a task 58 Open(ctx *ExecContext, handleID string) (DriverHandle, error) 59 60 // Drivers must validate their configuration 61 Validate(map[string]interface{}) error 62 63 // Abilities returns the abilities of the driver 64 Abilities() DriverAbilities 65 } 66 67 // DriverAbilities marks the abilities the driver has. 68 type DriverAbilities struct { 69 // SendSignals marks the driver as being able to send signals 70 SendSignals bool 71 } 72 73 // DriverContext is a means to inject dependencies such as loggers, configs, and 74 // node attributes into a Driver without having to change the Driver interface 75 // each time we do it. Used in conjection with Factory, above. 76 type DriverContext struct { 77 taskName string 78 config *config.Config 79 logger *log.Logger 80 node *structs.Node 81 taskEnv *env.TaskEnvironment 82 } 83 84 // NewEmptyDriverContext returns a DriverContext with all fields set to their 85 // zero value. 86 func NewEmptyDriverContext() *DriverContext { 87 return &DriverContext{ 88 taskName: "", 89 config: nil, 90 node: nil, 91 logger: nil, 92 taskEnv: nil, 93 } 94 } 95 96 // NewDriverContext initializes a new DriverContext with the specified fields. 97 // This enables other packages to create DriverContexts but keeps the fields 98 // private to the driver. If we want to change this later we can gorename all of 99 // the fields in DriverContext. 100 func NewDriverContext(taskName string, config *config.Config, node *structs.Node, 101 logger *log.Logger, taskEnv *env.TaskEnvironment) *DriverContext { 102 return &DriverContext{ 103 taskName: taskName, 104 config: config, 105 node: node, 106 logger: logger, 107 taskEnv: taskEnv, 108 } 109 } 110 111 // DriverHandle is an opaque handle into a driver used for task 112 // manipulation 113 type DriverHandle interface { 114 // Returns an opaque handle that can be used to re-open the handle 115 ID() string 116 117 // WaitCh is used to return a channel used wait for task completion 118 WaitCh() chan *dstructs.WaitResult 119 120 // Update is used to update the task if possible and update task related 121 // configurations. 122 Update(task *structs.Task) error 123 124 // Kill is used to stop the task 125 Kill() error 126 127 // Stats returns aggregated stats of the driver 128 Stats() (*cstructs.TaskResourceUsage, error) 129 130 // Signal is used to send a signal to the task 131 Signal(s os.Signal) error 132 } 133 134 // ExecContext is shared between drivers within an allocation 135 type ExecContext struct { 136 // AllocDir contains information about the alloc directory structure. 137 AllocDir *allocdir.AllocDir 138 139 // Alloc ID 140 AllocID string 141 } 142 143 // NewExecContext is used to create a new execution context 144 func NewExecContext(alloc *allocdir.AllocDir, allocID string) *ExecContext { 145 return &ExecContext{AllocDir: alloc, AllocID: allocID} 146 } 147 148 // GetTaskEnv converts the alloc dir, the node, task and alloc into a 149 // TaskEnvironment. 150 func GetTaskEnv(allocDir *allocdir.AllocDir, node *structs.Node, 151 task *structs.Task, alloc *structs.Allocation, vaultToken string) (*env.TaskEnvironment, error) { 152 153 tg := alloc.Job.LookupTaskGroup(alloc.TaskGroup) 154 env := env.NewTaskEnvironment(node). 155 SetTaskMeta(task.Meta). 156 SetTaskGroupMeta(tg.Meta). 157 SetJobMeta(alloc.Job.Meta). 158 SetJobName(alloc.Job.Name). 159 SetEnvvars(task.Env). 160 SetTaskName(task.Name) 161 162 if allocDir != nil { 163 env.SetAllocDir(allocDir.SharedDir) 164 taskdir, ok := allocDir.TaskDirs[task.Name] 165 if !ok { 166 return nil, fmt.Errorf("failed to get task directory for task %q", task.Name) 167 } 168 169 env.SetTaskLocalDir(filepath.Join(taskdir, allocdir.TaskLocal)) 170 env.SetSecretsDir(filepath.Join(taskdir, allocdir.TaskSecrets)) 171 } 172 173 if task.Resources != nil { 174 env.SetMemLimit(task.Resources.MemoryMB). 175 SetCpuLimit(task.Resources.CPU). 176 SetNetworks(task.Resources.Networks) 177 } 178 179 if alloc != nil { 180 env.SetAlloc(alloc) 181 } 182 183 if task.Vault != nil { 184 env.SetVaultToken(vaultToken, task.Vault.Env) 185 } 186 187 return env.Build(), nil 188 } 189 190 func mapMergeStrInt(maps ...map[string]int) map[string]int { 191 out := map[string]int{} 192 for _, in := range maps { 193 for key, val := range in { 194 out[key] = val 195 } 196 } 197 return out 198 } 199 200 func mapMergeStrStr(maps ...map[string]string) map[string]string { 201 out := map[string]string{} 202 for _, in := range maps { 203 for key, val := range in { 204 out[key] = val 205 } 206 } 207 return out 208 }