Merge pull request #1955 from hashicorp/b-fix-default-advertise
Choose safer default advertise address
This commit is contained in:
commit
8b0511713f
|
@ -45,13 +45,9 @@ type Agent struct {
|
|||
// consulSyncer registers the Nomad agent with the Consul Agent
|
||||
consulSyncer *consul.Syncer
|
||||
|
||||
client *client.Client
|
||||
clientHTTPAddr string
|
||||
client *client.Client
|
||||
|
||||
server *nomad.Server
|
||||
serverHTTPAddr string
|
||||
serverRPCAddr string
|
||||
serverSerfAddr string
|
||||
server *nomad.Server
|
||||
|
||||
shutdown bool
|
||||
shutdownCh chan struct{}
|
||||
|
@ -135,13 +131,13 @@ func (a *Agent) serverConfig() (*nomad.Config, error) {
|
|||
}
|
||||
|
||||
// Set up the bind addresses
|
||||
rpcAddr, err := a.getRPCAddr(true)
|
||||
rpcAddr, err := net.ResolveTCPAddr("tcp", a.config.normalizedAddrs.RPC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Failed to parse RPC address %q: %v", a.config.normalizedAddrs.RPC, err)
|
||||
}
|
||||
serfAddr, err := a.getSerfAddr(true)
|
||||
serfAddr, err := net.ResolveTCPAddr("tcp", a.config.normalizedAddrs.Serf)
|
||||
if err != nil {
|
||||
return nil, 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
|
||||
|
@ -149,21 +145,14 @@ func (a *Agent) serverConfig() (*nomad.Config, error) {
|
|||
conf.SerfConfig.MemberlistConfig.BindAddr = serfAddr.IP.String()
|
||||
|
||||
// Set up the advertise addresses
|
||||
httpAddr, err := a.getHTTPAddr(false)
|
||||
rpcAddr, err = net.ResolveTCPAddr("tcp", a.config.AdvertiseAddrs.RPC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Failed to parse RPC advertise address %q: %v", a.config.AdvertiseAddrs.RPC, err)
|
||||
}
|
||||
rpcAddr, err = a.getRPCAddr(false)
|
||||
serfAddr, err = net.ResolveTCPAddr("tcp", a.config.AdvertiseAddrs.Serf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Failed to parse Serf advertise address %q: %v", a.config.AdvertiseAddrs.Serf, err)
|
||||
}
|
||||
serfAddr, err = a.getSerfAddr(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.serverHTTPAddr = net.JoinHostPort(httpAddr.IP.String(), strconv.Itoa(httpAddr.Port))
|
||||
a.serverRPCAddr = net.JoinHostPort(rpcAddr.IP.String(), strconv.Itoa(rpcAddr.Port))
|
||||
a.serverSerfAddr = net.JoinHostPort(serfAddr.IP.String(), strconv.Itoa(serfAddr.Port))
|
||||
conf.RPCAdvertise = rpcAddr
|
||||
conf.SerfConfig.MemberlistConfig.AdvertiseAddr = serfAddr.IP.String()
|
||||
conf.SerfConfig.MemberlistConfig.AdvertisePort = serfAddr.Port
|
||||
|
@ -267,12 +256,7 @@ func (a *Agent) clientConfig() (*clientconfig.Config, error) {
|
|||
conf.Node.NodeClass = a.config.Client.NodeClass
|
||||
|
||||
// Set up the HTTP advertise address
|
||||
httpAddr, err := a.selectAddr(a.getHTTPAddr, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf.Node.HTTPAddr = httpAddr
|
||||
a.clientHTTPAddr = httpAddr
|
||||
conf.Node.HTTPAddr = a.config.AdvertiseAddrs.HTTP
|
||||
|
||||
// Reserve resources on the node.
|
||||
r := conf.Node.Reserved
|
||||
|
@ -330,18 +314,14 @@ func (a *Agent) setupServer() error {
|
|||
}
|
||||
a.server = server
|
||||
|
||||
// Resolve consul check addresses. Always use advertise address for services
|
||||
httpCheckAddr, err := a.selectAddr(a.getHTTPAddr, !a.config.Consul.ChecksUseAdvertise)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rpcCheckAddr, err := a.selectAddr(a.getRPCAddr, !a.config.Consul.ChecksUseAdvertise)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serfCheckAddr, err := a.selectAddr(a.getSerfAddr, !a.config.Consul.ChecksUseAdvertise)
|
||||
if err != nil {
|
||||
return err
|
||||
// Consul check addresses default to bind but can be toggled to use advertise
|
||||
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
|
||||
serfCheckAddr = a.config.AdvertiseAddrs.Serf
|
||||
}
|
||||
|
||||
// Create the Nomad Server services for Consul
|
||||
|
@ -349,7 +329,7 @@ func (a *Agent) setupServer() error {
|
|||
if a.config.Consul.AutoAdvertise {
|
||||
httpServ := &structs.Service{
|
||||
Name: a.config.Consul.ServerServiceName,
|
||||
PortLabel: a.serverHTTPAddr,
|
||||
PortLabel: a.config.AdvertiseAddrs.HTTP,
|
||||
Tags: []string{consul.ServiceTagHTTP},
|
||||
Checks: []*structs.ServiceCheck{
|
||||
&structs.ServiceCheck{
|
||||
|
@ -365,7 +345,7 @@ func (a *Agent) setupServer() error {
|
|||
}
|
||||
rpcServ := &structs.Service{
|
||||
Name: a.config.Consul.ServerServiceName,
|
||||
PortLabel: a.serverRPCAddr,
|
||||
PortLabel: a.config.AdvertiseAddrs.RPC,
|
||||
Tags: []string{consul.ServiceTagRPC},
|
||||
Checks: []*structs.ServiceCheck{
|
||||
&structs.ServiceCheck{
|
||||
|
@ -378,8 +358,8 @@ func (a *Agent) setupServer() error {
|
|||
},
|
||||
}
|
||||
serfServ := &structs.Service{
|
||||
PortLabel: a.serverSerfAddr,
|
||||
Name: a.config.Consul.ServerServiceName,
|
||||
PortLabel: a.config.AdvertiseAddrs.Serf,
|
||||
Tags: []string{consul.ServiceTagSerf},
|
||||
Checks: []*structs.ServiceCheck{
|
||||
&structs.ServiceCheck{
|
||||
|
@ -458,9 +438,9 @@ func (a *Agent) setupClient() error {
|
|||
a.client = client
|
||||
|
||||
// Resolve the http check address
|
||||
httpCheckAddr, err := a.selectAddr(a.getHTTPAddr, !a.config.Consul.ChecksUseAdvertise)
|
||||
if err != nil {
|
||||
return err
|
||||
httpCheckAddr := a.config.normalizedAddrs.HTTP
|
||||
if a.config.Consul.ChecksUseAdvertise {
|
||||
httpCheckAddr = a.config.AdvertiseAddrs.HTTP
|
||||
}
|
||||
|
||||
// Create the Nomad Client services for Consul
|
||||
|
@ -469,7 +449,7 @@ func (a *Agent) setupClient() error {
|
|||
if a.config.Consul.AutoAdvertise {
|
||||
httpServ := &structs.Service{
|
||||
Name: a.config.Consul.ClientServiceName,
|
||||
PortLabel: a.clientHTTPAddr,
|
||||
PortLabel: a.config.AdvertiseAddrs.HTTP,
|
||||
Tags: []string{consul.ServiceTagHTTP},
|
||||
Checks: []*structs.ServiceCheck{
|
||||
&structs.ServiceCheck{
|
||||
|
@ -493,103 +473,6 @@ func (a *Agent) setupClient() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Defines the selector interface
|
||||
type addrSelector func(bool) (*net.TCPAddr, error)
|
||||
|
||||
// selectAddr returns the right address given a selector, and return it as a PortLabel
|
||||
// preferBind is a weak preference, and will skip 0.0.0.0
|
||||
func (a *Agent) selectAddr(selector addrSelector, preferBind bool) (string, error) {
|
||||
addr, err := selector(preferBind)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if preferBind && addr.IP.String() == "0.0.0.0" {
|
||||
addr, err = selector(false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
address := net.JoinHostPort(addr.IP.String(), strconv.Itoa(addr.Port))
|
||||
return address, nil
|
||||
}
|
||||
|
||||
// getHTTPAddr returns the HTTP address to use based on the clients
|
||||
// configuration. If bind is true, an address appropriate for binding is
|
||||
// returned, otherwise an address for advertising is returned. Skip 0.0.0.0
|
||||
// unless returning a bind address, since that's the only time it's useful.
|
||||
func (a *Agent) getHTTPAddr(bind bool) (*net.TCPAddr, error) {
|
||||
advertAddr := a.config.AdvertiseAddrs.HTTP
|
||||
bindAddr := a.config.Addresses.HTTP
|
||||
globalBindAddr := a.config.BindAddr
|
||||
port := a.config.Ports.HTTP
|
||||
return pickAddress(bind, globalBindAddr, advertAddr, bindAddr, port, "HTTP")
|
||||
}
|
||||
|
||||
// getRPCAddr returns the HTTP address to use based on the clients
|
||||
// configuration. If bind is true, an address appropriate for binding is
|
||||
// returned, otherwise an address for advertising is returned. Skip 0.0.0.0
|
||||
// unless returning a bind address, since that's the only time it's useful.
|
||||
func (a *Agent) getRPCAddr(bind bool) (*net.TCPAddr, error) {
|
||||
advertAddr := a.config.AdvertiseAddrs.RPC
|
||||
bindAddr := a.config.Addresses.RPC
|
||||
globalBindAddr := a.config.BindAddr
|
||||
port := a.config.Ports.RPC
|
||||
return pickAddress(bind, globalBindAddr, advertAddr, bindAddr, port, "RPC")
|
||||
}
|
||||
|
||||
// getSerfAddr returns the Serf address to use based on the clients
|
||||
// configuration. If bind is true, an address appropriate for binding is
|
||||
// returned, otherwise an address for advertising is returned. Skip 0.0.0.0
|
||||
// unless returning a bind address, since that's the only time it's useful.
|
||||
func (a *Agent) getSerfAddr(bind bool) (*net.TCPAddr, error) {
|
||||
advertAddr := a.config.AdvertiseAddrs.Serf
|
||||
bindAddr := a.config.Addresses.Serf
|
||||
globalBindAddr := a.config.BindAddr
|
||||
port := a.config.Ports.Serf
|
||||
return pickAddress(bind, globalBindAddr, advertAddr, bindAddr, port, "Serf")
|
||||
}
|
||||
|
||||
// pickAddress is a shared helper to pick the address to either bind to or
|
||||
// advertise.
|
||||
func pickAddress(bind bool, globalBindAddr, advertiseAddr, bindAddr string, port int, service string) (*net.TCPAddr, error) {
|
||||
var serverAddr string
|
||||
if advertiseAddr != "" && !bind {
|
||||
serverAddr = advertiseAddr
|
||||
|
||||
// Check if the advertise has a port
|
||||
if host, pport, err := net.SplitHostPort(advertiseAddr); err == nil {
|
||||
if parsed, err := strconv.Atoi(pport); err == nil {
|
||||
serverAddr = host
|
||||
port = parsed
|
||||
}
|
||||
}
|
||||
} else if bindAddr != "" && !(bindAddr == "0.0.0.0" && !bind) {
|
||||
serverAddr = bindAddr
|
||||
} else if globalBindAddr != "" && !(globalBindAddr == "0.0.0.0" && !bind) {
|
||||
serverAddr = globalBindAddr
|
||||
} else {
|
||||
serverAddr = "127.0.0.1"
|
||||
}
|
||||
|
||||
ip := net.ParseIP(serverAddr)
|
||||
if ip == nil {
|
||||
joined := net.JoinHostPort(serverAddr, strconv.Itoa(port))
|
||||
addr, err := net.ResolveTCPAddr("tcp", joined)
|
||||
if err == nil {
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Failed to parse %s %q as IP and failed to resolve address: %v", service, serverAddr, err)
|
||||
}
|
||||
|
||||
return &net.TCPAddr{
|
||||
IP: ip,
|
||||
Port: port,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// reservePortsForClient reserves a range of ports for the client to use when
|
||||
// it creates various plugins for log collection, executors, drivers, etc
|
||||
func (a *Agent) reservePortsForClient(conf *clientconfig.Config) error {
|
||||
|
|
|
@ -72,6 +72,9 @@ func makeAgent(t testing.TB, cb func(*Config)) (string, *Agent) {
|
|||
cb(conf)
|
||||
}
|
||||
|
||||
if err := conf.normalizeAddrs(); err != nil {
|
||||
t.Fatalf("error normalizing config: %v", err)
|
||||
}
|
||||
agent, err := NewAgent(conf, os.Stderr)
|
||||
if err != nil {
|
||||
os.RemoveAll(dir)
|
||||
|
@ -93,26 +96,17 @@ 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}
|
||||
|
||||
// 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 err := conf.normalizeAddrs(); err != nil {
|
||||
t.Fatalf("error normalizing config: %v", err)
|
||||
}
|
||||
out, err := a.serverConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
|
@ -125,20 +119,27 @@ func TestAgent_ServerConfig(t *testing.T) {
|
|||
if serfPort != 4000 {
|
||||
t.Fatalf("expected 4000, got: %d", serfPort)
|
||||
}
|
||||
if addr := out.RPCAdvertise; addr.IP.String() != "127.0.0.1" || addr.Port != 4001 {
|
||||
|
||||
// Assert addresses weren't changed
|
||||
if addr := conf.AdvertiseAddrs.RPC; addr != "127.0.0.1:4001" {
|
||||
t.Fatalf("bad rpc advertise addr: %#v", addr)
|
||||
}
|
||||
if addr := a.serverHTTPAddr; addr != "10.10.11.1:4005" {
|
||||
if addr := conf.AdvertiseAddrs.HTTP; addr != "10.10.11.1:4005" {
|
||||
t.Fatalf("expect 10.11.11.1:4005, got: %v", addr)
|
||||
}
|
||||
if addr := a.serverRPCAddr; addr != "127.0.0.1:4001" {
|
||||
t.Fatalf("expect 127.0.0.1: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
|
||||
conf.Addresses.RPC = ""
|
||||
conf.Addresses.Serf = ""
|
||||
conf.Ports.RPC = 4003
|
||||
conf.Ports.Serf = 4004
|
||||
|
||||
if err := conf.normalizeAddrs(); err != nil {
|
||||
t.Fatalf("error normalizing config: %v", err)
|
||||
}
|
||||
out, err = a.serverConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
|
@ -152,93 +153,92 @@ func TestAgent_ServerConfig(t *testing.T) {
|
|||
|
||||
// Prefers advertise over bind addr
|
||||
conf.BindAddr = "127.0.0.3"
|
||||
conf.Addresses.HTTP = "127.0.0.2"
|
||||
conf.Addresses.RPC = "127.0.0.2"
|
||||
conf.Addresses.Serf = "127.0.0.2"
|
||||
conf.Addresses.HTTP = "127.0.0.2"
|
||||
conf.AdvertiseAddrs.HTTP = "10.0.0.10"
|
||||
conf.AdvertiseAddrs.RPC = ""
|
||||
conf.AdvertiseAddrs.Serf = "10.0.0.12:4004"
|
||||
|
||||
if err := conf.normalizeAddrs(); err != nil {
|
||||
t.Fatalf("error normalizing config: %v", err)
|
||||
}
|
||||
out, err = a.serverConfig()
|
||||
fmt.Println(conf.Addresses.RPC)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if addr := out.RPCAddr.IP.String(); addr != "127.0.0.2" {
|
||||
t.Fatalf("expect 127.0.0.2, got: %s", addr)
|
||||
}
|
||||
if port := out.RPCAddr.Port; port != 4003 {
|
||||
t.Fatalf("expect 4647, got: %d", port)
|
||||
}
|
||||
if addr := out.SerfConfig.MemberlistConfig.BindAddr; addr != "127.0.0.2" {
|
||||
t.Fatalf("expect 127.0.0.2, got: %s", addr)
|
||||
}
|
||||
if addr := a.serverHTTPAddr; addr != "10.0.0.10:4646" {
|
||||
t.Fatalf("expect 10.0.0.10:4646, got: %s", addr)
|
||||
if port := out.SerfConfig.MemberlistConfig.BindPort; port != 4004 {
|
||||
t.Fatalf("expect 4648, got: %d", port)
|
||||
}
|
||||
// NOTE: AdvertiseAddr > Addresses > BindAddr > Defaults
|
||||
if addr := a.serverRPCAddr; addr != "127.0.0.2:4003" {
|
||||
t.Fatalf("expect 127.0.0.2:4003, got: %s", addr)
|
||||
if addr := conf.Addresses.HTTP; addr != "127.0.0.2" {
|
||||
t.Fatalf("expect 127.0.0.2, got: %s", addr)
|
||||
}
|
||||
if addr := a.serverSerfAddr; addr != "10.0.0.12:4004" {
|
||||
t.Fatalf("expect 10.0.0.12:4004, got: %s", addr)
|
||||
if addr := conf.Addresses.RPC; addr != "127.0.0.2" {
|
||||
t.Fatalf("expect 127.0.0.2, got: %s", addr)
|
||||
}
|
||||
|
||||
// It correctly identifies the bind and advertise address when requested
|
||||
if addr, err := a.selectAddr(a.getHTTPAddr, true); addr != "127.0.0.2:4646" || err != nil {
|
||||
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, err := a.selectAddr(a.getHTTPAddr, false); addr != "10.0.0.10:4646" || err != nil {
|
||||
t.Fatalf("expect 10.0.0.10:4646, got: %s", addr)
|
||||
}
|
||||
|
||||
if addr, err := a.selectAddr(a.getRPCAddr, true); addr != "127.0.0.2:4003" || err != nil {
|
||||
if addr := conf.normalizedAddrs.RPC; addr != "127.0.0.2:4003" {
|
||||
t.Fatalf("expect 127.0.0.2:4003, got: %s", addr)
|
||||
}
|
||||
|
||||
if addr, err := a.selectAddr(a.getRPCAddr, false); addr != "127.0.0.2:4003" || err != nil {
|
||||
t.Fatalf("expect 127.0.0.2:4003, got: %s", addr)
|
||||
}
|
||||
|
||||
if addr, err := a.selectAddr(a.getSerfAddr, true); addr != "127.0.0.2:4004" || err != nil {
|
||||
t.Fatalf("expect 127.0.0.2:4004, got: %s", addr)
|
||||
}
|
||||
|
||||
if addr, err := a.selectAddr(a.getSerfAddr, false); addr != "10.0.0.12:4004" || err != nil {
|
||||
if addr := conf.normalizedAddrs.Serf; addr != "127.0.0.2:4004" {
|
||||
t.Fatalf("expect 10.0.0.12:4004, got: %s", addr)
|
||||
}
|
||||
|
||||
// We don't resolve 0.0.0.0 unless we're asking for bind
|
||||
conf.Addresses.HTTP = "0.0.0.0"
|
||||
conf.AdvertiseAddrs.HTTP = ""
|
||||
if addr, err := a.getHTTPAddr(false); addr.IP.String() != "127.0.0.3" || err != nil {
|
||||
t.Fatalf("expect 127.0.0.3, got: %s", addr.IP.String())
|
||||
if addr := conf.AdvertiseAddrs.HTTP; addr != "10.0.0.10:4646" {
|
||||
t.Fatalf("expect 10.0.0.10:4646, got: %s", addr)
|
||||
}
|
||||
|
||||
// We still get 0.0.0.0 when explicitly asking for bind
|
||||
if addr, err := a.getHTTPAddr(true); addr.IP.String() != "0.0.0.0" || err != nil {
|
||||
t.Fatalf("expect 0.0.0.0, got: %s", addr.IP.String())
|
||||
if addr := conf.AdvertiseAddrs.RPC; addr != "127.0.0.2:4003" {
|
||||
t.Fatalf("expect 127.0.0.2:4003, got: %s", addr)
|
||||
}
|
||||
|
||||
// selectAddr does not return 0.0.0.0 with preferBind
|
||||
if addr, err := a.selectAddr(a.getHTTPAddr, true); addr != "127.0.0.3:4646" || err != nil {
|
||||
t.Fatalf("expect 127.0.0.3:4646, 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 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") {
|
||||
t.Fatalf("expected unknown unit error, got: %#v", err)
|
||||
}
|
||||
|
||||
conf.Server.NodeGCThreshold = "10s"
|
||||
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 {
|
||||
t.Fatalf("expect 10s, got: %s", threshold)
|
||||
}
|
||||
|
||||
conf.Server.HeartbeatGrace = "42g"
|
||||
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") {
|
||||
t.Fatalf("expected unknown unit error, got: %#v", err)
|
||||
}
|
||||
|
||||
conf.Server.HeartbeatGrace = "37s"
|
||||
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 {
|
||||
t.Fatalf("expect 37s, got: %s", threshold)
|
||||
|
@ -254,6 +254,9 @@ func TestAgent_ServerConfig(t *testing.T) {
|
|||
conf.Ports.HTTP = 4646
|
||||
conf.Ports.RPC = 4647
|
||||
conf.Ports.Serf = 4648
|
||||
if err := conf.normalizeAddrs(); err != nil {
|
||||
t.Fatalf("error normalizing config: %v", err)
|
||||
}
|
||||
out, err = a.serverConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
|
@ -264,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 := a.serverHTTPAddr; 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 := a.serverRPCAddr; 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 := a.serverSerfAddr; 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)
|
||||
}
|
||||
|
||||
|
@ -302,11 +314,16 @@ func TestAgent_ServerConfig(t *testing.T) {
|
|||
|
||||
func TestAgent_ClientConfig(t *testing.T) {
|
||||
conf := DefaultConfig()
|
||||
// enabled just to allow using localhost for all addresses
|
||||
conf.DevMode = true
|
||||
a := &Agent{config: conf}
|
||||
conf.Client.Enabled = true
|
||||
conf.Addresses.HTTP = "127.0.0.1"
|
||||
conf.Ports.HTTP = 5678
|
||||
|
||||
if err := conf.normalizeAddrs(); err != nil {
|
||||
t.Fatalf("error normalizing config: %v", err)
|
||||
}
|
||||
c, err := a.clientConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("got err: %v", err)
|
||||
|
@ -318,10 +335,14 @@ func TestAgent_ClientConfig(t *testing.T) {
|
|||
}
|
||||
|
||||
conf = DefaultConfig()
|
||||
conf.DevMode = true
|
||||
a = &Agent{config: conf}
|
||||
conf.Client.Enabled = true
|
||||
conf.Addresses.HTTP = "127.0.0.1"
|
||||
|
||||
if err := conf.normalizeAddrs(); err != nil {
|
||||
t.Fatalf("error normalizing config: %v", err)
|
||||
}
|
||||
c, err = a.clientConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("got err: %v", err)
|
||||
|
|
|
@ -201,6 +201,12 @@ func (c *Command) readConfig() *Config {
|
|||
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
|
||||
}
|
||||
|
||||
if dev {
|
||||
// Skip validation for dev mode
|
||||
return config
|
||||
|
@ -213,7 +219,7 @@ func (c *Command) readConfig() *Config {
|
|||
}
|
||||
keyfile := filepath.Join(config.DataDir, serfKeyring)
|
||||
if _, err := os.Stat(keyfile); err == nil {
|
||||
c.Ui.Error("WARNING: keyring exists but -encrypt given, using keyring")
|
||||
c.Ui.Warn("WARNING: keyring exists but -encrypt given, using keyring")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,9 @@ func TestCommand_Args(t *testing.T) {
|
|||
ShutdownCh: shutdownCh,
|
||||
}
|
||||
|
||||
// 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=169.254.0.1")
|
||||
if code := cmd.Run(tc.args); code != 1 {
|
||||
t.Fatalf("args: %v\nexit: %d\n", tc.args, code)
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
|
||||
|
@ -342,8 +347,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"`
|
||||
|
@ -359,8 +364,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"`
|
||||
|
@ -438,6 +443,7 @@ func (r *Resources) ParseReserved() error {
|
|||
// DevConfig is a Config that is used for dev mode of Nomad.
|
||||
func DevConfig() *Config {
|
||||
conf := DefaultConfig()
|
||||
conf.BindAddr = "127.0.0.1"
|
||||
conf.LogLevel = "DEBUG"
|
||||
conf.Client.Enabled = true
|
||||
conf.Server.Enabled = true
|
||||
|
@ -466,7 +472,7 @@ func DefaultConfig() *Config {
|
|||
LogLevel: "INFO",
|
||||
Region: "global",
|
||||
Datacenter: "dc1",
|
||||
BindAddr: "127.0.0.1",
|
||||
BindAddr: "0.0.0.0",
|
||||
Ports: &Ports{
|
||||
HTTP: 4646,
|
||||
RPC: 4647,
|
||||
|
@ -664,6 +670,126 @@ func (c *Config) Merge(b *Config) *Config {
|
|||
return &result
|
||||
}
|
||||
|
||||
// normalizeAddrs normalizes 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),
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
if !isMissingPort(err) {
|
||||
return "", fmt.Errorf("Error parsing advertise address %q: %v", addr, err)
|
||||
}
|
||||
|
||||
// missing port, append the default
|
||||
return fmt.Sprintf("%s:%d", addr, defport), nil
|
||||
}
|
||||
return addr, 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)
|
||||
}
|
||||
|
||||
ips, err = net.LookupIP(host)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("No valid advertise addresses, please set `advertise` manually")
|
||||
}
|
||||
|
||||
// isMissingPort returns true if an error is a "missing port" error from
|
||||
// net.SplitHostPort.
|
||||
func isMissingPort(err error) bool {
|
||||
// matches error const in net/ipsock.go
|
||||
const missingPort = "missing port in address"
|
||||
return err != nil && strings.HasPrefix(err.Error(), missingPort)
|
||||
}
|
||||
|
||||
// Merge is used to merge two server configs together
|
||||
func (a *ServerConfig) Merge(b *ServerConfig) *ServerConfig {
|
||||
result := *a
|
||||
|
|
|
@ -2,6 +2,7 @@ package agent
|
|||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
|
@ -545,3 +546,14 @@ func TestResources_ParseReserved(t *testing.T) {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsMissingPort(t *testing.T) {
|
||||
_, _, err := net.SplitHostPort("localhost")
|
||||
if missing := isMissingPort(err); !missing {
|
||||
t.Errorf("expected missing port error, but got %v", err)
|
||||
}
|
||||
_, _, err = net.SplitHostPort("localhost:9000")
|
||||
if missing := isMissingPort(err); missing {
|
||||
t.Errorf("expected no error, but got %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 := agent.getHTTPAddr(true)
|
||||
lnAddr, err := net.ResolveTCPAddr("tcp", config.normalizedAddrs.HTTP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue