Support boot2docker or VM for dev/test

This commit is contained in:
Chris Bednarski 2015-10-06 17:53:05 -07:00
parent 67e3c4a4f5
commit d046858057
2 changed files with 55 additions and 15 deletions

View File

@ -4,10 +4,12 @@ import (
"encoding/json"
"fmt"
"log"
"runtime"
"strconv"
"strings"
docker "github.com/fsouza/go-dockerclient"
opts "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/opts"
"github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/nomad/structs"
@ -33,16 +35,47 @@ type dockerHandle struct {
doneCh chan struct{}
}
// getDefaultDockerHost is copied from fsouza. If it were exported we woudn't
// need this here.
func getDefaultDockerHost() (string, error) {
var defaultHost string
if runtime.GOOS == "windows" {
// If we do not have a host, default to TCP socket on Windows
defaultHost = fmt.Sprintf("tcp://%s:%d", opts.DefaultHTTPHost, opts.DefaultHTTPPort)
} else {
// If we do not have a host, default to unix socket
defaultHost = fmt.Sprintf("unix://%s", opts.DefaultUnixSocket)
}
return opts.ValidateHost(defaultHost)
}
func NewDockerDriver(ctx *DriverContext) Driver {
return &DockerDriver{*ctx}
}
// dockerClient creates *docker.Client using ClientConfig so we can get the
// correct socket for the daemon
// dockerClient creates *docker.Client. In test / dev mode we can use ENV vars
// to connect to the docker daemon. In production mode we will read
// docker.endpoint from the config file.
func (d *DockerDriver) dockerClient() (*docker.Client, error) {
dockerEndpoint := d.config.Read("docker.endpoint")
client, err := docker.NewClient(dockerEndpoint)
return client, err
// In dev mode, read DOCKER_* environment variables DOCKER_HOST,
// DOCKER_TLS_VERIFY, and DOCKER_CERT_PATH. This allows you to run tests and
// demo against boot2docker or a VM on OSX and Windows. This falls back on
// the default unix socket on linux if tests are run on linux.
//
// Also note that we need to turn on DevMode in the test configs.
if d.config.DevMode {
return docker.NewClientFromEnv()
}
// In prod mode we'll read the docker.endpoint configuration and fall back
// on the host-specific default. We do not read from the environment.
defaultEndpoint, err := getDefaultDockerHost()
if err != nil {
return nil, fmt.Errorf("Unable to determine default docker endpoint: %s", err)
}
dockerEndpoint := d.config.ReadDefault("docker.endpoint", defaultEndpoint)
return docker.NewClient(dockerEndpoint)
}
func (d *DockerDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
@ -408,6 +441,7 @@ func (h *dockerHandle) Kill() error {
err = h.client.RemoveImage(h.imageID)
if err != nil {
containers, err := h.client.ListContainers(docker.ListContainersOptions{
// The image might be in use by a stopped container, so check everything
All: true,
Filters: map[string][]string{
"image": []string{h.imageID},

View File

@ -9,6 +9,12 @@ import (
"github.com/hashicorp/nomad/nomad/structs"
)
func testDockerDriverContext(task string) *DriverContext {
cfg := testConfig()
cfg.DevMode = true
return NewDriverContext(task, cfg, cfg.Node, testLogger())
}
// dockerLocated looks to see whether docker is available on this system before
// we try to run tests. We'll keep it simple and just check for the CLI.
func dockerLocated() bool {
@ -33,7 +39,7 @@ func TestDockerDriver_Handle(t *testing.T) {
// The fingerprinter test should always pass, even if Docker is not installed.
func TestDockerDriver_Fingerprint(t *testing.T) {
d := NewDockerDriver(testDriverContext(""))
d := NewDockerDriver(testDockerDriverContext(""))
node := &structs.Node{
Attributes: make(map[string]string),
}
@ -56,14 +62,14 @@ func TestDockerDriver_StartOpen_Wait(t *testing.T) {
}
task := &structs.Task{
Name: "python-demo",
Name: "redis-demo",
Config: map[string]string{
"image": "redis",
},
Resources: basicResources,
}
driverCtx := testDriverContext(task.Name)
driverCtx := testDockerDriverContext(task.Name)
ctx := testDriverExecContext(task, driverCtx)
defer ctx.AllocDir.Destroy()
d := NewDockerDriver(driverCtx)
@ -93,7 +99,7 @@ func TestDockerDriver_Start_Wait(t *testing.T) {
}
task := &structs.Task{
Name: "python-demo",
Name: "redis-demo",
Config: map[string]string{
"image": "redis",
"command": "redis-server -v",
@ -104,7 +110,7 @@ func TestDockerDriver_Start_Wait(t *testing.T) {
},
}
driverCtx := testDriverContext(task.Name)
driverCtx := testDockerDriverContext(task.Name)
ctx := testDriverExecContext(task, driverCtx)
defer ctx.AllocDir.Destroy()
d := NewDockerDriver(driverCtx)
@ -140,7 +146,7 @@ func TestDockerDriver_Start_Kill_Wait(t *testing.T) {
}
task := &structs.Task{
Name: "python-demo",
Name: "redis-demo",
Config: map[string]string{
"image": "redis",
"command": "sleep 10",
@ -148,7 +154,7 @@ func TestDockerDriver_Start_Kill_Wait(t *testing.T) {
Resources: basicResources,
}
driverCtx := testDriverContext(task.Name)
driverCtx := testDockerDriverContext(task.Name)
ctx := testDriverExecContext(task, driverCtx)
defer ctx.AllocDir.Destroy()
d := NewDockerDriver(driverCtx)
@ -219,7 +225,7 @@ func TestDocker_StartN(t *testing.T) {
// Let's spin up a bunch of things
var err error
for idx, task := range taskList {
driverCtx := testDriverContext(task.Name)
driverCtx := testDockerDriverContext(task.Name)
ctx := testDriverExecContext(task, driverCtx)
defer ctx.AllocDir.Destroy()
d := NewDockerDriver(driverCtx)
@ -265,7 +271,7 @@ func TestDocker_StartNVersions(t *testing.T) {
// Let's spin up a bunch of things
var err error
for idx, task := range taskList {
driverCtx := testDriverContext(task.Name)
driverCtx := testDockerDriverContext(task.Name)
ctx := testDriverExecContext(task, driverCtx)
defer ctx.AllocDir.Destroy()
d := NewDockerDriver(driverCtx)
@ -299,7 +305,7 @@ func TestDockerHostNet(t *testing.T) {
CPU: 512,
},
}
driverCtx := testDriverContext(task.Name)
driverCtx := testDockerDriverContext(task.Name)
ctx := testDriverExecContext(task, driverCtx)
defer ctx.AllocDir.Destroy()
d := NewDockerDriver(driverCtx)