mirror of
https://github.com/coredns/coredns.git
synced 2025-10-27 16:24:19 -04:00
107 lines
2.3 KiB
Go
107 lines
2.3 KiB
Go
package xds
|
|
|
|
import (
|
|
"math/rand"
|
|
"net"
|
|
"sync"
|
|
|
|
xdspb "github.com/envoyproxy/go-control-plane/envoy/api/v2"
|
|
)
|
|
|
|
type assignment struct {
|
|
mu sync.RWMutex
|
|
cla map[string]*xdspb.ClusterLoadAssignment
|
|
version int // not sure what do with and if we should discard all clusters.
|
|
}
|
|
|
|
func (a *assignment) setClusterLoadAssignment(cluster string, cla *xdspb.ClusterLoadAssignment) {
|
|
// If cla is nil we just found a cluster, check if we already know about it, or if we need to make a new entry.
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
_, ok := a.cla[cluster]
|
|
if !ok {
|
|
a.cla[cluster] = cla
|
|
return
|
|
}
|
|
if cla == nil {
|
|
return
|
|
}
|
|
a.cla[cluster] = cla
|
|
|
|
}
|
|
|
|
func (a *assignment) clusterLoadAssignment(cluster string) *xdspb.ClusterLoadAssignment {
|
|
a.mu.RLock()
|
|
cla, ok := a.cla[cluster]
|
|
a.mu.RUnlock()
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return cla
|
|
}
|
|
|
|
func (a *assignment) clusters() []string {
|
|
a.mu.RLock()
|
|
defer a.mu.RUnlock()
|
|
clusters := make([]string, len(a.cla))
|
|
i := 0
|
|
for k := range a.cla {
|
|
clusters[i] = k
|
|
i++
|
|
}
|
|
return clusters
|
|
}
|
|
|
|
// Select selects a backend from cla, using weighted random selection. It only selects
|
|
// backends that are reporting healthy.
|
|
func (a *assignment) Select(cluster string) net.IP {
|
|
cla := a.clusterLoadAssignment(cluster)
|
|
if cla == nil {
|
|
return nil
|
|
}
|
|
|
|
total := 0
|
|
i := 0
|
|
for _, ep := range cla.Endpoints {
|
|
for _, lb := range ep.GetLbEndpoints() {
|
|
// if lb.GetHealthStatus() != corepb.HealthStatus_HEALTHY {
|
|
// continue
|
|
// }
|
|
total += int(lb.GetLoadBalancingWeight().GetValue())
|
|
i++
|
|
}
|
|
}
|
|
if total == 0 {
|
|
// all weights are 0, randomly select one of the endpoints.
|
|
r := rand.Intn(i)
|
|
i := 0
|
|
for _, ep := range cla.Endpoints {
|
|
for _, lb := range ep.GetLbEndpoints() {
|
|
// if lb.GetHealthStatus() != corepb.HealthStatus_HEALTHY {
|
|
// continue
|
|
// }
|
|
if r == i {
|
|
return net.ParseIP(lb.GetEndpoint().GetAddress().GetSocketAddress().GetAddress())
|
|
}
|
|
i++
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
r := rand.Intn(total) + 1
|
|
|
|
for _, ep := range cla.Endpoints {
|
|
for _, lb := range ep.GetLbEndpoints() {
|
|
// if lb.GetHealthStatus() != corepb.HealthStatus_HEALTHY {
|
|
// continue
|
|
// }
|
|
r -= int(lb.GetLoadBalancingWeight().GetValue())
|
|
if r <= 0 {
|
|
return net.ParseIP(lb.GetEndpoint().GetAddress().GetSocketAddress().GetAddress())
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|