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