github.com/mattyr/nomad@v0.3.3-0.20160919021406-3485a065154a/client/driver/driver.go (about)

     1  package driver
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"path/filepath"
     7  
     8  	"github.com/hashicorp/nomad/client/allocdir"
     9  	"github.com/hashicorp/nomad/client/config"
    10  	"github.com/hashicorp/nomad/client/driver/env"
    11  	"github.com/hashicorp/nomad/client/fingerprint"
    12  	"github.com/hashicorp/nomad/nomad/structs"
    13  
    14  	dstructs "github.com/hashicorp/nomad/client/driver/structs"
    15  	cstructs "github.com/hashicorp/nomad/client/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  	// Drivers must validate their configuration
    60  	Validate(map[string]interface{}) error
    61  }
    62  
    63  // DriverContext is a means to inject dependencies such as loggers, configs, and
    64  // node attributes into a Driver without having to change the Driver interface
    65  // each time we do it. Used in conjection with Factory, above.
    66  type DriverContext struct {
    67  	taskName string
    68  	config   *config.Config
    69  	logger   *log.Logger
    70  	node     *structs.Node
    71  	taskEnv  *env.TaskEnvironment
    72  }
    73  
    74  // NewEmptyDriverContext returns a DriverContext with all fields set to their
    75  // zero value.
    76  func NewEmptyDriverContext() *DriverContext {
    77  	return &DriverContext{
    78  		taskName: "",
    79  		config:   nil,
    80  		node:     nil,
    81  		logger:   nil,
    82  		taskEnv:  nil,
    83  	}
    84  }
    85  
    86  // NewDriverContext initializes a new DriverContext with the specified fields.
    87  // This enables other packages to create DriverContexts but keeps the fields
    88  // private to the driver. If we want to change this later we can gorename all of
    89  // the fields in DriverContext.
    90  func NewDriverContext(taskName string, config *config.Config, node *structs.Node,
    91  	logger *log.Logger, taskEnv *env.TaskEnvironment) *DriverContext {
    92  	return &DriverContext{
    93  		taskName: taskName,
    94  		config:   config,
    95  		node:     node,
    96  		logger:   logger,
    97  		taskEnv:  taskEnv,
    98  	}
    99  }
   100  
   101  // DriverHandle is an opaque handle into a driver used for task
   102  // manipulation
   103  type DriverHandle interface {
   104  	// Returns an opaque handle that can be used to re-open the handle
   105  	ID() string
   106  
   107  	// WaitCh is used to return a channel used wait for task completion
   108  	WaitCh() chan *dstructs.WaitResult
   109  
   110  	// Update is used to update the task if possible and update task related
   111  	// configurations.
   112  	Update(task *structs.Task) error
   113  
   114  	// Kill is used to stop the task
   115  	Kill() error
   116  
   117  	// Stats returns aggregated stats of the driver
   118  	Stats() (*cstructs.TaskResourceUsage, error)
   119  }
   120  
   121  // ExecContext is shared between drivers within an allocation
   122  type ExecContext struct {
   123  	// AllocDir contains information about the alloc directory structure.
   124  	AllocDir *allocdir.AllocDir
   125  
   126  	// Alloc ID
   127  	AllocID string
   128  }
   129  
   130  // NewExecContext is used to create a new execution context
   131  func NewExecContext(alloc *allocdir.AllocDir, allocID string) *ExecContext {
   132  	return &ExecContext{AllocDir: alloc, AllocID: allocID}
   133  }
   134  
   135  // GetTaskEnv converts the alloc dir, the node, task and alloc into a
   136  // TaskEnvironment.
   137  func GetTaskEnv(allocDir *allocdir.AllocDir, node *structs.Node,
   138  	task *structs.Task, alloc *structs.Allocation) (*env.TaskEnvironment, error) {
   139  
   140  	tg := alloc.Job.LookupTaskGroup(alloc.TaskGroup)
   141  	env := env.NewTaskEnvironment(node, task.ExcludeNomadEnv).
   142  		SetTaskMeta(task.Meta).
   143  		SetTaskGroupMeta(tg.Meta).
   144  		SetJobMeta(alloc.Job.Meta).
   145  		SetEnvvars(task.Env).
   146  		SetTaskName(task.Name)
   147  
   148  	if allocDir != nil {
   149  		env.SetAllocDir(allocDir.SharedDir)
   150  		taskdir, ok := allocDir.TaskDirs[task.Name]
   151  		if !ok {
   152  			return nil, fmt.Errorf("failed to get task directory for task %q", task.Name)
   153  		}
   154  
   155  		env.SetTaskLocalDir(filepath.Join(taskdir, allocdir.TaskLocal))
   156  		env.SetSecretDir(filepath.Join(taskdir, allocdir.TaskSecrets))
   157  	}
   158  
   159  	if task.Resources != nil {
   160  		env.SetMemLimit(task.Resources.MemoryMB).
   161  			SetCpuLimit(task.Resources.CPU).
   162  			SetNetworks(task.Resources.Networks)
   163  	}
   164  
   165  	if alloc != nil {
   166  		env.SetAlloc(alloc)
   167  	}
   168  
   169  	return env.Build(), nil
   170  }
   171  
   172  func mapMergeStrInt(maps ...map[string]int) map[string]int {
   173  	out := map[string]int{}
   174  	for _, in := range maps {
   175  		for key, val := range in {
   176  			out[key] = val
   177  		}
   178  	}
   179  	return out
   180  }
   181  
   182  func mapMergeStrStr(maps ...map[string]string) map[string]string {
   183  	out := map[string]string{}
   184  	for _, in := range maps {
   185  		for key, val := range in {
   186  			out[key] = val
   187  		}
   188  	}
   189  	return out
   190  }