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