Files
nomad/client/driver/driver_test.go
Michael Schurter a087a8be79 Fix inconsistent task env setting
Consolidate task environment building in GetTaskEnv since it can
determine what kind of filesystem isolation is used.

This means drivers no longer have to manipulate task environment paths.
2017-01-06 12:19:32 -08:00

259 lines
6.4 KiB
Go

package driver
import (
"io"
"log"
"math/rand"
"os"
"path/filepath"
"reflect"
"testing"
"time"
"github.com/hashicorp/nomad/client/allocdir"
"github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/helper/testtask"
"github.com/hashicorp/nomad/nomad/mock"
"github.com/hashicorp/nomad/nomad/structs"
)
var basicResources = &structs.Resources{
CPU: 250,
MemoryMB: 256,
DiskMB: 20,
Networks: []*structs.NetworkResource{
&structs.NetworkResource{
IP: "0.0.0.0",
ReservedPorts: []structs.Port{{"main", 12345}},
DynamicPorts: []structs.Port{{"HTTP", 43330}},
},
},
}
func init() {
rand.Seed(49875)
}
func TestMain(m *testing.M) {
if !testtask.Run() {
os.Exit(m.Run())
}
}
// copyFile moves an existing file to the destination
func copyFile(src, dst string, t *testing.T) {
in, err := os.Open(src)
if err != nil {
t.Fatalf("copying %v -> %v failed: %v", src, dst, err)
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
t.Fatalf("copying %v -> %v failed: %v", src, dst, err)
}
defer func() {
if err := out.Close(); err != nil {
t.Fatalf("copying %v -> %v failed: %v", src, dst, err)
}
}()
if _, err = io.Copy(out, in); err != nil {
t.Fatalf("copying %v -> %v failed: %v", src, dst, err)
}
if err := out.Sync(); err != nil {
t.Fatalf("copying %v -> %v failed: %v", src, dst, err)
}
}
func testLogger() *log.Logger {
return log.New(os.Stderr, "", log.LstdFlags)
}
func testConfig() *config.Config {
conf := config.DefaultConfig()
conf.StateDir = os.TempDir()
conf.AllocDir = os.TempDir()
conf.MaxKillTimeout = 10 * time.Second
return conf
}
type testContext struct {
AllocDir *allocdir.AllocDir
DriverCtx *DriverContext
ExecCtx *ExecContext
}
// testDriverContext sets up an alloc dir, task dir, DriverContext, and ExecContext.
//
// It is up to the caller to call AllocDir.Destroy to cleanup.
func testDriverContexts(t *testing.T, task *structs.Task) *testContext {
cfg := testConfig()
allocDir := allocdir.NewAllocDir(testLogger(), filepath.Join(cfg.AllocDir, structs.GenerateUUID()))
if err := allocDir.Build(); err != nil {
t.Fatalf("AllocDir.Build() failed: %v", err)
}
alloc := mock.Alloc()
// Build a temp driver so we can call FSIsolation and build the task dir
tmpdrv, err := NewDriver(task.Driver, NewEmptyDriverContext())
if err != nil {
allocDir.Destroy()
t.Fatalf("NewDriver(%q, nil) failed: %v", task.Driver, err)
return nil
}
// Build the task dir
td := allocDir.NewTaskDir(task.Name)
if err := td.Build(config.DefaultChrootEnv, tmpdrv.FSIsolation()); err != nil {
allocDir.Destroy()
t.Fatalf("TaskDir.Build(%#v, %q) failed: %v", config.DefaultChrootEnv, tmpdrv.FSIsolation())
return nil
}
execCtx := NewExecContext(td, alloc.ID)
taskEnv, err := GetTaskEnv(td, cfg.Node, task, alloc, cfg, "")
if err != nil {
allocDir.Destroy()
t.Fatalf("GetTaskEnv() failed: %v", err)
return nil
}
logger := testLogger()
emitter := func(m string, args ...interface{}) {
logger.Printf("[EVENT] "+m, args...)
}
driverCtx := NewDriverContext(task.Name, cfg, cfg.Node, logger, taskEnv, emitter)
return &testContext{allocDir, driverCtx, execCtx}
}
func TestDriver_GetTaskEnv(t *testing.T) {
task := &structs.Task{
Name: "Foo",
Driver: "mock_driver",
Env: map[string]string{
"HELLO": "world",
"lorem": "ipsum",
},
Resources: &structs.Resources{
CPU: 1000,
MemoryMB: 500,
Networks: []*structs.NetworkResource{
&structs.NetworkResource{
IP: "1.2.3.4",
ReservedPorts: []structs.Port{{"one", 80}, {"two", 443}},
DynamicPorts: []structs.Port{{"admin", 8081}, {"web", 8086}},
},
},
},
Meta: map[string]string{
"chocolate": "cake",
"strawberry": "icecream",
},
}
alloc := mock.Alloc()
alloc.Job.TaskGroups[0].Tasks[0] = task
alloc.Name = "Bar"
conf := testConfig()
allocDir := allocdir.NewAllocDir(testLogger(), filepath.Join(conf.AllocDir, alloc.ID))
env, err := GetTaskEnv(allocDir.NewTaskDir(task.Name), nil, task, alloc, conf, "")
if err != nil {
t.Fatalf("GetTaskEnv() failed: %v", err)
}
exp := map[string]string{
"NOMAD_CPU_LIMIT": "1000",
"NOMAD_MEMORY_LIMIT": "500",
"NOMAD_ADDR_one": "1.2.3.4:80",
"NOMAD_IP_one": "1.2.3.4",
"NOMAD_PORT_one": "80",
"NOMAD_HOST_PORT_one": "80",
"NOMAD_ADDR_two": "1.2.3.4:443",
"NOMAD_IP_two": "1.2.3.4",
"NOMAD_PORT_two": "443",
"NOMAD_HOST_PORT_two": "443",
"NOMAD_ADDR_admin": "1.2.3.4:8081",
"NOMAD_IP_admin": "1.2.3.4",
"NOMAD_PORT_admin": "8081",
"NOMAD_HOST_PORT_admin": "8081",
"NOMAD_ADDR_web": "1.2.3.4:8086",
"NOMAD_IP_web": "1.2.3.4",
"NOMAD_PORT_web": "8086",
"NOMAD_HOST_PORT_web": "8086",
"NOMAD_META_CHOCOLATE": "cake",
"NOMAD_META_STRAWBERRY": "icecream",
"NOMAD_META_ELB_CHECK_INTERVAL": "30s",
"NOMAD_META_ELB_CHECK_TYPE": "http",
"NOMAD_META_ELB_CHECK_MIN": "3",
"NOMAD_META_OWNER": "armon",
"HELLO": "world",
"lorem": "ipsum",
"NOMAD_ALLOC_ID": alloc.ID,
"NOMAD_ALLOC_NAME": alloc.Name,
"NOMAD_TASK_NAME": task.Name,
"NOMAD_JOB_NAME": alloc.Job.Name,
}
act := env.EnvMap()
// Since host env vars are included only ensure expected env vars are present
for expk, expv := range exp {
v, ok := act[expk]
if !ok {
t.Errorf("%q not found in task env", expk)
continue
}
if v != expv {
t.Errorf("Expected %s=%q but found %q", expk, expv, v)
}
}
}
func TestMapMergeStrInt(t *testing.T) {
a := map[string]int{
"cakes": 5,
"cookies": 3,
}
b := map[string]int{
"cakes": 3,
"pies": 2,
}
c := mapMergeStrInt(a, b)
d := map[string]int{
"cakes": 3,
"cookies": 3,
"pies": 2,
}
if !reflect.DeepEqual(c, d) {
t.Errorf("\nExpected\n%+v\nGot\n%+v\n", d, c)
}
}
func TestMapMergeStrStr(t *testing.T) {
a := map[string]string{
"cake": "chocolate",
"cookie": "caramel",
}
b := map[string]string{
"cake": "strawberry",
"pie": "apple",
}
c := mapMergeStrStr(a, b)
d := map[string]string{
"cake": "strawberry",
"cookie": "caramel",
"pie": "apple",
}
if !reflect.DeepEqual(c, d) {
t.Errorf("\nExpected\n%+v\nGot\n%+v\n", d, c)
}
}