github.com/ryanslade/nomad@v0.2.4-0.20160128061903-fc95782f2089/client/driver/driver.go (about)

     1  package driver
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"path/filepath"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/hashicorp/nomad/client/allocdir"
    11  	"github.com/hashicorp/nomad/client/config"
    12  	"github.com/hashicorp/nomad/client/driver/env"
    13  	"github.com/hashicorp/nomad/client/fingerprint"
    14  	"github.com/hashicorp/nomad/nomad/structs"
    15  
    16  	cstructs "github.com/hashicorp/nomad/client/driver/structs"
    17  )
    18  
    19  // BuiltinDrivers contains the built in registered drivers
    20  // which are available for allocation handling
    21  var BuiltinDrivers = map[string]Factory{
    22  	"docker":   NewDockerDriver,
    23  	"exec":     NewExecDriver,
    24  	"raw_exec": NewRawExecDriver,
    25  	"java":     NewJavaDriver,
    26  	"qemu":     NewQemuDriver,
    27  	"rkt":      NewRktDriver,
    28  }
    29  
    30  // NewDriver is used to instantiate and return a new driver
    31  // given the name and a logger
    32  func NewDriver(name string, ctx *DriverContext) (Driver, error) {
    33  	// Lookup the factory function
    34  	factory, ok := BuiltinDrivers[name]
    35  	if !ok {
    36  		return nil, fmt.Errorf("unknown driver '%s'", name)
    37  	}
    38  
    39  	// Instantiate the driver
    40  	f := factory(ctx)
    41  	return f, nil
    42  }
    43  
    44  // Factory is used to instantiate a new Driver
    45  type Factory func(*DriverContext) Driver
    46  
    47  // Driver is used for execution of tasks. This allows Nomad
    48  // to support many pluggable implementations of task drivers.
    49  // Examples could include LXC, Docker, Qemu, etc.
    50  type Driver interface {
    51  	// Drivers must support the fingerprint interface for detection
    52  	fingerprint.Fingerprint
    53  
    54  	// Start is used to being task execution
    55  	Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error)
    56  
    57  	// Open is used to re-open a handle to a task
    58  	Open(ctx *ExecContext, handleID string) (DriverHandle, error)
    59  }
    60  
    61  // DriverContext is a means to inject dependencies such as loggers, configs, and
    62  // node attributes into a Driver without having to change the Driver interface
    63  // each time we do it. Used in conjection with Factory, above.
    64  type DriverContext struct {
    65  	taskName string
    66  	config   *config.Config
    67  	logger   *log.Logger
    68  	node     *structs.Node
    69  	taskEnv  *env.TaskEnvironment
    70  }
    71  
    72  // NewDriverContext initializes a new DriverContext with the specified fields.
    73  // This enables other packages to create DriverContexts but keeps the fields
    74  // private to the driver. If we want to change this later we can gorename all of
    75  // the fields in DriverContext.
    76  func NewDriverContext(taskName string, config *config.Config, node *structs.Node,
    77  	logger *log.Logger, taskEnv *env.TaskEnvironment) *DriverContext {
    78  	return &DriverContext{
    79  		taskName: taskName,
    80  		config:   config,
    81  		node:     node,
    82  		logger:   logger,
    83  		taskEnv:  taskEnv,
    84  	}
    85  }
    86  
    87  // KillTimeout returns the timeout that should be used for the task between
    88  // signaling and killing the task.
    89  func (d *DriverContext) KillTimeout(task *structs.Task) time.Duration {
    90  	max := d.config.MaxKillTimeout.Nanoseconds()
    91  	desired := task.KillTimeout.Nanoseconds()
    92  	if desired < max {
    93  		return task.KillTimeout
    94  	}
    95  
    96  	return d.config.MaxKillTimeout
    97  }
    98  
    99  // DriverHandle is an opaque handle into a driver used for task
   100  // manipulation
   101  type DriverHandle interface {
   102  	// Returns an opaque handle that can be used to re-open the handle
   103  	ID() string
   104  
   105  	// WaitCh is used to return a channel used wait for task completion
   106  	WaitCh() chan *cstructs.WaitResult
   107  
   108  	// Update is used to update the task if possible
   109  	Update(task *structs.Task) error
   110  
   111  	// Kill is used to stop the task
   112  	Kill() error
   113  }
   114  
   115  // ExecContext is shared between drivers within an allocation
   116  type ExecContext struct {
   117  	sync.Mutex
   118  
   119  	// AllocDir contains information about the alloc directory structure.
   120  	AllocDir *allocdir.AllocDir
   121  
   122  	// Alloc ID
   123  	AllocID string
   124  }
   125  
   126  // NewExecContext is used to create a new execution context
   127  func NewExecContext(alloc *allocdir.AllocDir, allocID string) *ExecContext {
   128  	return &ExecContext{AllocDir: alloc, AllocID: allocID}
   129  }
   130  
   131  // GetTaskEnv converts the alloc dir, the node and task configuration into a
   132  // TaskEnvironment.
   133  func GetTaskEnv(alloc *allocdir.AllocDir, node *structs.Node, task *structs.Task) (*env.TaskEnvironment, error) {
   134  	env := env.NewTaskEnvironment(node).
   135  		SetMeta(task.Meta).
   136  		SetEnvvars(task.Env)
   137  
   138  	if alloc != nil {
   139  		env.SetAllocDir(alloc.SharedDir)
   140  		taskdir, ok := alloc.TaskDirs[task.Name]
   141  		if !ok {
   142  			return nil, fmt.Errorf("failed to get task directory for task %q", task.Name)
   143  		}
   144  
   145  		env.SetTaskLocalDir(filepath.Join(taskdir, allocdir.TaskLocal))
   146  	}
   147  
   148  	if task.Resources != nil {
   149  		env.SetMemLimit(task.Resources.MemoryMB)
   150  		env.SetCpuLimit(task.Resources.CPU)
   151  
   152  		if len(task.Resources.Networks) > 0 {
   153  			network := task.Resources.Networks[0]
   154  			env.SetTaskIp(network.IP)
   155  			env.SetPorts(network.MapLabelToValues(nil))
   156  		}
   157  	}
   158  
   159  	return env.Build(), nil
   160  }
   161  
   162  func mapMergeStrInt(maps ...map[string]int) map[string]int {
   163  	out := map[string]int{}
   164  	for _, in := range maps {
   165  		for key, val := range in {
   166  			out[key] = val
   167  		}
   168  	}
   169  	return out
   170  }
   171  
   172  func mapMergeStrStr(maps ...map[string]string) map[string]string {
   173  	out := map[string]string{}
   174  	for _, in := range maps {
   175  		for key, val := range in {
   176  			out[key] = val
   177  		}
   178  	}
   179  	return out
   180  }