diff --git a/command/agent/agent.go b/command/agent/agent.go index 60e7f0276..5c8399270 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -131,13 +131,13 @@ func (a *Agent) serverConfig() (*nomad.Config, error) { } // Set up the bind addresses - rpcAddr, err := net.ResolveTCPAddr("tcp", a.config.Addresses.RPC) + rpcAddr, err := net.ResolveTCPAddr("tcp", a.config.normalizedAddrs.RPC) if err != nil { - return nil, fmt.Errorf("Failed to parse RPC address %q: %v", a.config.Addresses.RPC, err) + return nil, fmt.Errorf("Failed to parse RPC address %q: %v", a.config.normalizedAddrs.RPC, err) } - serfAddr, err := net.ResolveTCPAddr("tcp", a.config.Addresses.Serf) + serfAddr, err := net.ResolveTCPAddr("tcp", a.config.normalizedAddrs.Serf) if err != nil { - return nil, fmt.Errorf("Failed to parse Serf address %q: %v", a.config.Addresses.Serf, err) + return nil, fmt.Errorf("Failed to parse Serf address %q: %v", a.config.normalizedAddrs.Serf, err) } conf.RPCAddr.Port = rpcAddr.Port conf.RPCAddr.IP = rpcAddr.IP @@ -256,7 +256,7 @@ func (a *Agent) clientConfig() (*clientconfig.Config, error) { conf.Node.NodeClass = a.config.Client.NodeClass // Set up the HTTP advertise address - conf.Node.HTTPAddr = a.config.Addresses.HTTP + conf.Node.HTTPAddr = a.config.AdvertiseAddrs.HTTP // Reserve resources on the node. r := conf.Node.Reserved @@ -315,9 +315,9 @@ func (a *Agent) setupServer() error { a.server = server // Consul check addresses default to bind but can be toggled to use advertise - httpCheckAddr := a.config.Addresses.HTTP - rpcCheckAddr := a.config.Addresses.RPC - serfCheckAddr := a.config.Addresses.Serf + httpCheckAddr := a.config.normalizedAddrs.HTTP + rpcCheckAddr := a.config.normalizedAddrs.RPC + serfCheckAddr := a.config.normalizedAddrs.Serf if a.config.Consul.ChecksUseAdvertise { httpCheckAddr = a.config.AdvertiseAddrs.HTTP rpcCheckAddr = a.config.AdvertiseAddrs.RPC @@ -438,7 +438,7 @@ func (a *Agent) setupClient() error { a.client = client // Resolve the http check address - httpCheckAddr := a.config.Addresses.HTTP + httpCheckAddr := a.config.normalizedAddrs.HTTP if a.config.Consul.ChecksUseAdvertise { httpCheckAddr = a.config.AdvertiseAddrs.HTTP } diff --git a/command/agent/agent_test.go b/command/agent/agent_test.go index 6e385d1c2..9615c027a 100644 --- a/command/agent/agent_test.go +++ b/command/agent/agent_test.go @@ -13,14 +13,6 @@ import ( sconfig "github.com/hashicorp/nomad/nomad/structs/config" ) -// getTestLogger returns a log func appropriate for passing to -// Config.normalize() -func getTestLogger(t testing.TB) func(string) { - return func(s string) { - t.Log(s) - } -} - func getPort() int { addr, err := net.ResolveTCPAddr("tcp", "localhost:0") if err != nil { @@ -80,8 +72,8 @@ func makeAgent(t testing.TB, cb func(*Config)) (string, *Agent) { cb(conf) } - if ok := conf.normalize(getTestLogger(t), config.DevMode); !ok { - t.Fatalf("error normalizing config") + if err := conf.normalizeAddrs(); err != nil { + t.Fatalf("error normalizing config: %v", err) } agent, err := NewAgent(conf, os.Stderr) if err != nil { @@ -104,30 +96,16 @@ func TestAgent_RPCPing(t *testing.T) { func TestAgent_ServerConfig(t *testing.T) { conf := DefaultConfig() + conf.DevMode = true // allow localhost for advertise addrs a := &Agent{config: conf} - testlogger := getTestLogger(t) - dev := false - // Returns error on bad serf addr - conf.AdvertiseAddrs.Serf = "nope" - _, err := a.serverConfig() - if err == nil || !strings.Contains(err.Error(), "Failed to parse Serf") { - t.Fatalf("expected serf address error, got: %#v", err) - } conf.AdvertiseAddrs.Serf = "127.0.0.1:4000" - - // Returns error on bad rpc addr - conf.AdvertiseAddrs.RPC = "nope" - _, err = a.serverConfig() - if err == nil || !strings.Contains(err.Error(), "Failed to parse RPC") { - t.Fatalf("expected rpc address error, got: %#v", err) - } conf.AdvertiseAddrs.RPC = "127.0.0.1:4001" conf.AdvertiseAddrs.HTTP = "10.10.11.1:4005" // Parses the advertise addrs correctly - if ok := conf.normalize(testlogger, dev); !ok { - t.Fatalf("failed to normalize config") + if err := conf.normalizeAddrs(); err != nil { + t.Fatalf("error normalizing config: %v", err) } out, err := a.serverConfig() if err != nil { @@ -149,8 +127,8 @@ func TestAgent_ServerConfig(t *testing.T) { if addr := conf.AdvertiseAddrs.HTTP; addr != "10.10.11.1:4005" { t.Fatalf("expect 10.11.11.1:4005, got: %v", addr) } - if addr := conf.Addresses.RPC; addr != "0.0.0.0:4647" { - t.Fatalf("expect 0.0.0.0:4001, got: %v", addr) + if addr := conf.Addresses.RPC; addr != "0.0.0.0" { + t.Fatalf("expect 0.0.0.0, got: %v", addr) } // Sets up the ports properly @@ -159,8 +137,8 @@ func TestAgent_ServerConfig(t *testing.T) { conf.Ports.RPC = 4003 conf.Ports.Serf = 4004 - if ok := conf.normalize(testlogger, dev); !ok { - t.Fatalf("failed to normalize config") + if err := conf.normalizeAddrs(); err != nil { + t.Fatalf("error normalizing config: %v", err) } out, err = a.serverConfig() if err != nil { @@ -182,8 +160,8 @@ func TestAgent_ServerConfig(t *testing.T) { conf.AdvertiseAddrs.RPC = "" conf.AdvertiseAddrs.Serf = "10.0.0.12:4004" - if ok := conf.normalize(testlogger, dev); !ok { - t.Fatalf("failed to normalize config") + if err := conf.normalizeAddrs(); err != nil { + t.Fatalf("error normalizing config: %v", err) } out, err = a.serverConfig() fmt.Println(conf.Addresses.RPC) @@ -202,28 +180,37 @@ func TestAgent_ServerConfig(t *testing.T) { if port := out.SerfConfig.MemberlistConfig.BindPort; port != 4004 { t.Fatalf("expect 4648, got: ^d", port) } - if addr := conf.Addresses.HTTP; addr != "127.0.0.2:4646" { + if addr := conf.Addresses.HTTP; addr != "127.0.0.2" { + t.Fatalf("expect 127.0.0.2, got: %s", addr) + } + if addr := conf.Addresses.RPC; addr != "127.0.0.2" { + t.Fatalf("expect 127.0.0.2, got: %s", addr) + } + if addr := conf.Addresses.Serf; addr != "127.0.0.2" { + t.Fatalf("expect 10.0.0.12, got: %s", addr) + } + if addr := conf.normalizedAddrs.HTTP; addr != "127.0.0.2:4646" { t.Fatalf("expect 127.0.0.2:4646, got: %s", addr) } - if addr := conf.Addresses.RPC; addr != "127.0.0.2:4003" { + if addr := conf.normalizedAddrs.RPC; addr != "127.0.0.2:4003" { t.Fatalf("expect 127.0.0.2:4003, got: %s", addr) } - if addr := conf.Addresses.Serf; addr != "127.0.0.2:4004" { + if addr := conf.normalizedAddrs.Serf; addr != "127.0.0.2:4004" { t.Fatalf("expect 10.0.0.12:4004, got: %s", addr) } if addr := conf.AdvertiseAddrs.HTTP; addr != "10.0.0.10:4646" { t.Fatalf("expect 10.0.0.10:4646, got: %s", addr) } - if addr := conf.AdvertiseAddrs.RPC; addr != "127.0.0.3:4003" { - t.Fatalf("expect 127.0.0.3:4003, got: %s", addr) + if addr := conf.AdvertiseAddrs.RPC; addr != "127.0.0.2:4003" { + t.Fatalf("expect 127.0.0.2:4003, got: %s", addr) } if addr := conf.AdvertiseAddrs.Serf; addr != "10.0.0.12:4004" { t.Fatalf("expect 10.0.0.12:4004, got: %s", addr) } conf.Server.NodeGCThreshold = "42g" - if ok := conf.normalize(testlogger, dev); !ok { - t.Fatalf("failed to normalize config") + if err := conf.normalizeAddrs(); err != nil { + t.Fatalf("error normalizing config: %v", err) } out, err = a.serverConfig() if err == nil || !strings.Contains(err.Error(), "unknown unit") { @@ -231,8 +218,8 @@ func TestAgent_ServerConfig(t *testing.T) { } conf.Server.NodeGCThreshold = "10s" - if ok := conf.normalize(testlogger, dev); !ok { - t.Fatalf("failed to normalize config") + if err := conf.normalizeAddrs(); err != nil { + t.Fatalf("error normalizing config: %v", err) } out, err = a.serverConfig() if threshold := out.NodeGCThreshold; threshold != time.Second*10 { @@ -240,8 +227,8 @@ func TestAgent_ServerConfig(t *testing.T) { } conf.Server.HeartbeatGrace = "42g" - if ok := conf.normalize(testlogger, dev); !ok { - t.Fatalf("failed to normalize config") + if err := conf.normalizeAddrs(); err != nil { + t.Fatalf("error normalizing config: %v", err) } out, err = a.serverConfig() if err == nil || !strings.Contains(err.Error(), "unknown unit") { @@ -249,8 +236,8 @@ func TestAgent_ServerConfig(t *testing.T) { } conf.Server.HeartbeatGrace = "37s" - if ok := conf.normalize(testlogger, dev); !ok { - t.Fatalf("failed to normalize config") + if err := conf.normalizeAddrs(); err != nil { + t.Fatalf("error normalizing config: %v", err) } out, err = a.serverConfig() if threshold := out.HeartbeatGrace; threshold != time.Second*37 { @@ -267,8 +254,8 @@ func TestAgent_ServerConfig(t *testing.T) { conf.Ports.HTTP = 4646 conf.Ports.RPC = 4647 conf.Ports.Serf = 4648 - if ok := conf.normalize(testlogger, dev); !ok { - t.Fatalf("failed to normalize config") + if err := conf.normalizeAddrs(); err != nil { + t.Fatalf("error normalizing config: %v", err) } out, err = a.serverConfig() if err != nil { @@ -280,13 +267,22 @@ func TestAgent_ServerConfig(t *testing.T) { if addr := out.SerfConfig.MemberlistConfig.BindAddr; addr != "127.0.0.3" { t.Fatalf("expect 127.0.0.3, got: %s", addr) } - if addr := conf.Addresses.HTTP; addr != "127.0.0.3:4646" { + if addr := conf.Addresses.HTTP; addr != "127.0.0.3" { + t.Fatalf("expect 127.0.0.3, got: %s", addr) + } + if addr := conf.Addresses.RPC; addr != "127.0.0.3" { + t.Fatalf("expect 127.0.0.3, got: %s", addr) + } + if addr := conf.Addresses.Serf; addr != "127.0.0.3" { + t.Fatalf("expect 127.0.0.3, got: %s", addr) + } + if addr := conf.normalizedAddrs.HTTP; addr != "127.0.0.3:4646" { t.Fatalf("expect 127.0.0.3:4646, got: %s", addr) } - if addr := conf.Addresses.RPC; addr != "127.0.0.3:4647" { + if addr := conf.normalizedAddrs.RPC; addr != "127.0.0.3:4647" { t.Fatalf("expect 127.0.0.3:4647, got: %s", addr) } - if addr := conf.Addresses.Serf; addr != "127.0.0.3:4648" { + if addr := conf.normalizedAddrs.Serf; addr != "127.0.0.3:4648" { t.Fatalf("expect 127.0.0.3:4648, got: %s", addr) } @@ -325,8 +321,8 @@ func TestAgent_ClientConfig(t *testing.T) { conf.Addresses.HTTP = "127.0.0.1" conf.Ports.HTTP = 5678 - if ok := conf.normalize(getTestLogger(t), conf.DevMode); !ok { - t.Fatalf("error normalizing config") + if err := conf.normalizeAddrs(); err != nil { + t.Fatalf("error normalizing config: %v", err) } c, err := a.clientConfig() if err != nil { @@ -344,8 +340,8 @@ func TestAgent_ClientConfig(t *testing.T) { conf.Client.Enabled = true conf.Addresses.HTTP = "127.0.0.1" - if ok := conf.normalize(getTestLogger(t), conf.DevMode); !ok { - t.Fatalf("error normalizing config") + if err := conf.normalizeAddrs(); err != nil { + t.Fatalf("error normalizing config: %v", err) } c, err = a.clientConfig() if err != nil { diff --git a/command/agent/command.go b/command/agent/command.go index 5253db259..c0ce3b78f 100644 --- a/command/agent/command.go +++ b/command/agent/command.go @@ -196,7 +196,14 @@ func (c *Command) readConfig() *Config { // Merge any CLI options over config file options config = config.Merge(cmdConfig) - if ok := config.normalize(c.Ui.Error, dev); !ok { + // Set the version info + config.Revision = c.Revision + config.Version = c.Version + config.VersionPrerelease = c.VersionPrerelease + + // Normalize binds, ports, addresses, and advertise + if err := config.normalizeAddrs(); err != nil { + c.Ui.Error(err.Error()) return nil } @@ -205,6 +212,17 @@ func (c *Command) readConfig() *Config { return config } + if config.Server.EncryptKey != "" { + if _, err := config.Server.EncryptBytes(); err != nil { + c.Ui.Error(fmt.Sprintf("Invalid encryption key: %s", err)) + return nil + } + keyfile := filepath.Join(config.DataDir, serfKeyring) + if _, err := os.Stat(keyfile); err == nil { + c.Ui.Warn("WARNING: keyring exists but -encrypt given, using keyring") + } + } + // Parse the RetryInterval. dur, err := time.ParseDuration(config.Server.RetryInterval) if err != nil { diff --git a/command/agent/command_test.go b/command/agent/command_test.go index 449fd6cac..248ef1185 100644 --- a/command/agent/command_test.go +++ b/command/agent/command_test.go @@ -61,7 +61,7 @@ func TestCommand_Args(t *testing.T) { // To prevent test failures on hosts whose hostname resolves to // a loopback address, we must append a bind address - tc.args = append(tc.args, "-bind=127.0.0.1") + tc.args = append(tc.args, "-bind=169.254.0.1") if code := cmd.Run(tc.args); code != 1 { t.Fatalf("args: %v\nexit: %d\n", tc.args, code) } diff --git a/command/agent/config.go b/command/agent/config.go index bd0ad60b1..e9b1cdfe8 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -46,8 +46,13 @@ type Config struct { Ports *Ports `mapstructure:"ports"` // Addresses is used to override the network addresses we bind to. + // + // Use normalizedAddrs if you need the host+port to bind to. Addresses *Addresses `mapstructure:"addresses"` + // normalizedAddr is set to the Address+Port by normalizeAddrs() + normalizedAddrs *Addresses + // AdvertiseAddrs is used to control the addresses we advertise. AdvertiseAddrs *AdvertiseAddrs `mapstructure:"advertise"` @@ -335,8 +340,8 @@ type Telemetry struct { CirconusBrokerSelectTag string `mapstructure:"circonus_broker_select_tag"` } -// Ports is used to encapsulate the various ports we bind to for network -// services. If any are not specified then the defaults are used instead. +// Ports encapsulates the various ports we bind to for network services. If any +// are not specified then the defaults are used instead. type Ports struct { HTTP int `mapstructure:"http"` RPC int `mapstructure:"rpc"` @@ -352,8 +357,8 @@ type Addresses struct { } // AdvertiseAddrs is used to control the addresses we advertise out for -// different network services. Not all network services support an -// advertise address. All are optional and default to BindAddr. +// different network services. All are optional and default to BindAddr and +// their default Port. type AdvertiseAddrs struct { HTTP string `mapstructure:"http"` RPC string `mapstructure:"rpc"` @@ -658,137 +663,116 @@ func (c *Config) Merge(b *Config) *Config { return &result } -// normalize config to set defaults and prevent nil derefence panics. -// -// Returns true if config is ok and false on errors. Since some normalization -// issues aren't fatal a logger must be provided to emit warnings. -func (c *Config) normalize(logger func(string), dev bool) bool { - // Set the version info - c.Revision = c.Revision - c.Version = c.Version - c.VersionPrerelease = c.VersionPrerelease - - // Normalize addresses - bind := c.BindAddr - if err := normalizeBind(&c.Addresses.HTTP, bind, &c.Ports.HTTP); err != nil { - logger(err.Error()) - return false - } - if err := normalizeBind(&c.Addresses.RPC, bind, &c.Ports.RPC); err != nil { - logger(err.Error()) - return false - } - if err := normalizeBind(&c.Addresses.Serf, bind, &c.Ports.Serf); err != nil { - logger(err.Error()) - return false +// normalize Addresses and AdvertiseAddrs to always be initialized and have +// sane defaults. +func (c *Config) normalizeAddrs() error { + c.Addresses.HTTP = normalizeBind(c.Addresses.HTTP, c.BindAddr) + c.Addresses.RPC = normalizeBind(c.Addresses.RPC, c.BindAddr) + c.Addresses.Serf = normalizeBind(c.Addresses.Serf, c.BindAddr) + c.normalizedAddrs = &Addresses{ + HTTP: fmt.Sprintf("%s:%d", c.Addresses.HTTP, c.Ports.HTTP), + RPC: fmt.Sprintf("%s:%d", c.Addresses.RPC, c.Ports.RPC), + Serf: fmt.Sprintf("%s:%d", c.Addresses.Serf, c.Ports.Serf), } - if err := normalizeAdvertise(&c.AdvertiseAddrs.HTTP, bind, c.Ports.HTTP, dev); err != nil { - logger(err.Error()) - return false - } - if err := normalizeAdvertise(&c.AdvertiseAddrs.RPC, bind, c.Ports.RPC, dev); err != nil { - logger(err.Error()) - return false - } - if err := normalizeAdvertise(&c.AdvertiseAddrs.Serf, bind, c.Ports.Serf, dev); err != nil { - logger(err.Error()) - return false + addr, err := normalizeAdvertise(c.AdvertiseAddrs.HTTP, c.Addresses.HTTP, c.Ports.HTTP, c.DevMode) + if err != nil { + return fmt.Errorf("Failed to parse HTTP advertise address: %v", err) } + c.AdvertiseAddrs.HTTP = addr - if c.Server.EncryptKey != "" { - if _, err := c.Server.EncryptBytes(); err != nil { - logger(fmt.Sprintf("Invalid encryption key: %s", err)) - return false - } - keyfile := filepath.Join(c.DataDir, serfKeyring) - if _, err := os.Stat(keyfile); err == nil { - logger("WARNING: keyring exists but -encrypt given, using keyring") - } + addr, err = normalizeAdvertise(c.AdvertiseAddrs.RPC, c.Addresses.RPC, c.Ports.RPC, c.DevMode) + if err != nil { + return fmt.Errorf("Failed to parse RPC advertise address: %v", err) } - return true + c.AdvertiseAddrs.RPC = addr + + addr, err = normalizeAdvertise(c.AdvertiseAddrs.Serf, c.Addresses.Serf, c.Ports.Serf, c.DevMode) + if err != nil { + return fmt.Errorf("Failed to parse Serf advertise address: %v", err) + } + c.AdvertiseAddrs.Serf = addr + + return nil } -// Use normalizeAdvertise(&config.AdvertiseAddrs., ) to -// retrieve a default address for advertising if one isn't set. -func normalizeAdvertise(addr *string, bind string, defport int, dev bool) error { - if *addr != "" { +// normalizeBind returns a normalized bind address. +// +// If addr is set it is used, if not the default bind address is used. +func normalizeBind(addr, bind string) string { + if addr == "" { + return bind + } + return addr +} + +// normalizeAdvertise returns a normalized advertise address. +// +// If addr is set, it is used and the default port is appended if no port is +// set. +// +// If addr is not set and bind is a valid address, the returned string is the +// bind+port. +// +// If addr is not set and bind is not a valid advertise address, the hostname +// is resolved and returned with the port. +// +// Loopback is only considered a valid advertise address in dev mode. +func normalizeAdvertise(addr string, bind string, defport int, dev bool) (string, error) { + if addr != "" { // Default to using manually configured address - _, _, err := net.SplitHostPort(*addr) + _, _, err := net.SplitHostPort(addr) if err != nil { if !isMissingPort(err) { - return fmt.Errorf("Error parsing advertise address %q: %v", *addr, err) + return "", fmt.Errorf("Error parsing advertise address %q: %v", addr, err) } // missing port, append the default - newaddr := fmt.Sprintf("%s:%d", *addr, defport) - *addr = newaddr - return nil + return fmt.Sprintf("%s:%d", addr, defport), nil } - return nil + return addr, nil } - // Fallback to Bind address if it's not 0.0.0.0 - if bind != "0.0.0.0" { - newaddr := fmt.Sprintf("%s:%d", bind, defport) - *addr = newaddr - return nil + // Fallback to bind address first, and then try resolving the local hostname + ips, err := net.LookupIP(bind) + if err != nil { + return "", fmt.Errorf("Error resolving bind address %q: %v", bind, err) + } + + // Return the first unicast address + for _, ip := range ips { + if ip.IsLinkLocalUnicast() || ip.IsGlobalUnicast() { + return fmt.Sprintf("%s:%d", ip, defport), nil + } + if ip.IsLoopback() && dev { + // loopback is fine for dev mode + return fmt.Sprintf("%s:%d", ip, defport), nil + } } // As a last resort resolve the hostname and use it if it's not // localhost (as localhost is never a sensible default) host, err := os.Hostname() if err != nil { - return fmt.Errorf("Unable to get hostname to set advertise address: %v", err) - } - ip, err := net.ResolveIPAddr("ip", host) - if err != nil { - //TODO It'd be nice if we could advertise unresolvable - // addresses for configurations where this process may have - // different name resolution than the rest of the cluster. - // Unfortunately both serf/memberlist and Nomad's raft layer - // require resovlable advertise addresses. - return fmt.Errorf("Unable to resolve hostname to set advertise address: %v", err) - } - if ip.IP.IsLoopback() && !dev { - return fmt.Errorf("Unable to select default advertise address as hostname resolves to localhost") - } - newaddr := fmt.Sprintf("%s:%d", ip.IP.String(), defport) - *addr = newaddr - return nil -} - -func normalizeBind(addr *string, bind string, defport *int) error { - if *addr == "" { - newaddr := fmt.Sprintf("%s:%d", bind, *defport) - *addr = newaddr - return nil + return "", fmt.Errorf("Unable to get hostname to set advertise address: %v", err) } - _, portstr, err := net.SplitHostPort(*addr) + ips, err = net.LookupIP(host) if err != nil { - if !isMissingPort(err) { - return fmt.Errorf("Error parsing bind address %q: %v", err, *addr) + return "", fmt.Errorf("Error resolving hostname %q for advertise address: %v", host, err) + } + + // Return the first unicast address + for _, ip := range ips { + if ip.IsLinkLocalUnicast() || ip.IsGlobalUnicast() { + return fmt.Sprintf("%s:%d", ip, defport), nil + } + if ip.IsLoopback() && dev { + // loopback is fine for dev mode + return fmt.Sprintf("%s:%d", ip, defport), nil } - - // missing port, add default - newaddr := fmt.Sprintf("%s:%d", *addr, *defport) - *addr = newaddr - return nil } - - port, err := strconv.Atoi(portstr) - if err != nil { - return fmt.Errorf("Error parsing bind address's port: %q: %v", portstr, *addr) - } - - // Set the default port for this service to the bound port to keep - // configuration consistent. - if port != *defport { - *defport = port - } - - return nil + return "", fmt.Errorf("No valid advertise addresses, please set `advertise` manually") } // isMissingPort returns true if an error is a "missing port" error from diff --git a/command/agent/http.go b/command/agent/http.go index fe3c417cf..90fbbcdbb 100644 --- a/command/agent/http.go +++ b/command/agent/http.go @@ -49,7 +49,7 @@ type HTTPServer struct { // NewHTTPServer starts new HTTP server over the agent func NewHTTPServer(agent *Agent, config *Config, logOutput io.Writer) (*HTTPServer, error) { // Start the listener - lnAddr, err := net.ResolveTCPAddr("tcp", config.Addresses.HTTP) + lnAddr, err := net.ResolveTCPAddr("tcp", config.normalizedAddrs.HTTP) if err != nil { return nil, err }