open-nomad/client/driver/driver.go

232 lines
6.5 KiB
Go
Raw Normal View History

2015-08-20 23:50:28 +00:00
package driver
import (
"errors"
2015-08-20 23:50:28 +00:00
"fmt"
"log"
2016-10-07 19:37:52 +00:00
"os"
2016-12-20 20:24:24 +00:00
"strings"
2015-08-20 23:50:28 +00:00
"github.com/hashicorp/nomad/client/allocdir"
"github.com/hashicorp/nomad/client/config"
2016-01-11 17:58:26 +00:00
"github.com/hashicorp/nomad/client/driver/env"
2015-08-20 23:50:28 +00:00
"github.com/hashicorp/nomad/client/fingerprint"
2015-08-23 23:49:48 +00:00
"github.com/hashicorp/nomad/nomad/structs"
dstructs "github.com/hashicorp/nomad/client/driver/structs"
cstructs "github.com/hashicorp/nomad/client/structs"
2015-08-20 23:50:28 +00:00
)
var (
// BuiltinDrivers contains the built in registered drivers
// which are available for allocation handling
BuiltinDrivers = map[string]Factory{
"docker": NewDockerDriver,
"exec": NewExecDriver,
"raw_exec": NewRawExecDriver,
"java": NewJavaDriver,
"qemu": NewQemuDriver,
"rkt": NewRktDriver,
}
// DriverStatsNotImplemented is the error to be returned if a driver doesn't
// implement stats.
DriverStatsNotImplemented = errors.New("stats not implemented for driver")
)
2015-08-20 23:50:28 +00:00
// NewDriver is used to instantiate and return a new driver
// given the name and a logger
func NewDriver(name string, ctx *DriverContext) (Driver, error) {
2015-08-20 23:50:28 +00:00
// Lookup the factory function
factory, ok := BuiltinDrivers[name]
if !ok {
return nil, fmt.Errorf("unknown driver '%s'", name)
}
// Instantiate the driver
f := factory(ctx)
2015-08-20 23:50:28 +00:00
return f, nil
}
// Factory is used to instantiate a new Driver
type Factory func(*DriverContext) Driver
2015-08-20 23:50:28 +00:00
// Driver is used for execution of tasks. This allows Nomad
// to support many pluggable implementations of task drivers.
// Examples could include LXC, Docker, Qemu, etc.
type Driver interface {
// Drivers must support the fingerprint interface for detection
fingerprint.Fingerprint
2015-08-23 23:49:48 +00:00
// Prestart prepares the task environment and performs expensive
// intialization steps like downloading images.
Prestart(*ExecContext, *structs.Task) error
2015-08-23 23:49:48 +00:00
// Start is used to being task execution
Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error)
// Open is used to re-open a handle to a task
Open(ctx *ExecContext, handleID string) (DriverHandle, error)
// Drivers must validate their configuration
Validate(map[string]interface{}) error
2016-10-19 22:06:23 +00:00
// Abilities returns the abilities of the driver
Abilities() DriverAbilities
// FSIsolation returns the method of filesystem isolation used
FSIsolation() cstructs.FSIsolation
2016-10-19 22:06:23 +00:00
}
// DriverAbilities marks the abilities the driver has.
type DriverAbilities struct {
// SendSignals marks the driver as being able to send signals
SendSignals bool
2015-08-23 23:49:48 +00:00
}
// LogEventFn is a callback which allows Drivers to emit task events.
type LogEventFn func(message string, args ...interface{})
// DriverContext is a means to inject dependencies such as loggers, configs, and
// node attributes into a Driver without having to change the Driver interface
// each time we do it. Used in conjection with Factory, above.
type DriverContext struct {
taskName string
config *config.Config
logger *log.Logger
node *structs.Node
2016-01-11 17:58:26 +00:00
taskEnv *env.TaskEnvironment
emitEvent LogEventFn
}
// NewEmptyDriverContext returns a DriverContext with all fields set to their
// zero value.
func NewEmptyDriverContext() *DriverContext {
return &DriverContext{}
}
// NewDriverContext initializes a new DriverContext with the specified fields.
// This enables other packages to create DriverContexts but keeps the fields
// private to the driver. If we want to change this later we can gorename all of
// the fields in DriverContext.
2016-01-11 17:58:26 +00:00
func NewDriverContext(taskName string, config *config.Config, node *structs.Node,
logger *log.Logger, taskEnv *env.TaskEnvironment, eventEmitter LogEventFn) *DriverContext {
return &DriverContext{
taskName: taskName,
config: config,
node: node,
logger: logger,
taskEnv: taskEnv,
emitEvent: eventEmitter,
}
}
2015-08-23 23:49:48 +00:00
// DriverHandle is an opaque handle into a driver used for task
// manipulation
type DriverHandle interface {
// Returns an opaque handle that can be used to re-open the handle
ID() string
// WaitCh is used to return a channel used wait for task completion
WaitCh() chan *dstructs.WaitResult
2015-08-23 23:49:48 +00:00
// Update is used to update the task if possible and update task related
// configurations.
2015-08-29 22:46:10 +00:00
Update(task *structs.Task) error
2015-08-23 23:49:48 +00:00
// Kill is used to stop the task
Kill() error
2016-04-28 23:06:01 +00:00
// Stats returns aggregated stats of the driver
2016-04-28 23:06:01 +00:00
Stats() (*cstructs.TaskResourceUsage, error)
2016-10-07 19:37:52 +00:00
// Signal is used to send a signal to the task
Signal(s os.Signal) error
2015-08-20 23:50:28 +00:00
}
2015-08-23 22:36:06 +00:00
// ExecContext is a task's execution context
2015-08-23 22:36:06 +00:00
type ExecContext struct {
// TaskDir contains information about the task directory structure.
TaskDir *allocdir.TaskDir
// Alloc ID
AllocID string
2015-08-23 22:36:06 +00:00
}
// NewExecContext is used to create a new execution context
func NewExecContext(td *allocdir.TaskDir, allocID string) *ExecContext {
return &ExecContext{TaskDir: td, AllocID: allocID}
2015-08-23 22:36:06 +00:00
}
// GetTaskEnv converts the alloc dir, the node, task and alloc into a
// TaskEnvironment.
func GetTaskEnv(taskDir *allocdir.TaskDir, node *structs.Node,
2016-12-20 20:24:24 +00:00
task *structs.Task, alloc *structs.Allocation, conf *config.Config,
vaultToken string) (*env.TaskEnvironment, error) {
2016-01-11 17:58:26 +00:00
env := env.NewTaskEnvironment(node).
SetTaskMeta(alloc.Job.CombinedTaskMeta(alloc.TaskGroup, task.Name)).
2016-10-11 17:57:12 +00:00
SetJobName(alloc.Job.Name).
SetEnvvars(task.Env).
SetTaskName(task.Name)
2016-01-11 17:58:26 +00:00
// Vary paths by filesystem isolation used
drv, err := NewDriver(task.Driver, NewEmptyDriverContext())
if err != nil {
return nil, err
}
switch drv.FSIsolation() {
case cstructs.FSIsolationNone:
// Use host paths
env.SetAllocDir(taskDir.SharedAllocDir)
env.SetTaskLocalDir(taskDir.LocalDir)
env.SetSecretsDir(taskDir.SecretsDir)
default:
// filesystem isolation; use container paths
env.SetAllocDir(allocdir.SharedAllocContainerPath)
env.SetTaskLocalDir(allocdir.TaskLocalContainerPath)
env.SetSecretsDir(allocdir.TaskSecretsContainerPath)
}
2015-09-23 06:11:55 +00:00
if task.Resources != nil {
env.SetMemLimit(task.Resources.MemoryMB).
SetCpuLimit(task.Resources.CPU).
SetNetworks(task.Resources.Networks)
}
if alloc != nil {
env.SetAlloc(alloc)
2015-09-23 06:11:55 +00:00
}
2016-09-20 20:22:29 +00:00
if task.Vault != nil {
env.SetVaultToken(vaultToken, task.Vault.Env)
}
2016-09-14 20:30:01 +00:00
2016-12-20 20:24:24 +00:00
// Set the host environment variables.
filter := strings.Split(conf.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",")
env.AppendHostEnvvars(filter)
2016-01-11 17:58:26 +00:00
return env.Build(), nil
}
func mapMergeStrInt(maps ...map[string]int) map[string]int {
out := map[string]int{}
for _, in := range maps {
for key, val := range in {
out[key] = val
}
}
return out
}
func mapMergeStrStr(maps ...map[string]string) map[string]string {
out := map[string]string{}
for _, in := range maps {
for key, val := range in {
out[key] = val
}
}
return out
}