github.com/ranjib/nomad@v0.1.1-0.20160225204057-97751b02f70b/client/driver/gypsy.go (about) 1 package driver 2 3 import ( 4 "fmt" 5 "github.com/hashicorp/nomad/client/config" 6 cstructs "github.com/hashicorp/nomad/client/driver/structs" 7 "github.com/hashicorp/nomad/client/fingerprint" 8 "github.com/hashicorp/nomad/nomad/structs" 9 "github.com/mitchellh/mapstructure" 10 gypsy "github.com/ranjib/gypsy/build" 11 lxc "gopkg.in/lxc/go-lxc.v2" 12 "log" 13 "time" 14 ) 15 16 type GypsyDriver struct { 17 DriverContext 18 fingerprint.StaticFingerprinter 19 } 20 21 type GypsyConfig struct { 22 ServerURL string `mapstructure:"server_url"` 23 Container string `mapstructure:"container"` 24 Pipeline string `mapstructure:"pipeline"` 25 RunId int `mapstructure:"run_id"` 26 } 27 28 type gypsyHandle struct { 29 logger *log.Logger 30 Id string 31 waitCh chan *cstructs.WaitResult 32 doneCh chan struct{} 33 executor *LXCExecutor 34 Pipeline string 35 RunId int 36 ServerURL string 37 } 38 39 func NewGypsyDriver(ctx *DriverContext) Driver { 40 return &GypsyDriver{DriverContext: *ctx} 41 } 42 43 func (d *GypsyDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) { 44 node.Attributes["driver.gypsy.version"] = "0.1" 45 node.Attributes["driver.gypsy"] = "1" 46 d.logger.Printf("[DEBUG] lxc.version: %s", node.Attributes["driver.gypsy.version"]) 47 return true, nil 48 } 49 50 func (d *GypsyDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) { 51 var config GypsyConfig 52 if err := mapstructure.WeakDecode(task.Config, &config); err != nil { 53 return nil, err 54 } 55 lxcConfig := &LXCExecutorConfig{ 56 Name: ctx.AllocID, 57 CloneFrom: config.Container, 58 } 59 executor, e := NewLXCExecutor(lxcConfig, d.logger) 60 d.logger.Printf("[DEBUG] Using lxc name: %s", lxcConfig.Name) 61 //envVars := TaskEnvironmentVariables(ctx, task) 62 if e != nil { 63 d.logger.Printf("[ERROR] failed to create container: %s", e) 64 return nil, e 65 } 66 d.logger.Printf("[DEBUG] Successfully created container: %s", lxcConfig.Name) 67 var gypsyServerURL string 68 if config.ServerURL == "" { 69 gypsyServerURL = "http://127.0.0.1:5678" 70 } else { 71 gypsyServerURL = config.ServerURL 72 } 73 h := &gypsyHandle{ 74 Id: ctx.AllocID, 75 logger: d.logger, 76 doneCh: make(chan struct{}), 77 waitCh: make(chan *cstructs.WaitResult, 1), 78 executor: executor, 79 Pipeline: config.Pipeline, 80 RunId: config.RunId, 81 ServerURL: gypsyServerURL, 82 } 83 84 if err := h.executor.Limit(task.Resources); err != nil { 85 d.logger.Printf("[WARN] Failed to set resource constraints %s", err) 86 return nil, err 87 } 88 89 if err := h.executor.Start(); err != nil { 90 d.logger.Printf("[WARN] Failed to start container %s", err) 91 return nil, err 92 } 93 go h.run() 94 return h, nil 95 } 96 97 func (h *gypsyHandle) performBuild() error { 98 container := h.executor.Container() 99 h.logger.Printf("[INFO] Waiting for ip allocation of container: %s\n", container.Name()) 100 container.WaitIPAddresses(30 * time.Second) 101 client := gypsy.NewBuilder(h.ServerURL, h.Pipeline, h.RunId) 102 pipeline, err := client.FetchPipeline(h.Pipeline) 103 if err != nil { 104 h.logger.Printf("[ERR] Failed to fetch pipeline %s", err) 105 return err 106 } 107 err = client.PerformBuild(container, pipeline.Scripts) 108 if err != nil { 109 h.logger.Printf("[ERR] Failed to build pipeline %s. Error: %v", h.Pipeline, err) 110 return err 111 } 112 if len(pipeline.Artifacts) > 0 { 113 err = client.UploadArtifacts(container, pipeline.Artifacts) 114 if err != nil { 115 h.logger.Printf("[ERR] Failed to upload pipeline %s artifact. Error: %v", h.Pipeline, err) 116 return err 117 } 118 } 119 client.Run.Success = true 120 client.PostRunData() 121 err = client.DestroyContainer(container) 122 if err != nil { 123 h.logger.Printf("[ERR] Failed to build pipeline %s. Error: %v", h.Pipeline, err) 124 return err 125 } 126 return nil 127 } 128 func (h *gypsyHandle) run() { 129 var waitResult *cstructs.WaitResult 130 err := h.performBuild() 131 if err != nil { 132 waitResult = cstructs.NewWaitResult(-1, -1, err) 133 } else { 134 waitResult = cstructs.NewWaitResult(0, 0, nil) 135 } 136 close(h.doneCh) 137 h.waitCh <- waitResult 138 close(h.waitCh) 139 } 140 141 func (d *GypsyDriver) Open(ctx *ExecContext, name string) (DriverHandle, error) { 142 lxcpath := lxc.DefaultConfigPath() 143 c, err := lxc.NewContainer(name, lxcpath) 144 if err != nil { 145 d.logger.Printf("[WARN] Failed to initialize container %s", err) 146 return nil, err 147 } 148 h := &gypsyHandle{ 149 Id: ctx.AllocID, 150 logger: d.logger, 151 doneCh: make(chan struct{}), 152 waitCh: make(chan *cstructs.WaitResult, 1), 153 executor: &LXCExecutor{ 154 container: c, 155 logger: d.logger, 156 }, 157 } 158 return h, nil 159 } 160 161 func (h *gypsyHandle) ID() string { 162 return fmt.Sprintf("Gypsy:%s", h.Id) 163 } 164 165 func (h *gypsyHandle) WaitCh() chan *cstructs.WaitResult { 166 return h.waitCh 167 } 168 169 func (h *gypsyHandle) Kill() error { 170 return h.executor.Shutdown() 171 } 172 173 func (h *gypsyHandle) Update(task *structs.Task) error { 174 h.logger.Printf("[WARN] Update is not supported by lxc driver") 175 return nil 176 }