From 4598087df34d4437db07ad90326ab7e32ff7e1b5 Mon Sep 17 00:00:00 2001 From: Hans Hasselberg Date: Fri, 5 Jun 2015 13:44:42 +0200 Subject: [PATCH] Implement advertise_addrs for SerfLan, SerfWan and RPC. Fixes #550. This will make it possible to configure the advertised adresses for SerfLan, SerfWan and RPC. It will enable multiple consul clients on a single host which is very useful in a container environment. This option might override advertise_addr and advertise_addr_wan depending on the configuration. It will be configureable with advertise_addrs. Example: { "advertise_addrs": { "serf_lan": "10.0.120.91:4424", "serf_wan": "201.20.10.61:4423", "rpc": "10.20.10.61:4424" } } --- command/agent/agent.go | 11 +++++ command/agent/agent_test.go | 32 +++++++++++++ command/agent/config.go | 48 +++++++++++++++++++ command/agent/config_test.go | 48 +++++++++++++++++++ .../source/docs/agent/options.html.markdown | 10 ++++ 5 files changed, 149 insertions(+) diff --git a/command/agent/agent.go b/command/agent/agent.go index ea3c51507..14dcf9064 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -244,6 +244,17 @@ func (a *Agent) consulConfig() *consul.Config { Port: a.config.Ports.Server, } } + if a.config.AdvertiseAddrs.SerfLan != nil { + base.SerfLANConfig.MemberlistConfig.AdvertiseAddr = a.config.AdvertiseAddrs.SerfLan.IP.String() + base.SerfLANConfig.MemberlistConfig.AdvertisePort = a.config.AdvertiseAddrs.SerfLan.Port + } + if a.config.AdvertiseAddrs.SerfWan != nil { + base.SerfWANConfig.MemberlistConfig.AdvertiseAddr = a.config.AdvertiseAddrs.SerfWan.IP.String() + base.SerfWANConfig.MemberlistConfig.AdvertisePort = a.config.AdvertiseAddrs.SerfWan.Port + } + if a.config.AdvertiseAddrs.RPC != nil { + base.RPCAdvertise = a.config.AdvertiseAddrs.RPC + } if a.config.Bootstrap { base.Bootstrap = true } diff --git a/command/agent/agent_test.go b/command/agent/agent_test.go index 7a2b43f76..495613ebb 100644 --- a/command/agent/agent_test.go +++ b/command/agent/agent_test.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "io/ioutil" + "net" "os" "path/filepath" "reflect" @@ -134,6 +135,37 @@ func TestAgent_RPCPing(t *testing.T) { } } +func TestAgent_CheckAdvertiseAddrsSettings(t *testing.T) { + c := nextConfig() + c.AdvertiseAddrs.SerfLan, _ = net.ResolveTCPAddr("tcp", "127.0.0.42:1233") + c.AdvertiseAddrs.SerfWan, _ = net.ResolveTCPAddr("tcp", "127.0.0.43:1234") + c.AdvertiseAddrs.RPC, _ = net.ResolveTCPAddr("tcp", "127.0.0.44:1235") + dir, agent := makeAgent(t, c) + defer os.RemoveAll(dir) + defer agent.Shutdown() + + serfLanAddr := agent.consulConfig().SerfLANConfig.MemberlistConfig.AdvertiseAddr + if serfLanAddr != "127.0.0.42" { + t.Fatalf("SerfLan is not properly set to '127.0.0.42': %s", serfLanAddr) + } + serfLanPort := agent.consulConfig().SerfLANConfig.MemberlistConfig.AdvertisePort + if serfLanPort != 1233 { + t.Fatalf("SerfLan is not properly set to '1233': %s", serfLanPort) + } + serfWanAddr := agent.consulConfig().SerfWANConfig.MemberlistConfig.AdvertiseAddr + if serfWanAddr != "127.0.0.43" { + t.Fatalf("SerfWan is not properly set to '127.0.0.43': %s", serfWanAddr) + } + serfWanPort := agent.consulConfig().SerfWANConfig.MemberlistConfig.AdvertisePort + if serfWanPort != 1234 { + t.Fatalf("SerfWan is not properly set to '1234': %s", serfWanPort) + } + rpc := agent.consulConfig().RPCAdvertise + if rpc != c.AdvertiseAddrs.RPC { + t.Fatalf("RPC is not properly set to %v: %s", c.AdvertiseAddrs.RPC, rpc) + } +} + func TestAgent_AddService(t *testing.T) { dir, agent := makeAgent(t, nextConfig()) defer os.RemoveAll(dir) diff --git a/command/agent/config.go b/command/agent/config.go index ce6511107..5b3357a34 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -40,6 +40,15 @@ type AddressConfig struct { RPC string // CLI RPC } +type AdvertiseAddrsConfig struct { + SerfLan *net.TCPAddr `mapstructure:"-"` + SerfLanRaw string `mapstructure:"serf_lan"` + SerfWan *net.TCPAddr `mapstructure:"-"` + SerfWanRaw string `mapstructure:"serf_wan"` + RPC *net.TCPAddr `mapstructure:"-"` + RPCRaw string `mapstructure:"rpc"` +} + // DNSConfig is used to fine tune the DNS sub-system. // It can be used to control cache values, and stale // reads @@ -142,6 +151,9 @@ type Config struct { // and Consul RPC IP. If not specified, bind address is used. AdvertiseAddr string `mapstructure:"advertise_addr"` + // AdvertiseAddrs configuration + AdvertiseAddrs AdvertiseAddrsConfig `mapstructure:"advertise_addrs"` + // AdvertiseAddrWan is the address we use for advertising our // Serf WAN IP. If not specified, the general advertise address is used. AdvertiseAddrWan string `mapstructure:"advertise_addr_wan"` @@ -638,6 +650,30 @@ func DecodeConfig(r io.Reader) (*Config, error) { result.SessionTTLMin = dur } + if result.AdvertiseAddrs.SerfLanRaw != "" { + addr, err := net.ResolveTCPAddr("tcp", result.AdvertiseAddrs.SerfLanRaw) + if err != nil { + return nil, fmt.Errorf("AdvertiseAddrs.SerfLan is invalid: %v", err) + } + result.AdvertiseAddrs.SerfLan = addr + } + + if result.AdvertiseAddrs.SerfWanRaw != "" { + addr, err := net.ResolveTCPAddr("tcp", result.AdvertiseAddrs.SerfWanRaw) + if err != nil { + return nil, fmt.Errorf("AdvertiseAddrs.SerfWan is invalid: %v", err) + } + result.AdvertiseAddrs.SerfWan = addr + } + + if result.AdvertiseAddrs.RPCRaw != "" { + addr, err := net.ResolveTCPAddr("tcp", result.AdvertiseAddrs.RPCRaw) + if err != nil { + return nil, fmt.Errorf("AdvertiseAddrs.RPC is invalid: %v", err) + } + result.AdvertiseAddrs.RPC = addr + } + return &result, nil } @@ -819,6 +855,18 @@ func MergeConfig(a, b *Config) *Config { if b.AdvertiseAddrWan != "" { result.AdvertiseAddrWan = b.AdvertiseAddrWan } + if b.AdvertiseAddrs.SerfLan != nil { + result.AdvertiseAddrs.SerfLan = b.AdvertiseAddrs.SerfLan + result.AdvertiseAddrs.SerfLanRaw = b.AdvertiseAddrs.SerfLanRaw + } + if b.AdvertiseAddrs.SerfWan != nil { + result.AdvertiseAddrs.SerfWan = b.AdvertiseAddrs.SerfWan + result.AdvertiseAddrs.SerfWanRaw = b.AdvertiseAddrs.SerfWanRaw + } + if b.AdvertiseAddrs.RPC != nil { + result.AdvertiseAddrs.RPC = b.AdvertiseAddrs.RPC + result.AdvertiseAddrs.RPCRaw = b.AdvertiseAddrs.RPCRaw + } if b.Server == true { result.Server = b.Server } diff --git a/command/agent/config_test.go b/command/agent/config_test.go index ac22af300..ed2a2921e 100644 --- a/command/agent/config_test.go +++ b/command/agent/config_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/base64" "io/ioutil" + "net" "os" "path/filepath" "reflect" @@ -211,6 +212,45 @@ func TestDecodeConfig(t *testing.T) { t.Fatalf("bad: %#v", config) } + // Advertise addresses for serflan + input = `{"advertise_addrs": {"serf_lan": "127.0.0.5:1234"}}` + config, err = DecodeConfig(bytes.NewReader([]byte(input))) + if err != nil { + t.Fatalf("err: %s", err) + } + if config.AdvertiseAddrs.SerfLanRaw != "127.0.0.5:1234" { + t.Fatalf("bad: %#v", config) + } + if config.AdvertiseAddrs.SerfLan.String() != "127.0.0.5:1234" { + t.Fatalf("bad: %#v", config) + } + + // Advertise addresses for serfwan + input = `{"advertise_addrs": {"serf_wan": "127.0.0.5:1234"}}` + config, err = DecodeConfig(bytes.NewReader([]byte(input))) + if err != nil { + t.Fatalf("err: %s", err) + } + if config.AdvertiseAddrs.SerfWanRaw != "127.0.0.5:1234" { + t.Fatalf("bad: %#v", config) + } + if config.AdvertiseAddrs.SerfWan.String() != "127.0.0.5:1234" { + t.Fatalf("bad: %#v", config) + } + + // Advertise addresses for rpc + input = `{"advertise_addrs": {"rpc": "127.0.0.5:1234"}}` + config, err = DecodeConfig(bytes.NewReader([]byte(input))) + if err != nil { + t.Fatalf("err: %s", err) + } + if config.AdvertiseAddrs.RPCRaw != "127.0.0.5:1234" { + t.Fatalf("bad: %#v", config) + } + if config.AdvertiseAddrs.RPC.String() != "127.0.0.5:1234" { + t.Fatalf("bad: %#v", config) + } + // leave_on_terminate input = `{"leave_on_terminate": true}` config, err = DecodeConfig(bytes.NewReader([]byte(input))) @@ -1166,6 +1206,14 @@ func TestMergeConfig(t *testing.T) { AtlasJoin: true, SessionTTLMinRaw: "1000s", SessionTTLMin: 1000 * time.Second, + AdvertiseAddrs: AdvertiseAddrsConfig{ + SerfLan: &net.TCPAddr{}, + SerfLanRaw: "127.0.0.5:1231", + SerfWan: &net.TCPAddr{}, + SerfWanRaw: "127.0.0.5:1232", + RPC: &net.TCPAddr{}, + RPCRaw: "127.0.0.5:1233", + }, } c := MergeConfig(a, b) diff --git a/website/source/docs/agent/options.html.markdown b/website/source/docs/agent/options.html.markdown index 7e8cdda1f..ac579974d 100644 --- a/website/source/docs/agent/options.html.markdown +++ b/website/source/docs/agent/options.html.markdown @@ -322,6 +322,16 @@ definitions support being updated during a reload. * `advertise_addr` Equivalent to the [`-advertise` command-line flag](#_advertise). +* `advertise_addrs` Allows to set + the advertised addresses for SerfLan, SerfWan and RPC together with the port. This gives + you more control than (#_advertise) or (#_advertise-wan) while it serves the same purpose. + These settings might override (#_advertise) and (#_advertise-wan). +

+ This is a nested setting that allows the following keys: + * `serf_lan` - The SerfLan address. Accepts values in the form of "host:port" like "10.23.31.101:8301". + * `serf_wan` - The SerfWan address. Accepts values in the form of "host:port" like "10.23.31.101:8302". + * `rpc` - The RPC address. Accepts values in the form of "host:port" like "10.23.31.101:8400". + * `advertise_addr_wan` Equivalent to the [`-advertise-wan` command-line flag](#_advertise-wan).