From 62d9c44c11b4482411237e3394ab2d2046ef4f18 Mon Sep 17 00:00:00 2001 From: kaiyou Date: Thu, 21 May 2020 17:50:50 +0200 Subject: [PATCH] Refactor cluster.Join to prepare for rejoin Now cluster.Join will resolve hostnames itself, then will avoid trying to join hosts that are already cluster members. --- cluster/cluster.go | 48 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/cluster/cluster.go b/cluster/cluster.go index f7ca417..c5e1b2f 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -4,6 +4,7 @@ import ( "crypto/rand" "encoding/base64" "fmt" + "net" "os" "time" @@ -74,21 +75,46 @@ func (c *Cluster) Name() string { return c.localNode.Name } -// Join tries to join the cluster by contacting provided addresses -// Provided addresses are passed as is, if no address is provided, known -// cluster nodes are contacted instead. -// Joining fail if none of the provided addresses or none of the known -// nodes can be joined. -func (c *Cluster) Join(addrs []string) error { - if len(addrs) == 0 { - for _, n := range c.state.Nodes { - addrs = append(addrs, n.Addr.String()) +// Join tries to join the cluster by contacting provided ips. +// If no ip is provided, ips of known nodes are used instead. +// Only addresses that are not already members are joined. +func (c *Cluster) Join(hosts []string) error { + addrs := make([]net.IP, 0, len(hosts)) + + // resolve hostnames so we are able to proerly filter out + // cluster members later + for _, host := range hosts { + if addr := net.ParseIP(host); addr != nil { + addrs = append(addrs, addr) + } else if ips, err := net.LookupIP(host); err == nil { + addrs = append(addrs, ips...) } } - if _, err := c.ml.Join(addrs); err != nil { + // add known hosts if necessary + if len(addrs) == 0 { + for _, n := range c.state.Nodes { + addrs = append(addrs, n.Addr) + } + } + + // filter out addresses that are already members + targets := make([]string, 0, len(addrs)) + members := c.ml.Members() +AddrLoop: + for _, addr := range addrs { + for _, member := range members { + if member.Addr.Equal(addr) { + continue AddrLoop + } + } + targets = append(targets, addr.String()) + } + + // finally try and join any remaining address + if _, err := c.ml.Join(targets); err != nil { return err - } else if len(addrs) > 0 && c.ml.NumMembers() < 2 { + } else if len(targets) > 0 && c.ml.NumMembers() < 2 { return errors.New("could not join to any of the provided addresses") } return nil