github.com/jmitchell/nomad@v0.1.3-0.20151007230021-7ab84c2862d8/command/agent/config_test.go (about)

     1  package agent
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"reflect"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/nomad/nomad/structs"
    11  )
    12  
    13  func TestConfig_Merge(t *testing.T) {
    14  	c1 := &Config{
    15  		Region:                    "global",
    16  		Datacenter:                "dc1",
    17  		NodeName:                  "node1",
    18  		DataDir:                   "/tmp/dir1",
    19  		LogLevel:                  "INFO",
    20  		EnableDebug:               false,
    21  		LeaveOnInt:                false,
    22  		LeaveOnTerm:               false,
    23  		EnableSyslog:              false,
    24  		SyslogFacility:            "local0.info",
    25  		DisableUpdateCheck:        false,
    26  		DisableAnonymousSignature: false,
    27  		BindAddr:                  "127.0.0.1",
    28  		Telemetry: &Telemetry{
    29  			StatsiteAddr:    "127.0.0.1:8125",
    30  			StatsdAddr:      "127.0.0.1:8125",
    31  			DisableHostname: false,
    32  		},
    33  		Client: &ClientConfig{
    34  			Enabled:   false,
    35  			StateDir:  "/tmp/state1",
    36  			AllocDir:  "/tmp/alloc1",
    37  			NodeID:    "node1",
    38  			NodeClass: "class1",
    39  			Options: map[string]string{
    40  				"foo": "bar",
    41  			},
    42  			NetworkSpeed: 100,
    43  		},
    44  		Server: &ServerConfig{
    45  			Enabled:         false,
    46  			BootstrapExpect: 1,
    47  			DataDir:         "/tmp/data1",
    48  			ProtocolVersion: 1,
    49  			NumSchedulers:   1,
    50  		},
    51  		Ports: &Ports{
    52  			HTTP: 4646,
    53  			RPC:  4647,
    54  			Serf: 4648,
    55  		},
    56  		Addresses: &Addresses{
    57  			HTTP: "127.0.0.1",
    58  			RPC:  "127.0.0.1",
    59  			Serf: "127.0.0.1",
    60  		},
    61  		AdvertiseAddrs: &AdvertiseAddrs{
    62  			RPC:  "127.0.0.1",
    63  			Serf: "127.0.0.1",
    64  		},
    65  	}
    66  
    67  	c2 := &Config{
    68  		Region:                    "region2",
    69  		Datacenter:                "dc2",
    70  		NodeName:                  "node2",
    71  		DataDir:                   "/tmp/dir2",
    72  		LogLevel:                  "DEBUG",
    73  		EnableDebug:               true,
    74  		LeaveOnInt:                true,
    75  		LeaveOnTerm:               true,
    76  		EnableSyslog:              true,
    77  		SyslogFacility:            "local0.debug",
    78  		DisableUpdateCheck:        true,
    79  		DisableAnonymousSignature: true,
    80  		BindAddr:                  "127.0.0.2",
    81  		Telemetry: &Telemetry{
    82  			StatsiteAddr:    "127.0.0.2:8125",
    83  			StatsdAddr:      "127.0.0.2:8125",
    84  			DisableHostname: true,
    85  		},
    86  		Client: &ClientConfig{
    87  			Enabled:   true,
    88  			StateDir:  "/tmp/state2",
    89  			AllocDir:  "/tmp/alloc2",
    90  			NodeID:    "node2",
    91  			NodeClass: "class2",
    92  			Servers:   []string{"server2"},
    93  			Meta: map[string]string{
    94  				"baz": "zip",
    95  			},
    96  			Options: map[string]string{
    97  				"foo": "bar",
    98  				"baz": "zip",
    99  			},
   100  			NetworkSpeed: 100,
   101  		},
   102  		Server: &ServerConfig{
   103  			Enabled:           true,
   104  			BootstrapExpect:   2,
   105  			DataDir:           "/tmp/data2",
   106  			ProtocolVersion:   2,
   107  			NumSchedulers:     2,
   108  			EnabledSchedulers: []string{structs.JobTypeBatch},
   109  		},
   110  		Ports: &Ports{
   111  			HTTP: 20000,
   112  			RPC:  21000,
   113  			Serf: 22000,
   114  		},
   115  		Addresses: &Addresses{
   116  			HTTP: "127.0.0.2",
   117  			RPC:  "127.0.0.2",
   118  			Serf: "127.0.0.2",
   119  		},
   120  		AdvertiseAddrs: &AdvertiseAddrs{
   121  			RPC:  "127.0.0.2",
   122  			Serf: "127.0.0.2",
   123  		},
   124  	}
   125  
   126  	result := c1.Merge(c2)
   127  	if !reflect.DeepEqual(result, c2) {
   128  		t.Fatalf("bad:\n%#v\n%#v", result.Server, c2.Server)
   129  	}
   130  }
   131  
   132  func TestConfig_LoadConfigFile(t *testing.T) {
   133  	// Fails if the file doesn't exist
   134  	if _, err := LoadConfigFile("/unicorns/leprechauns"); err == nil {
   135  		t.Fatalf("expected error, got nothing")
   136  	}
   137  
   138  	fh, err := ioutil.TempFile("", "nomad")
   139  	if err != nil {
   140  		t.Fatalf("err: %s", err)
   141  	}
   142  	defer os.RemoveAll(fh.Name())
   143  
   144  	// Invalid content returns error
   145  	if _, err := fh.WriteString("nope"); err != nil {
   146  		t.Fatalf("err: %s", err)
   147  	}
   148  	if _, err := LoadConfigFile(fh.Name()); err == nil {
   149  		t.Fatalf("expected load error, got nothing")
   150  	}
   151  
   152  	// Valid content parses successfully
   153  	if err := fh.Truncate(0); err != nil {
   154  		t.Fatalf("err: %s", err)
   155  	}
   156  	if _, err := fh.Seek(0, 0); err != nil {
   157  		t.Fatalf("err: %s", err)
   158  	}
   159  	if _, err := fh.WriteString(`{"region":"west"}`); err != nil {
   160  		t.Fatalf("err: %s", err)
   161  	}
   162  
   163  	config, err := LoadConfigFile(fh.Name())
   164  	if err != nil {
   165  		t.Fatalf("err: %s", err)
   166  	}
   167  	if config.Region != "west" {
   168  		t.Fatalf("bad region: %q", config.Region)
   169  	}
   170  }
   171  
   172  func TestConfig_LoadConfigDir(t *testing.T) {
   173  	// Fails if the dir doesn't exist.
   174  	if _, err := LoadConfigDir("/unicorns/leprechauns"); err == nil {
   175  		t.Fatalf("expected error, got nothing")
   176  	}
   177  
   178  	dir, err := ioutil.TempDir("", "nomad")
   179  	if err != nil {
   180  		t.Fatalf("err: %s", err)
   181  	}
   182  	defer os.RemoveAll(dir)
   183  
   184  	// Returns empty config on empty dir
   185  	config, err := LoadConfig(dir)
   186  	if err != nil {
   187  		t.Fatalf("err: %s", err)
   188  	}
   189  	if config == nil {
   190  		t.Fatalf("should not be nil")
   191  	}
   192  
   193  	file1 := filepath.Join(dir, "conf1.hcl")
   194  	err = ioutil.WriteFile(file1, []byte(`{"region":"west"}`), 0600)
   195  	if err != nil {
   196  		t.Fatalf("err: %s", err)
   197  	}
   198  
   199  	file2 := filepath.Join(dir, "conf2.hcl")
   200  	err = ioutil.WriteFile(file2, []byte(`{"datacenter":"sfo"}`), 0600)
   201  	if err != nil {
   202  		t.Fatalf("err: %s", err)
   203  	}
   204  
   205  	file3 := filepath.Join(dir, "conf3.hcl")
   206  	err = ioutil.WriteFile(file3, []byte(`nope`), 0600)
   207  	if err != nil {
   208  		t.Fatalf("err: %s", err)
   209  	}
   210  
   211  	// Fails if we have a bad config file
   212  	if _, err := LoadConfigDir(dir); err == nil {
   213  		t.Fatalf("expected load error, got nothing")
   214  	}
   215  
   216  	if err := os.Remove(file3); err != nil {
   217  		t.Fatalf("err: %s", err)
   218  	}
   219  
   220  	// Works if configs are valid
   221  	config, err = LoadConfigDir(dir)
   222  	if err != nil {
   223  		t.Fatalf("err: %s", err)
   224  	}
   225  	if config.Region != "west" || config.Datacenter != "sfo" {
   226  		t.Fatalf("bad: %#v", config)
   227  	}
   228  }
   229  
   230  func TestConfig_LoadConfig(t *testing.T) {
   231  	// Fails if the target doesn't exist
   232  	if _, err := LoadConfig("/unicorns/leprechauns"); err == nil {
   233  		t.Fatalf("expected error, got nothing")
   234  	}
   235  
   236  	fh, err := ioutil.TempFile("", "nomad")
   237  	if err != nil {
   238  		t.Fatalf("err: %s", err)
   239  	}
   240  	defer os.Remove(fh.Name())
   241  
   242  	if _, err := fh.WriteString(`{"region":"west"}`); err != nil {
   243  		t.Fatalf("err: %s", err)
   244  	}
   245  
   246  	// Works on a config file
   247  	config, err := LoadConfig(fh.Name())
   248  	if err != nil {
   249  		t.Fatalf("err: %s", err)
   250  	}
   251  	if config.Region != "west" {
   252  		t.Fatalf("bad: %#v", config)
   253  	}
   254  
   255  	dir, err := ioutil.TempDir("", "nomad")
   256  	if err != nil {
   257  		t.Fatalf("err: %s", err)
   258  	}
   259  	defer os.RemoveAll(dir)
   260  
   261  	file1 := filepath.Join(dir, "config1.hcl")
   262  	err = ioutil.WriteFile(file1, []byte(`{"datacenter":"sfo"}`), 0600)
   263  	if err != nil {
   264  		t.Fatalf("err: %s", err)
   265  	}
   266  
   267  	// Works on config dir
   268  	config, err = LoadConfig(dir)
   269  	if err != nil {
   270  		t.Fatalf("err: %s", err)
   271  	}
   272  	if config.Datacenter != "sfo" {
   273  		t.Fatalf("bad: %#v", config)
   274  	}
   275  }
   276  
   277  func TestConfig_Listener(t *testing.T) {
   278  	config := DefaultConfig()
   279  
   280  	// Fails on invalid input
   281  	if _, err := config.Listener("tcp", "nope", 8080); err == nil {
   282  		t.Fatalf("expected addr error")
   283  	}
   284  	if _, err := config.Listener("nope", "127.0.0.1", 8080); err == nil {
   285  		t.Fatalf("expected protocol err")
   286  	}
   287  	if _, err := config.Listener("tcp", "127.0.0.1", -1); err == nil {
   288  		t.Fatalf("expected port error")
   289  	}
   290  
   291  	// Works with valid inputs
   292  	ln, err := config.Listener("tcp", "127.0.0.1", 24000)
   293  	if err != nil {
   294  		t.Fatalf("err: %s", err)
   295  	}
   296  	ln.Close()
   297  
   298  	if net := ln.Addr().Network(); net != "tcp" {
   299  		t.Fatalf("expected tcp, got: %q", net)
   300  	}
   301  	if addr := ln.Addr().String(); addr != "127.0.0.1:24000" {
   302  		t.Fatalf("expected 127.0.0.1:4646, got: %q", addr)
   303  	}
   304  
   305  	// Falls back to default bind address if non provided
   306  	config.BindAddr = "0.0.0.0"
   307  	ln, err = config.Listener("tcp4", "", 24000)
   308  	if err != nil {
   309  		t.Fatalf("err: %s", err)
   310  	}
   311  	ln.Close()
   312  
   313  	if addr := ln.Addr().String(); addr != "0.0.0.0:24000" {
   314  		t.Fatalf("expected 0.0.0.0:24000, got: %q", addr)
   315  	}
   316  }
   317  
   318  func TestConfig_LoadConfigString(t *testing.T) {
   319  	// Load the config
   320  	config, err := LoadConfigString(testConfig)
   321  	if err != nil {
   322  		t.Fatalf("err: %s", err)
   323  	}
   324  
   325  	// Expected output
   326  	expect := &Config{
   327  		Region:      "foobar",
   328  		Datacenter:  "dc2",
   329  		NodeName:    "my-web",
   330  		DataDir:     "/tmp/nomad",
   331  		LogLevel:    "ERR",
   332  		BindAddr:    "192.168.0.1",
   333  		EnableDebug: true,
   334  		Ports: &Ports{
   335  			HTTP: 1234,
   336  			RPC:  2345,
   337  			Serf: 3456,
   338  		},
   339  		Addresses: &Addresses{
   340  			HTTP: "127.0.0.1",
   341  			RPC:  "127.0.0.2",
   342  			Serf: "127.0.0.3",
   343  		},
   344  		AdvertiseAddrs: &AdvertiseAddrs{
   345  			RPC:  "127.0.0.3",
   346  			Serf: "127.0.0.4",
   347  		},
   348  		Client: &ClientConfig{
   349  			Enabled:   true,
   350  			StateDir:  "/tmp/client-state",
   351  			AllocDir:  "/tmp/alloc",
   352  			Servers:   []string{"a.b.c:80", "127.0.0.1:1234"},
   353  			NodeID:    "xyz123",
   354  			NodeClass: "linux-medium-64bit",
   355  			Meta: map[string]string{
   356  				"foo": "bar",
   357  				"baz": "zip",
   358  			},
   359  			Options: map[string]string{
   360  				"foo": "bar",
   361  				"baz": "zip",
   362  			},
   363  			NetworkSpeed: 100,
   364  		},
   365  		Server: &ServerConfig{
   366  			Enabled:           true,
   367  			BootstrapExpect:   5,
   368  			DataDir:           "/tmp/data",
   369  			ProtocolVersion:   3,
   370  			NumSchedulers:     2,
   371  			EnabledSchedulers: []string{"test"},
   372  		},
   373  		Telemetry: &Telemetry{
   374  			StatsiteAddr:    "127.0.0.1:1234",
   375  			StatsdAddr:      "127.0.0.1:2345",
   376  			DisableHostname: true,
   377  		},
   378  		LeaveOnInt:                true,
   379  		LeaveOnTerm:               true,
   380  		EnableSyslog:              true,
   381  		SyslogFacility:            "LOCAL1",
   382  		DisableUpdateCheck:        true,
   383  		DisableAnonymousSignature: true,
   384  		Atlas: &AtlasConfig{
   385  			Infrastructure: "armon/test",
   386  			Token:          "abcd",
   387  			Join:           true,
   388  			Endpoint:       "127.0.0.1:1234",
   389  		},
   390  	}
   391  
   392  	// Check parsing
   393  	if !reflect.DeepEqual(config, expect) {
   394  		t.Fatalf("bad: got: %#v\nexpect: %#v", config, expect)
   395  	}
   396  }
   397  
   398  const testConfig = `
   399  region = "foobar"
   400  datacenter = "dc2"
   401  name = "my-web"
   402  data_dir = "/tmp/nomad"
   403  log_level = "ERR"
   404  bind_addr = "192.168.0.1"
   405  enable_debug = true
   406  ports {
   407  	http = 1234
   408  	rpc = 2345
   409  	serf = 3456
   410  }
   411  addresses {
   412  	http = "127.0.0.1"
   413  	rpc = "127.0.0.2"
   414  	serf = "127.0.0.3"
   415  }
   416  advertise {
   417  	rpc = "127.0.0.3"
   418  	serf = "127.0.0.4"
   419  }
   420  client {
   421  	enabled = true
   422  	state_dir = "/tmp/client-state"
   423  	alloc_dir = "/tmp/alloc"
   424  	servers = ["a.b.c:80", "127.0.0.1:1234"]
   425  	node_id = "xyz123"
   426  	node_class = "linux-medium-64bit"
   427  	meta {
   428  		foo = "bar"
   429  		baz = "zip"
   430  	}
   431  	options {
   432  		foo = "bar"
   433  		baz = "zip"
   434  	}
   435  	network_speed = 100
   436  }
   437  server {
   438  	enabled = true
   439  	bootstrap_expect = 5
   440  	data_dir = "/tmp/data"
   441  	protocol_version = 3
   442  	num_schedulers = 2
   443  	enabled_schedulers = ["test"]
   444  }
   445  telemetry {
   446  	statsite_address = "127.0.0.1:1234"
   447  	statsd_address = "127.0.0.1:2345"
   448  	disable_hostname = true
   449  }
   450  leave_on_interrupt = true
   451  leave_on_terminate = true
   452  enable_syslog = true
   453  syslog_facility = "LOCAL1"
   454  disable_update_check = true
   455  disable_anonymous_signature = true
   456  atlas {
   457  	infrastructure = "armon/test"
   458  	token = "abcd"
   459  	join = true
   460  	endpoint = "127.0.0.1:1234"
   461  }
   462  `