github.com/rohankumardubey/nomad@v0.11.8/command/agent/config_parse_test.go (about) 1 package agent 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "sort" 7 "testing" 8 "time" 9 10 "github.com/hashicorp/nomad/helper" 11 "github.com/hashicorp/nomad/nomad/structs" 12 "github.com/hashicorp/nomad/nomad/structs/config" 13 "github.com/stretchr/testify/require" 14 ) 15 16 var basicConfig = &Config{ 17 Region: "foobar", 18 Datacenter: "dc2", 19 NodeName: "my-web", 20 DataDir: "/tmp/nomad", 21 PluginDir: "/tmp/nomad-plugins", 22 LogFile: "/var/log/nomad.log", 23 LogLevel: "ERR", 24 LogJson: true, 25 BindAddr: "192.168.0.1", 26 EnableDebug: true, 27 Ports: &Ports{ 28 HTTP: 1234, 29 RPC: 2345, 30 Serf: 3456, 31 }, 32 Addresses: &Addresses{ 33 HTTP: "127.0.0.1", 34 RPC: "127.0.0.2", 35 Serf: "127.0.0.3", 36 }, 37 AdvertiseAddrs: &AdvertiseAddrs{ 38 RPC: "127.0.0.3", 39 Serf: "127.0.0.4", 40 }, 41 Client: &ClientConfig{ 42 Enabled: true, 43 StateDir: "/tmp/client-state", 44 AllocDir: "/tmp/alloc", 45 Servers: []string{"a.b.c:80", "127.0.0.1:1234"}, 46 NodeClass: "linux-medium-64bit", 47 ServerJoin: &ServerJoin{ 48 RetryJoin: []string{"1.1.1.1", "2.2.2.2"}, 49 RetryInterval: time.Duration(15) * time.Second, 50 RetryIntervalHCL: "15s", 51 RetryMaxAttempts: 3, 52 }, 53 Meta: map[string]string{ 54 "foo": "bar", 55 "baz": "zip", 56 }, 57 Options: map[string]string{ 58 "foo": "bar", 59 "baz": "zip", 60 }, 61 ChrootEnv: map[string]string{ 62 "/opt/myapp/etc": "/etc", 63 "/opt/myapp/bin": "/bin", 64 }, 65 NetworkInterface: "eth0", 66 NetworkSpeed: 100, 67 CpuCompute: 4444, 68 MemoryMB: 0, 69 MaxKillTimeout: "10s", 70 ClientMinPort: 1000, 71 ClientMaxPort: 2000, 72 Reserved: &Resources{ 73 CPU: 10, 74 MemoryMB: 10, 75 DiskMB: 10, 76 ReservedPorts: "1,100,10-12", 77 }, 78 GCInterval: 6 * time.Second, 79 GCIntervalHCL: "6s", 80 GCParallelDestroys: 6, 81 GCDiskUsageThreshold: 82, 82 GCInodeUsageThreshold: 91, 83 GCMaxAllocs: 50, 84 NoHostUUID: helper.BoolToPtr(false), 85 DisableRemoteExec: true, 86 HostVolumes: []*structs.ClientHostVolumeConfig{ 87 {Name: "tmp", Path: "/tmp"}, 88 }, 89 CNIPath: "/tmp/cni_path", 90 BridgeNetworkName: "custom_bridge_name", 91 BridgeNetworkSubnet: "custom_bridge_subnet", 92 }, 93 Server: &ServerConfig{ 94 Enabled: true, 95 AuthoritativeRegion: "foobar", 96 BootstrapExpect: 5, 97 DataDir: "/tmp/data", 98 ProtocolVersion: 3, 99 RaftProtocol: 3, 100 NumSchedulers: helper.IntToPtr(2), 101 EnabledSchedulers: []string{"test"}, 102 NodeGCThreshold: "12h", 103 EvalGCThreshold: "12h", 104 JobGCInterval: "3m", 105 JobGCThreshold: "12h", 106 DeploymentGCThreshold: "12h", 107 CSIVolumeClaimGCThreshold: "12h", 108 CSIPluginGCThreshold: "12h", 109 HeartbeatGrace: 30 * time.Second, 110 HeartbeatGraceHCL: "30s", 111 MinHeartbeatTTL: 33 * time.Second, 112 MinHeartbeatTTLHCL: "33s", 113 MaxHeartbeatsPerSecond: 11.0, 114 RetryJoin: []string{"1.1.1.1", "2.2.2.2"}, 115 StartJoin: []string{"1.1.1.1", "2.2.2.2"}, 116 RetryInterval: 15 * time.Second, 117 RetryIntervalHCL: "15s", 118 RejoinAfterLeave: true, 119 RetryMaxAttempts: 3, 120 NonVotingServer: true, 121 RedundancyZone: "foo", 122 UpgradeVersion: "0.8.0", 123 EncryptKey: "abc", 124 ServerJoin: &ServerJoin{ 125 RetryJoin: []string{"1.1.1.1", "2.2.2.2"}, 126 RetryInterval: time.Duration(15) * time.Second, 127 RetryIntervalHCL: "15s", 128 RetryMaxAttempts: 3, 129 }, 130 DefaultSchedulerConfig: &structs.SchedulerConfiguration{ 131 SchedulerAlgorithm: "spread", 132 PreemptionConfig: structs.PreemptionConfig{ 133 SystemSchedulerEnabled: true, 134 BatchSchedulerEnabled: true, 135 ServiceSchedulerEnabled: true, 136 }, 137 }, 138 }, 139 ACL: &ACLConfig{ 140 Enabled: true, 141 TokenTTL: 60 * time.Second, 142 TokenTTLHCL: "60s", 143 PolicyTTL: 60 * time.Second, 144 PolicyTTLHCL: "60s", 145 ReplicationToken: "foobar", 146 }, 147 Audit: &config.AuditConfig{ 148 Enabled: helper.BoolToPtr(true), 149 Sinks: []*config.AuditSink{ 150 { 151 DeliveryGuarantee: "enforced", 152 Name: "file", 153 Type: "file", 154 Format: "json", 155 Path: "/opt/nomad/audit.log", 156 RotateDuration: 24 * time.Hour, 157 RotateDurationHCL: "24h", 158 RotateBytes: 100, 159 RotateMaxFiles: 10, 160 }, 161 }, 162 Filters: []*config.AuditFilter{ 163 { 164 Name: "default", 165 Type: "HTTPEvent", 166 Endpoints: []string{"/v1/metrics"}, 167 Stages: []string{"*"}, 168 Operations: []string{"*"}, 169 }, 170 }, 171 }, 172 Telemetry: &Telemetry{ 173 StatsiteAddr: "127.0.0.1:1234", 174 StatsdAddr: "127.0.0.1:2345", 175 PrometheusMetrics: true, 176 DisableHostname: true, 177 UseNodeName: false, 178 CollectionInterval: "3s", 179 collectionInterval: 3 * time.Second, 180 PublishAllocationMetrics: true, 181 PublishNodeMetrics: true, 182 DisableTaggedMetrics: true, 183 BackwardsCompatibleMetrics: true, 184 }, 185 LeaveOnInt: true, 186 LeaveOnTerm: true, 187 EnableSyslog: true, 188 SyslogFacility: "LOCAL1", 189 DisableUpdateCheck: helper.BoolToPtr(true), 190 DisableAnonymousSignature: true, 191 Consul: &config.ConsulConfig{ 192 ServerServiceName: "nomad", 193 ServerHTTPCheckName: "nomad-server-http-health-check", 194 ServerSerfCheckName: "nomad-server-serf-health-check", 195 ServerRPCCheckName: "nomad-server-rpc-health-check", 196 ClientServiceName: "nomad-client", 197 ClientHTTPCheckName: "nomad-client-http-health-check", 198 Addr: "127.0.0.1:9500", 199 AllowUnauthenticated: &trueValue, 200 Token: "token1", 201 Auth: "username:pass", 202 EnableSSL: &trueValue, 203 VerifySSL: &trueValue, 204 CAFile: "/path/to/ca/file", 205 CertFile: "/path/to/cert/file", 206 KeyFile: "/path/to/key/file", 207 ServerAutoJoin: &trueValue, 208 ClientAutoJoin: &trueValue, 209 AutoAdvertise: &trueValue, 210 ChecksUseAdvertise: &trueValue, 211 Timeout: 5 * time.Second, 212 }, 213 Vault: &config.VaultConfig{ 214 Addr: "127.0.0.1:9500", 215 AllowUnauthenticated: &trueValue, 216 ConnectionRetryIntv: config.DefaultVaultConnectRetryIntv, 217 Enabled: &falseValue, 218 Role: "test_role", 219 TLSCaFile: "/path/to/ca/file", 220 TLSCaPath: "/path/to/ca", 221 TLSCertFile: "/path/to/cert/file", 222 TLSKeyFile: "/path/to/key/file", 223 TLSServerName: "foobar", 224 TLSSkipVerify: &trueValue, 225 TaskTokenTTL: "1s", 226 Token: "12345", 227 }, 228 TLSConfig: &config.TLSConfig{ 229 EnableHTTP: true, 230 EnableRPC: true, 231 VerifyServerHostname: true, 232 CAFile: "foo", 233 CertFile: "bar", 234 KeyFile: "pipe", 235 RPCUpgradeMode: true, 236 VerifyHTTPSClient: true, 237 TLSPreferServerCipherSuites: true, 238 TLSCipherSuites: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 239 TLSMinVersion: "tls12", 240 }, 241 HTTPAPIResponseHeaders: map[string]string{ 242 "Access-Control-Allow-Origin": "*", 243 }, 244 Sentinel: &config.SentinelConfig{ 245 Imports: []*config.SentinelImport{ 246 { 247 Name: "foo", 248 Path: "foo", 249 Args: []string{"a", "b", "c"}, 250 }, 251 { 252 Name: "bar", 253 Path: "bar", 254 Args: []string{"x", "y", "z"}, 255 }, 256 }, 257 }, 258 Autopilot: &config.AutopilotConfig{ 259 CleanupDeadServers: &trueValue, 260 ServerStabilizationTime: 23057 * time.Second, 261 ServerStabilizationTimeHCL: "23057s", 262 LastContactThreshold: 12705 * time.Second, 263 LastContactThresholdHCL: "12705s", 264 MaxTrailingLogs: 17849, 265 MinQuorum: 3, 266 EnableRedundancyZones: &trueValue, 267 DisableUpgradeMigration: &trueValue, 268 EnableCustomUpgrades: &trueValue, 269 }, 270 Plugins: []*config.PluginConfig{ 271 { 272 Name: "docker", 273 Args: []string{"foo", "bar"}, 274 Config: map[string]interface{}{ 275 "foo": "bar", 276 "nested": []map[string]interface{}{ 277 { 278 "bam": 2, 279 }, 280 }, 281 }, 282 }, 283 { 284 Name: "exec", 285 Config: map[string]interface{}{ 286 "foo": true, 287 }, 288 }, 289 }, 290 } 291 292 var pluginConfig = &Config{ 293 Region: "", 294 Datacenter: "", 295 NodeName: "", 296 DataDir: "", 297 PluginDir: "", 298 LogLevel: "", 299 BindAddr: "", 300 EnableDebug: false, 301 Ports: nil, 302 Addresses: nil, 303 AdvertiseAddrs: nil, 304 Client: &ClientConfig{ 305 Enabled: false, 306 StateDir: "", 307 AllocDir: "", 308 Servers: nil, 309 NodeClass: "", 310 Meta: nil, 311 Options: nil, 312 ChrootEnv: nil, 313 NetworkInterface: "", 314 NetworkSpeed: 0, 315 CpuCompute: 0, 316 MemoryMB: 5555, 317 MaxKillTimeout: "", 318 ClientMinPort: 0, 319 ClientMaxPort: 0, 320 Reserved: nil, 321 GCInterval: 0, 322 GCParallelDestroys: 0, 323 GCDiskUsageThreshold: 0, 324 GCInodeUsageThreshold: 0, 325 GCMaxAllocs: 0, 326 NoHostUUID: nil, 327 }, 328 Server: nil, 329 ACL: nil, 330 Telemetry: nil, 331 LeaveOnInt: false, 332 LeaveOnTerm: false, 333 EnableSyslog: false, 334 SyslogFacility: "", 335 DisableUpdateCheck: nil, 336 DisableAnonymousSignature: false, 337 Consul: nil, 338 Vault: nil, 339 TLSConfig: nil, 340 HTTPAPIResponseHeaders: map[string]string{}, 341 Sentinel: nil, 342 Plugins: []*config.PluginConfig{ 343 { 344 Name: "docker", 345 Config: map[string]interface{}{ 346 "allow_privileged": true, 347 }, 348 }, 349 { 350 Name: "raw_exec", 351 Config: map[string]interface{}{ 352 "enabled": true, 353 }, 354 }, 355 }, 356 } 357 358 var nonoptConfig = &Config{ 359 Region: "", 360 Datacenter: "", 361 NodeName: "", 362 DataDir: "", 363 PluginDir: "", 364 LogLevel: "", 365 BindAddr: "", 366 EnableDebug: false, 367 Ports: nil, 368 Addresses: nil, 369 AdvertiseAddrs: nil, 370 Client: &ClientConfig{ 371 Enabled: false, 372 StateDir: "", 373 AllocDir: "", 374 Servers: nil, 375 NodeClass: "", 376 Meta: nil, 377 Options: nil, 378 ChrootEnv: nil, 379 NetworkInterface: "", 380 NetworkSpeed: 0, 381 CpuCompute: 0, 382 MemoryMB: 5555, 383 MaxKillTimeout: "", 384 ClientMinPort: 0, 385 ClientMaxPort: 0, 386 Reserved: nil, 387 GCInterval: 0, 388 GCParallelDestroys: 0, 389 GCDiskUsageThreshold: 0, 390 GCInodeUsageThreshold: 0, 391 GCMaxAllocs: 0, 392 NoHostUUID: nil, 393 }, 394 Server: nil, 395 ACL: nil, 396 Telemetry: nil, 397 LeaveOnInt: false, 398 LeaveOnTerm: false, 399 EnableSyslog: false, 400 SyslogFacility: "", 401 DisableUpdateCheck: nil, 402 DisableAnonymousSignature: false, 403 Consul: nil, 404 Vault: nil, 405 TLSConfig: nil, 406 HTTPAPIResponseHeaders: map[string]string{}, 407 Sentinel: nil, 408 } 409 410 func TestConfig_ParseMerge(t *testing.T) { 411 t.Parallel() 412 413 path, err := filepath.Abs(filepath.Join(".", "testdata", "basic.hcl")) 414 require.NoError(t, err) 415 416 actual, err := ParseConfigFile(path) 417 require.NoError(t, err) 418 419 require.Equal(t, basicConfig.Client, actual.Client) 420 421 oldDefault := &Config{ 422 Consul: config.DefaultConsulConfig(), 423 Vault: config.DefaultVaultConfig(), 424 Autopilot: config.DefaultAutopilotConfig(), 425 Client: &ClientConfig{}, 426 Server: &ServerConfig{}, 427 Audit: &config.AuditConfig{}, 428 } 429 merged := oldDefault.Merge(actual) 430 require.Equal(t, basicConfig.Client, merged.Client) 431 432 } 433 434 func TestConfig_Parse(t *testing.T) { 435 t.Parallel() 436 437 basicConfig.addDefaults() 438 pluginConfig.addDefaults() 439 nonoptConfig.addDefaults() 440 441 cases := []struct { 442 File string 443 Result *Config 444 Err bool 445 }{ 446 { 447 "basic.hcl", 448 basicConfig, 449 false, 450 }, 451 { 452 "basic.json", 453 basicConfig, 454 false, 455 }, 456 { 457 "plugin.hcl", 458 pluginConfig, 459 false, 460 }, 461 { 462 "plugin.json", 463 pluginConfig, 464 false, 465 }, 466 { 467 "non-optional.hcl", 468 nonoptConfig, 469 false, 470 }, 471 } 472 473 for _, tc := range cases { 474 t.Run(tc.File, func(t *testing.T) { 475 require := require.New(t) 476 path, err := filepath.Abs(filepath.Join("./testdata", tc.File)) 477 require.NoError(err) 478 479 actual, err := ParseConfigFile(path) 480 require.NoError(err) 481 482 // ParseConfig used to re-merge defaults for these three objects, 483 // despite them already being merged in LoadConfig. The test structs 484 // expect these defaults to be set, but not the DefaultConfig 485 // defaults, which include additional settings 486 oldDefault := &Config{ 487 Consul: config.DefaultConsulConfig(), 488 Vault: config.DefaultVaultConfig(), 489 Autopilot: config.DefaultAutopilotConfig(), 490 } 491 actual = oldDefault.Merge(actual) 492 493 //panic(fmt.Sprintf("first: %+v \n second: %+v", actual.TLSConfig, tc.Result.TLSConfig)) 494 require.EqualValues(tc.Result, removeHelperAttributes(actual)) 495 }) 496 } 497 } 498 499 // In order to compare the Config struct after parsing, and from generating what 500 // is expected in the test, we need to remove helper attributes that are 501 // instantiated in the process of parsing the configuration 502 func removeHelperAttributes(c *Config) *Config { 503 if c.TLSConfig != nil { 504 c.TLSConfig.KeyLoader = nil 505 } 506 return c 507 } 508 509 func (c *Config) addDefaults() { 510 if c.Client == nil { 511 c.Client = &ClientConfig{} 512 } 513 if c.Client.ServerJoin == nil { 514 c.Client.ServerJoin = &ServerJoin{} 515 } 516 if c.ACL == nil { 517 c.ACL = &ACLConfig{} 518 } 519 if c.Audit == nil { 520 c.Audit = &config.AuditConfig{} 521 } 522 if c.Consul == nil { 523 c.Consul = config.DefaultConsulConfig() 524 } 525 if c.Autopilot == nil { 526 c.Autopilot = config.DefaultAutopilotConfig() 527 } 528 if c.Vault == nil { 529 c.Vault = config.DefaultVaultConfig() 530 } 531 if c.Telemetry == nil { 532 c.Telemetry = &Telemetry{} 533 } 534 if c.Server == nil { 535 c.Server = &ServerConfig{} 536 } 537 if c.Server.ServerJoin == nil { 538 c.Server.ServerJoin = &ServerJoin{} 539 } 540 } 541 542 // Tests for a panic parsing json with an object of exactly 543 // length 1 described in 544 // https://github.com/hashicorp/nomad/issues/1290 545 func TestConfig_ParsePanic(t *testing.T) { 546 c, err := ParseConfigFile("./testdata/obj-len-one.hcl") 547 if err != nil { 548 t.Fatalf("parse error: %s\n", err) 549 } 550 551 d, err := ParseConfigFile("./testdata/obj-len-one.json") 552 if err != nil { 553 t.Fatalf("parse error: %s\n", err) 554 } 555 556 require.EqualValues(t, c, d) 557 } 558 559 // Top level keys left by hcl when parsing slices in the config 560 // structure should not be unexpected 561 func TestConfig_ParseSliceExtra(t *testing.T) { 562 c, err := ParseConfigFile("./testdata/config-slices.json") 563 require.NoError(t, err) 564 565 opt := map[string]string{"o0": "foo", "o1": "bar"} 566 meta := map[string]string{"m0": "foo", "m1": "bar", "m2": "true", "m3": "1.2"} 567 env := map[string]string{"e0": "baz"} 568 srv := []string{"foo", "bar"} 569 570 require.EqualValues(t, opt, c.Client.Options) 571 require.EqualValues(t, meta, c.Client.Meta) 572 require.EqualValues(t, env, c.Client.ChrootEnv) 573 require.EqualValues(t, srv, c.Client.Servers) 574 require.EqualValues(t, srv, c.Server.EnabledSchedulers) 575 require.EqualValues(t, srv, c.Server.StartJoin) 576 require.EqualValues(t, srv, c.Server.RetryJoin) 577 578 // the alt format is also accepted by hcl as valid config data 579 c, err = ParseConfigFile("./testdata/config-slices-alt.json") 580 require.NoError(t, err) 581 582 require.EqualValues(t, opt, c.Client.Options) 583 require.EqualValues(t, meta, c.Client.Meta) 584 require.EqualValues(t, env, c.Client.ChrootEnv) 585 require.EqualValues(t, srv, c.Client.Servers) 586 require.EqualValues(t, srv, c.Server.EnabledSchedulers) 587 require.EqualValues(t, srv, c.Server.StartJoin) 588 require.EqualValues(t, srv, c.Server.RetryJoin) 589 590 // small files keep more extra keys than large ones 591 _, err = ParseConfigFile("./testdata/obj-len-one-server.json") 592 require.NoError(t, err) 593 } 594 595 var sample0 = &Config{ 596 Region: "global", 597 Datacenter: "dc1", 598 DataDir: "/opt/data/nomad/data", 599 LogLevel: "INFO", 600 BindAddr: "0.0.0.0", 601 AdvertiseAddrs: &AdvertiseAddrs{ 602 HTTP: "host.example.com", 603 RPC: "host.example.com", 604 Serf: "host.example.com", 605 }, 606 Client: &ClientConfig{ServerJoin: &ServerJoin{}}, 607 Server: &ServerConfig{ 608 Enabled: true, 609 BootstrapExpect: 3, 610 RetryJoin: []string{"10.0.0.101", "10.0.0.102", "10.0.0.103"}, 611 EncryptKey: "sHck3WL6cxuhuY7Mso9BHA==", 612 ServerJoin: &ServerJoin{}, 613 }, 614 ACL: &ACLConfig{ 615 Enabled: true, 616 }, 617 Audit: &config.AuditConfig{ 618 Enabled: helper.BoolToPtr(true), 619 Sinks: []*config.AuditSink{ 620 { 621 DeliveryGuarantee: "enforced", 622 Name: "file", 623 Type: "file", 624 Format: "json", 625 Path: "/opt/nomad/audit.log", 626 RotateDuration: 24 * time.Hour, 627 RotateDurationHCL: "24h", 628 RotateBytes: 100, 629 RotateMaxFiles: 10, 630 }, 631 }, 632 Filters: []*config.AuditFilter{ 633 { 634 Name: "default", 635 Type: "HTTPEvent", 636 Endpoints: []string{"/v1/metrics"}, 637 Stages: []string{"*"}, 638 Operations: []string{"*"}, 639 }, 640 }, 641 }, 642 Telemetry: &Telemetry{ 643 PrometheusMetrics: true, 644 DisableHostname: true, 645 CollectionInterval: "60s", 646 collectionInterval: 60 * time.Second, 647 PublishAllocationMetrics: true, 648 PublishNodeMetrics: true, 649 }, 650 LeaveOnInt: true, 651 LeaveOnTerm: true, 652 EnableSyslog: true, 653 SyslogFacility: "LOCAL0", 654 Consul: &config.ConsulConfig{ 655 Token: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", 656 ServerAutoJoin: helper.BoolToPtr(false), 657 ClientAutoJoin: helper.BoolToPtr(false), 658 }, 659 Vault: &config.VaultConfig{ 660 Enabled: helper.BoolToPtr(true), 661 Role: "nomad-cluster", 662 Addr: "http://host.example.com:8200", 663 }, 664 TLSConfig: &config.TLSConfig{ 665 EnableHTTP: true, 666 EnableRPC: true, 667 VerifyServerHostname: true, 668 CAFile: "/opt/data/nomad/certs/nomad-ca.pem", 669 CertFile: "/opt/data/nomad/certs/server.pem", 670 KeyFile: "/opt/data/nomad/certs/server-key.pem", 671 }, 672 Autopilot: &config.AutopilotConfig{ 673 CleanupDeadServers: helper.BoolToPtr(true), 674 }, 675 } 676 677 func TestConfig_ParseSample0(t *testing.T) { 678 c, err := ParseConfigFile("./testdata/sample0.json") 679 require.NoError(t, err) 680 require.EqualValues(t, sample0, c) 681 } 682 683 var sample1 = &Config{ 684 Region: "global", 685 Datacenter: "dc1", 686 DataDir: "/opt/data/nomad/data", 687 LogLevel: "INFO", 688 BindAddr: "0.0.0.0", 689 AdvertiseAddrs: &AdvertiseAddrs{ 690 HTTP: "host.example.com", 691 RPC: "host.example.com", 692 Serf: "host.example.com", 693 }, 694 Client: &ClientConfig{ServerJoin: &ServerJoin{}}, 695 Server: &ServerConfig{ 696 Enabled: true, 697 BootstrapExpect: 3, 698 RetryJoin: []string{"10.0.0.101", "10.0.0.102", "10.0.0.103"}, 699 EncryptKey: "sHck3WL6cxuhuY7Mso9BHA==", 700 ServerJoin: &ServerJoin{}, 701 }, 702 ACL: &ACLConfig{ 703 Enabled: true, 704 }, 705 Audit: &config.AuditConfig{ 706 Enabled: helper.BoolToPtr(true), 707 Sinks: []*config.AuditSink{ 708 { 709 Name: "file", 710 Type: "file", 711 DeliveryGuarantee: "enforced", 712 Format: "json", 713 Path: "/opt/nomad/audit.log", 714 RotateDuration: 24 * time.Hour, 715 RotateDurationHCL: "24h", 716 RotateBytes: 100, 717 RotateMaxFiles: 10, 718 }, 719 }, 720 Filters: []*config.AuditFilter{ 721 { 722 Name: "default", 723 Type: "HTTPEvent", 724 Endpoints: []string{"/v1/metrics"}, 725 Stages: []string{"*"}, 726 Operations: []string{"*"}, 727 }, 728 }, 729 }, 730 Telemetry: &Telemetry{ 731 PrometheusMetrics: true, 732 DisableHostname: true, 733 CollectionInterval: "60s", 734 collectionInterval: 60 * time.Second, 735 PublishAllocationMetrics: true, 736 PublishNodeMetrics: true, 737 }, 738 LeaveOnInt: true, 739 LeaveOnTerm: true, 740 EnableSyslog: true, 741 SyslogFacility: "LOCAL0", 742 Consul: &config.ConsulConfig{ 743 EnableSSL: helper.BoolToPtr(true), 744 Token: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", 745 ServerAutoJoin: helper.BoolToPtr(false), 746 ClientAutoJoin: helper.BoolToPtr(false), 747 }, 748 Vault: &config.VaultConfig{ 749 Enabled: helper.BoolToPtr(true), 750 Role: "nomad-cluster", 751 Addr: "http://host.example.com:8200", 752 }, 753 TLSConfig: &config.TLSConfig{ 754 EnableHTTP: true, 755 EnableRPC: true, 756 VerifyServerHostname: true, 757 CAFile: "/opt/data/nomad/certs/nomad-ca.pem", 758 CertFile: "/opt/data/nomad/certs/server.pem", 759 KeyFile: "/opt/data/nomad/certs/server-key.pem", 760 }, 761 Autopilot: &config.AutopilotConfig{ 762 CleanupDeadServers: helper.BoolToPtr(true), 763 }, 764 } 765 766 func TestConfig_ParseDir(t *testing.T) { 767 c, err := LoadConfig("./testdata/sample1") 768 require.NoError(t, err) 769 770 // LoadConfig Merges all the config files in testdata/sample1, which makes empty 771 // maps & slices rather than nil, so set those 772 require.Empty(t, c.Client.Options) 773 c.Client.Options = nil 774 require.Empty(t, c.Client.Meta) 775 c.Client.Meta = nil 776 require.Empty(t, c.Client.ChrootEnv) 777 c.Client.ChrootEnv = nil 778 require.Empty(t, c.Server.StartJoin) 779 c.Server.StartJoin = nil 780 require.Empty(t, c.HTTPAPIResponseHeaders) 781 c.HTTPAPIResponseHeaders = nil 782 783 // LoadDir lists the config files 784 expectedFiles := []string{ 785 "testdata/sample1/sample0.json", 786 "testdata/sample1/sample1.json", 787 "testdata/sample1/sample2.hcl", 788 } 789 require.Equal(t, expectedFiles, c.Files) 790 c.Files = nil 791 792 require.EqualValues(t, sample1, c) 793 } 794 795 // TestConfig_ParseDir_Matches_IndividualParsing asserts 796 // that parsing a directory config is the equivalent of 797 // parsing individual files in any order 798 func TestConfig_ParseDir_Matches_IndividualParsing(t *testing.T) { 799 dirConfig, err := LoadConfig("./testdata/sample1") 800 require.NoError(t, err) 801 802 dirConfig = DefaultConfig().Merge(dirConfig) 803 804 files := []string{ 805 "testdata/sample1/sample0.json", 806 "testdata/sample1/sample1.json", 807 "testdata/sample1/sample2.hcl", 808 } 809 810 for _, perm := range permutations(files) { 811 t.Run(fmt.Sprintf("permutation %v", perm), func(t *testing.T) { 812 config := DefaultConfig() 813 814 for _, f := range perm { 815 fc, err := LoadConfig(f) 816 require.NoError(t, err) 817 818 config = config.Merge(fc) 819 } 820 821 // sort files to get stable view 822 sort.Strings(config.Files) 823 sort.Strings(dirConfig.Files) 824 825 require.EqualValues(t, dirConfig, config) 826 }) 827 } 828 829 } 830 831 // https://stackoverflow.com/a/30226442 832 func permutations(arr []string) [][]string { 833 var helper func([]string, int) 834 res := [][]string{} 835 836 helper = func(arr []string, n int) { 837 if n == 1 { 838 tmp := make([]string, len(arr)) 839 copy(tmp, arr) 840 res = append(res, tmp) 841 } else { 842 for i := 0; i < n; i++ { 843 helper(arr, n-1) 844 if n%2 == 1 { 845 tmp := arr[i] 846 arr[i] = arr[n-1] 847 arr[n-1] = tmp 848 } else { 849 tmp := arr[0] 850 arr[0] = arr[n-1] 851 arr[n-1] = tmp 852 } 853 } 854 } 855 } 856 helper(arr, len(arr)) 857 return res 858 }