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 `