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