mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 02:03:20 -04:00 
			
		
		
		
	Traffic is a plugin that communicates via the xDS protocol to an Envoy control plane. Using the data from this control plane it hands out IP addresses. This allows you (via controlling the data in the control plane) to drain or send more traffic to specific endpoints. The plugin itself only acts upon this data; it doesn't do anything fancy by itself. Code used here is copied from grpc-go and other places, this is clearly marked in the source files. Signed-off-by: Miek Gieben <miek@miek.nl>
		
			
				
	
	
		
			117 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package xds
 | |
| 
 | |
| import (
 | |
| 	"math/rand"
 | |
| 	"net"
 | |
| 	"sync"
 | |
| 
 | |
| 	xdspb "github.com/envoyproxy/go-control-plane/envoy/api/v2"
 | |
| 	corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
 | |
| )
 | |
| 
 | |
| type assignment struct {
 | |
| 	mu  sync.RWMutex
 | |
| 	cla map[string]*xdspb.ClusterLoadAssignment
 | |
| }
 | |
| 
 | |
| // NewAssignment returns a pointer to an assignment.
 | |
| func NewAssignment() *assignment {
 | |
| 	return &assignment{cla: make(map[string]*xdspb.ClusterLoadAssignment)}
 | |
| }
 | |
| 
 | |
| // SetClusterLoadAssignment sets the assignment for the cluster to cla.
 | |
| 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 assignment for the cluster or nil if there is none.
 | |
| 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 cluster load assignments, using weighted random selection. It only selects
 | |
| // backends that are reporting healthy.
 | |
| func (a *assignment) Select(cluster string) (net.IP, bool) {
 | |
| 	cla := a.ClusterLoadAssignment(cluster)
 | |
| 	if cla == nil {
 | |
| 		return nil, false
 | |
| 	}
 | |
| 
 | |
| 	total := 0
 | |
| 	healthy := 0
 | |
| 	for _, ep := range cla.Endpoints {
 | |
| 		for _, lb := range ep.GetLbEndpoints() {
 | |
| 			if lb.GetHealthStatus() != corepb.HealthStatus_HEALTHY {
 | |
| 				continue
 | |
| 			}
 | |
| 			total += int(lb.GetLoadBalancingWeight().GetValue())
 | |
| 			healthy++
 | |
| 		}
 | |
| 	}
 | |
| 	if healthy == 0 {
 | |
| 		return nil, true
 | |
| 	}
 | |
| 
 | |
| 	if total == 0 {
 | |
| 		// all weights are 0, randomly select one of the endpoints.
 | |
| 		r := rand.Intn(healthy)
 | |
| 		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()), true
 | |
| 				}
 | |
| 				i++
 | |
| 			}
 | |
| 		}
 | |
| 		return nil, true
 | |
| 	}
 | |
| 
 | |
| 	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()), true
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return nil, true
 | |
| }
 |