Files
coredns/plugin/traffic/xds/assignment.go
Miek Gieben a231daf17f more updates
Signed-off-by: Miek Gieben <miek@miek.nl>
2020-01-16 16:39:28 +01:00

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
}