github.com/huiliang/nomad@v0.2.1-0.20151124023127-7a8b664699ff/client/driver/driver.go (about)

     1  package driver
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"path/filepath"
     7  	"sync"
     8  
     9  	"github.com/hashicorp/nomad/client/allocdir"
    10  	"github.com/hashicorp/nomad/client/config"
    11  	"github.com/hashicorp/nomad/client/driver/environment"
    12  	"github.com/hashicorp/nomad/client/fingerprint"
    13  	"github.com/hashicorp/nomad/nomad/structs"
    14  
    15  	cstructs "github.com/hashicorp/nomad/client/driver/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  
    60  // DriverContext is a means to inject dependencies such as loggers, configs, and
    61  // node attributes into a Driver without having to change the Driver interface
    62  // each time we do it. Used in conjection with Factory, above.
    63  type DriverContext struct {
    64  	taskName string
    65  	config   *config.Config
    66  	logger   *log.Logger
    67  	node     *structs.Node
    68  }
    69  
    70  // NewDriverContext initializes a new DriverContext with the specified fields.
    71  // This enables other packages to create DriverContexts but keeps the fields
    72  // private to the driver. If we want to change this later we can gorename all of
    73  // the fields in DriverContext.
    74  func NewDriverContext(taskName string, config *config.Config, node *structs.Node, logger *log.Logger) *DriverContext {
    75  	return &DriverContext{
    76  		taskName: taskName,
    77  		config:   config,
    78  		node:     node,
    79  		logger:   logger,
    80  	}
    81  }
    82  
    83  // DriverHandle is an opaque handle into a driver used for task
    84  // manipulation
    85  type DriverHandle interface {
    86  	// Returns an opaque handle that can be used to re-open the handle
    87  	ID() string
    88  
    89  	// WaitCh is used to return a channel used wait for task completion
    90  	WaitCh() chan *cstructs.WaitResult
    91  
    92  	// Update is used to update the task if possible
    93  	Update(task *structs.Task) error
    94  
    95  	// Kill is used to stop the task
    96  	Kill() error
    97  }
    98  
    99  // ExecContext is shared between drivers within an allocation
   100  type ExecContext struct {
   101  	sync.Mutex
   102  
   103  	// AllocDir contains information about the alloc directory structure.
   104  	AllocDir *allocdir.AllocDir
   105  
   106  	// Alloc ID
   107  	AllocID string
   108  }
   109  
   110  // NewExecContext is used to create a new execution context
   111  func NewExecContext(alloc *allocdir.AllocDir, allocID string) *ExecContext {
   112  	return &ExecContext{AllocDir: alloc, AllocID: allocID}
   113  }
   114  
   115  // TaskEnvironmentVariables converts exec context and task configuration into a
   116  // TaskEnvironment.
   117  func TaskEnvironmentVariables(ctx *ExecContext, task *structs.Task) environment.TaskEnvironment {
   118  	env := environment.NewTaskEnivornment()
   119  	env.SetMeta(task.Meta)
   120  
   121  	if ctx.AllocDir != nil {
   122  		env.SetAllocDir(ctx.AllocDir.SharedDir)
   123  		taskdir, ok := ctx.AllocDir.TaskDirs[task.Name]
   124  		if !ok {
   125  			// TODO: Update this to return an error
   126  		}
   127  
   128  		env.SetTaskLocalDir(filepath.Join(taskdir, allocdir.TaskLocal))
   129  	}
   130  
   131  	if task.Resources != nil {
   132  		env.SetMemLimit(task.Resources.MemoryMB)
   133  		env.SetCpuLimit(task.Resources.CPU)
   134  
   135  		if len(task.Resources.Networks) > 0 {
   136  			network := task.Resources.Networks[0]
   137  			env.SetTaskIp(network.IP)
   138  			env.SetPorts(network.MapLabelToValues(nil))
   139  		}
   140  	}
   141  
   142  	if task.Env != nil {
   143  		env.SetEnvvars(task.Env)
   144  	}
   145  
   146  	return env
   147  }
   148  
   149  func mapMergeStrInt(maps ...map[string]int) map[string]int {
   150  	out := map[string]int{}
   151  	for _, in := range maps {
   152  		for key, val := range in {
   153  			out[key] = val
   154  		}
   155  	}
   156  	return out
   157  }
   158  
   159  func mapMergeStrStr(maps ...map[string]string) map[string]string {
   160  	out := map[string]string{}
   161  	for _, in := range maps {
   162  		for key, val := range in {
   163  			out[key] = val
   164  		}
   165  	}
   166  	return out
   167  }