mirror of https://github.com/hashicorp/consul
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
6.3 KiB
180 lines
6.3 KiB
package xdscommon |
|
|
|
import ( |
|
"github.com/golang/protobuf/proto" |
|
|
|
"github.com/hashicorp/consul/agent/connect" |
|
"github.com/hashicorp/consul/agent/proxycfg" |
|
"github.com/hashicorp/consul/agent/structs" |
|
"github.com/hashicorp/consul/api" |
|
) |
|
|
|
const ( |
|
// Resource types in xDS v3. These are copied from |
|
// envoyproxy/go-control-plane/pkg/resource/v3/resource.go since we don't need any of |
|
// the rest of that package. |
|
apiTypePrefix = "type.googleapis.com/" |
|
|
|
// EndpointType is the TypeURL for Endpoint discovery responses. |
|
EndpointType = apiTypePrefix + "envoy.config.endpoint.v3.ClusterLoadAssignment" |
|
|
|
// ClusterType is the TypeURL for Cluster discovery responses. |
|
ClusterType = apiTypePrefix + "envoy.config.cluster.v3.Cluster" |
|
|
|
// RouteType is the TypeURL for Route discovery responses. |
|
RouteType = apiTypePrefix + "envoy.config.route.v3.RouteConfiguration" |
|
|
|
// ListenerType is the TypeURL for Listener discovery responses. |
|
ListenerType = apiTypePrefix + "envoy.config.listener.v3.Listener" |
|
) |
|
|
|
type IndexedResources struct { |
|
// Index is a map of typeURL => resourceName => resource |
|
Index map[string]map[string]proto.Message |
|
|
|
// ChildIndex is a map of typeURL => parentResourceName => list of |
|
// childResourceNames. This only applies if the child and parent do not |
|
// share a name. |
|
ChildIndex map[string]map[string][]string |
|
} |
|
|
|
func EmptyIndexedResources() *IndexedResources { |
|
return &IndexedResources{ |
|
Index: map[string]map[string]proto.Message{ |
|
ListenerType: make(map[string]proto.Message), |
|
RouteType: make(map[string]proto.Message), |
|
ClusterType: make(map[string]proto.Message), |
|
EndpointType: make(map[string]proto.Message), |
|
}, |
|
ChildIndex: map[string]map[string][]string{ |
|
ListenerType: make(map[string][]string), |
|
ClusterType: make(map[string][]string), |
|
}, |
|
} |
|
} |
|
|
|
type ServiceConfig struct { |
|
// Kind identifies the final proxy kind that will make the request to the |
|
// destination service. |
|
Kind api.ServiceKind |
|
Meta map[string]string |
|
} |
|
|
|
// PluginConfiguration is passed into Envoy plugins. It should depend on the |
|
// API client rather than the structs package because the API client is meant |
|
// to be public. |
|
type PluginConfiguration struct { |
|
// ServiceConfigs is a mapping from service names to the data Envoy plugins |
|
// need to override the default Envoy configurations. |
|
ServiceConfigs map[api.CompoundServiceName]ServiceConfig |
|
|
|
// SNIToServiceName is a mapping from SNIs to service names. This allows |
|
// Envoy plugins to easily convert from an SNI Envoy resource name to the |
|
// associated service's CompoundServiceName |
|
SNIToServiceName map[string]api.CompoundServiceName |
|
|
|
// EnvoyIDToServiceName is a mapping from EnvoyIDs to service names. This allows |
|
// Envoy plugins to easily convert from an EnvoyID Envoy resource name to the |
|
// associated service's CompoundServiceName |
|
EnvoyIDToServiceName map[string]api.CompoundServiceName |
|
|
|
// Kind is mode the local Envoy proxy is running in. For now, only |
|
// terminating gateways are supported. |
|
Kind api.ServiceKind |
|
} |
|
|
|
// MakePluginConfiguration generates the configuration that will be sent to |
|
// Envoy plugins. |
|
func MakePluginConfiguration(cfgSnap *proxycfg.ConfigSnapshot) PluginConfiguration { |
|
serviceConfigs := make(map[api.CompoundServiceName]ServiceConfig) |
|
sniMappings := make(map[string]api.CompoundServiceName) |
|
envoyIDMappings := make(map[string]api.CompoundServiceName) |
|
|
|
trustDomain := "" |
|
if cfgSnap.Roots != nil { |
|
trustDomain = cfgSnap.Roots.TrustDomain |
|
} |
|
|
|
switch cfgSnap.Kind { |
|
case structs.ServiceKindConnectProxy: |
|
connectProxies := make(map[proxycfg.UpstreamID]struct{}) |
|
for uid, upstreamData := range cfgSnap.ConnectProxy.WatchedUpstreamEndpoints { |
|
for _, serviceNodes := range upstreamData { |
|
// Lambdas and likely other integrations won't be attached to nodes. |
|
// After agentless, we may need to reconsider this. |
|
if len(serviceNodes) == 0 { |
|
connectProxies[uid] = struct{}{} |
|
} |
|
for _, serviceNode := range serviceNodes { |
|
if serviceNode.Service.Kind == structs.ServiceKindTypical || serviceNode.Service.Kind == structs.ServiceKindConnectProxy { |
|
connectProxies[uid] = struct{}{} |
|
} |
|
} |
|
} |
|
} |
|
|
|
// TODO(peering): consider PeerUpstreamEndpoints in addition to DiscoveryChain |
|
|
|
for uid, dc := range cfgSnap.ConnectProxy.DiscoveryChain { |
|
if _, ok := connectProxies[uid]; !ok { |
|
continue |
|
} |
|
|
|
serviceConfigs[upstreamIDToCompoundServiceName(uid)] = ServiceConfig{ |
|
Meta: dc.ServiceMeta, |
|
Kind: api.ServiceKindConnectProxy, |
|
} |
|
|
|
compoundServiceName := upstreamIDToCompoundServiceName(uid) |
|
meta := uid.EnterpriseMeta |
|
sni := connect.ServiceSNI(uid.Name, "", meta.NamespaceOrDefault(), meta.PartitionOrDefault(), cfgSnap.Datacenter, trustDomain) |
|
sniMappings[sni] = compoundServiceName |
|
envoyIDMappings[uid.EnvoyID()] = compoundServiceName |
|
} |
|
case structs.ServiceKindTerminatingGateway: |
|
for svc, c := range cfgSnap.TerminatingGateway.ServiceConfigs { |
|
compoundServiceName := serviceNameToCompoundServiceName(svc) |
|
serviceConfigs[compoundServiceName] = ServiceConfig{ |
|
Meta: c.Meta, |
|
Kind: api.ServiceKindTerminatingGateway, |
|
} |
|
|
|
sni := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, trustDomain) |
|
sniMappings[sni] = compoundServiceName |
|
|
|
envoyID := proxycfg.NewUpstreamIDFromServiceName(svc) |
|
envoyIDMappings[envoyID.EnvoyID()] = compoundServiceName |
|
|
|
resolver, hasResolver := cfgSnap.TerminatingGateway.ServiceResolvers[svc] |
|
if hasResolver { |
|
for subsetName := range resolver.Subsets { |
|
sni := connect.ServiceSNI(svc.Name, subsetName, svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, trustDomain) |
|
sniMappings[sni] = compoundServiceName |
|
} |
|
} |
|
} |
|
} |
|
|
|
return PluginConfiguration{ |
|
ServiceConfigs: serviceConfigs, |
|
SNIToServiceName: sniMappings, |
|
EnvoyIDToServiceName: envoyIDMappings, |
|
Kind: api.ServiceKind(cfgSnap.Kind), |
|
} |
|
} |
|
|
|
func serviceNameToCompoundServiceName(svc structs.ServiceName) api.CompoundServiceName { |
|
return api.CompoundServiceName{ |
|
Name: svc.Name, |
|
Partition: svc.PartitionOrDefault(), |
|
Namespace: svc.NamespaceOrDefault(), |
|
} |
|
} |
|
|
|
func upstreamIDToCompoundServiceName(uid proxycfg.UpstreamID) api.CompoundServiceName { |
|
return api.CompoundServiceName{ |
|
Name: uid.Name, |
|
Partition: uid.PartitionOrDefault(), |
|
Namespace: uid.NamespaceOrDefault(), |
|
} |
|
}
|
|
|