github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/client/driver/driver.go (about)

     1  package driver
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"sync"
     7  
     8  	"github.com/hashicorp/nomad/client/allocdir"
     9  	"github.com/hashicorp/nomad/client/config"
    10  	"github.com/hashicorp/nomad/client/driver/environment"
    11  	"github.com/hashicorp/nomad/client/fingerprint"
    12  	"github.com/hashicorp/nomad/nomad/structs"
    13  )
    14  
    15  // BuiltinDrivers contains the built in registered drivers
    16  // which are available for allocation handling
    17  var BuiltinDrivers = map[string]Factory{
    18  	"docker":   NewDockerDriver,
    19  	"exec":     NewExecDriver,
    20  	"raw_exec": NewRawExecDriver,
    21  	"java":     NewJavaDriver,
    22  	"qemu":     NewQemuDriver,
    23  	"rkt":      NewRktDriver,
    24  }
    25  
    26  // NewDriver is used to instantiate and return a new driver
    27  // given the name and a logger
    28  func NewDriver(name string, ctx *DriverContext) (Driver, error) {
    29  	// Lookup the factory function
    30  	factory, ok := BuiltinDrivers[name]
    31  	if !ok {
    32  		return nil, fmt.Errorf("unknown driver '%s'", name)
    33  	}
    34  
    35  	// Instantiate the driver
    36  	f := factory(ctx)
    37  	return f, nil
    38  }
    39  
    40  // Factory is used to instantiate a new Driver
    41  type Factory func(*DriverContext) Driver
    42  
    43  // Driver is used for execution of tasks. This allows Nomad
    44  // to support many pluggable implementations of task drivers.
    45  // Examples could include LXC, Docker, Qemu, etc.
    46  type Driver interface {
    47  	// Drivers must support the fingerprint interface for detection
    48  	fingerprint.Fingerprint
    49  
    50  	// Start is used to being task execution
    51  	Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error)
    52  
    53  	// Open is used to re-open a handle to a task
    54  	Open(ctx *ExecContext, handleID string) (DriverHandle, error)
    55  }
    56  
    57  // DriverContext is a means to inject dependencies such as loggers, configs, and
    58  // node attributes into a Driver without having to change the Driver interface
    59  // each time we do it. Used in conjection with Factory, above.
    60  type DriverContext struct {
    61  	taskName string
    62  	config   *config.Config
    63  	logger   *log.Logger
    64  	node     *structs.Node
    65  }
    66  
    67  // NewDriverContext initializes a new DriverContext with the specified fields.
    68  // This enables other packages to create DriverContexts but keeps the fields
    69  // private to the driver. If we want to change this later we can gorename all of
    70  // the fields in DriverContext.
    71  func NewDriverContext(taskName string, config *config.Config, node *structs.Node, logger *log.Logger) *DriverContext {
    72  	return &DriverContext{
    73  		taskName: taskName,
    74  		config:   config,
    75  		node:     node,
    76  		logger:   logger,
    77  	}
    78  }
    79  
    80  // DriverHandle is an opaque handle into a driver used for task
    81  // manipulation
    82  type DriverHandle interface {
    83  	// Returns an opaque handle that can be used to re-open the handle
    84  	ID() string
    85  
    86  	// WaitCh is used to return a channel used wait for task completion
    87  	WaitCh() chan error
    88  
    89  	// Update is used to update the task if possible
    90  	Update(task *structs.Task) error
    91  
    92  	// Kill is used to stop the task
    93  	Kill() error
    94  }
    95  
    96  // ExecContext is shared between drivers within an allocation
    97  type ExecContext struct {
    98  	sync.Mutex
    99  
   100  	// AllocDir contains information about the alloc directory structure.
   101  	AllocDir *allocdir.AllocDir
   102  }
   103  
   104  // NewExecContext is used to create a new execution context
   105  func NewExecContext(alloc *allocdir.AllocDir) *ExecContext {
   106  	return &ExecContext{AllocDir: alloc}
   107  }
   108  
   109  // TaskEnvironmentVariables converts exec context and task configuration into a
   110  // TaskEnvironment.
   111  func TaskEnvironmentVariables(ctx *ExecContext, task *structs.Task) environment.TaskEnvironment {
   112  	env := environment.NewTaskEnivornment()
   113  	env.SetMeta(task.Meta)
   114  
   115  	if ctx.AllocDir != nil {
   116  		env.SetAllocDir(ctx.AllocDir.SharedDir)
   117  	}
   118  
   119  	if task.Resources != nil {
   120  		env.SetMemLimit(task.Resources.MemoryMB)
   121  		env.SetCpuLimit(task.Resources.CPU)
   122  
   123  		if len(task.Resources.Networks) > 0 {
   124  			network := task.Resources.Networks[0]
   125  			env.SetTaskIp(network.IP)
   126  			env.SetPorts(network.MapDynamicPorts())
   127  		}
   128  	}
   129  
   130  	if task.Env != nil {
   131  		env.SetEnvvars(task.Env)
   132  	}
   133  
   134  	return env
   135  }