github.com/ranjib/nomad@v0.1.1-0.20160225204057-97751b02f70b/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 "gypsy": NewGypsyDriver, 25 "java": NewJavaDriver, 26 "lxc": NewLXCDriver, 27 "qemu": NewQemuDriver, 28 "raw_exec": NewRawExecDriver, 29 "rkt": NewRktDriver, 30 "systemd": NewSystemdDriver, 31 } 32 33 // NewDriver is used to instantiate and return a new driver 34 // given the name and a logger 35 func NewDriver(name string, ctx *DriverContext) (Driver, error) { 36 // Lookup the factory function 37 factory, ok := BuiltinDrivers[name] 38 if !ok { 39 return nil, fmt.Errorf("unknown driver '%s'", name) 40 } 41 42 // Instantiate the driver 43 f := factory(ctx) 44 return f, nil 45 } 46 47 // Factory is used to instantiate a new Driver 48 type Factory func(*DriverContext) Driver 49 50 // Driver is used for execution of tasks. This allows Nomad 51 // to support many pluggable implementations of task drivers. 52 // Examples could include LXC, Docker, Qemu, etc. 53 type Driver interface { 54 // Drivers must support the fingerprint interface for detection 55 fingerprint.Fingerprint 56 57 // Start is used to being task execution 58 Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) 59 60 // Open is used to re-open a handle to a task 61 Open(ctx *ExecContext, handleID string) (DriverHandle, error) 62 } 63 64 // DriverContext is a means to inject dependencies such as loggers, configs, and 65 // node attributes into a Driver without having to change the Driver interface 66 // each time we do it. Used in conjection with Factory, above. 67 type DriverContext struct { 68 taskName string 69 config *config.Config 70 logger *log.Logger 71 node *structs.Node 72 taskEnv *env.TaskEnvironment 73 } 74 75 // NewDriverContext initializes a new DriverContext with the specified fields. 76 // This enables other packages to create DriverContexts but keeps the fields 77 // private to the driver. If we want to change this later we can gorename all of 78 // the fields in DriverContext. 79 func NewDriverContext(taskName string, config *config.Config, node *structs.Node, 80 logger *log.Logger, taskEnv *env.TaskEnvironment) *DriverContext { 81 return &DriverContext{ 82 taskName: taskName, 83 config: config, 84 node: node, 85 logger: logger, 86 taskEnv: taskEnv, 87 } 88 } 89 90 // KillTimeout returns the timeout that should be used for the task between 91 // signaling and killing the task. 92 func (d *DriverContext) KillTimeout(task *structs.Task) time.Duration { 93 max := d.config.MaxKillTimeout.Nanoseconds() 94 desired := task.KillTimeout.Nanoseconds() 95 96 // Make the minimum time between signal and kill, 1 second. 97 if desired == 0 { 98 desired = (1 * time.Second).Nanoseconds() 99 } 100 101 if desired < max { 102 return time.Duration(desired) 103 } 104 105 return d.config.MaxKillTimeout 106 } 107 108 // DriverHandle is an opaque handle into a driver used for task 109 // manipulation 110 type DriverHandle interface { 111 // Returns an opaque handle that can be used to re-open the handle 112 ID() string 113 114 // WaitCh is used to return a channel used wait for task completion 115 WaitCh() chan *cstructs.WaitResult 116 117 // Update is used to update the task if possible and update task related 118 // configurations. 119 Update(task *structs.Task) error 120 121 // Kill is used to stop the task 122 Kill() error 123 } 124 125 // ExecContext is shared between drivers within an allocation 126 type ExecContext struct { 127 sync.Mutex 128 129 // AllocDir contains information about the alloc directory structure. 130 AllocDir *allocdir.AllocDir 131 132 // Alloc ID 133 AllocID string 134 } 135 136 // NewExecContext is used to create a new execution context 137 func NewExecContext(alloc *allocdir.AllocDir, allocID string) *ExecContext { 138 return &ExecContext{AllocDir: alloc, AllocID: allocID} 139 } 140 141 // GetTaskEnv converts the alloc dir, the node and task configuration into a 142 // TaskEnvironment. 143 func GetTaskEnv(alloc *allocdir.AllocDir, node *structs.Node, task *structs.Task) (*env.TaskEnvironment, error) { 144 env := env.NewTaskEnvironment(node). 145 SetMeta(task.Meta). 146 SetEnvvars(task.Env) 147 148 if alloc != nil { 149 env.SetAllocDir(alloc.SharedDir) 150 taskdir, ok := alloc.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 } 157 158 if task.Resources != nil { 159 env.SetMemLimit(task.Resources.MemoryMB) 160 env.SetCpuLimit(task.Resources.CPU) 161 env.SetNetworks(task.Resources.Networks) 162 } 163 164 return env.Build(), nil 165 } 166 167 func mapMergeStrInt(maps ...map[string]int) map[string]int { 168 out := map[string]int{} 169 for _, in := range maps { 170 for key, val := range in { 171 out[key] = val 172 } 173 } 174 return out 175 } 176 177 func mapMergeStrStr(maps ...map[string]string) map[string]string { 178 out := map[string]string{} 179 for _, in := range maps { 180 for key, val := range in { 181 out[key] = val 182 } 183 } 184 return out 185 }