2018-10-03 18:18:55 +00:00
|
|
|
package xds
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2019-06-24 19:05:36 +00:00
|
|
|
"fmt"
|
2018-10-03 18:18:55 +00:00
|
|
|
|
|
|
|
envoy "github.com/envoyproxy/go-control-plane/envoy/api/v2"
|
2019-03-22 19:37:14 +00:00
|
|
|
envoycore "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
|
2018-10-03 18:18:55 +00:00
|
|
|
envoyendpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
|
|
|
|
|
|
"github.com/hashicorp/consul/agent/proxycfg"
|
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
2019-03-22 19:37:14 +00:00
|
|
|
"github.com/hashicorp/consul/api"
|
2018-10-03 18:18:55 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// endpointsFromSnapshot returns the xDS API representation of the "endpoints"
|
|
|
|
func endpointsFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) {
|
|
|
|
if cfgSnap == nil {
|
|
|
|
return nil, errors.New("nil config given")
|
|
|
|
}
|
2019-06-24 19:05:36 +00:00
|
|
|
|
|
|
|
switch cfgSnap.Kind {
|
|
|
|
case structs.ServiceKindConnectProxy:
|
|
|
|
return endpointsFromSnapshotConnectProxy(cfgSnap, token)
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("Invalid service kind: %v", cfgSnap.Kind)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// endpointsFromSnapshotConnectProxy returns the xDS API representation of the "endpoints"
|
|
|
|
// (upstream instances) in the snapshot.
|
|
|
|
func endpointsFromSnapshotConnectProxy(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) {
|
|
|
|
if cfgSnap == nil {
|
|
|
|
return nil, errors.New("nil config given")
|
|
|
|
}
|
2018-10-03 18:18:55 +00:00
|
|
|
resources := make([]proto.Message, 0, len(cfgSnap.UpstreamEndpoints))
|
|
|
|
for id, endpoints := range cfgSnap.UpstreamEndpoints {
|
|
|
|
la := makeLoadAssignment(id, endpoints)
|
|
|
|
resources = append(resources, la)
|
|
|
|
}
|
|
|
|
return resources, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeEndpoint(clusterName, host string, port int) envoyendpoint.LbEndpoint {
|
|
|
|
return envoyendpoint.LbEndpoint{
|
2019-06-07 12:10:43 +00:00
|
|
|
HostIdentifier: &envoyendpoint.LbEndpoint_Endpoint{Endpoint: &envoyendpoint.Endpoint{
|
2018-10-03 18:18:55 +00:00
|
|
|
Address: makeAddressPtr(host, port),
|
|
|
|
},
|
2019-06-07 12:10:43 +00:00
|
|
|
}}
|
2018-10-03 18:18:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func makeLoadAssignment(clusterName string, endpoints structs.CheckServiceNodes) *envoy.ClusterLoadAssignment {
|
|
|
|
es := make([]envoyendpoint.LbEndpoint, 0, len(endpoints))
|
|
|
|
for _, ep := range endpoints {
|
|
|
|
addr := ep.Service.Address
|
|
|
|
if addr == "" {
|
|
|
|
addr = ep.Node.Address
|
|
|
|
}
|
2019-03-22 19:37:14 +00:00
|
|
|
healthStatus := envoycore.HealthStatus_HEALTHY
|
|
|
|
weight := 1
|
|
|
|
if ep.Service.Weights != nil {
|
|
|
|
weight = ep.Service.Weights.Passing
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, chk := range ep.Checks {
|
|
|
|
if chk.Status == api.HealthCritical {
|
|
|
|
// This can't actually happen now because health always filters critical
|
|
|
|
// but in the future it may not so set this correctly!
|
|
|
|
healthStatus = envoycore.HealthStatus_UNHEALTHY
|
|
|
|
}
|
|
|
|
if chk.Status == api.HealthWarning && ep.Service.Weights != nil {
|
|
|
|
weight = ep.Service.Weights.Warning
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Make weights fit Envoy's limits. A zero weight means that either Warning
|
|
|
|
// (likely) or Passing (weirdly) weight has been set to 0 effectively making
|
|
|
|
// this instance unhealthy and should not be sent traffic.
|
|
|
|
if weight < 1 {
|
|
|
|
healthStatus = envoycore.HealthStatus_UNHEALTHY
|
|
|
|
weight = 1
|
|
|
|
}
|
|
|
|
if weight > 128 {
|
|
|
|
weight = 128
|
|
|
|
}
|
2018-10-03 18:18:55 +00:00
|
|
|
es = append(es, envoyendpoint.LbEndpoint{
|
2019-06-07 12:10:43 +00:00
|
|
|
HostIdentifier: &envoyendpoint.LbEndpoint_Endpoint{
|
|
|
|
Endpoint: &envoyendpoint.Endpoint{
|
|
|
|
Address: makeAddressPtr(addr, ep.Service.Port),
|
|
|
|
}},
|
2019-03-22 19:37:14 +00:00
|
|
|
HealthStatus: healthStatus,
|
|
|
|
LoadBalancingWeight: makeUint32Value(weight),
|
2018-10-03 18:18:55 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
return &envoy.ClusterLoadAssignment{
|
|
|
|
ClusterName: clusterName,
|
|
|
|
Endpoints: []envoyendpoint.LocalityLbEndpoints{{
|
|
|
|
LbEndpoints: es,
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
}
|