github.com/quite/nomad@v0.8.6/command/agent/config_parse.go (about) 1 package agent 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "os" 8 "path/filepath" 9 "time" 10 11 multierror "github.com/hashicorp/go-multierror" 12 "github.com/hashicorp/go-version" 13 "github.com/hashicorp/hcl" 14 "github.com/hashicorp/hcl/hcl/ast" 15 "github.com/hashicorp/nomad/helper" 16 "github.com/hashicorp/nomad/helper/tlsutil" 17 "github.com/hashicorp/nomad/nomad/structs/config" 18 "github.com/mitchellh/mapstructure" 19 ) 20 21 // ParseConfigFile parses the given path as a config file. 22 func ParseConfigFile(path string) (*Config, error) { 23 path, err := filepath.Abs(path) 24 if err != nil { 25 return nil, err 26 } 27 28 f, err := os.Open(path) 29 if err != nil { 30 return nil, err 31 } 32 defer f.Close() 33 34 config, err := ParseConfig(f) 35 if err != nil { 36 return nil, err 37 } 38 39 return config, nil 40 } 41 42 // ParseConfig parses the config from the given io.Reader. 43 // 44 // Due to current internal limitations, the entire contents of the 45 // io.Reader will be copied into memory first before parsing. 46 func ParseConfig(r io.Reader) (*Config, error) { 47 // Copy the reader into an in-memory buffer first since HCL requires it. 48 var buf bytes.Buffer 49 if _, err := io.Copy(&buf, r); err != nil { 50 return nil, err 51 } 52 53 // Parse the buffer 54 root, err := hcl.Parse(buf.String()) 55 if err != nil { 56 return nil, fmt.Errorf("error parsing: %s", err) 57 } 58 buf.Reset() 59 60 // Top-level item should be a list 61 list, ok := root.Node.(*ast.ObjectList) 62 if !ok { 63 return nil, fmt.Errorf("error parsing: root should be an object") 64 } 65 66 var config Config 67 if err := parseConfig(&config, list); err != nil { 68 return nil, fmt.Errorf("error parsing 'config': %v", err) 69 } 70 71 return &config, nil 72 } 73 74 func parseConfig(result *Config, list *ast.ObjectList) error { 75 // Check for invalid keys 76 valid := []string{ 77 "region", 78 "datacenter", 79 "name", 80 "data_dir", 81 "log_level", 82 "bind_addr", 83 "enable_debug", 84 "ports", 85 "addresses", 86 "interfaces", 87 "advertise", 88 "client", 89 "server", 90 "telemetry", 91 "leave_on_interrupt", 92 "leave_on_terminate", 93 "enable_syslog", 94 "syslog_facility", 95 "disable_update_check", 96 "disable_anonymous_signature", 97 "consul", 98 "vault", 99 "tls", 100 "http_api_response_headers", 101 "acl", 102 "sentinel", 103 "autopilot", 104 } 105 if err := helper.CheckHCLKeys(list, valid); err != nil { 106 return multierror.Prefix(err, "config:") 107 } 108 109 // Decode the full thing into a map[string]interface for ease 110 var m map[string]interface{} 111 if err := hcl.DecodeObject(&m, list); err != nil { 112 return err 113 } 114 delete(m, "ports") 115 delete(m, "addresses") 116 delete(m, "interfaces") 117 delete(m, "advertise") 118 delete(m, "client") 119 delete(m, "server") 120 delete(m, "telemetry") 121 delete(m, "consul") 122 delete(m, "vault") 123 delete(m, "tls") 124 delete(m, "http_api_response_headers") 125 delete(m, "acl") 126 delete(m, "sentinel") 127 delete(m, "autopilot") 128 129 // Decode the rest 130 if err := mapstructure.WeakDecode(m, result); err != nil { 131 return err 132 } 133 134 // Parse ports 135 if o := list.Filter("ports"); len(o.Items) > 0 { 136 if err := parsePorts(&result.Ports, o); err != nil { 137 return multierror.Prefix(err, "ports ->") 138 } 139 } 140 141 // Parse addresses 142 if o := list.Filter("addresses"); len(o.Items) > 0 { 143 if err := parseAddresses(&result.Addresses, o); err != nil { 144 return multierror.Prefix(err, "addresses ->") 145 } 146 } 147 148 // Parse advertise 149 if o := list.Filter("advertise"); len(o.Items) > 0 { 150 if err := parseAdvertise(&result.AdvertiseAddrs, o); err != nil { 151 return multierror.Prefix(err, "advertise ->") 152 } 153 } 154 155 // Parse client config 156 if o := list.Filter("client"); len(o.Items) > 0 { 157 if err := parseClient(&result.Client, o); err != nil { 158 return multierror.Prefix(err, "client ->") 159 } 160 } 161 162 // Parse server config 163 if o := list.Filter("server"); len(o.Items) > 0 { 164 if err := parseServer(&result.Server, o); err != nil { 165 return multierror.Prefix(err, "server ->") 166 } 167 } 168 169 // Parse ACL config 170 if o := list.Filter("acl"); len(o.Items) > 0 { 171 if err := parseACL(&result.ACL, o); err != nil { 172 return multierror.Prefix(err, "acl ->") 173 } 174 } 175 176 // Parse telemetry config 177 if o := list.Filter("telemetry"); len(o.Items) > 0 { 178 if err := parseTelemetry(&result.Telemetry, o); err != nil { 179 return multierror.Prefix(err, "telemetry ->") 180 } 181 } 182 183 // Parse the consul config 184 if o := list.Filter("consul"); len(o.Items) > 0 { 185 if err := parseConsulConfig(&result.Consul, o); err != nil { 186 return multierror.Prefix(err, "consul ->") 187 } 188 } 189 190 // Parse the vault config 191 if o := list.Filter("vault"); len(o.Items) > 0 { 192 if err := parseVaultConfig(&result.Vault, o); err != nil { 193 return multierror.Prefix(err, "vault ->") 194 } 195 } 196 197 // Parse the TLS config 198 if o := list.Filter("tls"); len(o.Items) > 0 { 199 if err := parseTLSConfig(&result.TLSConfig, o); err != nil { 200 return multierror.Prefix(err, "tls ->") 201 } 202 } 203 204 // Parse Sentinel config 205 if o := list.Filter("sentinel"); len(o.Items) > 0 { 206 if err := parseSentinel(&result.Sentinel, o); err != nil { 207 return multierror.Prefix(err, "sentinel->") 208 } 209 } 210 211 // Parse Autopilot config 212 if o := list.Filter("autopilot"); len(o.Items) > 0 { 213 if err := parseAutopilot(&result.Autopilot, o); err != nil { 214 return multierror.Prefix(err, "autopilot->") 215 } 216 } 217 218 // Parse out http_api_response_headers fields. These are in HCL as a list so 219 // we need to iterate over them and merge them. 220 if headersO := list.Filter("http_api_response_headers"); len(headersO.Items) > 0 { 221 for _, o := range headersO.Elem().Items { 222 var m map[string]interface{} 223 if err := hcl.DecodeObject(&m, o.Val); err != nil { 224 return err 225 } 226 if err := mapstructure.WeakDecode(m, &result.HTTPAPIResponseHeaders); err != nil { 227 return err 228 } 229 } 230 } 231 232 return nil 233 } 234 235 func parsePorts(result **Ports, list *ast.ObjectList) error { 236 list = list.Elem() 237 if len(list.Items) > 1 { 238 return fmt.Errorf("only one 'ports' block allowed") 239 } 240 241 // Get our ports object 242 listVal := list.Items[0].Val 243 244 // Check for invalid keys 245 valid := []string{ 246 "http", 247 "rpc", 248 "serf", 249 } 250 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 251 return err 252 } 253 254 var m map[string]interface{} 255 if err := hcl.DecodeObject(&m, listVal); err != nil { 256 return err 257 } 258 259 var ports Ports 260 if err := mapstructure.WeakDecode(m, &ports); err != nil { 261 return err 262 } 263 *result = &ports 264 return nil 265 } 266 267 func parseAddresses(result **Addresses, list *ast.ObjectList) error { 268 list = list.Elem() 269 if len(list.Items) > 1 { 270 return fmt.Errorf("only one 'addresses' block allowed") 271 } 272 273 // Get our addresses object 274 listVal := list.Items[0].Val 275 276 // Check for invalid keys 277 valid := []string{ 278 "http", 279 "rpc", 280 "serf", 281 } 282 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 283 return err 284 } 285 286 var m map[string]interface{} 287 if err := hcl.DecodeObject(&m, listVal); err != nil { 288 return err 289 } 290 291 var addresses Addresses 292 if err := mapstructure.WeakDecode(m, &addresses); err != nil { 293 return err 294 } 295 *result = &addresses 296 return nil 297 } 298 299 func parseAdvertise(result **AdvertiseAddrs, list *ast.ObjectList) error { 300 list = list.Elem() 301 if len(list.Items) > 1 { 302 return fmt.Errorf("only one 'advertise' block allowed") 303 } 304 305 // Get our advertise object 306 listVal := list.Items[0].Val 307 308 // Check for invalid keys 309 valid := []string{ 310 "http", 311 "rpc", 312 "serf", 313 } 314 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 315 return err 316 } 317 318 var m map[string]interface{} 319 if err := hcl.DecodeObject(&m, listVal); err != nil { 320 return err 321 } 322 323 var advertise AdvertiseAddrs 324 if err := mapstructure.WeakDecode(m, &advertise); err != nil { 325 return err 326 } 327 *result = &advertise 328 return nil 329 } 330 331 func parseClient(result **ClientConfig, list *ast.ObjectList) error { 332 list = list.Elem() 333 if len(list.Items) > 1 { 334 return fmt.Errorf("only one 'client' block allowed") 335 } 336 337 // Get our client object 338 obj := list.Items[0] 339 340 // Value should be an object 341 var listVal *ast.ObjectList 342 if ot, ok := obj.Val.(*ast.ObjectType); ok { 343 listVal = ot.List 344 } else { 345 return fmt.Errorf("client value: should be an object") 346 } 347 348 // Check for invalid keys 349 valid := []string{ 350 "enabled", 351 "state_dir", 352 "alloc_dir", 353 "servers", 354 "node_class", 355 "options", 356 "meta", 357 "chroot_env", 358 "network_interface", 359 "network_speed", 360 "memory_total_mb", 361 "cpu_total_compute", 362 "max_kill_timeout", 363 "client_max_port", 364 "client_min_port", 365 "reserved", 366 "stats", 367 "gc_interval", 368 "gc_disk_usage_threshold", 369 "gc_inode_usage_threshold", 370 "gc_parallel_destroys", 371 "gc_max_allocs", 372 "no_host_uuid", 373 "server_join", 374 } 375 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 376 return err 377 } 378 379 var m map[string]interface{} 380 if err := hcl.DecodeObject(&m, listVal); err != nil { 381 return err 382 } 383 384 delete(m, "options") 385 delete(m, "meta") 386 delete(m, "chroot_env") 387 delete(m, "reserved") 388 delete(m, "stats") 389 delete(m, "server_join") 390 391 var config ClientConfig 392 dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ 393 DecodeHook: mapstructure.StringToTimeDurationHookFunc(), 394 WeaklyTypedInput: true, 395 Result: &config, 396 }) 397 if err != nil { 398 return err 399 } 400 if err := dec.Decode(m); err != nil { 401 return err 402 } 403 404 // Parse out options fields. These are in HCL as a list so we need to 405 // iterate over them and merge them. 406 if optionsO := listVal.Filter("options"); len(optionsO.Items) > 0 { 407 for _, o := range optionsO.Elem().Items { 408 var m map[string]interface{} 409 if err := hcl.DecodeObject(&m, o.Val); err != nil { 410 return err 411 } 412 if err := mapstructure.WeakDecode(m, &config.Options); err != nil { 413 return err 414 } 415 } 416 } 417 418 // Parse out options meta. These are in HCL as a list so we need to 419 // iterate over them and merge them. 420 if metaO := listVal.Filter("meta"); len(metaO.Items) > 0 { 421 for _, o := range metaO.Elem().Items { 422 var m map[string]interface{} 423 if err := hcl.DecodeObject(&m, o.Val); err != nil { 424 return err 425 } 426 if err := mapstructure.WeakDecode(m, &config.Meta); err != nil { 427 return err 428 } 429 } 430 } 431 432 // Parse out chroot_env fields. These are in HCL as a list so we need to 433 // iterate over them and merge them. 434 if chrootEnvO := listVal.Filter("chroot_env"); len(chrootEnvO.Items) > 0 { 435 for _, o := range chrootEnvO.Elem().Items { 436 var m map[string]interface{} 437 if err := hcl.DecodeObject(&m, o.Val); err != nil { 438 return err 439 } 440 if err := mapstructure.WeakDecode(m, &config.ChrootEnv); err != nil { 441 return err 442 } 443 } 444 } 445 446 // Parse reserved config 447 if o := listVal.Filter("reserved"); len(o.Items) > 0 { 448 if err := parseReserved(&config.Reserved, o); err != nil { 449 return multierror.Prefix(err, "reserved ->") 450 } 451 } 452 453 // Parse ServerJoin config 454 if o := listVal.Filter("server_join"); len(o.Items) > 0 { 455 if err := parseServerJoin(&config.ServerJoin, o); err != nil { 456 return multierror.Prefix(err, "server_join->") 457 } 458 } 459 460 *result = &config 461 return nil 462 } 463 464 func parseReserved(result **Resources, list *ast.ObjectList) error { 465 list = list.Elem() 466 if len(list.Items) > 1 { 467 return fmt.Errorf("only one 'reserved' block allowed") 468 } 469 470 // Get our reserved object 471 obj := list.Items[0] 472 473 // Value should be an object 474 var listVal *ast.ObjectList 475 if ot, ok := obj.Val.(*ast.ObjectType); ok { 476 listVal = ot.List 477 } else { 478 return fmt.Errorf("client value: should be an object") 479 } 480 481 // Check for invalid keys 482 valid := []string{ 483 "cpu", 484 "memory", 485 "disk", 486 "iops", 487 "reserved_ports", 488 } 489 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 490 return err 491 } 492 493 var m map[string]interface{} 494 if err := hcl.DecodeObject(&m, listVal); err != nil { 495 return err 496 } 497 498 var reserved Resources 499 if err := mapstructure.WeakDecode(m, &reserved); err != nil { 500 return err 501 } 502 if err := reserved.ParseReserved(); err != nil { 503 return err 504 } 505 506 *result = &reserved 507 return nil 508 } 509 510 func parseServer(result **ServerConfig, list *ast.ObjectList) error { 511 list = list.Elem() 512 if len(list.Items) > 1 { 513 return fmt.Errorf("only one 'server' block allowed") 514 } 515 516 // Get our server object 517 obj := list.Items[0] 518 519 // Value should be an object 520 var listVal *ast.ObjectList 521 if ot, ok := obj.Val.(*ast.ObjectType); ok { 522 listVal = ot.List 523 } else { 524 return fmt.Errorf("client value: should be an object") 525 } 526 527 // Check for invalid keys 528 valid := []string{ 529 "enabled", 530 "bootstrap_expect", 531 "data_dir", 532 "protocol_version", 533 "raft_protocol", 534 "num_schedulers", 535 "enabled_schedulers", 536 "node_gc_threshold", 537 "eval_gc_threshold", 538 "job_gc_threshold", 539 "deployment_gc_threshold", 540 "heartbeat_grace", 541 "min_heartbeat_ttl", 542 "max_heartbeats_per_second", 543 "rejoin_after_leave", 544 "encrypt", 545 "authoritative_region", 546 "non_voting_server", 547 "redundancy_zone", 548 "upgrade_version", 549 550 "server_join", 551 552 // For backwards compatibility 553 "start_join", 554 "retry_join", 555 "retry_max", 556 "retry_interval", 557 } 558 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 559 return err 560 } 561 562 var m map[string]interface{} 563 if err := hcl.DecodeObject(&m, listVal); err != nil { 564 return err 565 } 566 567 delete(m, "server_join") 568 569 var config ServerConfig 570 dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ 571 DecodeHook: mapstructure.StringToTimeDurationHookFunc(), 572 WeaklyTypedInput: true, 573 Result: &config, 574 }) 575 if err != nil { 576 return err 577 } 578 if err := dec.Decode(m); err != nil { 579 return err 580 } 581 582 if config.UpgradeVersion != "" { 583 if _, err := version.NewVersion(config.UpgradeVersion); err != nil { 584 return fmt.Errorf("error parsing upgrade_version: %v", err) 585 } 586 } 587 588 // Parse ServerJoin config 589 if o := listVal.Filter("server_join"); len(o.Items) > 0 { 590 if err := parseServerJoin(&config.ServerJoin, o); err != nil { 591 return multierror.Prefix(err, "server_join->") 592 } 593 } 594 595 *result = &config 596 return nil 597 } 598 599 func parseServerJoin(result **ServerJoin, list *ast.ObjectList) error { 600 list = list.Elem() 601 if len(list.Items) > 1 { 602 return fmt.Errorf("only one 'server_join' block allowed") 603 } 604 605 // Get our object 606 listVal := list.Items[0].Val 607 608 // Check for invalid keys 609 valid := []string{ 610 "start_join", 611 "retry_join", 612 "retry_max", 613 "retry_interval", 614 } 615 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 616 return err 617 } 618 619 var m map[string]interface{} 620 if err := hcl.DecodeObject(&m, listVal); err != nil { 621 return err 622 } 623 624 var serverJoinInfo ServerJoin 625 dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ 626 DecodeHook: mapstructure.StringToTimeDurationHookFunc(), 627 WeaklyTypedInput: true, 628 Result: &serverJoinInfo, 629 }) 630 if err != nil { 631 return err 632 } 633 if err := dec.Decode(m); err != nil { 634 return err 635 } 636 637 *result = &serverJoinInfo 638 return nil 639 } 640 641 func parseACL(result **ACLConfig, list *ast.ObjectList) error { 642 list = list.Elem() 643 if len(list.Items) > 1 { 644 return fmt.Errorf("only one 'acl' block allowed") 645 } 646 647 // Get our server object 648 obj := list.Items[0] 649 650 // Value should be an object 651 var listVal *ast.ObjectList 652 if ot, ok := obj.Val.(*ast.ObjectType); ok { 653 listVal = ot.List 654 } else { 655 return fmt.Errorf("acl value: should be an object") 656 } 657 658 // Check for invalid keys 659 valid := []string{ 660 "enabled", 661 "token_ttl", 662 "policy_ttl", 663 "replication_token", 664 } 665 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 666 return err 667 } 668 669 var m map[string]interface{} 670 if err := hcl.DecodeObject(&m, listVal); err != nil { 671 return err 672 } 673 674 var config ACLConfig 675 dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ 676 DecodeHook: mapstructure.StringToTimeDurationHookFunc(), 677 WeaklyTypedInput: true, 678 Result: &config, 679 }) 680 if err != nil { 681 return err 682 } 683 if err := dec.Decode(m); err != nil { 684 return err 685 } 686 687 *result = &config 688 return nil 689 } 690 691 func parseTelemetry(result **Telemetry, list *ast.ObjectList) error { 692 list = list.Elem() 693 if len(list.Items) > 1 { 694 return fmt.Errorf("only one 'telemetry' block allowed") 695 } 696 697 // Get our telemetry object 698 listVal := list.Items[0].Val 699 700 // Check for invalid keys 701 valid := []string{ 702 "statsite_address", 703 "statsd_address", 704 "disable_hostname", 705 "use_node_name", 706 "collection_interval", 707 "publish_allocation_metrics", 708 "publish_node_metrics", 709 "datadog_address", 710 "datadog_tags", 711 "prometheus_metrics", 712 "circonus_api_token", 713 "circonus_api_app", 714 "circonus_api_url", 715 "circonus_submission_interval", 716 "circonus_submission_url", 717 "circonus_check_id", 718 "circonus_check_force_metric_activation", 719 "circonus_check_instance_id", 720 "circonus_check_search_tag", 721 "circonus_check_display_name", 722 "circonus_check_tags", 723 "circonus_broker_id", 724 "circonus_broker_select_tag", 725 "disable_tagged_metrics", 726 "backwards_compatible_metrics", 727 } 728 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 729 return err 730 } 731 732 var m map[string]interface{} 733 if err := hcl.DecodeObject(&m, listVal); err != nil { 734 return err 735 } 736 737 var telemetry Telemetry 738 if err := mapstructure.WeakDecode(m, &telemetry); err != nil { 739 return err 740 } 741 if telemetry.CollectionInterval != "" { 742 if dur, err := time.ParseDuration(telemetry.CollectionInterval); err != nil { 743 return fmt.Errorf("error parsing value of %q: %v", "collection_interval", err) 744 } else { 745 telemetry.collectionInterval = dur 746 } 747 } 748 *result = &telemetry 749 return nil 750 } 751 752 func parseConsulConfig(result **config.ConsulConfig, list *ast.ObjectList) error { 753 list = list.Elem() 754 if len(list.Items) > 1 { 755 return fmt.Errorf("only one 'consul' block allowed") 756 } 757 758 // Get our Consul object 759 listVal := list.Items[0].Val 760 761 // Check for invalid keys 762 valid := []string{ 763 "address", 764 "auth", 765 "auto_advertise", 766 "ca_file", 767 "cert_file", 768 "checks_use_advertise", 769 "client_auto_join", 770 "client_service_name", 771 "client_http_check_name", 772 "key_file", 773 "server_auto_join", 774 "server_service_name", 775 "server_http_check_name", 776 "server_serf_check_name", 777 "server_rpc_check_name", 778 "ssl", 779 "timeout", 780 "token", 781 "verify_ssl", 782 } 783 784 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 785 return err 786 } 787 788 var m map[string]interface{} 789 if err := hcl.DecodeObject(&m, listVal); err != nil { 790 return err 791 } 792 793 consulConfig := config.DefaultConsulConfig() 794 dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ 795 DecodeHook: mapstructure.StringToTimeDurationHookFunc(), 796 WeaklyTypedInput: true, 797 Result: &consulConfig, 798 }) 799 if err != nil { 800 return err 801 } 802 if err := dec.Decode(m); err != nil { 803 return err 804 } 805 806 *result = consulConfig 807 return nil 808 } 809 810 func parseTLSConfig(result **config.TLSConfig, list *ast.ObjectList) error { 811 list = list.Elem() 812 if len(list.Items) > 1 { 813 return fmt.Errorf("only one 'tls' block allowed") 814 } 815 816 // Get the TLS object 817 listVal := list.Items[0].Val 818 819 valid := []string{ 820 "http", 821 "rpc", 822 "verify_server_hostname", 823 "rpc_upgrade_mode", 824 "ca_file", 825 "cert_file", 826 "key_file", 827 "verify_https_client", 828 "tls_cipher_suites", 829 "tls_min_version", 830 "tls_prefer_server_cipher_suites", 831 } 832 833 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 834 return err 835 } 836 837 var m map[string]interface{} 838 if err := hcl.DecodeObject(&m, listVal); err != nil { 839 return err 840 } 841 842 var tlsConfig config.TLSConfig 843 if err := mapstructure.WeakDecode(m, &tlsConfig); err != nil { 844 return err 845 } 846 847 if _, err := tlsutil.ParseCiphers(tlsConfig.TLSCipherSuites); err != nil { 848 return err 849 } 850 851 if _, err := tlsutil.ParseMinVersion(tlsConfig.TLSMinVersion); err != nil { 852 return err 853 } 854 855 *result = &tlsConfig 856 return nil 857 } 858 859 func parseVaultConfig(result **config.VaultConfig, list *ast.ObjectList) error { 860 list = list.Elem() 861 if len(list.Items) > 1 { 862 return fmt.Errorf("only one 'vault' block allowed") 863 } 864 865 // Get our Vault object 866 listVal := list.Items[0].Val 867 868 // Check for invalid keys 869 valid := []string{ 870 "address", 871 "allow_unauthenticated", 872 "enabled", 873 "task_token_ttl", 874 "ca_file", 875 "ca_path", 876 "cert_file", 877 "create_from_role", 878 "key_file", 879 "tls_server_name", 880 "tls_skip_verify", 881 "token", 882 } 883 884 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 885 return err 886 } 887 888 var m map[string]interface{} 889 if err := hcl.DecodeObject(&m, listVal); err != nil { 890 return err 891 } 892 893 vaultConfig := config.DefaultVaultConfig() 894 dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ 895 DecodeHook: mapstructure.StringToTimeDurationHookFunc(), 896 WeaklyTypedInput: true, 897 Result: &vaultConfig, 898 }) 899 if err != nil { 900 return err 901 } 902 if err := dec.Decode(m); err != nil { 903 return err 904 } 905 906 *result = vaultConfig 907 return nil 908 } 909 910 func parseSentinel(result **config.SentinelConfig, list *ast.ObjectList) error { 911 list = list.Elem() 912 if len(list.Items) > 1 { 913 return fmt.Errorf("only one 'sentinel' block allowed") 914 } 915 916 // Get our sentinel object 917 obj := list.Items[0] 918 919 // Value should be an object 920 var listVal *ast.ObjectList 921 if ot, ok := obj.Val.(*ast.ObjectType); ok { 922 listVal = ot.List 923 } else { 924 return fmt.Errorf("sentinel value: should be an object") 925 } 926 927 // Check for invalid keys 928 valid := []string{ 929 "import", 930 } 931 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 932 return err 933 } 934 935 var config config.SentinelConfig 936 if err := hcl.DecodeObject(&config, listVal); err != nil { 937 return err 938 } 939 940 *result = &config 941 return nil 942 } 943 944 func parseAutopilot(result **config.AutopilotConfig, list *ast.ObjectList) error { 945 list = list.Elem() 946 if len(list.Items) > 1 { 947 return fmt.Errorf("only one 'autopilot' block allowed") 948 } 949 950 // Get our Autopilot object 951 listVal := list.Items[0].Val 952 953 // Check for invalid keys 954 valid := []string{ 955 "cleanup_dead_servers", 956 "server_stabilization_time", 957 "last_contact_threshold", 958 "max_trailing_logs", 959 "enable_redundancy_zones", 960 "disable_upgrade_migration", 961 "enable_custom_upgrades", 962 } 963 964 if err := helper.CheckHCLKeys(listVal, valid); err != nil { 965 return err 966 } 967 968 var m map[string]interface{} 969 if err := hcl.DecodeObject(&m, listVal); err != nil { 970 return err 971 } 972 973 autopilotConfig := config.DefaultAutopilotConfig() 974 dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ 975 DecodeHook: mapstructure.StringToTimeDurationHookFunc(), 976 WeaklyTypedInput: true, 977 Result: &autopilotConfig, 978 }) 979 if err != nil { 980 return err 981 } 982 if err := dec.Decode(m); err != nil { 983 return err 984 } 985 986 *result = autopilotConfig 987 return nil 988 }