1package config
2
3import (
4	"encoding/base64"
5	"encoding/json"
6	"fmt"
7	"io/ioutil"
8	"net"
9	"os"
10	"path/filepath"
11	"reflect"
12	"regexp"
13	"sort"
14	"strings"
15	"time"
16
17	"github.com/hashicorp/consul/agent/connect/ca"
18	"github.com/hashicorp/consul/agent/consul"
19	"github.com/hashicorp/consul/agent/structs"
20	"github.com/hashicorp/consul/ipaddr"
21	"github.com/hashicorp/consul/lib"
22	"github.com/hashicorp/consul/tlsutil"
23	"github.com/hashicorp/consul/types"
24	multierror "github.com/hashicorp/go-multierror"
25	"github.com/hashicorp/go-sockaddr/template"
26	"golang.org/x/time/rate"
27)
28
29// Builder constructs a valid runtime configuration from multiple
30// configuration sources.
31//
32// To build the runtime configuration first call Build() which merges
33// the sources in a pre-defined order, converts the data types and
34// structures into their final form and performs the syntactic
35// validation.
36//
37// The sources are merged in the following order:
38//
39//  * default configuration
40//  * config files in alphabetical order
41//  * command line arguments
42//
43// The config sources are merged sequentially and later values
44// overwrite previously set values. Slice values are merged by
45// concatenating the two slices. Map values are merged by over-
46// laying the later maps on top of earlier ones.
47//
48// Then call Validate() to perform the semantic validation to ensure
49// that the configuration is ready to be used.
50//
51// Splitting the construction into two phases greatly simplifies testing
52// since not all pre-conditions have to be satisfied when performing
53// syntactical tests.
54type Builder struct {
55	// Flags contains the parsed command line arguments.
56	Flags Flags
57
58	// Head, Sources, and Tail are used to manage the order of the
59	// config sources, as described in the comments above.
60	Head    []Source
61	Sources []Source
62	Tail    []Source
63
64	// Warnings contains the warnings encountered when
65	// parsing the configuration.
66	Warnings []string
67
68	// Hostname returns the hostname of the machine. If nil, os.Hostname
69	// is called.
70	Hostname func() (string, error)
71
72	// GetPrivateIPv4 and GetPublicIPv6 return suitable default addresses
73	// for cases when the user doesn't supply them.
74	GetPrivateIPv4 func() ([]*net.IPAddr, error)
75	GetPublicIPv6  func() ([]*net.IPAddr, error)
76
77	// err contains the first error that occurred during
78	// building the runtime configuration.
79	err error
80}
81
82// NewBuilder returns a new configuration builder based on the given command
83// line flags.
84func NewBuilder(flags Flags) (*Builder, error) {
85	// We expect all flags to be parsed and flags.Args to be empty.
86	// Therefore, we bail if we find unparsed args.
87	if len(flags.Args) > 0 {
88		return nil, fmt.Errorf("config: Unknown extra arguments: %v", flags.Args)
89	}
90
91	newSource := func(name string, v interface{}) Source {
92		b, err := json.MarshalIndent(v, "", "    ")
93		if err != nil {
94			panic(err)
95		}
96		return Source{Name: name, Format: "json", Data: string(b)}
97	}
98
99	b := &Builder{
100		Flags: flags,
101		Head:  []Source{DefaultSource()},
102	}
103
104	if b.boolVal(b.Flags.DevMode) {
105		b.Head = append(b.Head, DevSource())
106	}
107
108	// Since the merge logic is to overwrite all fields with later
109	// values except slices which are merged by appending later values
110	// we need to merge all slice values defined in flags before we
111	// merge the config files since the flag values for slices are
112	// otherwise appended instead of prepended.
113	slices, values := b.splitSlicesAndValues(b.Flags.Config)
114	b.Head = append(b.Head, newSource("flags.slices", slices))
115	for _, path := range b.Flags.ConfigFiles {
116		sources, err := b.ReadPath(path)
117		if err != nil {
118			return nil, err
119		}
120		b.Sources = append(b.Sources, sources...)
121	}
122	b.Tail = append(b.Tail, newSource("flags.values", values))
123	for i, s := range b.Flags.HCL {
124		b.Tail = append(b.Tail, Source{
125			Name:   fmt.Sprintf("flags-%d.hcl", i),
126			Format: "hcl",
127			Data:   s,
128		})
129	}
130	b.Tail = append(b.Tail, NonUserSource(), DefaultConsulSource(), DefaultEnterpriseSource(), DefaultVersionSource())
131	if b.boolVal(b.Flags.DevMode) {
132		b.Tail = append(b.Tail, DevConsulSource())
133	}
134	return b, nil
135}
136
137// ReadPath reads a single config file or all files in a directory (but
138// not its sub-directories) and appends them to the list of config
139// sources.
140func (b *Builder) ReadPath(path string) ([]Source, error) {
141	f, err := os.Open(path)
142	if err != nil {
143		return nil, fmt.Errorf("config: Open failed on %s. %s", path, err)
144	}
145	defer f.Close()
146
147	fi, err := f.Stat()
148	if err != nil {
149		return nil, fmt.Errorf("config: Stat failed on %s. %s", path, err)
150	}
151
152	if !fi.IsDir() {
153		src, err := b.ReadFile(path)
154		if err != nil {
155			return nil, err
156		}
157		return []Source{src}, nil
158	}
159
160	fis, err := f.Readdir(-1)
161	if err != nil {
162		return nil, fmt.Errorf("config: Readdir failed on %s. %s", path, err)
163	}
164
165	// sort files by name
166	sort.Sort(byName(fis))
167
168	var sources []Source
169	for _, fi := range fis {
170		fp := filepath.Join(path, fi.Name())
171		// check for a symlink and resolve the path
172		if fi.Mode()&os.ModeSymlink > 0 {
173			var err error
174			fp, err = filepath.EvalSymlinks(fp)
175			if err != nil {
176				return nil, err
177			}
178			fi, err = os.Stat(fp)
179			if err != nil {
180				return nil, err
181			}
182		}
183		// do not recurse into sub dirs
184		if fi.IsDir() {
185			continue
186		}
187
188		src, err := b.ReadFile(fp)
189		if err != nil {
190			return nil, err
191		}
192		sources = append(sources, src)
193	}
194	return sources, nil
195}
196
197// ReadFile parses a JSON or HCL config file and appends it to the list of
198// config sources.
199func (b *Builder) ReadFile(path string) (Source, error) {
200	data, err := ioutil.ReadFile(path)
201	if err != nil {
202		return Source{}, fmt.Errorf("config: ReadFile failed on %s: %s", path, err)
203	}
204	return Source{Name: path, Data: string(data)}, nil
205}
206
207type byName []os.FileInfo
208
209func (a byName) Len() int           { return len(a) }
210func (a byName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
211func (a byName) Less(i, j int) bool { return a[i].Name() < a[j].Name() }
212
213func (b *Builder) BuildAndValidate() (RuntimeConfig, error) {
214	rt, err := b.Build()
215	if err != nil {
216		return RuntimeConfig{}, err
217	}
218	if err := b.Validate(rt); err != nil {
219		return RuntimeConfig{}, err
220	}
221	return rt, nil
222}
223
224// Build constructs the runtime configuration from the config sources
225// and the command line flags. The config sources are processed in the
226// order they were added with the flags being processed last to give
227// precedence over the other sources. If the error is nil then
228// warnings can still contain deprecation or format warnings that should
229// be presented to the user.
230func (b *Builder) Build() (rt RuntimeConfig, err error) {
231	b.err = nil
232	b.Warnings = nil
233
234	// ----------------------------------------------------------------
235	// merge config sources as follows
236	//
237
238	configFormat := b.stringVal(b.Flags.ConfigFormat)
239	if configFormat != "" && configFormat != "json" && configFormat != "hcl" {
240		return RuntimeConfig{}, fmt.Errorf("config: -config-format must be either 'hcl' or 'json'")
241	}
242
243	// build the list of config sources
244	var srcs []Source
245	srcs = append(srcs, b.Head...)
246	for _, src := range b.Sources {
247		src.Format = FormatFrom(src.Name)
248		if configFormat != "" {
249			src.Format = configFormat
250		} else {
251			// If they haven't forced things to a specific format,
252			// then skip anything we don't understand, which is the
253			// behavior before we added the -config-format option.
254			switch src.Format {
255			case "json", "hcl":
256				// OK
257			default:
258				// SKIP
259				continue
260			}
261		}
262		if src.Format == "" {
263			return RuntimeConfig{}, fmt.Errorf(`config: Missing or invalid file extension for %q. Please use ".json" or ".hcl".`, src.Name)
264		}
265		srcs = append(srcs, src)
266	}
267	srcs = append(srcs, b.Tail...)
268
269	// parse the config sources into a configuration
270	var c Config
271	for _, s := range srcs {
272		if s.Name == "" || s.Data == "" {
273			continue
274		}
275		c2, err := Parse(s.Data, s.Format)
276		if err != nil {
277			return RuntimeConfig{}, fmt.Errorf("Error parsing %s: %s", s.Name, err)
278		}
279
280		// if we have a single 'check' or 'service' we need to add them to the
281		// list of checks and services first since we cannot merge them
282		// generically and later values would clobber earlier ones.
283		if c2.Check != nil {
284			c2.Checks = append(c2.Checks, *c2.Check)
285			c2.Check = nil
286		}
287		if c2.Service != nil {
288			c2.Services = append(c2.Services, *c2.Service)
289			c2.Service = nil
290		}
291
292		c = Merge(c, c2)
293	}
294
295	// ----------------------------------------------------------------
296	// process/merge some complex values
297	//
298
299	var dnsServiceTTL = map[string]time.Duration{}
300	for k, v := range c.DNS.ServiceTTL {
301		dnsServiceTTL[k] = b.durationVal(fmt.Sprintf("dns_config.service_ttl[%q]", k), &v)
302	}
303
304	soa := RuntimeSOAConfig{Refresh: 3600, Retry: 600, Expire: 86400, Minttl: 0}
305	if c.DNS.SOA != nil {
306		if c.DNS.SOA.Expire != nil {
307			soa.Expire = *c.DNS.SOA.Expire
308		}
309		if c.DNS.SOA.Minttl != nil {
310			soa.Minttl = *c.DNS.SOA.Minttl
311		}
312		if c.DNS.SOA.Refresh != nil {
313			soa.Refresh = *c.DNS.SOA.Refresh
314		}
315		if c.DNS.SOA.Retry != nil {
316			soa.Retry = *c.DNS.SOA.Retry
317		}
318	}
319
320	leaveOnTerm := !b.boolVal(c.ServerMode)
321	if c.LeaveOnTerm != nil {
322		leaveOnTerm = b.boolVal(c.LeaveOnTerm)
323	}
324
325	skipLeaveOnInt := b.boolVal(c.ServerMode)
326	if c.SkipLeaveOnInt != nil {
327		skipLeaveOnInt = b.boolVal(c.SkipLeaveOnInt)
328	}
329
330	// ----------------------------------------------------------------
331	// checks and services
332	//
333
334	var checks []*structs.CheckDefinition
335	if c.Check != nil {
336		checks = append(checks, b.checkVal(c.Check))
337	}
338	for _, check := range c.Checks {
339		checks = append(checks, b.checkVal(&check))
340	}
341
342	var services []*structs.ServiceDefinition
343	for _, service := range c.Services {
344		services = append(services, b.serviceVal(&service))
345	}
346	if c.Service != nil {
347		services = append(services, b.serviceVal(c.Service))
348	}
349
350	// ----------------------------------------------------------------
351	// addresses
352	//
353
354	// determine port values and replace values <= 0 and > 65535 with -1
355	dnsPort := b.portVal("ports.dns", c.Ports.DNS)
356	httpPort := b.portVal("ports.http", c.Ports.HTTP)
357	httpsPort := b.portVal("ports.https", c.Ports.HTTPS)
358	serverPort := b.portVal("ports.server", c.Ports.Server)
359	grpcPort := b.portVal("ports.grpc", c.Ports.GRPC)
360	serfPortLAN := b.portVal("ports.serf_lan", c.Ports.SerfLAN)
361	serfPortWAN := b.portVal("ports.serf_wan", c.Ports.SerfWAN)
362	proxyMinPort := b.portVal("ports.proxy_min_port", c.Ports.ProxyMinPort)
363	proxyMaxPort := b.portVal("ports.proxy_max_port", c.Ports.ProxyMaxPort)
364	sidecarMinPort := b.portVal("ports.sidecar_min_port", c.Ports.SidecarMinPort)
365	sidecarMaxPort := b.portVal("ports.sidecar_max_port", c.Ports.SidecarMaxPort)
366	if proxyMaxPort < proxyMinPort {
367		return RuntimeConfig{}, fmt.Errorf(
368			"proxy_min_port must be less than proxy_max_port. To disable, set both to zero.")
369	}
370	if sidecarMaxPort < sidecarMinPort {
371		return RuntimeConfig{}, fmt.Errorf(
372			"sidecar_min_port must be less than sidecar_max_port. To disable, set both to zero.")
373	}
374
375	// determine the default bind and advertise address
376	//
377	// First check whether the user provided an ANY address or whether
378	// the expanded template results in an ANY address. In that case we
379	// derive an advertise address from the current network
380	// configuration since we can listen on an ANY address for incoming
381	// traffic but cannot advertise it as the address on which the
382	// server can be reached.
383
384	bindAddrs := b.expandAddrs("bind_addr", c.BindAddr)
385	if len(bindAddrs) == 0 {
386		return RuntimeConfig{}, fmt.Errorf("bind_addr cannot be empty")
387	}
388	if len(bindAddrs) > 1 {
389		return RuntimeConfig{}, fmt.Errorf("bind_addr cannot contain multiple addresses. Use 'addresses.{dns,http,https}' instead.")
390	}
391	if isUnixAddr(bindAddrs[0]) {
392		return RuntimeConfig{}, fmt.Errorf("bind_addr cannot be a unix socket")
393	}
394	if !isIPAddr(bindAddrs[0]) {
395		return RuntimeConfig{}, fmt.Errorf("bind_addr must be an ip address")
396	}
397	if ipaddr.IsAny(b.stringVal(c.AdvertiseAddrLAN)) {
398		return RuntimeConfig{}, fmt.Errorf("Advertise address cannot be 0.0.0.0, :: or [::]")
399	}
400	if ipaddr.IsAny(b.stringVal(c.AdvertiseAddrWAN)) {
401		return RuntimeConfig{}, fmt.Errorf("Advertise WAN address cannot be 0.0.0.0, :: or [::]")
402	}
403
404	bindAddr := bindAddrs[0].(*net.IPAddr)
405	advertiseAddr := b.makeIPAddr(b.expandFirstIP("advertise_addr", c.AdvertiseAddrLAN), bindAddr)
406	if ipaddr.IsAny(advertiseAddr) {
407
408		var addrtyp string
409		var detect func() ([]*net.IPAddr, error)
410		switch {
411		case ipaddr.IsAnyV4(advertiseAddr):
412			addrtyp = "private IPv4"
413			detect = b.GetPrivateIPv4
414			if detect == nil {
415				detect = ipaddr.GetPrivateIPv4
416			}
417
418		case ipaddr.IsAnyV6(advertiseAddr):
419			addrtyp = "public IPv6"
420			detect = b.GetPublicIPv6
421			if detect == nil {
422				detect = ipaddr.GetPublicIPv6
423			}
424		}
425
426		advertiseAddrs, err := detect()
427		if err != nil {
428			return RuntimeConfig{}, fmt.Errorf("Error detecting %s address: %s", addrtyp, err)
429		}
430		if len(advertiseAddrs) == 0 {
431			return RuntimeConfig{}, fmt.Errorf("No %s address found", addrtyp)
432		}
433		if len(advertiseAddrs) > 1 {
434			return RuntimeConfig{}, fmt.Errorf("Multiple %s addresses found. Please configure one with 'bind' and/or 'advertise'.", addrtyp)
435		}
436		advertiseAddr = advertiseAddrs[0]
437	}
438
439	// derive other bind addresses from the bindAddr
440	rpcBindAddr := b.makeTCPAddr(bindAddr, nil, serverPort)
441	serfBindAddrLAN := b.makeTCPAddr(b.expandFirstIP("serf_lan", c.SerfBindAddrLAN), bindAddr, serfPortLAN)
442
443	// Only initialize serf WAN bind address when its enabled
444	var serfBindAddrWAN *net.TCPAddr
445	if serfPortWAN >= 0 {
446		serfBindAddrWAN = b.makeTCPAddr(b.expandFirstIP("serf_wan", c.SerfBindAddrWAN), bindAddr, serfPortWAN)
447	}
448
449	// derive other advertise addresses from the advertise address
450	advertiseAddrLAN := b.makeIPAddr(b.expandFirstIP("advertise_addr", c.AdvertiseAddrLAN), advertiseAddr)
451	advertiseAddrWAN := b.makeIPAddr(b.expandFirstIP("advertise_addr_wan", c.AdvertiseAddrWAN), advertiseAddrLAN)
452	rpcAdvertiseAddr := &net.TCPAddr{IP: advertiseAddrLAN.IP, Port: serverPort}
453	serfAdvertiseAddrLAN := &net.TCPAddr{IP: advertiseAddrLAN.IP, Port: serfPortLAN}
454	// Only initialize serf WAN advertise address when its enabled
455	var serfAdvertiseAddrWAN *net.TCPAddr
456	if serfPortWAN >= 0 {
457		serfAdvertiseAddrWAN = &net.TCPAddr{IP: advertiseAddrWAN.IP, Port: serfPortWAN}
458	}
459
460	// determine client addresses
461	clientAddrs := b.expandIPs("client_addr", c.ClientAddr)
462	dnsAddrs := b.makeAddrs(b.expandAddrs("addresses.dns", c.Addresses.DNS), clientAddrs, dnsPort)
463	httpAddrs := b.makeAddrs(b.expandAddrs("addresses.http", c.Addresses.HTTP), clientAddrs, httpPort)
464	httpsAddrs := b.makeAddrs(b.expandAddrs("addresses.https", c.Addresses.HTTPS), clientAddrs, httpsPort)
465	grpcAddrs := b.makeAddrs(b.expandAddrs("addresses.grpc", c.Addresses.GRPC), clientAddrs, grpcPort)
466
467	for _, a := range dnsAddrs {
468		if x, ok := a.(*net.TCPAddr); ok {
469			dnsAddrs = append(dnsAddrs, &net.UDPAddr{IP: x.IP, Port: x.Port})
470		}
471	}
472
473	// expand dns recursors
474	uniq := map[string]bool{}
475	dnsRecursors := []string{}
476	for _, r := range c.DNSRecursors {
477		x, err := template.Parse(r)
478		if err != nil {
479			return RuntimeConfig{}, fmt.Errorf("Invalid DNS recursor template %q: %s", r, err)
480		}
481		for _, addr := range strings.Fields(x) {
482			if strings.HasPrefix(addr, "unix://") {
483				return RuntimeConfig{}, fmt.Errorf("DNS Recursors cannot be unix sockets: %s", addr)
484			}
485			if uniq[addr] {
486				continue
487			}
488			uniq[addr] = true
489			dnsRecursors = append(dnsRecursors, addr)
490		}
491	}
492
493	// Create the default set of tagged addresses.
494	if c.TaggedAddresses == nil {
495		c.TaggedAddresses = make(map[string]string)
496	}
497	c.TaggedAddresses["lan"] = advertiseAddrLAN.IP.String()
498	c.TaggedAddresses["wan"] = advertiseAddrWAN.IP.String()
499
500	// segments
501	var segments []structs.NetworkSegment
502	for _, s := range c.Segments {
503		name := b.stringVal(s.Name)
504		port := b.portVal(fmt.Sprintf("segments[%s].port", name), s.Port)
505		if port <= 0 {
506			return RuntimeConfig{}, fmt.Errorf("Port for segment %q cannot be <= 0", name)
507		}
508
509		bind := b.makeTCPAddr(
510			b.expandFirstIP(fmt.Sprintf("segments[%s].bind", name), s.Bind),
511			bindAddr,
512			port,
513		)
514
515		advertise := b.makeTCPAddr(
516			b.expandFirstIP(fmt.Sprintf("segments[%s].advertise", name), s.Advertise),
517			advertiseAddrLAN,
518			port,
519		)
520
521		segments = append(segments, structs.NetworkSegment{
522			Name:        name,
523			Bind:        bind,
524			Advertise:   advertise,
525			RPCListener: b.boolVal(s.RPCListener),
526		})
527	}
528
529	// Parse the metric filters
530	var telemetryAllowedPrefixes, telemetryBlockedPrefixes []string
531	for _, rule := range c.Telemetry.PrefixFilter {
532		if rule == "" {
533			b.warn("Cannot have empty filter rule in prefix_filter")
534			continue
535		}
536		switch rule[0] {
537		case '+':
538			telemetryAllowedPrefixes = append(telemetryAllowedPrefixes, rule[1:])
539		case '-':
540			telemetryBlockedPrefixes = append(telemetryBlockedPrefixes, rule[1:])
541		default:
542			b.warn("Filter rule must begin with either '+' or '-': %q", rule)
543		}
544	}
545
546	// raft performance scaling
547	performanceRaftMultiplier := b.intVal(c.Performance.RaftMultiplier)
548	if performanceRaftMultiplier < 1 || uint(performanceRaftMultiplier) > consul.MaxRaftMultiplier {
549		return RuntimeConfig{}, fmt.Errorf("performance.raft_multiplier cannot be %d. Must be between 1 and %d", performanceRaftMultiplier, consul.MaxRaftMultiplier)
550	}
551	consulRaftElectionTimeout := b.durationVal("consul.raft.election_timeout", c.Consul.Raft.ElectionTimeout) * time.Duration(performanceRaftMultiplier)
552	consulRaftHeartbeatTimeout := b.durationVal("consul.raft.heartbeat_timeout", c.Consul.Raft.HeartbeatTimeout) * time.Duration(performanceRaftMultiplier)
553	consulRaftLeaderLeaseTimeout := b.durationVal("consul.raft.leader_lease_timeout", c.Consul.Raft.LeaderLeaseTimeout) * time.Duration(performanceRaftMultiplier)
554
555	// Connect proxy defaults.
556	connectEnabled := b.boolVal(c.Connect.Enabled)
557	connectCAProvider := b.stringVal(c.Connect.CAProvider)
558	connectCAConfig := c.Connect.CAConfig
559	if connectCAConfig != nil {
560		TranslateKeys(connectCAConfig, map[string]string{
561			// Consul CA config
562			"private_key":     "PrivateKey",
563			"root_cert":       "RootCert",
564			"rotation_period": "RotationPeriod",
565
566			// Vault CA config
567			"address":               "Address",
568			"token":                 "Token",
569			"root_pki_path":         "RootPKIPath",
570			"intermediate_pki_path": "IntermediatePKIPath",
571
572			// Common CA config
573			"leaf_cert_ttl": "LeafCertTTL",
574		})
575	}
576
577	proxyDefaultExecMode := b.stringVal(c.Connect.ProxyDefaults.ExecMode)
578	proxyDefaultDaemonCommand := c.Connect.ProxyDefaults.DaemonCommand
579	proxyDefaultScriptCommand := c.Connect.ProxyDefaults.ScriptCommand
580	proxyDefaultConfig := c.Connect.ProxyDefaults.Config
581
582	enableRemoteScriptChecks := b.boolVal(c.EnableScriptChecks)
583	enableLocalScriptChecks := b.boolValWithDefault(c.EnableLocalScriptChecks, enableRemoteScriptChecks)
584
585	// ----------------------------------------------------------------
586	// build runtime config
587	//
588	rt = RuntimeConfig{
589		// non-user configurable values
590		ACLDisabledTTL:             b.durationVal("acl_disabled_ttl", c.ACLDisabledTTL),
591		AEInterval:                 b.durationVal("ae_interval", c.AEInterval),
592		CheckDeregisterIntervalMin: b.durationVal("check_deregister_interval_min", c.CheckDeregisterIntervalMin),
593		CheckReapInterval:          b.durationVal("check_reap_interval", c.CheckReapInterval),
594		Revision:                   b.stringVal(c.Revision),
595		SegmentLimit:               b.intVal(c.SegmentLimit),
596		SegmentNameLimit:           b.intVal(c.SegmentNameLimit),
597		SyncCoordinateIntervalMin:  b.durationVal("sync_coordinate_interval_min", c.SyncCoordinateIntervalMin),
598		SyncCoordinateRateTarget:   b.float64Val(c.SyncCoordinateRateTarget),
599		Version:                    b.stringVal(c.Version),
600		VersionPrerelease:          b.stringVal(c.VersionPrerelease),
601
602		// consul configuration
603		ConsulCoordinateUpdateBatchSize:  b.intVal(c.Consul.Coordinate.UpdateBatchSize),
604		ConsulCoordinateUpdateMaxBatches: b.intVal(c.Consul.Coordinate.UpdateMaxBatches),
605		ConsulCoordinateUpdatePeriod:     b.durationVal("consul.coordinate.update_period", c.Consul.Coordinate.UpdatePeriod),
606		ConsulRaftElectionTimeout:        consulRaftElectionTimeout,
607		ConsulRaftHeartbeatTimeout:       consulRaftHeartbeatTimeout,
608		ConsulRaftLeaderLeaseTimeout:     consulRaftLeaderLeaseTimeout,
609		ConsulServerHealthInterval:       b.durationVal("consul.server.health_interval", c.Consul.Server.HealthInterval),
610
611		// gossip configuration
612		GossipLANGossipInterval: b.durationVal("gossip_lan..gossip_interval", c.GossipLAN.GossipInterval),
613		GossipLANGossipNodes:    b.intVal(c.GossipLAN.GossipNodes),
614		GossipLANProbeInterval:  b.durationVal("gossip_lan..probe_interval", c.GossipLAN.ProbeInterval),
615		GossipLANProbeTimeout:   b.durationVal("gossip_lan..probe_timeout", c.GossipLAN.ProbeTimeout),
616		GossipLANSuspicionMult:  b.intVal(c.GossipLAN.SuspicionMult),
617		GossipLANRetransmitMult: b.intVal(c.GossipLAN.RetransmitMult),
618		GossipWANGossipInterval: b.durationVal("gossip_wan..gossip_interval", c.GossipWAN.GossipInterval),
619		GossipWANGossipNodes:    b.intVal(c.GossipWAN.GossipNodes),
620		GossipWANProbeInterval:  b.durationVal("gossip_wan..probe_interval", c.GossipWAN.ProbeInterval),
621		GossipWANProbeTimeout:   b.durationVal("gossip_wan..probe_timeout", c.GossipWAN.ProbeTimeout),
622		GossipWANSuspicionMult:  b.intVal(c.GossipWAN.SuspicionMult),
623		GossipWANRetransmitMult: b.intVal(c.GossipWAN.RetransmitMult),
624
625		// ACL
626		ACLAgentMasterToken:    b.stringVal(c.ACLAgentMasterToken),
627		ACLAgentToken:          b.stringVal(c.ACLAgentToken),
628		ACLDatacenter:          strings.ToLower(b.stringVal(c.ACLDatacenter)),
629		ACLDefaultPolicy:       b.stringVal(c.ACLDefaultPolicy),
630		ACLDownPolicy:          b.stringVal(c.ACLDownPolicy),
631		ACLEnforceVersion8:     b.boolVal(c.ACLEnforceVersion8),
632		ACLEnableKeyListPolicy: b.boolVal(c.ACLEnableKeyListPolicy),
633		ACLMasterToken:         b.stringVal(c.ACLMasterToken),
634		ACLReplicationToken:    b.stringVal(c.ACLReplicationToken),
635		ACLTTL:                 b.durationVal("acl_ttl", c.ACLTTL),
636		ACLToken:               b.stringVal(c.ACLToken),
637		EnableACLReplication:   b.boolVal(c.EnableACLReplication),
638
639		// Autopilot
640		AutopilotCleanupDeadServers:      b.boolVal(c.Autopilot.CleanupDeadServers),
641		AutopilotDisableUpgradeMigration: b.boolVal(c.Autopilot.DisableUpgradeMigration),
642		AutopilotLastContactThreshold:    b.durationVal("autopilot.last_contact_threshold", c.Autopilot.LastContactThreshold),
643		AutopilotMaxTrailingLogs:         b.intVal(c.Autopilot.MaxTrailingLogs),
644		AutopilotRedundancyZoneTag:       b.stringVal(c.Autopilot.RedundancyZoneTag),
645		AutopilotServerStabilizationTime: b.durationVal("autopilot.server_stabilization_time", c.Autopilot.ServerStabilizationTime),
646		AutopilotUpgradeVersionTag:       b.stringVal(c.Autopilot.UpgradeVersionTag),
647
648		// DNS
649		DNSAddrs:              dnsAddrs,
650		DNSAllowStale:         b.boolVal(c.DNS.AllowStale),
651		DNSARecordLimit:       b.intVal(c.DNS.ARecordLimit),
652		DNSDisableCompression: b.boolVal(c.DNS.DisableCompression),
653		DNSDomain:             b.stringVal(c.DNSDomain),
654		DNSEnableTruncate:     b.boolVal(c.DNS.EnableTruncate),
655		DNSMaxStale:           b.durationVal("dns_config.max_stale", c.DNS.MaxStale),
656		DNSNodeTTL:            b.durationVal("dns_config.node_ttl", c.DNS.NodeTTL),
657		DNSOnlyPassing:        b.boolVal(c.DNS.OnlyPassing),
658		DNSPort:               dnsPort,
659		DNSRecursorTimeout:    b.durationVal("recursor_timeout", c.DNS.RecursorTimeout),
660		DNSRecursors:          dnsRecursors,
661		DNSServiceTTL:         dnsServiceTTL,
662		DNSSOA:                soa,
663		DNSUDPAnswerLimit:     b.intVal(c.DNS.UDPAnswerLimit),
664		DNSNodeMetaTXT:        b.boolValWithDefault(c.DNS.NodeMetaTXT, true),
665
666		// HTTP
667		HTTPPort:            httpPort,
668		HTTPSPort:           httpsPort,
669		HTTPAddrs:           httpAddrs,
670		HTTPSAddrs:          httpsAddrs,
671		HTTPBlockEndpoints:  c.HTTPConfig.BlockEndpoints,
672		HTTPResponseHeaders: c.HTTPConfig.ResponseHeaders,
673
674		// Telemetry
675		Telemetry: lib.TelemetryConfig{
676			CirconusAPIApp:                     b.stringVal(c.Telemetry.CirconusAPIApp),
677			CirconusAPIToken:                   b.stringVal(c.Telemetry.CirconusAPIToken),
678			CirconusAPIURL:                     b.stringVal(c.Telemetry.CirconusAPIURL),
679			CirconusBrokerID:                   b.stringVal(c.Telemetry.CirconusBrokerID),
680			CirconusBrokerSelectTag:            b.stringVal(c.Telemetry.CirconusBrokerSelectTag),
681			CirconusCheckDisplayName:           b.stringVal(c.Telemetry.CirconusCheckDisplayName),
682			CirconusCheckForceMetricActivation: b.stringVal(c.Telemetry.CirconusCheckForceMetricActivation),
683			CirconusCheckID:                    b.stringVal(c.Telemetry.CirconusCheckID),
684			CirconusCheckInstanceID:            b.stringVal(c.Telemetry.CirconusCheckInstanceID),
685			CirconusCheckSearchTag:             b.stringVal(c.Telemetry.CirconusCheckSearchTag),
686			CirconusCheckTags:                  b.stringVal(c.Telemetry.CirconusCheckTags),
687			CirconusSubmissionInterval:         b.stringVal(c.Telemetry.CirconusSubmissionInterval),
688			CirconusSubmissionURL:              b.stringVal(c.Telemetry.CirconusSubmissionURL),
689			DisableHostname:                    b.boolVal(c.Telemetry.DisableHostname),
690			DogstatsdAddr:                      b.stringVal(c.Telemetry.DogstatsdAddr),
691			DogstatsdTags:                      c.Telemetry.DogstatsdTags,
692			PrometheusRetentionTime:            b.durationVal("prometheus_retention_time", c.Telemetry.PrometheusRetentionTime),
693			FilterDefault:                      b.boolVal(c.Telemetry.FilterDefault),
694			AllowedPrefixes:                    telemetryAllowedPrefixes,
695			BlockedPrefixes:                    telemetryBlockedPrefixes,
696			MetricsPrefix:                      b.stringVal(c.Telemetry.MetricsPrefix),
697			StatsdAddr:                         b.stringVal(c.Telemetry.StatsdAddr),
698			StatsiteAddr:                       b.stringVal(c.Telemetry.StatsiteAddr),
699		},
700
701		// Agent
702		AdvertiseAddrLAN:                        advertiseAddrLAN,
703		AdvertiseAddrWAN:                        advertiseAddrWAN,
704		BindAddr:                                bindAddr,
705		Bootstrap:                               b.boolVal(c.Bootstrap),
706		BootstrapExpect:                         b.intVal(c.BootstrapExpect),
707		CAFile:                                  b.stringVal(c.CAFile),
708		CAPath:                                  b.stringVal(c.CAPath),
709		CertFile:                                b.stringVal(c.CertFile),
710		CheckUpdateInterval:                     b.durationVal("check_update_interval", c.CheckUpdateInterval),
711		Checks:                                  checks,
712		ClientAddrs:                             clientAddrs,
713		ConnectEnabled:                          connectEnabled,
714		ConnectCAProvider:                       connectCAProvider,
715		ConnectCAConfig:                         connectCAConfig,
716		ConnectProxyAllowManagedRoot:            b.boolVal(c.Connect.Proxy.AllowManagedRoot),
717		ConnectProxyAllowManagedAPIRegistration: b.boolVal(c.Connect.Proxy.AllowManagedAPIRegistration),
718		ConnectProxyBindMinPort:                 proxyMinPort,
719		ConnectProxyBindMaxPort:                 proxyMaxPort,
720		ConnectSidecarMinPort:                   sidecarMinPort,
721		ConnectSidecarMaxPort:                   sidecarMaxPort,
722		ConnectProxyDefaultExecMode:             proxyDefaultExecMode,
723		ConnectProxyDefaultDaemonCommand:        proxyDefaultDaemonCommand,
724		ConnectProxyDefaultScriptCommand:        proxyDefaultScriptCommand,
725		ConnectProxyDefaultConfig:               proxyDefaultConfig,
726		DataDir:                                 b.stringVal(c.DataDir),
727		Datacenter:                              strings.ToLower(b.stringVal(c.Datacenter)),
728		DevMode:                                 b.boolVal(b.Flags.DevMode),
729		DisableAnonymousSignature:               b.boolVal(c.DisableAnonymousSignature),
730		DisableCoordinates:                      b.boolVal(c.DisableCoordinates),
731		DisableHostNodeID:                       b.boolVal(c.DisableHostNodeID),
732		DisableHTTPUnprintableCharFilter:        b.boolVal(c.DisableHTTPUnprintableCharFilter),
733		DisableKeyringFile:                      b.boolVal(c.DisableKeyringFile),
734		DisableRemoteExec:                       b.boolVal(c.DisableRemoteExec),
735		DisableUpdateCheck:                      b.boolVal(c.DisableUpdateCheck),
736		DiscardCheckOutput:                      b.boolVal(c.DiscardCheckOutput),
737		DiscoveryMaxStale:                       b.durationVal("discovery_max_stale", c.DiscoveryMaxStale),
738		EnableAgentTLSForChecks:                 b.boolVal(c.EnableAgentTLSForChecks),
739		EnableDebug:                             b.boolVal(c.EnableDebug),
740		EnableRemoteScriptChecks:                enableRemoteScriptChecks,
741		EnableLocalScriptChecks:                 enableLocalScriptChecks,
742		EnableSyslog:                            b.boolVal(c.EnableSyslog),
743		EnableUI:                                b.boolVal(c.UI),
744		EncryptKey:                              b.stringVal(c.EncryptKey),
745		EncryptVerifyIncoming:                   b.boolVal(c.EncryptVerifyIncoming),
746		EncryptVerifyOutgoing:                   b.boolVal(c.EncryptVerifyOutgoing),
747		GRPCPort:                                grpcPort,
748		GRPCAddrs:                               grpcAddrs,
749		KeyFile:                                 b.stringVal(c.KeyFile),
750		LeaveDrainTime:                          b.durationVal("performance.leave_drain_time", c.Performance.LeaveDrainTime),
751		LeaveOnTerm:                             leaveOnTerm,
752		LogLevel:                                b.stringVal(c.LogLevel),
753		LogFile:                                 b.stringVal(c.LogFile),
754		LogRotateBytes:                          b.intVal(c.LogRotateBytes),
755		LogRotateDuration:                       b.durationVal("log_rotate_duration", c.LogRotateDuration),
756		NodeID:                                  types.NodeID(b.stringVal(c.NodeID)),
757		NodeMeta:                                c.NodeMeta,
758		NodeName:                                b.nodeName(c.NodeName),
759		NonVotingServer:                         b.boolVal(c.NonVotingServer),
760		PidFile:                                 b.stringVal(c.PidFile),
761		RPCAdvertiseAddr:                        rpcAdvertiseAddr,
762		RPCBindAddr:                             rpcBindAddr,
763		RPCHoldTimeout:                          b.durationVal("performance.rpc_hold_timeout", c.Performance.RPCHoldTimeout),
764		RPCMaxBurst:                             b.intVal(c.Limits.RPCMaxBurst),
765		RPCProtocol:                             b.intVal(c.RPCProtocol),
766		RPCRateLimit:                            rate.Limit(b.float64Val(c.Limits.RPCRate)),
767		RaftProtocol:                            b.intVal(c.RaftProtocol),
768		RaftSnapshotThreshold:                   b.intVal(c.RaftSnapshotThreshold),
769		RaftSnapshotInterval:                    b.durationVal("raft_snapshot_interval", c.RaftSnapshotInterval),
770		ReconnectTimeoutLAN:                     b.durationVal("reconnect_timeout", c.ReconnectTimeoutLAN),
771		ReconnectTimeoutWAN:                     b.durationVal("reconnect_timeout_wan", c.ReconnectTimeoutWAN),
772		RejoinAfterLeave:                        b.boolVal(c.RejoinAfterLeave),
773		RetryJoinIntervalLAN:                    b.durationVal("retry_interval", c.RetryJoinIntervalLAN),
774		RetryJoinIntervalWAN:                    b.durationVal("retry_interval_wan", c.RetryJoinIntervalWAN),
775		RetryJoinLAN:                            b.expandAllOptionalAddrs("retry_join", c.RetryJoinLAN),
776		RetryJoinMaxAttemptsLAN:                 b.intVal(c.RetryJoinMaxAttemptsLAN),
777		RetryJoinMaxAttemptsWAN:                 b.intVal(c.RetryJoinMaxAttemptsWAN),
778		RetryJoinWAN:                            b.expandAllOptionalAddrs("retry_join_wan", c.RetryJoinWAN),
779		SegmentName:                             b.stringVal(c.SegmentName),
780		Segments:                                segments,
781		SerfAdvertiseAddrLAN:                    serfAdvertiseAddrLAN,
782		SerfAdvertiseAddrWAN:                    serfAdvertiseAddrWAN,
783		SerfBindAddrLAN:                         serfBindAddrLAN,
784		SerfBindAddrWAN:                         serfBindAddrWAN,
785		SerfPortLAN:                             serfPortLAN,
786		SerfPortWAN:                             serfPortWAN,
787		ServerMode:                              b.boolVal(c.ServerMode),
788		ServerName:                              b.stringVal(c.ServerName),
789		ServerPort:                              serverPort,
790		Services:                                services,
791		SessionTTLMin:                           b.durationVal("session_ttl_min", c.SessionTTLMin),
792		SkipLeaveOnInt:                          skipLeaveOnInt,
793		StartJoinAddrsLAN:                       b.expandAllOptionalAddrs("start_join", c.StartJoinAddrsLAN),
794		StartJoinAddrsWAN:                       b.expandAllOptionalAddrs("start_join_wan", c.StartJoinAddrsWAN),
795		SyslogFacility:                          b.stringVal(c.SyslogFacility),
796		TLSCipherSuites:                         b.tlsCipherSuites("tls_cipher_suites", c.TLSCipherSuites),
797		TLSMinVersion:                           b.stringVal(c.TLSMinVersion),
798		TLSPreferServerCipherSuites:             b.boolVal(c.TLSPreferServerCipherSuites),
799		TaggedAddresses:                         c.TaggedAddresses,
800		TranslateWANAddrs:                       b.boolVal(c.TranslateWANAddrs),
801		UIDir:                                   b.stringVal(c.UIDir),
802		UnixSocketGroup:                         b.stringVal(c.UnixSocket.Group),
803		UnixSocketMode:                          b.stringVal(c.UnixSocket.Mode),
804		UnixSocketUser:                          b.stringVal(c.UnixSocket.User),
805		VerifyIncoming:                          b.boolVal(c.VerifyIncoming),
806		VerifyIncomingHTTPS:                     b.boolVal(c.VerifyIncomingHTTPS),
807		VerifyIncomingRPC:                       b.boolVal(c.VerifyIncomingRPC),
808		VerifyOutgoing:                          b.boolVal(c.VerifyOutgoing),
809		VerifyServerHostname:                    b.boolVal(c.VerifyServerHostname),
810		Watches:                                 c.Watches,
811	}
812
813	if rt.BootstrapExpect == 1 {
814		rt.Bootstrap = true
815		rt.BootstrapExpect = 0
816		b.warn(`BootstrapExpect is set to 1; this is the same as Bootstrap mode.`)
817	}
818
819	if rt.ACLReplicationToken != "" {
820		rt.EnableACLReplication = true
821	}
822
823	return rt, nil
824}
825
826// Validate performs semantical validation of the runtime configuration.
827func (b *Builder) Validate(rt RuntimeConfig) error {
828	// reDatacenter defines a regexp for a valid datacenter name
829	var reDatacenter = regexp.MustCompile("^[a-z0-9_-]+$")
830
831	// ----------------------------------------------------------------
832	// check required params we cannot recover from first
833	//
834
835	if rt.Datacenter == "" {
836		return fmt.Errorf("datacenter cannot be empty")
837	}
838	if !reDatacenter.MatchString(rt.Datacenter) {
839		return fmt.Errorf("datacenter cannot be %q. Please use only [a-z0-9-_].", rt.Datacenter)
840	}
841	if rt.DataDir == "" && !rt.DevMode {
842		return fmt.Errorf("data_dir cannot be empty")
843	}
844	if !rt.DevMode {
845		fi, err := os.Stat(rt.DataDir)
846		switch {
847		case err != nil && !os.IsNotExist(err):
848			return fmt.Errorf("Error getting info on data_dir: %s", err)
849		case err == nil && !fi.IsDir():
850			return fmt.Errorf("data_dir %q is not a directory", rt.DataDir)
851		}
852	}
853	if rt.NodeName == "" {
854		return fmt.Errorf("node_name cannot be empty")
855	}
856	if ipaddr.IsAny(rt.AdvertiseAddrLAN.IP) {
857		return fmt.Errorf("Advertise address cannot be 0.0.0.0, :: or [::]")
858	}
859	if ipaddr.IsAny(rt.AdvertiseAddrWAN.IP) {
860		return fmt.Errorf("Advertise WAN address cannot be 0.0.0.0, :: or [::]")
861	}
862	if err := b.validateSegments(rt); err != nil {
863		return err
864	}
865	for _, a := range rt.DNSAddrs {
866		if _, ok := a.(*net.UnixAddr); ok {
867			return fmt.Errorf("DNS address cannot be a unix socket")
868		}
869	}
870	for _, a := range rt.DNSRecursors {
871		if ipaddr.IsAny(a) {
872			return fmt.Errorf("DNS recursor address cannot be 0.0.0.0, :: or [::]")
873		}
874	}
875	if rt.Bootstrap && !rt.ServerMode {
876		return fmt.Errorf("'bootstrap = true' requires 'server = true'")
877	}
878	if rt.BootstrapExpect < 0 {
879		return fmt.Errorf("bootstrap_expect cannot be %d. Must be greater than or equal to zero", rt.BootstrapExpect)
880	}
881	if rt.BootstrapExpect > 0 && !rt.ServerMode {
882		return fmt.Errorf("'bootstrap_expect > 0' requires 'server = true'")
883	}
884	if rt.BootstrapExpect > 0 && rt.DevMode {
885		return fmt.Errorf("'bootstrap_expect > 0' not allowed in dev mode")
886	}
887	if rt.BootstrapExpect > 0 && rt.Bootstrap {
888		return fmt.Errorf("'bootstrap_expect > 0' and 'bootstrap = true' are mutually exclusive")
889	}
890	if rt.AEInterval <= 0 {
891		return fmt.Errorf("ae_interval cannot be %s. Must be positive", rt.AEInterval)
892	}
893	if rt.AutopilotMaxTrailingLogs < 0 {
894		return fmt.Errorf("autopilot.max_trailing_logs cannot be %d. Must be greater than or equal to zero", rt.AutopilotMaxTrailingLogs)
895	}
896	if rt.ACLDatacenter != "" && !reDatacenter.MatchString(rt.ACLDatacenter) {
897		return fmt.Errorf("acl_datacenter cannot be %q. Please use only [a-z0-9-_].", rt.ACLDatacenter)
898	}
899	if rt.EnableUI && rt.UIDir != "" {
900		return fmt.Errorf(
901			"Both the ui and ui-dir flags were specified, please provide only one.\n" +
902				"If trying to use your own web UI resources, use the ui-dir flag.\n" +
903				"If using Consul version 0.7.0 or later, the web UI is included in the binary so use ui to enable it")
904	}
905	if rt.DNSUDPAnswerLimit < 0 {
906		return fmt.Errorf("dns_config.udp_answer_limit cannot be %d. Must be greater than or equal to zero", rt.DNSUDPAnswerLimit)
907	}
908	if rt.DNSARecordLimit < 0 {
909		return fmt.Errorf("dns_config.a_record_limit cannot be %d. Must be greater than or equal to zero", rt.DNSARecordLimit)
910	}
911	if err := structs.ValidateMetadata(rt.NodeMeta, false); err != nil {
912		return fmt.Errorf("node_meta invalid: %v", err)
913	}
914	if rt.EncryptKey != "" {
915		if _, err := decodeBytes(rt.EncryptKey); err != nil {
916			return fmt.Errorf("encrypt has invalid key: %s", err)
917		}
918		keyfileLAN := filepath.Join(rt.DataDir, SerfLANKeyring)
919		if _, err := os.Stat(keyfileLAN); err == nil {
920			b.warn("WARNING: LAN keyring exists but -encrypt given, using keyring")
921		}
922		if rt.ServerMode {
923			keyfileWAN := filepath.Join(rt.DataDir, SerfWANKeyring)
924			if _, err := os.Stat(keyfileWAN); err == nil {
925				b.warn("WARNING: WAN keyring exists but -encrypt given, using keyring")
926			}
927		}
928	}
929
930	// Check the data dir for signs of an un-migrated Consul 0.5.x or older
931	// server. Consul refuses to start if this is present to protect a server
932	// with existing data from starting on a fresh data set.
933	if rt.ServerMode {
934		mdbPath := filepath.Join(rt.DataDir, "mdb")
935		if _, err := os.Stat(mdbPath); !os.IsNotExist(err) {
936			if os.IsPermission(err) {
937				return fmt.Errorf(
938					"CRITICAL: Permission denied for data folder at %q!\n"+
939						"Consul will refuse to boot without access to this directory.\n"+
940						"Please correct permissions and try starting again.", mdbPath)
941			}
942			return fmt.Errorf("CRITICAL: Deprecated data folder found at %q!\n"+
943				"Consul will refuse to boot with this directory present.\n"+
944				"See https://www.consul.io/docs/upgrade-specific.html for more information.", mdbPath)
945		}
946	}
947
948	inuse := map[string]string{}
949	if err := addrsUnique(inuse, "DNS", rt.DNSAddrs); err != nil {
950		// cannot happen since this is the first address
951		// we leave this for consistency
952		return err
953	}
954	if err := addrsUnique(inuse, "HTTP", rt.HTTPAddrs); err != nil {
955		return err
956	}
957	if err := addrsUnique(inuse, "HTTPS", rt.HTTPSAddrs); err != nil {
958		return err
959	}
960	if err := addrUnique(inuse, "RPC Advertise", rt.RPCAdvertiseAddr); err != nil {
961		return err
962	}
963	if err := addrUnique(inuse, "Serf Advertise LAN", rt.SerfAdvertiseAddrLAN); err != nil {
964		return err
965	}
966	// Validate serf WAN advertise address only when its set
967	if rt.SerfAdvertiseAddrWAN != nil {
968		if err := addrUnique(inuse, "Serf Advertise WAN", rt.SerfAdvertiseAddrWAN); err != nil {
969			return err
970		}
971	}
972	if b.err != nil {
973		return b.err
974	}
975
976	// Check for errors in the service definitions
977	for _, s := range rt.Services {
978		if err := s.Validate(); err != nil {
979			return fmt.Errorf("service %q: %s", s.Name, err)
980		}
981	}
982
983	// Validate the given Connect CA provider config
984	validCAProviders := map[string]bool{
985		"":                       true,
986		structs.ConsulCAProvider: true,
987		structs.VaultCAProvider:  true,
988	}
989	if _, ok := validCAProviders[rt.ConnectCAProvider]; !ok {
990		return fmt.Errorf("%s is not a valid CA provider", rt.ConnectCAProvider)
991	} else {
992		switch rt.ConnectCAProvider {
993		case structs.ConsulCAProvider:
994			if _, err := ca.ParseConsulCAConfig(rt.ConnectCAConfig); err != nil {
995				return err
996			}
997		case structs.VaultCAProvider:
998			if _, err := ca.ParseVaultCAConfig(rt.ConnectCAConfig); err != nil {
999				return err
1000			}
1001		}
1002	}
1003
1004	// ----------------------------------------------------------------
1005	// warnings
1006	//
1007
1008	if rt.ServerMode && !rt.DevMode && !rt.Bootstrap && rt.BootstrapExpect == 2 {
1009		b.warn(`bootstrap_expect = 2: A cluster with 2 servers will provide no failure tolerance. See https://www.consul.io/docs/internals/consensus.html#deployment-table`)
1010	}
1011
1012	if rt.ServerMode && !rt.Bootstrap && rt.BootstrapExpect > 2 && rt.BootstrapExpect%2 == 0 {
1013		b.warn(`bootstrap_expect is even number: A cluster with an even number of servers does not achieve optimum fault tolerance. See https://www.consul.io/docs/internals/consensus.html#deployment-table`)
1014	}
1015
1016	if rt.ServerMode && rt.Bootstrap && rt.BootstrapExpect == 0 {
1017		b.warn(`bootstrap = true: do not enable unless necessary`)
1018	}
1019
1020	if rt.ServerMode && !rt.DevMode && !rt.Bootstrap && rt.BootstrapExpect > 1 {
1021		b.warn("bootstrap_expect > 0: expecting %d servers", rt.BootstrapExpect)
1022	}
1023
1024	return nil
1025}
1026
1027// addrUnique checks if the given address is already in use for another
1028// protocol.
1029func addrUnique(inuse map[string]string, name string, addr net.Addr) error {
1030	key := addr.Network() + ":" + addr.String()
1031	if other, ok := inuse[key]; ok {
1032		return fmt.Errorf("%s address %s already configured for %s", name, addr.String(), other)
1033	}
1034	inuse[key] = name
1035	return nil
1036}
1037
1038// addrsUnique checks if any of the give addresses is already in use for
1039// another protocol.
1040func addrsUnique(inuse map[string]string, name string, addrs []net.Addr) error {
1041	for _, a := range addrs {
1042		if err := addrUnique(inuse, name, a); err != nil {
1043			return err
1044		}
1045	}
1046	return nil
1047}
1048
1049// splitSlicesAndValues moves all slice values defined in c to 'slices'
1050// and all other values to 'values'.
1051func (b *Builder) splitSlicesAndValues(c Config) (slices, values Config) {
1052	v, t := reflect.ValueOf(c), reflect.TypeOf(c)
1053	rs, rv := reflect.New(t), reflect.New(t)
1054
1055	for i := 0; i < t.NumField(); i++ {
1056		f := t.Field(i)
1057		if f.Type.Kind() == reflect.Slice {
1058			rs.Elem().Field(i).Set(v.Field(i))
1059		} else {
1060			rv.Elem().Field(i).Set(v.Field(i))
1061		}
1062	}
1063	return rs.Elem().Interface().(Config), rv.Elem().Interface().(Config)
1064}
1065
1066func (b *Builder) warn(msg string, args ...interface{}) {
1067	b.Warnings = append(b.Warnings, fmt.Sprintf(msg, args...))
1068}
1069
1070func (b *Builder) checkVal(v *CheckDefinition) *structs.CheckDefinition {
1071	if v == nil {
1072		return nil
1073	}
1074
1075	id := types.CheckID(b.stringVal(v.ID))
1076
1077	return &structs.CheckDefinition{
1078		ID:                             id,
1079		Name:                           b.stringVal(v.Name),
1080		Notes:                          b.stringVal(v.Notes),
1081		ServiceID:                      b.stringVal(v.ServiceID),
1082		Token:                          b.stringVal(v.Token),
1083		Status:                         b.stringVal(v.Status),
1084		ScriptArgs:                     v.ScriptArgs,
1085		HTTP:                           b.stringVal(v.HTTP),
1086		Header:                         v.Header,
1087		Method:                         b.stringVal(v.Method),
1088		TCP:                            b.stringVal(v.TCP),
1089		Interval:                       b.durationVal(fmt.Sprintf("check[%s].interval", id), v.Interval),
1090		DockerContainerID:              b.stringVal(v.DockerContainerID),
1091		Shell:                          b.stringVal(v.Shell),
1092		GRPC:                           b.stringVal(v.GRPC),
1093		GRPCUseTLS:                     b.boolVal(v.GRPCUseTLS),
1094		TLSSkipVerify:                  b.boolVal(v.TLSSkipVerify),
1095		AliasNode:                      b.stringVal(v.AliasNode),
1096		AliasService:                   b.stringVal(v.AliasService),
1097		Timeout:                        b.durationVal(fmt.Sprintf("check[%s].timeout", id), v.Timeout),
1098		TTL:                            b.durationVal(fmt.Sprintf("check[%s].ttl", id), v.TTL),
1099		DeregisterCriticalServiceAfter: b.durationVal(fmt.Sprintf("check[%s].deregister_critical_service_after", id), v.DeregisterCriticalServiceAfter),
1100	}
1101}
1102
1103func (b *Builder) serviceVal(v *ServiceDefinition) *structs.ServiceDefinition {
1104	if v == nil {
1105		return nil
1106	}
1107
1108	var checks structs.CheckTypes
1109	for _, check := range v.Checks {
1110		checks = append(checks, b.checkVal(&check).CheckType())
1111	}
1112	if v.Check != nil {
1113		checks = append(checks, b.checkVal(v.Check).CheckType())
1114	}
1115
1116	meta := make(map[string]string)
1117	if err := structs.ValidateMetadata(v.Meta, false); err != nil {
1118		b.err = multierror.Append(fmt.Errorf("invalid meta for service %s: %v", b.stringVal(v.Name), err))
1119	} else {
1120		meta = v.Meta
1121	}
1122	serviceWeights := &structs.Weights{Passing: 1, Warning: 1}
1123	if v.Weights != nil {
1124		if v.Weights.Passing != nil {
1125			serviceWeights.Passing = *v.Weights.Passing
1126		}
1127		if v.Weights.Warning != nil {
1128			serviceWeights.Warning = *v.Weights.Warning
1129		}
1130	}
1131
1132	if err := structs.ValidateWeights(serviceWeights); err != nil {
1133		b.err = multierror.Append(fmt.Errorf("Invalid weight definition for service %s: %s", b.stringVal(v.Name), err))
1134	}
1135	return &structs.ServiceDefinition{
1136		Kind:              b.serviceKindVal(v.Kind),
1137		ID:                b.stringVal(v.ID),
1138		Name:              b.stringVal(v.Name),
1139		Tags:              v.Tags,
1140		Address:           b.stringVal(v.Address),
1141		Meta:              meta,
1142		Port:              b.intVal(v.Port),
1143		Token:             b.stringVal(v.Token),
1144		EnableTagOverride: b.boolVal(v.EnableTagOverride),
1145		Weights:           serviceWeights,
1146		Checks:            checks,
1147		// DEPRECATED (ProxyDestination) - don't populate deprecated field, just use
1148		// it as a default below on read. Remove that when remofing ProxyDestination
1149		Proxy:   b.serviceProxyVal(v.Proxy, v.ProxyDestination),
1150		Connect: b.serviceConnectVal(v.Connect),
1151	}
1152}
1153
1154func (b *Builder) serviceKindVal(v *string) structs.ServiceKind {
1155	if v == nil {
1156		return structs.ServiceKindTypical
1157	}
1158	switch *v {
1159	case string(structs.ServiceKindConnectProxy):
1160		return structs.ServiceKindConnectProxy
1161	default:
1162		return structs.ServiceKindTypical
1163	}
1164}
1165
1166func (b *Builder) serviceProxyVal(v *ServiceProxy, deprecatedDest *string) *structs.ConnectProxyConfig {
1167	if v == nil {
1168		if deprecatedDest != nil {
1169			return &structs.ConnectProxyConfig{
1170				DestinationServiceName: b.stringVal(deprecatedDest),
1171			}
1172		}
1173		return nil
1174	}
1175
1176	return &structs.ConnectProxyConfig{
1177		DestinationServiceName: b.stringVal(v.DestinationServiceName),
1178		DestinationServiceID:   b.stringVal(v.DestinationServiceID),
1179		LocalServiceAddress:    b.stringVal(v.LocalServiceAddress),
1180		LocalServicePort:       b.intVal(v.LocalServicePort),
1181		Config:                 v.Config,
1182		Upstreams:              b.upstreamsVal(v.Upstreams),
1183	}
1184}
1185
1186func (b *Builder) upstreamsVal(v []Upstream) structs.Upstreams {
1187	ups := make(structs.Upstreams, len(v))
1188	for i, u := range v {
1189		ups[i] = structs.Upstream{
1190			DestinationType:      b.stringVal(u.DestinationType),
1191			DestinationNamespace: b.stringVal(u.DestinationNamespace),
1192			DestinationName:      b.stringVal(u.DestinationName),
1193			Datacenter:           b.stringVal(u.Datacenter),
1194			LocalBindAddress:     b.stringVal(u.LocalBindAddress),
1195			LocalBindPort:        b.intVal(u.LocalBindPort),
1196			Config:               u.Config,
1197		}
1198		if ups[i].DestinationType == "" {
1199			ups[i].DestinationType = structs.UpstreamDestTypeService
1200		}
1201	}
1202	return ups
1203}
1204
1205func (b *Builder) serviceConnectVal(v *ServiceConnect) *structs.ServiceConnect {
1206	if v == nil {
1207		return nil
1208	}
1209
1210	var proxy *structs.ServiceDefinitionConnectProxy
1211	if v.Proxy != nil {
1212		proxy = &structs.ServiceDefinitionConnectProxy{
1213			ExecMode:  b.stringVal(v.Proxy.ExecMode),
1214			Command:   v.Proxy.Command,
1215			Config:    v.Proxy.Config,
1216			Upstreams: b.upstreamsVal(v.Proxy.Upstreams),
1217		}
1218	}
1219
1220	sidecar := b.serviceVal(v.SidecarService)
1221	if sidecar != nil {
1222		// Sanity checks
1223		if sidecar.ID != "" {
1224			b.err = multierror.Append(b.err, fmt.Errorf("sidecar_service can't specify an ID"))
1225			sidecar.ID = ""
1226		}
1227		if sidecar.Connect != nil {
1228			if sidecar.Connect.SidecarService != nil {
1229				b.err = multierror.Append(b.err, fmt.Errorf("sidecar_service can't have a nested sidecar_service"))
1230				sidecar.Connect.SidecarService = nil
1231			}
1232			if sidecar.Connect.Proxy != nil {
1233				b.err = multierror.Append(b.err, fmt.Errorf("sidecar_service can't have a managed proxy"))
1234				sidecar.Connect.Proxy = nil
1235			}
1236		}
1237	}
1238
1239	return &structs.ServiceConnect{
1240		Native:         b.boolVal(v.Native),
1241		Proxy:          proxy,
1242		SidecarService: sidecar,
1243	}
1244}
1245
1246func (b *Builder) boolValWithDefault(v *bool, default_val bool) bool {
1247	if v == nil {
1248		return default_val
1249	}
1250
1251	return *v
1252}
1253
1254func (b *Builder) boolVal(v *bool) bool {
1255	return b.boolValWithDefault(v, false)
1256}
1257
1258func (b *Builder) durationVal(name string, v *string) (d time.Duration) {
1259	if v == nil {
1260		return 0
1261	}
1262	d, err := time.ParseDuration(*v)
1263	if err != nil {
1264		b.err = multierror.Append(fmt.Errorf("%s: invalid duration: %q: %s", name, *v, err))
1265	}
1266	return d
1267}
1268
1269func (b *Builder) intVal(v *int) int {
1270	if v == nil {
1271		return 0
1272	}
1273	return *v
1274}
1275
1276func (b *Builder) portVal(name string, v *int) int {
1277	if v == nil || *v <= 0 {
1278		return -1
1279	}
1280	if *v > 65535 {
1281		b.err = multierror.Append(b.err, fmt.Errorf("%s: invalid port: %d", name, *v))
1282	}
1283	return *v
1284}
1285
1286func (b *Builder) stringVal(v *string) string {
1287	if v == nil {
1288		return ""
1289	}
1290	return *v
1291}
1292
1293func (b *Builder) float64Val(v *float64) float64 {
1294	if v == nil {
1295		return 0
1296	}
1297
1298	return *v
1299}
1300
1301func (b *Builder) tlsCipherSuites(name string, v *string) []uint16 {
1302	if v == nil {
1303		return nil
1304	}
1305
1306	var a []uint16
1307	a, err := tlsutil.ParseCiphers(*v)
1308	if err != nil {
1309		b.err = multierror.Append(b.err, fmt.Errorf("%s: invalid tls cipher suites: %s", name, err))
1310	}
1311	return a
1312}
1313
1314func (b *Builder) nodeName(v *string) string {
1315	nodeName := b.stringVal(v)
1316	if nodeName == "" {
1317		fn := b.Hostname
1318		if fn == nil {
1319			fn = os.Hostname
1320		}
1321		name, err := fn()
1322		if err != nil {
1323			b.err = multierror.Append(b.err, fmt.Errorf("node_name: %s", err))
1324			return ""
1325		}
1326		nodeName = name
1327	}
1328	return strings.TrimSpace(nodeName)
1329}
1330
1331// expandAddrs expands the go-sockaddr template in s and returns the
1332// result as a list of *net.IPAddr and *net.UnixAddr.
1333func (b *Builder) expandAddrs(name string, s *string) []net.Addr {
1334	if s == nil || *s == "" {
1335		return nil
1336	}
1337
1338	x, err := template.Parse(*s)
1339	if err != nil {
1340		b.err = multierror.Append(b.err, fmt.Errorf("%s: error parsing %q: %s", name, *s, err))
1341		return nil
1342	}
1343
1344	var addrs []net.Addr
1345	for _, a := range strings.Fields(x) {
1346		switch {
1347		case strings.HasPrefix(a, "unix://"):
1348			addrs = append(addrs, &net.UnixAddr{Name: a[len("unix://"):], Net: "unix"})
1349		default:
1350			// net.ParseIP does not like '[::]'
1351			ip := net.ParseIP(a)
1352			if a == "[::]" {
1353				ip = net.ParseIP("::")
1354			}
1355			if ip == nil {
1356				b.err = multierror.Append(b.err, fmt.Errorf("%s: invalid ip address: %s", name, a))
1357				return nil
1358			}
1359			addrs = append(addrs, &net.IPAddr{IP: ip})
1360		}
1361	}
1362
1363	return addrs
1364}
1365
1366// expandOptionalAddrs expands the go-sockaddr template in s and returns the
1367// result as a list of strings. If s does not contain a go-sockaddr template,
1368// the result list will contain the input string as a single element with no
1369// error set. In contrast to expandAddrs, expandOptionalAddrs does not validate
1370// if the result contains valid addresses and returns a list of strings.
1371// However, if the expansion of the go-sockaddr template fails an error is set.
1372func (b *Builder) expandOptionalAddrs(name string, s *string) []string {
1373	if s == nil || *s == "" {
1374		return nil
1375	}
1376
1377	x, err := template.Parse(*s)
1378	if err != nil {
1379		b.err = multierror.Append(b.err, fmt.Errorf("%s: error parsing %q: %s", name, *s, err))
1380		return nil
1381	}
1382
1383	if x != *s {
1384		// A template has been expanded, split the results from go-sockaddr
1385		return strings.Fields(x)
1386	} else {
1387		// No template has been expanded, pass through the input
1388		return []string{*s}
1389	}
1390}
1391
1392func (b *Builder) expandAllOptionalAddrs(name string, addrs []string) []string {
1393	out := make([]string, 0, len(addrs))
1394	for _, a := range addrs {
1395		expanded := b.expandOptionalAddrs(name, &a)
1396		if expanded != nil {
1397			out = append(out, expanded...)
1398		}
1399	}
1400	return out
1401}
1402
1403// expandIPs expands the go-sockaddr template in s and returns a list of
1404// *net.IPAddr. If one of the expanded addresses is a unix socket
1405// address an error is set and nil is returned.
1406func (b *Builder) expandIPs(name string, s *string) []*net.IPAddr {
1407	if s == nil || *s == "" {
1408		return nil
1409	}
1410
1411	addrs := b.expandAddrs(name, s)
1412	var x []*net.IPAddr
1413	for _, addr := range addrs {
1414		switch a := addr.(type) {
1415		case *net.IPAddr:
1416			x = append(x, a)
1417		case *net.UnixAddr:
1418			b.err = multierror.Append(b.err, fmt.Errorf("%s cannot be a unix socket", name))
1419			return nil
1420		default:
1421			b.err = multierror.Append(b.err, fmt.Errorf("%s has invalid address type %T", name, a))
1422			return nil
1423		}
1424	}
1425	return x
1426}
1427
1428// expandFirstAddr expands the go-sockaddr template in s and returns the
1429// first address which is either a *net.IPAddr or a *net.UnixAddr. If
1430// the template expands to multiple addresses an error is set and nil
1431// is returned.
1432func (b *Builder) expandFirstAddr(name string, s *string) net.Addr {
1433	if s == nil || *s == "" {
1434		return nil
1435	}
1436
1437	addrs := b.expandAddrs(name, s)
1438	if len(addrs) == 0 {
1439		return nil
1440	}
1441	if len(addrs) > 1 {
1442		var x []string
1443		for _, a := range addrs {
1444			x = append(x, a.String())
1445		}
1446		b.err = multierror.Append(b.err, fmt.Errorf("%s: multiple addresses found: %s", name, strings.Join(x, " ")))
1447		return nil
1448	}
1449	return addrs[0]
1450}
1451
1452// expandFirstIP expands the go-sockaddr template in s and returns the
1453// first address if it is not a unix socket address. If the template
1454// expands to multiple addresses an error is set and nil is returned.
1455func (b *Builder) expandFirstIP(name string, s *string) *net.IPAddr {
1456	if s == nil || *s == "" {
1457		return nil
1458	}
1459
1460	addr := b.expandFirstAddr(name, s)
1461	if addr == nil {
1462		return nil
1463	}
1464	switch a := addr.(type) {
1465	case *net.IPAddr:
1466		return a
1467	case *net.UnixAddr:
1468		b.err = multierror.Append(b.err, fmt.Errorf("%s cannot be a unix socket", name))
1469		return nil
1470	default:
1471		b.err = multierror.Append(b.err, fmt.Errorf("%s has invalid address type %T", name, a))
1472		return nil
1473	}
1474}
1475
1476func (b *Builder) makeIPAddr(pri *net.IPAddr, sec *net.IPAddr) *net.IPAddr {
1477	if pri != nil {
1478		return pri
1479	}
1480	return sec
1481}
1482
1483func (b *Builder) makeTCPAddr(pri *net.IPAddr, sec net.Addr, port int) *net.TCPAddr {
1484	if pri == nil && reflect.ValueOf(sec).IsNil() || port <= 0 {
1485		return nil
1486	}
1487	addr := pri
1488	if addr == nil {
1489		switch a := sec.(type) {
1490		case *net.IPAddr:
1491			addr = a
1492		case *net.TCPAddr:
1493			addr = &net.IPAddr{IP: a.IP}
1494		default:
1495			panic(fmt.Sprintf("makeTCPAddr requires a net.IPAddr or a net.TCPAddr. Got %T", a))
1496		}
1497	}
1498	return &net.TCPAddr{IP: addr.IP, Port: port}
1499}
1500
1501// makeAddr creates an *net.TCPAddr or a *net.UnixAddr from either the
1502// primary or secondary address and the given port. If the port is <= 0
1503// then the address is considered to be disabled and nil is returned.
1504func (b *Builder) makeAddr(pri, sec net.Addr, port int) net.Addr {
1505	if reflect.ValueOf(pri).IsNil() && reflect.ValueOf(sec).IsNil() || port <= 0 {
1506		return nil
1507	}
1508	addr := pri
1509	if addr == nil {
1510		addr = sec
1511	}
1512	switch a := addr.(type) {
1513	case *net.IPAddr:
1514		return &net.TCPAddr{IP: a.IP, Port: port}
1515	case *net.UnixAddr:
1516		return a
1517	default:
1518		panic(fmt.Sprintf("invalid address type %T", a))
1519	}
1520}
1521
1522// makeAddrs creates a list of *net.TCPAddr or *net.UnixAddr entries
1523// from either the primary or secondary addresses and the given port.
1524// If the port is <= 0 then the address is considered to be disabled
1525// and nil is returned.
1526func (b *Builder) makeAddrs(pri []net.Addr, sec []*net.IPAddr, port int) []net.Addr {
1527	if len(pri) == 0 && len(sec) == 0 || port <= 0 {
1528		return nil
1529	}
1530	addrs := pri
1531	if len(addrs) == 0 {
1532		addrs = []net.Addr{}
1533		for _, a := range sec {
1534			addrs = append(addrs, a)
1535		}
1536	}
1537	var x []net.Addr
1538	for _, a := range addrs {
1539		x = append(x, b.makeAddr(a, nil, port))
1540	}
1541	return x
1542}
1543
1544// isUnixAddr returns true when the given address is a unix socket address type.
1545func (b *Builder) isUnixAddr(a net.Addr) bool {
1546	_, ok := a.(*net.UnixAddr)
1547	return a != nil && ok
1548}
1549
1550// decodeBytes returns the encryption key decoded.
1551func decodeBytes(key string) ([]byte, error) {
1552	return base64.StdEncoding.DecodeString(key)
1553}
1554
1555func isIPAddr(a net.Addr) bool {
1556	_, ok := a.(*net.IPAddr)
1557	return ok
1558}
1559
1560func isUnixAddr(a net.Addr) bool {
1561	_, ok := a.(*net.UnixAddr)
1562	return ok
1563}
1564