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.
This commit is contained in:
kaiyou 2020-05-21 17:50:50 +02:00
parent 0ab363f218
commit 62d9c44c11
1 changed files with 37 additions and 11 deletions

View File

@ -4,6 +4,7 @@ import (
"crypto/rand" "crypto/rand"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"net"
"os" "os"
"time" "time"
@ -74,21 +75,46 @@ func (c *Cluster) Name() string {
return c.localNode.Name return c.localNode.Name
} }
// Join tries to join the cluster by contacting provided addresses // Join tries to join the cluster by contacting provided ips.
// Provided addresses are passed as is, if no address is provided, known // If no ip is provided, ips of known nodes are used instead.
// cluster nodes are contacted instead. // Only addresses that are not already members are joined.
// Joining fail if none of the provided addresses or none of the known func (c *Cluster) Join(hosts []string) error {
// nodes can be joined. addrs := make([]net.IP, 0, len(hosts))
func (c *Cluster) Join(addrs []string) error {
if len(addrs) == 0 { // resolve hostnames so we are able to proerly filter out
for _, n := range c.state.Nodes { // cluster members later
addrs = append(addrs, n.Addr.String()) 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 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 errors.New("could not join to any of the provided addresses")
} }
return nil return nil