Merge pull request #23 from hashicorp/f-driver-config

Added config to drivers; needed for docker driver to get the socket endpoint
This commit is contained in:
Chris Bednarski
2015-09-10 11:29:42 -07:00
12 changed files with 79 additions and 50 deletions

View File

@@ -342,8 +342,9 @@ func (c *Client) fingerprint() error {
// setupDrivers is used to find the available drivers
func (c *Client) setupDrivers() error {
var avail []string
driverCtx := driver.NewDriverContext(c.config, c.config.Node, c.logger)
for name := range driver.BuiltinDrivers {
d, err := driver.NewDriver(name, c.logger)
d, err := driver.NewDriver(name, driverCtx)
if err != nil {
return err
}

View File

@@ -8,6 +8,8 @@ import (
"regexp"
"strings"
docker "github.com/fsouza/go-dockerclient"
"github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/nomad/structs"
)
@@ -18,7 +20,7 @@ var (
)
type DockerDriver struct {
logger *log.Logger
DriverContext
}
type dockerPID struct {
@@ -34,11 +36,8 @@ type dockerHandle struct {
doneCh chan struct{}
}
func NewDockerDriver(logger *log.Logger) Driver {
d := &DockerDriver{
logger: logger,
}
return d
func NewDockerDriver(ctx *DriverContext) Driver {
return &DockerDriver{*ctx}
}
func (d *DockerDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
@@ -111,6 +110,10 @@ func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle
// nomad process is restarted. Also, you will need to parse the containerID
// out of the run command output since run combines pull, create and start
// into a single command.
client, err := docker.NewClient(d.config.ReadDefault("docker.endpoint", "unix:///var/run/docker.sock"))
client.ListImages(docker.ListImagesOptions{All: false})
startBytes, err := exec.Command("docker", "start", containerID).CombinedOutput()
if err != nil {
d.logger.Printf("[ERROR] driver.docker %s", strings.TrimSpace(string(startBytes)))

View File

@@ -26,7 +26,7 @@ func TestDockerDriver_Handle(t *testing.T) {
}
func TestDockerDriver_Fingerprint(t *testing.T) {
d := NewDockerDriver(testLogger())
d := NewDockerDriver(testDriverContext())
node := &structs.Node{
Attributes: make(map[string]string),
}
@@ -49,7 +49,7 @@ func TestDockerDriver_StartOpen_Wait(t *testing.T) {
t.SkipNow()
}
ctx := NewExecContext()
d := NewDockerDriver(testLogger())
d := NewDockerDriver(testDriverContext())
task := &structs.Task{
Config: map[string]string{
@@ -80,7 +80,7 @@ func TestDockerDriver_Start_Wait(t *testing.T) {
t.SkipNow()
}
ctx := NewExecContext()
d := NewDockerDriver(testLogger())
d := NewDockerDriver(testDriverContext())
task := &structs.Task{
Config: map[string]string{
@@ -117,7 +117,7 @@ func TestDockerDriver_Start_Kill_Wait(t *testing.T) {
t.SkipNow()
}
ctx := NewExecContext()
d := NewDockerDriver(testLogger())
d := NewDockerDriver(testDriverContext())
task := &structs.Task{
Config: map[string]string{

View File

@@ -5,6 +5,7 @@ import (
"log"
"sync"
"github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/client/fingerprint"
"github.com/hashicorp/nomad/nomad/structs"
)
@@ -12,14 +13,15 @@ import (
// BuiltinDrivers contains the built in registered drivers
// which are available for allocation handling
var BuiltinDrivers = map[string]Factory{
"exec": NewExecDriver,
"java": NewJavaDriver,
"qemu": NewQemuDriver,
"docker": NewDockerDriver,
"exec": NewExecDriver,
"java": NewJavaDriver,
"qemu": NewQemuDriver,
}
// NewDriver is used to instantiate and return a new driver
// given the name and a logger
func NewDriver(name string, logger *log.Logger) (Driver, error) {
func NewDriver(name string, ctx *DriverContext) (Driver, error) {
// Lookup the factory function
factory, ok := BuiltinDrivers[name]
if !ok {
@@ -27,12 +29,12 @@ func NewDriver(name string, logger *log.Logger) (Driver, error) {
}
// Instantiate the driver
f := factory(logger)
f := factory(ctx)
return f, nil
}
// Factory is used to instantiate a new Driver
type Factory func(*log.Logger) Driver
type Factory func(*DriverContext) Driver
// Driver is used for execution of tasks. This allows Nomad
// to support many pluggable implementations of task drivers.
@@ -48,6 +50,27 @@ type Driver interface {
Open(ctx *ExecContext, handleID string) (DriverHandle, error)
}
// 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 {
config *config.Config
logger *log.Logger
node *structs.Node
}
// 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.
func NewDriverContext(config *config.Config, node *structs.Node, logger *log.Logger) *DriverContext {
return &DriverContext{
config: config,
node: node,
logger: logger,
}
}
// DriverHandle is an opaque handle into a driver used for task
// manipulation
type DriverHandle interface {

View File

@@ -3,8 +3,20 @@ package driver
import (
"log"
"os"
"github.com/hashicorp/nomad/client/config"
)
func testLogger() *log.Logger {
return log.New(os.Stderr, "", log.LstdFlags)
}
func testConfig() *config.Config {
return &config.Config{}
}
func testDriverContext() *DriverContext {
cfg := testConfig()
ctx := NewDriverContext(cfg, cfg.Node, testLogger())
return ctx
}

View File

@@ -2,7 +2,6 @@ package driver
import (
"fmt"
"log"
"os"
"os/exec"
"strconv"
@@ -19,7 +18,7 @@ import (
// fork/execs tasks. It should probably not be used for most things,
// but is useful for testing purposes or for very simple tasks.
type ExecDriver struct {
logger *log.Logger
DriverContext
}
// execHandle is returned from Start/Open as a handle to the PID
@@ -30,11 +29,8 @@ type execHandle struct {
}
// NewExecDriver is used to create a new exec driver
func NewExecDriver(logger *log.Logger) Driver {
d := &ExecDriver{
logger: logger,
}
return d
func NewExecDriver(ctx *DriverContext) Driver {
return &ExecDriver{*ctx}
}
func (d *ExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {

View File

@@ -9,7 +9,7 @@ import (
)
func TestExecDriver_Fingerprint(t *testing.T) {
d := NewExecDriver(testLogger())
d := NewExecDriver(testDriverContext())
node := &structs.Node{
Attributes: make(map[string]string),
}
@@ -27,7 +27,7 @@ func TestExecDriver_Fingerprint(t *testing.T) {
func TestExecDriver_StartOpen_Wait(t *testing.T) {
ctx := NewExecContext()
d := NewExecDriver(testLogger())
d := NewExecDriver(testDriverContext())
task := &structs.Task{
Config: map[string]string{
@@ -55,7 +55,7 @@ func TestExecDriver_StartOpen_Wait(t *testing.T) {
func TestExecDriver_Start_Wait(t *testing.T) {
ctx := NewExecContext()
d := NewExecDriver(testLogger())
d := NewExecDriver(testDriverContext())
task := &structs.Task{
Config: map[string]string{
@@ -90,7 +90,7 @@ func TestExecDriver_Start_Wait(t *testing.T) {
func TestExecDriver_Start_Kill_Wait(t *testing.T) {
ctx := NewExecContext()
d := NewExecDriver(testLogger())
d := NewExecDriver(testDriverContext())
task := &structs.Task{
Config: map[string]string{

View File

@@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
@@ -23,7 +22,7 @@ import (
// JavaDriver is a simple driver to execute applications packaged in Jars.
// It literally just fork/execs tasks with the java command.
type JavaDriver struct {
logger *log.Logger
DriverContext
}
// javaHandle is returned from Start/Open as a handle to the PID
@@ -34,11 +33,8 @@ type javaHandle struct {
}
// NewJavaDriver is used to create a new exec driver
func NewJavaDriver(logger *log.Logger) Driver {
d := &JavaDriver{
logger: logger,
}
return d
func NewJavaDriver(ctx *DriverContext) Driver {
return &JavaDriver{*ctx}
}
func (d *JavaDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {

View File

@@ -10,7 +10,7 @@ import (
)
func TestJavaDriver_Fingerprint(t *testing.T) {
d := NewJavaDriver(testLogger())
d := NewJavaDriver(testDriverContext())
node := &structs.Node{
Attributes: make(map[string]string),
}
@@ -34,7 +34,7 @@ func TestJavaDriver_Fingerprint(t *testing.T) {
func TestJavaDriver_StartOpen_Wait(t *testing.T) {
ctx := NewExecContext()
ctx.AllocDir = os.TempDir()
d := NewJavaDriver(testLogger())
d := NewJavaDriver(testDriverContext())
task := &structs.Task{
Config: map[string]string{
@@ -71,7 +71,7 @@ func TestJavaDriver_StartOpen_Wait(t *testing.T) {
func TestJavaDriver_Start_Wait(t *testing.T) {
ctx := NewExecContext()
ctx.AllocDir = os.TempDir()
d := NewJavaDriver(testLogger())
d := NewJavaDriver(testDriverContext())
task := &structs.Task{
Config: map[string]string{
@@ -109,7 +109,7 @@ func TestJavaDriver_Start_Wait(t *testing.T) {
func TestJavaDriver_Start_Kill_Wait(t *testing.T) {
ctx := NewExecContext()
ctx.AllocDir = os.TempDir()
d := NewJavaDriver(testLogger())
d := NewJavaDriver(testDriverContext())
task := &structs.Task{
Config: map[string]string{

View File

@@ -21,14 +21,14 @@ import (
)
var (
reQemuVersion = regexp.MustCompile("QEMU emulator version ([\\d\\.]+),.+")
reQemuVersion = regexp.MustCompile("QEMU emulator version ([\\d\\.]+).+")
)
// QemuDriver is a driver for running images via Qemu
// We attempt to chose sane defaults for now, with more configuration available
// planned in the future
type QemuDriver struct {
logger *log.Logger
DriverContext
}
// qemuHandle is returned from Start/Open as a handle to the PID
@@ -47,11 +47,8 @@ type qemuPID struct {
}
// NewQemuDriver is used to create a new exec driver
func NewQemuDriver(logger *log.Logger) Driver {
d := &QemuDriver{
logger: logger,
}
return d
func NewQemuDriver(ctx *DriverContext) Driver {
return &QemuDriver{*ctx}
}
func (d *QemuDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {

View File

@@ -25,7 +25,7 @@ func TestQemuDriver_Handle(t *testing.T) {
}
func TestQemuDriver_Fingerprint(t *testing.T) {
d := NewQemuDriver(testLogger())
d := NewQemuDriver(testDriverContext())
node := &structs.Node{
Attributes: make(map[string]string),
}
@@ -47,7 +47,7 @@ func TestQemuDriver_Fingerprint(t *testing.T) {
func TestQemuDriver_Start(t *testing.T) {
ctx := NewExecContext()
ctx.AllocDir = os.TempDir()
d := NewQemuDriver(testLogger())
d := NewQemuDriver(testDriverContext())
// TODO: use test server to load from a fixture
task := &structs.Task{
@@ -92,7 +92,7 @@ func TestQemuDriver_Start(t *testing.T) {
func TestQemuDriver_RequiresMemory(t *testing.T) {
ctx := NewExecContext()
ctx.AllocDir = os.TempDir()
d := NewQemuDriver(testLogger())
d := NewQemuDriver(testDriverContext())
// TODO: use test server to load from a fixture
task := &structs.Task{

View File

@@ -129,7 +129,8 @@ func (r *TaskRunner) setStatus(status, desc string) {
// createDriver makes a driver for the task
func (r *TaskRunner) createDriver() (driver.Driver, error) {
driver, err := driver.NewDriver(r.task.Driver, r.logger)
driverCtx := driver.NewDriverContext(r.config, r.config.Node, r.logger)
driver, err := driver.NewDriver(r.task.Driver, driverCtx)
if err != nil {
err = fmt.Errorf("failed to create driver '%s' for alloc %s: %v",
r.task.Driver, r.allocID, err)