Run all known addresses through go-sockaddr/template.

The following is now possible:

```
$ consul agent -dev -client="{{GetPrivateIP}}" -bind='{{GetInterfaceIP "en0"}}'
```
This commit is contained in:
Sean Chittenden 2016-12-02 16:35:38 +11:00
parent f3ed18e95f
commit 830125a8b3
No known key found for this signature in database
GPG Key ID: 4EBC9DC16C2E5E16
2 changed files with 152 additions and 0 deletions

View File

@ -2,6 +2,7 @@ package agent
import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@ -12,6 +13,7 @@ import (
"reflect"
"regexp"
"strconv"
"strings"
"sync"
"time"
@ -21,6 +23,7 @@ import (
"github.com/hashicorp/consul/lib"
"github.com/hashicorp/consul/logger"
"github.com/hashicorp/consul/types"
"github.com/hashicorp/go-sockaddr/template"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/serf/coordinate"
"github.com/hashicorp/serf/serf"
@ -140,6 +143,12 @@ func Create(config *Config, logOutput io.Writer, logWriter *logger.LogWriter,
// Try to get an advertise address
if config.AdvertiseAddr != "" {
ipStr, err := parseSingleIPTemplate(config.AdvertiseAddr)
if err != nil {
return nil, fmt.Errorf("Advertise address resolution failed: %v", err)
}
config.AdvertiseAddr = ipStr
if ip := net.ParseIP(config.AdvertiseAddr); ip == nil {
return nil, fmt.Errorf("Failed to parse advertise address: %v", config.AdvertiseAddr)
}
@ -161,6 +170,12 @@ func Create(config *Config, logOutput io.Writer, logWriter *logger.LogWriter,
// Try to get an advertise address for the wan
if config.AdvertiseAddrWan != "" {
ipStr, err := parseSingleIPTemplate(config.AdvertiseAddrWan)
if err != nil {
return nil, fmt.Errorf("Advertise WAN address resolution failed: %v", err)
}
config.AdvertiseAddrWan = ipStr
if ip := net.ParseIP(config.AdvertiseAddrWan); ip == nil {
return nil, fmt.Errorf("Failed to parse advertise address for wan: %v", config.AdvertiseAddrWan)
}
@ -192,6 +207,10 @@ func Create(config *Config, logOutput io.Writer, logWriter *logger.LogWriter,
endpoints: make(map[string]string),
}
if err := agent.resolveTmplAddrs(); err != nil {
return nil, err
}
// Initialize the local state.
agent.state.Init(config, agent.logger)
@ -400,6 +419,121 @@ func (a *Agent) consulConfig() *consul.Config {
return base
}
// parseSingleIPTemplate is used as a helper function to parse out a single IP
// address from a config parameter.
func parseSingleIPTemplate(ipTmpl string) (string, error) {
out, err := template.Parse(ipTmpl)
if err != nil {
return "", fmt.Errorf("Unable to parse address template %q: %v", ipTmpl, err)
}
ips := strings.Split(out, " ")
switch len(ips) {
case 0:
return "", errors.New("No addresses found, please configure one.")
case 1:
return ips[0], nil
default:
return "", fmt.Errorf("Multiple addresses found (%q), please configure one.", out)
}
}
// resolveTmplAddrs iterates over the myriad of addresses in the agent's config
// and performs go-sockaddr/template Parse on each known address in case the
// user specified a template config for any of their values.
func (a *Agent) resolveTmplAddrs() error {
if a.config.AdvertiseAddr != "" {
ipStr, err := parseSingleIPTemplate(a.config.AdvertiseAddr)
if err != nil {
return fmt.Errorf("Advertise address resolution failed: %v", err)
}
a.config.AdvertiseAddr = ipStr
}
if a.config.Addresses.DNS != "" {
ipStr, err := parseSingleIPTemplate(a.config.Addresses.DNS)
if err != nil {
return fmt.Errorf("DNS address resolution failed: %v", err)
}
a.config.Addresses.DNS = ipStr
}
if a.config.Addresses.HTTP != "" {
ipStr, err := parseSingleIPTemplate(a.config.Addresses.HTTP)
if err != nil {
return fmt.Errorf("HTTP address resolution failed: %v", err)
}
a.config.Addresses.HTTP = ipStr
}
if a.config.Addresses.HTTPS != "" {
ipStr, err := parseSingleIPTemplate(a.config.Addresses.HTTPS)
if err != nil {
return fmt.Errorf("HTTPS address resolution failed: %v", err)
}
a.config.Addresses.HTTPS = ipStr
}
if a.config.Addresses.RPC != "" {
ipStr, err := parseSingleIPTemplate(a.config.Addresses.RPC)
if err != nil {
return fmt.Errorf("RPC address resolution failed: %v", err)
}
a.config.Addresses.RPC = ipStr
}
if a.config.AdvertiseAddrWan != "" {
ipStr, err := parseSingleIPTemplate(a.config.AdvertiseAddrWan)
if err != nil {
return fmt.Errorf("Advertise WAN address resolution failed: %v", err)
}
a.config.AdvertiseAddrWan = ipStr
}
if a.config.BindAddr != "" {
ipStr, err := parseSingleIPTemplate(a.config.BindAddr)
if err != nil {
return fmt.Errorf("Bind address resolution failed: %v", err)
}
a.config.BindAddr = ipStr
}
if a.config.ClientAddr != "" {
ipStr, err := parseSingleIPTemplate(a.config.ClientAddr)
if err != nil {
return fmt.Errorf("Client address resolution failed: %v", err)
}
a.config.ClientAddr = ipStr
}
if a.config.SerfLanBindAddr != "" {
ipStr, err := parseSingleIPTemplate(a.config.SerfLanBindAddr)
if err != nil {
return fmt.Errorf("Serf LAN Address resolution failed: %v", err)
}
a.config.SerfLanBindAddr = ipStr
}
if a.config.SerfWanBindAddr != "" {
ipStr, err := parseSingleIPTemplate(a.config.SerfWanBindAddr)
if err != nil {
return fmt.Errorf("Serf WAN Address resolution failed: %v", err)
}
a.config.SerfWanBindAddr = ipStr
}
// Parse all tagged addresses
for k, v := range a.config.TaggedAddresses {
ipStr, err := parseSingleIPTemplate(v)
if err != nil {
return fmt.Errorf("%s address resolution failed: %v", k, err)
}
a.config.TaggedAddresses[k] = ipStr
}
return nil
}
// setupServer is used to initialize the Consul server
func (a *Agent) setupServer() error {
config := a.consulConfig()

View File

@ -967,6 +967,12 @@ func DecodeConfig(r io.Reader) (*Config, error) {
}
if result.AdvertiseAddrs.SerfLanRaw != "" {
ipStr, err := parseSingleIPTemplate(result.AdvertiseAddrs.SerfLanRaw)
if err != nil {
return nil, fmt.Errorf("Serf Advertise LAN address resolution failed: %v", err)
}
result.AdvertiseAddrs.SerfLanRaw = ipStr
addr, err := net.ResolveTCPAddr("tcp", result.AdvertiseAddrs.SerfLanRaw)
if err != nil {
return nil, fmt.Errorf("AdvertiseAddrs.SerfLan is invalid: %v", err)
@ -975,6 +981,12 @@ func DecodeConfig(r io.Reader) (*Config, error) {
}
if result.AdvertiseAddrs.SerfWanRaw != "" {
ipStr, err := parseSingleIPTemplate(result.AdvertiseAddrs.SerfWanRaw)
if err != nil {
return nil, fmt.Errorf("Serf Advertise WAN address resolution failed: %v", err)
}
result.AdvertiseAddrs.SerfWanRaw = ipStr
addr, err := net.ResolveTCPAddr("tcp", result.AdvertiseAddrs.SerfWanRaw)
if err != nil {
return nil, fmt.Errorf("AdvertiseAddrs.SerfWan is invalid: %v", err)
@ -983,6 +995,12 @@ func DecodeConfig(r io.Reader) (*Config, error) {
}
if result.AdvertiseAddrs.RPCRaw != "" {
ipStr, err := parseSingleIPTemplate(result.AdvertiseAddrs.RPCRaw)
if err != nil {
return nil, fmt.Errorf("RPC Advertise address resolution failed: %v", err)
}
result.AdvertiseAddrs.RPCRaw = ipStr
addr, err := net.ResolveTCPAddr("tcp", result.AdvertiseAddrs.RPCRaw)
if err != nil {
return nil, fmt.Errorf("AdvertiseAddrs.RPC is invalid: %v", err)