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