mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 02:03:20 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			108 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			2.4 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
 | |
| 
 | |
| }
 | |
| 
 | |
| // ClusterLoadAssignment returns the healthy endpoints and their weight.
 | |
| 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
 | |
| }
 |