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