open-nomad/command/agent/config_test.go

459 lines
10 KiB
Go
Raw Normal View History

2015-09-10 04:42:50 +00:00
package agent
import (
2015-09-10 05:11:48 +00:00
"io/ioutil"
"os"
"path/filepath"
2015-09-10 04:42:50 +00:00
"reflect"
"testing"
"time"
"github.com/hashicorp/nomad/nomad/structs"
2015-09-10 04:42:50 +00:00
)
func TestConfig_Merge(t *testing.T) {
c1 := &Config{
Region: "global",
2015-09-10 04:42:50 +00:00
Datacenter: "dc1",
NodeName: "node1",
DataDir: "/tmp/dir1",
LogLevel: "INFO",
EnableDebug: false,
LeaveOnInt: false,
LeaveOnTerm: false,
EnableSyslog: false,
SyslogFacility: "local0.info",
DisableUpdateCheck: false,
DisableAnonymousSignature: false,
2015-09-11 02:04:06 +00:00
BindAddr: "127.0.0.1",
Telemetry: &Telemetry{
StatsiteAddr: "127.0.0.1:8125",
StatsdAddr: "127.0.0.1:8125",
DisableHostname: false,
},
Client: &ClientConfig{
Enabled: false,
StateDir: "/tmp/state1",
AllocDir: "/tmp/alloc1",
NodeClass: "class1",
2015-10-03 00:02:32 +00:00
Options: map[string]string{
"foo": "bar",
},
NetworkSpeed: 100,
MaxKillTimeout: "20s",
ClientMaxPort: 19996,
Reserved: &Resources{
CPU: 10,
MemoryMB: 10,
DiskMB: 10,
IOPS: 10,
Networks: []*NetworkResource{
{
Device: "eth0",
IP: "10.105.0.6",
MBits: 100,
ReservedPorts: "1,10-30,55",
},
},
},
},
Server: &ServerConfig{
Enabled: false,
BootstrapExpect: 1,
DataDir: "/tmp/data1",
ProtocolVersion: 1,
NumSchedulers: 1,
NodeGCThreshold: "1h",
2016-03-04 23:44:12 +00:00
HeartbeatGrace: "30s",
},
2015-09-11 02:04:06 +00:00
Ports: &Ports{
HTTP: 4646,
RPC: 4647,
Serf: 4648,
},
Addresses: &Addresses{
HTTP: "127.0.0.1",
RPC: "127.0.0.1",
Serf: "127.0.0.1",
},
AdvertiseAddrs: &AdvertiseAddrs{
RPC: "127.0.0.1",
Serf: "127.0.0.1",
},
2015-11-30 23:21:50 +00:00
Atlas: &AtlasConfig{
Infrastructure: "hashicorp/test1",
Token: "abc",
Join: false,
Endpoint: "foo",
},
2015-09-10 04:42:50 +00:00
}
c2 := &Config{
Region: "region2",
Datacenter: "dc2",
NodeName: "node2",
DataDir: "/tmp/dir2",
LogLevel: "DEBUG",
EnableDebug: true,
LeaveOnInt: true,
LeaveOnTerm: true,
EnableSyslog: true,
SyslogFacility: "local0.debug",
DisableUpdateCheck: true,
DisableAnonymousSignature: true,
2015-09-11 02:04:06 +00:00
BindAddr: "127.0.0.2",
Telemetry: &Telemetry{
StatsiteAddr: "127.0.0.2:8125",
StatsdAddr: "127.0.0.2:8125",
DisableHostname: true,
},
Client: &ClientConfig{
Enabled: true,
StateDir: "/tmp/state2",
AllocDir: "/tmp/alloc2",
NodeClass: "class2",
Servers: []string{"server2"},
2015-10-03 00:02:32 +00:00
Meta: map[string]string{
"baz": "zip",
},
Options: map[string]string{
"foo": "bar",
"baz": "zip",
},
2016-02-09 00:27:31 +00:00
ClientMaxPort: 20000,
ClientMinPort: 22000,
NetworkSpeed: 105,
MaxKillTimeout: "50s",
Reserved: &Resources{
CPU: 15,
MemoryMB: 15,
DiskMB: 15,
IOPS: 15,
Networks: []*NetworkResource{
{
Device: "eth0",
IP: "10.105.0.6",
MBits: 105,
ReservedPorts: "1,10-30,55",
},
},
},
},
Server: &ServerConfig{
Enabled: true,
BootstrapExpect: 2,
DataDir: "/tmp/data2",
ProtocolVersion: 2,
NumSchedulers: 2,
EnabledSchedulers: []string{structs.JobTypeBatch},
NodeGCThreshold: "12h",
2016-03-04 23:44:12 +00:00
HeartbeatGrace: "2m",
RejoinAfterLeave: true,
StartJoin: []string{"1.1.1.1"},
RetryJoin: []string{"1.1.1.1"},
RetryInterval: "10s",
retryInterval: time.Second * 10,
},
2015-09-11 02:04:06 +00:00
Ports: &Ports{
HTTP: 20000,
RPC: 21000,
Serf: 22000,
},
Addresses: &Addresses{
HTTP: "127.0.0.2",
RPC: "127.0.0.2",
Serf: "127.0.0.2",
},
AdvertiseAddrs: &AdvertiseAddrs{
RPC: "127.0.0.2",
Serf: "127.0.0.2",
},
2015-11-30 23:21:50 +00:00
Atlas: &AtlasConfig{
Infrastructure: "hashicorp/test2",
Token: "xyz",
Join: true,
Endpoint: "bar",
},
2015-09-10 04:42:50 +00:00
}
result := c1.Merge(c2)
if !reflect.DeepEqual(result, c2) {
t.Fatalf("bad:\n%#v\n%#v", result, c2)
2015-09-10 04:42:50 +00:00
}
}
2015-09-10 05:11:48 +00:00
func TestConfig_ParseConfigFile(t *testing.T) {
2015-09-10 05:11:48 +00:00
// Fails if the file doesn't exist
if _, err := ParseConfigFile("/unicorns/leprechauns"); err == nil {
2015-09-10 05:11:48 +00:00
t.Fatalf("expected error, got nothing")
}
fh, err := ioutil.TempFile("", "nomad")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(fh.Name())
// Invalid content returns error
2015-11-09 19:49:27 +00:00
if _, err := fh.WriteString("nope;!!!"); err != nil {
2015-09-10 05:11:48 +00:00
t.Fatalf("err: %s", err)
}
if _, err := ParseConfigFile(fh.Name()); err == nil {
2015-09-10 05:11:48 +00:00
t.Fatalf("expected load error, got nothing")
}
// Valid content parses successfully
if err := fh.Truncate(0); err != nil {
t.Fatalf("err: %s", err)
}
if _, err := fh.Seek(0, 0); err != nil {
t.Fatalf("err: %s", err)
}
if _, err := fh.WriteString(`{"region":"west"}`); err != nil {
t.Fatalf("err: %s", err)
}
config, err := ParseConfigFile(fh.Name())
2015-09-10 05:11:48 +00:00
if err != nil {
t.Fatalf("err: %s", err)
}
if config.Region != "west" {
t.Fatalf("bad region: %q", config.Region)
}
}
func TestConfig_LoadConfigDir(t *testing.T) {
// Fails if the dir doesn't exist.
if _, err := LoadConfigDir("/unicorns/leprechauns"); err == nil {
t.Fatalf("expected error, got nothing")
}
dir, err := ioutil.TempDir("", "nomad")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(dir)
// Returns empty config on empty dir
config, err := LoadConfig(dir)
if err != nil {
t.Fatalf("err: %s", err)
}
if config == nil {
t.Fatalf("should not be nil")
}
2015-09-10 05:11:48 +00:00
file1 := filepath.Join(dir, "conf1.hcl")
err = ioutil.WriteFile(file1, []byte(`{"region":"west"}`), 0600)
if err != nil {
t.Fatalf("err: %s", err)
}
file2 := filepath.Join(dir, "conf2.hcl")
err = ioutil.WriteFile(file2, []byte(`{"datacenter":"sfo"}`), 0600)
if err != nil {
t.Fatalf("err: %s", err)
}
file3 := filepath.Join(dir, "conf3.hcl")
2015-11-09 19:49:27 +00:00
err = ioutil.WriteFile(file3, []byte(`nope;!!!`), 0600)
2015-09-10 05:11:48 +00:00
if err != nil {
t.Fatalf("err: %s", err)
}
// Fails if we have a bad config file
if _, err := LoadConfigDir(dir); err == nil {
t.Fatalf("expected load error, got nothing")
}
if err := os.Remove(file3); err != nil {
t.Fatalf("err: %s", err)
}
// Works if configs are valid
config, err = LoadConfigDir(dir)
2015-09-10 05:11:48 +00:00
if err != nil {
t.Fatalf("err: %s", err)
}
if config.Region != "west" || config.Datacenter != "sfo" {
t.Fatalf("bad: %#v", config)
}
}
func TestConfig_LoadConfig(t *testing.T) {
// Fails if the target doesn't exist
if _, err := LoadConfig("/unicorns/leprechauns"); err == nil {
t.Fatalf("expected error, got nothing")
}
fh, err := ioutil.TempFile("", "nomad")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.Remove(fh.Name())
if _, err := fh.WriteString(`{"region":"west"}`); err != nil {
t.Fatalf("err: %s", err)
}
// Works on a config file
config, err := LoadConfig(fh.Name())
if err != nil {
t.Fatalf("err: %s", err)
}
if config.Region != "west" {
t.Fatalf("bad: %#v", config)
}
expectedConfigFiles := []string{fh.Name()}
if !reflect.DeepEqual(config.Files, expectedConfigFiles) {
t.Errorf("Loaded configs don't match\nExpected\n%+vGot\n%+v\n",
expectedConfigFiles, config.Files)
}
2015-09-10 05:11:48 +00:00
dir, err := ioutil.TempDir("", "nomad")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(dir)
file1 := filepath.Join(dir, "config1.hcl")
err = ioutil.WriteFile(file1, []byte(`{"datacenter":"sfo"}`), 0600)
if err != nil {
t.Fatalf("err: %s", err)
}
// Works on config dir
config, err = LoadConfig(dir)
if err != nil {
t.Fatalf("err: %s", err)
}
if config.Datacenter != "sfo" {
t.Fatalf("bad: %#v", config)
}
expectedConfigFiles = []string{file1}
if !reflect.DeepEqual(config.Files, expectedConfigFiles) {
t.Errorf("Loaded configs don't match\nExpected\n%+vGot\n%+v\n",
expectedConfigFiles, config.Files)
}
2015-12-05 01:12:47 +00:00
}
func TestConfig_LoadConfigsFileOrder(t *testing.T) {
config1, err := LoadConfigDir("test-resources/etcnomad")
if err != nil {
t.Fatalf("Failed to load config: %s", err)
}
config2, err := LoadConfig("test-resources/myconf")
if err != nil {
t.Fatalf("Failed to load config: %s", err)
}
expected := []string{
// filepath.FromSlash changes these to backslash \ on Windows
filepath.FromSlash("test-resources/etcnomad/common.hcl"),
filepath.FromSlash("test-resources/etcnomad/server.json"),
filepath.FromSlash("test-resources/myconf"),
2015-12-05 01:12:47 +00:00
}
2015-12-05 01:12:47 +00:00
config := config1.Merge(config2)
if !reflect.DeepEqual(config.Files, expected) {
t.Errorf("Loaded configs don't match\nwant: %+v\n got: %+v\n",
2015-12-05 01:12:47 +00:00
expected, config.Files)
}
2015-09-10 05:11:48 +00:00
}
2015-09-11 02:15:17 +00:00
func TestConfig_Listener(t *testing.T) {
config := DefaultConfig()
// Fails on invalid input
2015-12-02 18:59:27 +00:00
if ln, err := config.Listener("tcp", "nope", 8080); err == nil {
ln.Close()
2015-09-11 02:15:17 +00:00
t.Fatalf("expected addr error")
}
2015-12-02 18:59:27 +00:00
if ln, err := config.Listener("nope", "127.0.0.1", 8080); err == nil {
ln.Close()
2015-09-11 02:15:17 +00:00
t.Fatalf("expected protocol err")
}
2015-12-02 18:59:27 +00:00
if ln, err := config.Listener("tcp", "127.0.0.1", -1); err == nil {
ln.Close()
2015-09-11 02:15:17 +00:00
t.Fatalf("expected port error")
}
// Works with valid inputs
ln, err := config.Listener("tcp", "127.0.0.1", 24000)
if err != nil {
t.Fatalf("err: %s", err)
}
ln.Close()
if net := ln.Addr().Network(); net != "tcp" {
t.Fatalf("expected tcp, got: %q", net)
}
if addr := ln.Addr().String(); addr != "127.0.0.1:24000" {
t.Fatalf("expected 127.0.0.1:4646, got: %q", addr)
}
// Falls back to default bind address if non provided
config.BindAddr = "0.0.0.0"
ln, err = config.Listener("tcp4", "", 24000)
if err != nil {
t.Fatalf("err: %s", err)
}
ln.Close()
if addr := ln.Addr().String(); addr != "0.0.0.0:24000" {
t.Fatalf("expected 0.0.0.0:24000, got: %q", addr)
}
}
2015-09-22 18:29:53 +00:00
func TestNetworkResources_ParseReserved(t *testing.T) {
cases := []struct {
Input string
Parsed []int
Err bool
}{
{
"1,2,3",
[]int{1, 2, 3},
false,
2015-09-22 18:29:53 +00:00
},
{
"3,1,2,1,2,3,1-3",
[]int{1, 2, 3},
false,
2015-09-22 18:29:53 +00:00
},
{
"3-1",
nil,
true,
2015-09-22 18:29:53 +00:00
},
{
"1-3,2-4",
[]int{1, 2, 3, 4},
false,
2015-09-22 18:29:53 +00:00
},
{
"1-3,4,5-5,6,7,8-10",
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
false,
},
2015-09-22 18:29:53 +00:00
}
for i, tc := range cases {
n := &NetworkResource{ReservedPorts: tc.Input}
err := n.ParseReserved()
if (err != nil) != tc.Err {
t.Fatalf("test case %d: %v", i, err)
continue
}
2015-09-22 18:29:53 +00:00
if !reflect.DeepEqual(n.ParsedReservedPorts, tc.Parsed) {
t.Fatalf("test case %d: \n\n%#v\n\n%#v", i, n.ParsedReservedPorts, tc.Parsed)
}
}
}