github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/client/driver/driver.go (about)

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