github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/agent/xds/endpoints.go (about)

     1  package xds
     2  
     3  import (
     4  	"errors"
     5  
     6  	envoy "github.com/envoyproxy/go-control-plane/envoy/api/v2"
     7  	envoycore "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
     8  	envoyendpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
     9  	"github.com/gogo/protobuf/proto"
    10  
    11  	"github.com/hashicorp/consul/agent/proxycfg"
    12  	"github.com/hashicorp/consul/agent/structs"
    13  	"github.com/hashicorp/consul/api"
    14  )
    15  
    16  // endpointsFromSnapshot returns the xDS API representation of the "endpoints"
    17  // (upstream instances) in the snapshot.
    18  func endpointsFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) {
    19  	if cfgSnap == nil {
    20  		return nil, errors.New("nil config given")
    21  	}
    22  	resources := make([]proto.Message, 0, len(cfgSnap.UpstreamEndpoints))
    23  	for id, endpoints := range cfgSnap.UpstreamEndpoints {
    24  		la := makeLoadAssignment(id, endpoints)
    25  		resources = append(resources, la)
    26  	}
    27  	return resources, nil
    28  }
    29  
    30  func makeEndpoint(clusterName, host string, port int) envoyendpoint.LbEndpoint {
    31  	return envoyendpoint.LbEndpoint{
    32  		Endpoint: &envoyendpoint.Endpoint{
    33  			Address: makeAddressPtr(host, port),
    34  		},
    35  	}
    36  }
    37  
    38  func makeLoadAssignment(clusterName string, endpoints structs.CheckServiceNodes) *envoy.ClusterLoadAssignment {
    39  	es := make([]envoyendpoint.LbEndpoint, 0, len(endpoints))
    40  	for _, ep := range endpoints {
    41  		addr := ep.Service.Address
    42  		if addr == "" {
    43  			addr = ep.Node.Address
    44  		}
    45  		healthStatus := envoycore.HealthStatus_HEALTHY
    46  		weight := 1
    47  		if ep.Service.Weights != nil {
    48  			weight = ep.Service.Weights.Passing
    49  		}
    50  
    51  		for _, chk := range ep.Checks {
    52  			if chk.Status == api.HealthCritical {
    53  				// This can't actually happen now because health always filters critical
    54  				// but in the future it may not so set this correctly!
    55  				healthStatus = envoycore.HealthStatus_UNHEALTHY
    56  			}
    57  			if chk.Status == api.HealthWarning && ep.Service.Weights != nil {
    58  				weight = ep.Service.Weights.Warning
    59  			}
    60  		}
    61  		// Make weights fit Envoy's limits. A zero weight means that either Warning
    62  		// (likely) or Passing (weirdly) weight has been set to 0 effectively making
    63  		// this instance unhealthy and should not be sent traffic.
    64  		if weight < 1 {
    65  			healthStatus = envoycore.HealthStatus_UNHEALTHY
    66  			weight = 1
    67  		}
    68  		if weight > 128 {
    69  			weight = 128
    70  		}
    71  		es = append(es, envoyendpoint.LbEndpoint{
    72  			Endpoint: &envoyendpoint.Endpoint{
    73  				Address: makeAddressPtr(addr, ep.Service.Port),
    74  			},
    75  			HealthStatus:        healthStatus,
    76  			LoadBalancingWeight: makeUint32Value(weight),
    77  		})
    78  	}
    79  	return &envoy.ClusterLoadAssignment{
    80  		ClusterName: clusterName,
    81  		Endpoints: []envoyendpoint.LocalityLbEndpoints{{
    82  			LbEndpoints: es,
    83  		}},
    84  	}
    85  }