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  }