github.com/huiliang/nomad@v0.2.1-0.20151124023127-7a8b664699ff/client/driver/raw_exec.go (about) 1 package driver 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "strconv" 7 "time" 8 9 "github.com/hashicorp/nomad/client/allocdir" 10 "github.com/hashicorp/nomad/client/config" 11 "github.com/hashicorp/nomad/client/driver/executor" 12 cstructs "github.com/hashicorp/nomad/client/driver/structs" 13 "github.com/hashicorp/nomad/client/fingerprint" 14 "github.com/hashicorp/nomad/client/getter" 15 "github.com/hashicorp/nomad/nomad/structs" 16 "github.com/mitchellh/mapstructure" 17 ) 18 19 const ( 20 // The option that enables this driver in the Config.Options map. 21 rawExecConfigOption = "driver.raw_exec.enable" 22 ) 23 24 // The RawExecDriver is a privileged version of the exec driver. It provides no 25 // resource isolation and just fork/execs. The Exec driver should be preferred 26 // and this should only be used when explicitly needed. 27 type RawExecDriver struct { 28 DriverContext 29 fingerprint.StaticFingerprinter 30 } 31 32 // rawExecHandle is returned from Start/Open as a handle to the PID 33 type rawExecHandle struct { 34 cmd executor.Executor 35 waitCh chan *cstructs.WaitResult 36 doneCh chan struct{} 37 } 38 39 // NewRawExecDriver is used to create a new raw exec driver 40 func NewRawExecDriver(ctx *DriverContext) Driver { 41 return &RawExecDriver{DriverContext: *ctx} 42 } 43 44 func (d *RawExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) { 45 // Check that the user has explicitly enabled this executor. 46 enabled, err := strconv.ParseBool(cfg.ReadDefault(rawExecConfigOption, "false")) 47 if err != nil { 48 return false, fmt.Errorf("Failed to parse %v option: %v", rawExecConfigOption, err) 49 } 50 51 if enabled { 52 d.logger.Printf("[WARN] driver.raw_exec: raw exec is enabled. Only enable if needed") 53 node.Attributes["driver.raw_exec"] = "1" 54 return true, nil 55 } 56 57 return false, nil 58 } 59 60 func (d *RawExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) { 61 var driverConfig ExecDriverConfig 62 if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil { 63 return nil, err 64 } 65 // Get the tasks local directory. 66 taskName := d.DriverContext.taskName 67 taskDir, ok := ctx.AllocDir.TaskDirs[taskName] 68 if !ok { 69 return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName) 70 } 71 72 // Get the command to be ran 73 command := driverConfig.Command 74 if command == "" { 75 return nil, fmt.Errorf("missing command for Raw Exec driver") 76 } 77 78 // Check if an artificat is specified and attempt to download it 79 source, ok := task.Config["artifact_source"] 80 if ok && source != "" { 81 // Proceed to download an artifact to be executed. 82 _, err := getter.GetArtifact( 83 filepath.Join(taskDir, allocdir.TaskLocal), 84 driverConfig.ArtifactSource, 85 driverConfig.Checksum, 86 d.logger, 87 ) 88 if err != nil { 89 return nil, err 90 } 91 } 92 93 // Get the environment variables. 94 envVars := TaskEnvironmentVariables(ctx, task) 95 96 // Setup the command 97 cmd := executor.NewBasicExecutor() 98 executor.SetCommand(cmd, command, driverConfig.Args) 99 if err := cmd.Limit(task.Resources); err != nil { 100 return nil, fmt.Errorf("failed to constrain resources: %s", err) 101 } 102 103 // Populate environment variables 104 cmd.Command().Env = envVars.List() 105 106 if err := cmd.ConfigureTaskDir(d.taskName, ctx.AllocDir); err != nil { 107 return nil, fmt.Errorf("failed to configure task directory: %v", err) 108 } 109 110 if err := cmd.Start(); err != nil { 111 return nil, fmt.Errorf("failed to start command: %v", err) 112 } 113 114 // Return a driver handle 115 h := &execHandle{ 116 cmd: cmd, 117 doneCh: make(chan struct{}), 118 waitCh: make(chan *cstructs.WaitResult, 1), 119 } 120 go h.run() 121 return h, nil 122 } 123 124 func (d *RawExecDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) { 125 // Find the process 126 cmd := executor.NewBasicExecutor() 127 if err := cmd.Open(handleID); err != nil { 128 return nil, fmt.Errorf("failed to open ID %v: %v", handleID, err) 129 } 130 131 // Return a driver handle 132 h := &execHandle{ 133 cmd: cmd, 134 doneCh: make(chan struct{}), 135 waitCh: make(chan *cstructs.WaitResult, 1), 136 } 137 go h.run() 138 return h, nil 139 } 140 141 func (h *rawExecHandle) ID() string { 142 id, _ := h.cmd.ID() 143 return id 144 } 145 146 func (h *rawExecHandle) WaitCh() chan *cstructs.WaitResult { 147 return h.waitCh 148 } 149 150 func (h *rawExecHandle) Update(task *structs.Task) error { 151 // Update is not possible 152 return nil 153 } 154 155 func (h *rawExecHandle) Kill() error { 156 h.cmd.Shutdown() 157 select { 158 case <-h.doneCh: 159 return nil 160 case <-time.After(5 * time.Second): 161 return h.cmd.ForceStop() 162 } 163 } 164 165 func (h *rawExecHandle) run() { 166 res := h.cmd.Wait() 167 close(h.doneCh) 168 h.waitCh <- res 169 close(h.waitCh) 170 }