github.com/ryanslade/nomad@v0.2.4-0.20160128061903-fc95782f2089/client/driver/driver.go (about) 1 package driver 2 3 import ( 4 "fmt" 5 "log" 6 "path/filepath" 7 "sync" 8 "time" 9 10 "github.com/hashicorp/nomad/client/allocdir" 11 "github.com/hashicorp/nomad/client/config" 12 "github.com/hashicorp/nomad/client/driver/env" 13 "github.com/hashicorp/nomad/client/fingerprint" 14 "github.com/hashicorp/nomad/nomad/structs" 15 16 cstructs "github.com/hashicorp/nomad/client/driver/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 61 // DriverContext is a means to inject dependencies such as loggers, configs, and 62 // node attributes into a Driver without having to change the Driver interface 63 // each time we do it. Used in conjection with Factory, above. 64 type DriverContext struct { 65 taskName string 66 config *config.Config 67 logger *log.Logger 68 node *structs.Node 69 taskEnv *env.TaskEnvironment 70 } 71 72 // NewDriverContext initializes a new DriverContext with the specified fields. 73 // This enables other packages to create DriverContexts but keeps the fields 74 // private to the driver. If we want to change this later we can gorename all of 75 // the fields in DriverContext. 76 func NewDriverContext(taskName string, config *config.Config, node *structs.Node, 77 logger *log.Logger, taskEnv *env.TaskEnvironment) *DriverContext { 78 return &DriverContext{ 79 taskName: taskName, 80 config: config, 81 node: node, 82 logger: logger, 83 taskEnv: taskEnv, 84 } 85 } 86 87 // KillTimeout returns the timeout that should be used for the task between 88 // signaling and killing the task. 89 func (d *DriverContext) KillTimeout(task *structs.Task) time.Duration { 90 max := d.config.MaxKillTimeout.Nanoseconds() 91 desired := task.KillTimeout.Nanoseconds() 92 if desired < max { 93 return task.KillTimeout 94 } 95 96 return d.config.MaxKillTimeout 97 } 98 99 // DriverHandle is an opaque handle into a driver used for task 100 // manipulation 101 type DriverHandle interface { 102 // Returns an opaque handle that can be used to re-open the handle 103 ID() string 104 105 // WaitCh is used to return a channel used wait for task completion 106 WaitCh() chan *cstructs.WaitResult 107 108 // Update is used to update the task if possible 109 Update(task *structs.Task) error 110 111 // Kill is used to stop the task 112 Kill() error 113 } 114 115 // ExecContext is shared between drivers within an allocation 116 type ExecContext struct { 117 sync.Mutex 118 119 // AllocDir contains information about the alloc directory structure. 120 AllocDir *allocdir.AllocDir 121 122 // Alloc ID 123 AllocID string 124 } 125 126 // NewExecContext is used to create a new execution context 127 func NewExecContext(alloc *allocdir.AllocDir, allocID string) *ExecContext { 128 return &ExecContext{AllocDir: alloc, AllocID: allocID} 129 } 130 131 // GetTaskEnv converts the alloc dir, the node and task configuration into a 132 // TaskEnvironment. 133 func GetTaskEnv(alloc *allocdir.AllocDir, node *structs.Node, task *structs.Task) (*env.TaskEnvironment, error) { 134 env := env.NewTaskEnvironment(node). 135 SetMeta(task.Meta). 136 SetEnvvars(task.Env) 137 138 if alloc != nil { 139 env.SetAllocDir(alloc.SharedDir) 140 taskdir, ok := alloc.TaskDirs[task.Name] 141 if !ok { 142 return nil, fmt.Errorf("failed to get task directory for task %q", task.Name) 143 } 144 145 env.SetTaskLocalDir(filepath.Join(taskdir, allocdir.TaskLocal)) 146 } 147 148 if task.Resources != nil { 149 env.SetMemLimit(task.Resources.MemoryMB) 150 env.SetCpuLimit(task.Resources.CPU) 151 152 if len(task.Resources.Networks) > 0 { 153 network := task.Resources.Networks[0] 154 env.SetTaskIp(network.IP) 155 env.SetPorts(network.MapLabelToValues(nil)) 156 } 157 } 158 159 return env.Build(), nil 160 } 161 162 func mapMergeStrInt(maps ...map[string]int) map[string]int { 163 out := map[string]int{} 164 for _, in := range maps { 165 for key, val := range in { 166 out[key] = val 167 } 168 } 169 return out 170 } 171 172 func mapMergeStrStr(maps ...map[string]string) map[string]string { 173 out := map[string]string{} 174 for _, in := range maps { 175 for key, val := range in { 176 out[key] = val 177 } 178 } 179 return out 180 }