github.com/janma/nomad@v0.11.3/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  	"github.com/hashicorp/hcl"
    12  	"github.com/hashicorp/nomad/helper"
    13  	"github.com/hashicorp/nomad/nomad/structs/config"
    14  )
    15  
    16  func ParseConfigFile(path string) (*Config, error) {
    17  	// slurp
    18  	var buf bytes.Buffer
    19  	path, err := filepath.Abs(path)
    20  	if err != nil {
    21  		return nil, err
    22  	}
    23  
    24  	f, err := os.Open(path)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  	defer f.Close()
    29  	if _, err := io.Copy(&buf, f); err != nil {
    30  		return nil, err
    31  	}
    32  
    33  	// parse
    34  	c := &Config{
    35  		Client:    &ClientConfig{ServerJoin: &ServerJoin{}},
    36  		ACL:       &ACLConfig{},
    37  		Audit:     &config.AuditConfig{},
    38  		Server:    &ServerConfig{ServerJoin: &ServerJoin{}},
    39  		Consul:    &config.ConsulConfig{},
    40  		Autopilot: &config.AutopilotConfig{},
    41  		Telemetry: &Telemetry{},
    42  		Vault:     &config.VaultConfig{},
    43  	}
    44  
    45  	err = hcl.Decode(c, buf.String())
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  
    50  	// convert strings to time.Durations
    51  	tds := []td{
    52  		{"gc_interval", &c.Client.GCInterval, &c.Client.GCIntervalHCL},
    53  		{"acl.token_ttl", &c.ACL.TokenTTL, &c.ACL.TokenTTLHCL},
    54  		{"acl.policy_ttl", &c.ACL.PolicyTTL, &c.ACL.PolicyTTLHCL},
    55  		{"client.server_join.retry_interval", &c.Client.ServerJoin.RetryInterval, &c.Client.ServerJoin.RetryIntervalHCL},
    56  		{"server.heartbeat_grace", &c.Server.HeartbeatGrace, &c.Server.HeartbeatGraceHCL},
    57  		{"server.min_heartbeat_ttl", &c.Server.MinHeartbeatTTL, &c.Server.MinHeartbeatTTLHCL},
    58  		{"server.retry_interval", &c.Server.RetryInterval, &c.Server.RetryIntervalHCL},
    59  		{"server.server_join.retry_interval", &c.Server.ServerJoin.RetryInterval, &c.Server.ServerJoin.RetryIntervalHCL},
    60  		{"consul.timeout", &c.Consul.Timeout, &c.Consul.TimeoutHCL},
    61  		{"autopilot.server_stabilization_time", &c.Autopilot.ServerStabilizationTime, &c.Autopilot.ServerStabilizationTimeHCL},
    62  		{"autopilot.last_contact_threshold", &c.Autopilot.LastContactThreshold, &c.Autopilot.LastContactThresholdHCL},
    63  		{"telemetry.collection_interval", &c.Telemetry.collectionInterval, &c.Telemetry.CollectionInterval},
    64  	}
    65  
    66  	// Add enterprise audit sinks for time.Duration parsing
    67  	for i, sink := range c.Audit.Sinks {
    68  		tds = append(tds, td{
    69  			fmt.Sprintf("audit.sink.%d", i), &sink.RotateDuration, &sink.RotateDurationHCL,
    70  		})
    71  	}
    72  
    73  	// convert strings to time.Durations
    74  	err = durations(tds)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	// report unexpected keys
    80  	err = extraKeys(c)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	return c, nil
    86  }
    87  
    88  // td holds args for one duration conversion
    89  type td struct {
    90  	path string
    91  	td   *time.Duration
    92  	str  *string
    93  }
    94  
    95  // durations parses the duration strings specified in the config files
    96  // into time.Durations
    97  func durations(xs []td) error {
    98  	for _, x := range xs {
    99  		if x.td != nil && x.str != nil && "" != *x.str {
   100  			d, err := time.ParseDuration(*x.str)
   101  			if err != nil {
   102  				return fmt.Errorf("%s can't parse time duration %s", x.path, *x.str)
   103  			}
   104  
   105  			*x.td = d
   106  		}
   107  	}
   108  
   109  	return nil
   110  }
   111  
   112  func extraKeys(c *Config) error {
   113  	// hcl leaves behind extra keys when parsing JSON. These keys
   114  	// are kept on the top level, taken from slices or the keys of
   115  	// structs contained in slices. Clean up before looking for
   116  	// extra keys.
   117  	for range c.HTTPAPIResponseHeaders {
   118  		helper.RemoveEqualFold(&c.ExtraKeysHCL, "http_api_response_headers")
   119  	}
   120  
   121  	for _, p := range c.Plugins {
   122  		helper.RemoveEqualFold(&c.ExtraKeysHCL, p.Name)
   123  		helper.RemoveEqualFold(&c.ExtraKeysHCL, "config")
   124  		helper.RemoveEqualFold(&c.ExtraKeysHCL, "plugin")
   125  	}
   126  
   127  	for _, k := range []string{"options", "meta", "chroot_env", "servers", "server_join"} {
   128  		helper.RemoveEqualFold(&c.ExtraKeysHCL, k)
   129  		helper.RemoveEqualFold(&c.ExtraKeysHCL, "client")
   130  	}
   131  
   132  	// stats is an unused key, continue to silently ignore it
   133  	helper.RemoveEqualFold(&c.Client.ExtraKeysHCL, "stats")
   134  
   135  	// Remove HostVolume extra keys
   136  	for _, hv := range c.Client.HostVolumes {
   137  		helper.RemoveEqualFold(&c.Client.ExtraKeysHCL, hv.Name)
   138  		helper.RemoveEqualFold(&c.Client.ExtraKeysHCL, "host_volume")
   139  	}
   140  
   141  	// Remove AuditConfig extra keys
   142  	for _, f := range c.Audit.Filters {
   143  		helper.RemoveEqualFold(&c.Audit.ExtraKeysHCL, f.Name)
   144  		helper.RemoveEqualFold(&c.Audit.ExtraKeysHCL, "filter")
   145  	}
   146  
   147  	for _, s := range c.Audit.Sinks {
   148  		helper.RemoveEqualFold(&c.Audit.ExtraKeysHCL, s.Name)
   149  		helper.RemoveEqualFold(&c.Audit.ExtraKeysHCL, "sink")
   150  	}
   151  
   152  	for _, k := range []string{"enabled_schedulers", "start_join", "retry_join", "server_join"} {
   153  		helper.RemoveEqualFold(&c.ExtraKeysHCL, k)
   154  		helper.RemoveEqualFold(&c.ExtraKeysHCL, "server")
   155  	}
   156  
   157  	for _, k := range []string{"datadog_tags"} {
   158  		helper.RemoveEqualFold(&c.ExtraKeysHCL, k)
   159  		helper.RemoveEqualFold(&c.ExtraKeysHCL, "telemetry")
   160  	}
   161  
   162  	return helper.UnusedKeys(c)
   163  }