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