diff --git a/internal/redis/node.go b/internal/redis/node.go index 3281ff3..bb4e55f 100644 --- a/internal/redis/node.go +++ b/internal/redis/node.go @@ -34,6 +34,23 @@ type Node struct { conn *client.Client } +func uniqLookup(host string) ([]net.IP, error) { + ret := make([]net.IP, 0) + res, err := net.LookupIP(host) + if err != nil { + return ret, err + } + seen := map[string]struct{}{} + for _, ip := range res { + key := string(ip) + if _, ok := seen[key]; !ok { + seen[key] = struct{}{} + ret = append(ret, ip) + } + } + return ret, err +} + // NewNode is a Node constructor func NewNode(config *config.Config, logger *slog.Logger, fqdn string) (*Node, error) { var host string @@ -45,7 +62,7 @@ func NewNode(config *config.Config, logger *slog.Logger, fqdn string) (*Node, er } nodeLogger := logger.With("module", "node", "fqdn", host) now := time.Now() - ips, err := net.LookupIP(fqdn) + ips, err := uniqLookup(fqdn) if err != nil { nodeLogger.Warn("Dns lookup failed", "error", err) ips = []net.IP{} @@ -127,7 +144,7 @@ func (n *Node) RefreshAddrs() error { } n.logger.Debug("Updating ips cache") now := time.Now() - ips, err := net.LookupIP(n.fqdn) + ips, err := uniqLookup(n.fqdn) if err != nil { n.logger.Error("Updating ips cache failed", "error", err) return err diff --git a/tests/features/00_cluster_smoke.feature b/tests/features/00_cluster_smoke.feature index 914e53c..851536e 100644 --- a/tests/features/00_cluster_smoke.feature +++ b/tests/features/00_cluster_smoke.feature @@ -11,3 +11,78 @@ Feature: Cluster mode smoke tests """ ["redis1","redis2","redis3"] """ + + Scenario: Cluster mode duplicate ip resolve does not break rdsync + Given clustered shard is up and running + When I run command on host "redis1" + """ + echo '192.168.234.14 redis2 test1' >> /etc/hosts + echo '192.168.234.14 redis2 test2' >> /etc/hosts + echo '192.168.234.15 redis3 test3' >> /etc/hosts + echo '192.168.234.15 redis3 test4' >> /etc/hosts + """ + Then redis host "redis1" should be master + And redis host "redis2" should become replica of "redis1" within "15" seconds + And replication on redis host "redis2" should run fine within "15" seconds + And redis host "redis3" should become replica of "redis1" within "15" seconds + And replication on redis host "redis3" should run fine within "15" seconds + And zookeeper node "/test/active_nodes" should match json_exactly within "30" seconds + """ + ["redis1","redis2","redis3"] + """ + When I run command on host "redis3" + """ + supervisorctl stop rdsync + """ + And I run command on host "redis2" + """ + supervisorctl stop rdsync + """ + And I run command on host "redis1" + """ + supervisorctl stop rdsync + """ + And I run command on redis host "redis1" + """ + CONFIG SET quorum-replicas redis2:6379 + """ + And I run command on host "redis1" + """ + supervisorctl start rdsync + """ + And I run command on host "redis2" + """ + supervisorctl start rdsync + """ + And I run command on host "redis3" + """ + supervisorctl start rdsync + """ + When I set zookeeper node "/test/active_nodes" to + """ + [] + """ + Then zookeeper node "/test/active_nodes" should match json_exactly within "30" seconds + """ + ["redis1","redis2","redis3"] + """ + When I run command on redis host "redis1" + """ + CONFIG GET quorum-replicas + """ + Then redis cmd result should match regexp + """ + .*redis2.* + """ + And redis cmd result should match regexp + """ + .*redis3.* + """ + And redis cmd result should match regexp + """ + .*192.168.234.14.* + """ + And redis cmd result should match regexp + """ + .*192.168.234.15.* + """ diff --git a/tests/features/00_sentinel_smoke.feature b/tests/features/00_sentinel_smoke.feature index aa9b6c2..6d4fca8 100644 --- a/tests/features/00_sentinel_smoke.feature +++ b/tests/features/00_sentinel_smoke.feature @@ -14,3 +14,81 @@ Feature: Sentinel mode smoke tests And senticache host "redis1" should have master "redis1" within "30" seconds And senticache host "redis2" should have master "redis1" within "30" seconds And senticache host "redis3" should have master "redis1" within "30" seconds + + Scenario: Sentinel mode duplicate ip resolve does not break rdsync + Given sentinel shard is up and running + When I run command on host "redis1" + """ + echo '192.168.234.14 redis2 test1' >> /etc/hosts + echo '192.168.234.14 redis2 test2' >> /etc/hosts + echo '192.168.234.15 redis3 test3' >> /etc/hosts + echo '192.168.234.15 redis3 test4' >> /etc/hosts + """ + Then redis host "redis1" should be master + And redis host "redis2" should become replica of "redis1" within "15" seconds + And replication on redis host "redis2" should run fine within "15" seconds + And redis host "redis3" should become replica of "redis1" within "15" seconds + And replication on redis host "redis3" should run fine within "15" seconds + And zookeeper node "/test/active_nodes" should match json_exactly within "30" seconds + """ + ["redis1","redis2","redis3"] + """ + And senticache host "redis1" should have master "redis1" within "30" seconds + And senticache host "redis2" should have master "redis1" within "30" seconds + And senticache host "redis3" should have master "redis1" within "30" seconds + When I run command on host "redis3" + """ + supervisorctl stop rdsync + """ + And I run command on host "redis2" + """ + supervisorctl stop rdsync + """ + And I run command on host "redis1" + """ + supervisorctl stop rdsync + """ + And I run command on redis host "redis1" + """ + CONFIG SET quorum-replicas redis2:6379 + """ + And I run command on host "redis1" + """ + supervisorctl start rdsync + """ + And I run command on host "redis2" + """ + supervisorctl start rdsync + """ + And I run command on host "redis3" + """ + supervisorctl start rdsync + """ + When I set zookeeper node "/test/active_nodes" to + """ + [] + """ + Then zookeeper node "/test/active_nodes" should match json_exactly within "30" seconds + """ + ["redis1","redis2","redis3"] + """ + When I run command on redis host "redis1" + """ + CONFIG GET quorum-replicas + """ + Then redis cmd result should match regexp + """ + .*redis2.* + """ + And redis cmd result should match regexp + """ + .*redis3.* + """ + And redis cmd result should match regexp + """ + .*192.168.234.14.* + """ + And redis cmd result should match regexp + """ + .*192.168.234.15.* + """