Some tests included for making sure the JSON blob pulled from Zookeeper is correct. Updated client to be able to take Zookeeper json cluster config that is currently being used in aurora (clusters.json usually located at /etc/aurora/cluster.json). Changed error messages to no longer have a period at the end as that was throwing off printing of the error. Modified samuel's ZK library slightly to stop verbose logging using a NoOpLogger from stackoverflow.
88 lines
2.1 KiB
Go
88 lines
2.1 KiB
Go
package zk
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"sync"
|
|
)
|
|
|
|
// DNSHostProvider is the default HostProvider. It currently matches
|
|
// the Java StaticHostProvider, resolving hosts from DNS once during
|
|
// the call to Init. It could be easily extended to re-query DNS
|
|
// periodically or if there is trouble connecting.
|
|
type DNSHostProvider struct {
|
|
mu sync.Mutex // Protects everything, so we can add asynchronous updates later.
|
|
servers []string
|
|
curr int
|
|
last int
|
|
lookupHost func(string) ([]string, error) // Override of net.LookupHost, for testing.
|
|
}
|
|
|
|
// Init is called first, with the servers specified in the connection
|
|
// string. It uses DNS to look up addresses for each server, then
|
|
// shuffles them all together.
|
|
func (hp *DNSHostProvider) Init(servers []string) error {
|
|
hp.mu.Lock()
|
|
defer hp.mu.Unlock()
|
|
|
|
lookupHost := hp.lookupHost
|
|
if lookupHost == nil {
|
|
lookupHost = net.LookupHost
|
|
}
|
|
|
|
found := []string{}
|
|
for _, server := range servers {
|
|
host, port, err := net.SplitHostPort(server)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
addrs, err := lookupHost(host)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, addr := range addrs {
|
|
found = append(found, net.JoinHostPort(addr, port))
|
|
}
|
|
}
|
|
|
|
if len(found) == 0 {
|
|
return fmt.Errorf("No hosts found for addresses %q", servers)
|
|
}
|
|
|
|
// Randomize the order of the servers to avoid creating hotspots
|
|
stringShuffle(found)
|
|
|
|
hp.servers = found
|
|
hp.curr = -1
|
|
hp.last = -1
|
|
|
|
return nil
|
|
}
|
|
|
|
// Len returns the number of servers available
|
|
func (hp *DNSHostProvider) Len() int {
|
|
hp.mu.Lock()
|
|
defer hp.mu.Unlock()
|
|
return len(hp.servers)
|
|
}
|
|
|
|
// Next returns the next server to connect to. retryStart will be true
|
|
// if we've looped through all known servers without Connected() being
|
|
// called.
|
|
func (hp *DNSHostProvider) Next() (server string, retryStart bool) {
|
|
hp.mu.Lock()
|
|
defer hp.mu.Unlock()
|
|
hp.curr = (hp.curr + 1) % len(hp.servers)
|
|
retryStart = hp.curr == hp.last
|
|
if hp.last == -1 {
|
|
hp.last = 0
|
|
}
|
|
return hp.servers[hp.curr], retryStart
|
|
}
|
|
|
|
// Connected notifies the HostProvider of a successful connection.
|
|
func (hp *DNSHostProvider) Connected() {
|
|
hp.mu.Lock()
|
|
defer hp.mu.Unlock()
|
|
hp.last = hp.curr
|
|
}
|