2023-08-15 18:57:07 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
2023-08-17 18:43:21 +00:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2023-08-15 18:57:07 +00:00
|
|
|
|
|
|
|
package xdsv2
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2023-08-29 21:39:29 +00:00
|
|
|
|
2023-08-15 18:57:07 +00:00
|
|
|
"github.com/hashicorp/go-hclog"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
|
|
|
|
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
2023-08-29 21:39:29 +00:00
|
|
|
proxytracker "github.com/hashicorp/consul/internal/mesh/proxy-tracker"
|
2023-08-15 18:57:07 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ResourceGenerator is associated with a single gRPC stream and creates xDS
|
|
|
|
// resources for a single client.
|
|
|
|
type ResourceGenerator struct {
|
|
|
|
Logger hclog.Logger
|
|
|
|
ProxyFeatures xdscommon.SupportedProxyFeatures
|
|
|
|
}
|
|
|
|
|
2023-11-07 15:00:08 +00:00
|
|
|
// NewResourceGenerator will create a new ResourceGenerator.
|
2023-08-15 18:57:07 +00:00
|
|
|
func NewResourceGenerator(
|
|
|
|
logger hclog.Logger,
|
|
|
|
) *ResourceGenerator {
|
|
|
|
return &ResourceGenerator{
|
|
|
|
Logger: logger,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-07 15:00:08 +00:00
|
|
|
// ProxyResources is the main state used to convert proxyState resources to Envoy resources.
|
2023-08-15 18:57:07 +00:00
|
|
|
type ProxyResources struct {
|
2023-11-07 15:00:08 +00:00
|
|
|
// proxyState is the final proxyState computed by Consul controllers.
|
|
|
|
proxyState *proxytracker.ProxyState
|
|
|
|
// envoyResources is a map of each resource type (listener, endpoint, route, cluster, etc.)
|
|
|
|
// with a corresponding map of k/v pairs of resource name to envoy proto message.
|
|
|
|
// map[string]map[string]proto.Message is used over map[string][]proto.Message because
|
|
|
|
// AllResourcesFromIR() will create envoy resource by walking the object graph from listener
|
|
|
|
// to endpoint. In the process, the same resource might be referenced more than once,
|
|
|
|
// so the map is used to prevent duplicate resources being created and also will use
|
|
|
|
// an O(1) lookup to see if it exists (it actually will set the map key rather than
|
|
|
|
// checks everywhere) where as each lookup would be O(n) with a []proto structure.
|
|
|
|
envoyResources map[string]map[string]proto.Message
|
2023-08-15 18:57:07 +00:00
|
|
|
}
|
|
|
|
|
2023-08-29 15:15:34 +00:00
|
|
|
func (g *ResourceGenerator) AllResourcesFromIR(proxyState *proxytracker.ProxyState) (map[string][]proto.Message, error) {
|
2023-08-15 18:57:07 +00:00
|
|
|
pr := &ProxyResources{
|
|
|
|
proxyState: proxyState,
|
2023-11-07 15:00:08 +00:00
|
|
|
envoyResources: make(map[string]map[string]proto.Message),
|
2023-08-15 18:57:07 +00:00
|
|
|
}
|
2023-11-07 15:00:08 +00:00
|
|
|
pr.envoyResources[xdscommon.ListenerType] = make(map[string]proto.Message)
|
|
|
|
pr.envoyResources[xdscommon.RouteType] = make(map[string]proto.Message)
|
|
|
|
pr.envoyResources[xdscommon.ClusterType] = make(map[string]proto.Message)
|
|
|
|
pr.envoyResources[xdscommon.EndpointType] = make(map[string]proto.Message)
|
|
|
|
|
|
|
|
err := pr.makeEnvoyResourceGraphsStartingFromListeners()
|
2023-08-15 18:57:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to generate xDS resources for ProxyState: %v", err)
|
|
|
|
}
|
|
|
|
|
2023-11-07 15:00:08 +00:00
|
|
|
// Now account for Clusters that did not have a destination.
|
|
|
|
for name := range proxyState.Clusters {
|
|
|
|
if _, ok := pr.envoyResources[xdscommon.ClusterType][name]; !ok {
|
|
|
|
pr.addEnvoyClustersAndEndpointsToEnvoyResources(name)
|
|
|
|
}
|
2023-08-15 18:57:07 +00:00
|
|
|
}
|
|
|
|
|
2023-11-07 15:00:08 +00:00
|
|
|
envoyResources := convertResourceMapsToResourceArrays(pr.envoyResources)
|
|
|
|
return envoyResources, nil
|
|
|
|
}
|
2023-08-17 19:55:54 +00:00
|
|
|
|
2023-11-07 15:00:08 +00:00
|
|
|
// convertResourceMapsToResourceArrays will convert map[string]map[string]proto.Message, which is used to
|
|
|
|
// prevent duplicate resource being created, to map[string][]proto.Message which is used by Delta server.
|
|
|
|
func convertResourceMapsToResourceArrays(resourceMap map[string]map[string]proto.Message) map[string][]proto.Message {
|
|
|
|
resources := make(map[string][]proto.Message)
|
|
|
|
resources[xdscommon.ListenerType] = make([]proto.Message, 0)
|
|
|
|
resources[xdscommon.RouteType] = make([]proto.Message, 0)
|
|
|
|
resources[xdscommon.ClusterType] = make([]proto.Message, 0)
|
|
|
|
resources[xdscommon.EndpointType] = make([]proto.Message, 0)
|
2023-08-15 18:57:07 +00:00
|
|
|
|
2023-11-07 15:00:08 +00:00
|
|
|
// This conversion incurs processing cost which is done once in the generating envoy resources.
|
|
|
|
// This tradeoff is preferable to doing array scan every time an envoy resource needs to be
|
|
|
|
// to pr.envoyResource to see if it already exists.
|
|
|
|
for resourceTypeName, resourceMap := range resourceMap {
|
|
|
|
for _, resource := range resourceMap {
|
|
|
|
resources[resourceTypeName] = append(resources[resourceTypeName], resource)
|
|
|
|
}
|
2023-08-17 21:04:53 +00:00
|
|
|
}
|
2023-11-07 15:00:08 +00:00
|
|
|
return resources
|
2023-08-15 18:57:07 +00:00
|
|
|
}
|