diff --git a/.changelog/23454.txt b/.changelog/23454.txt new file mode 100644 index 00000000000..78523e636b8 --- /dev/null +++ b/.changelog/23454.txt @@ -0,0 +1,3 @@ +```release-note:bug +xds: Fixed XDS package to generate correct endpoints and cluster configurations for API Gateways when peered, and updated the API Gateway update handler to propogate mesh gateway config to its upstreams. +``` \ No newline at end of file diff --git a/agent/proxycfg/api_gateway.go b/agent/proxycfg/api_gateway.go index d5d898d7c7b..3364a8b0863 100644 --- a/agent/proxycfg/api_gateway.go +++ b/agent/proxycfg/api_gateway.go @@ -367,6 +367,19 @@ func (h *handlerAPIGateway) handleRouteConfigUpdate(ctx context.Context, u Updat for _, rule := range route.Rules { for _, service := range rule.Services { effectiveLimits := apiGatewayEffectiveUpstreamLimits(defaultLimits, service.Limits) + + // Retrieving the meshGatewayConfig from handlerAPIGateway instance. + // `handlerAPIGateway` embeds `handlerState`, which exposes `serviceInstance.proxyCfg`. + // serviceInstance.proxyCfg.MeshGateway is replicated from NodeService during state setup/update. + // and NodeService populated for all gateway's during service resistration `AgentRegisterService`. + // + // So, Whenever any change happens in NodeService, proxyCfg manager will recreate + // the state where it copies NodeService to serviceInstance and + // then calls this api_gateway handleUpdates method. + // which will update the Mesh-Gateway config to api_gateway upstreams (below). + // h.service = + meshGatewayConfig := h.proxyCfg.MeshGateway + for _, listener := range snap.APIGateway.Listeners { shouldBind := false for _, parent := range route.Parents { @@ -393,6 +406,11 @@ func (h *handlerAPIGateway) handleRouteConfigUpdate(ctx context.Context, u Updat // Pass the protocol that was configured on the listener in order // to force that protocol on the Envoy listener. Config: upstreamCfg, + + // Propogate the meshGatewayConfig in api gateway upstreams + // so that meshGatewayMode can be used in XDS for + // endpoints and cluster config generation. + MeshGateway: meshGatewayConfig, } listenerKey := APIGatewayListenerKeyFromListener(listener) @@ -425,6 +443,7 @@ func (h *handlerAPIGateway) handleRouteConfigUpdate(ctx context.Context, u Updat for _, service := range route.Services { effectiveLimits := apiGatewayEffectiveUpstreamLimits(defaultLimits, service.Limits) + meshGatewayConfig := h.proxyCfg.MeshGateway upstreamID := NewUpstreamIDFromServiceName(service.ServiceName()) seenUpstreamIDs.add(upstreamID) @@ -454,7 +473,8 @@ func (h *handlerAPIGateway) handleRouteConfigUpdate(ctx context.Context, u Updat LocalBindPort: listener.Port, // Pass the protocol that was configured on the ingress listener in order // to force that protocol on the Envoy listener. - Config: upstreamCfg, + Config: upstreamCfg, + MeshGateway: meshGatewayConfig, } listenerKey := APIGatewayListenerKeyFromListener(listener) diff --git a/agent/proxycfg/state.go b/agent/proxycfg/state.go index 9e293038045..b93e78712c2 100644 --- a/agent/proxycfg/state.go +++ b/agent/proxycfg/state.go @@ -226,6 +226,7 @@ func newKindHandler(config stateConfig, s serviceInstance, ch chan UpdateEvent) case structs.ServiceKindIngressGateway: handler = &handlerIngressGateway{handlerState: h} case structs.ServiceKindAPIGateway: + h.logger = config.logger.Named(logging.APIGateway) handler = &handlerAPIGateway{handlerState: h} default: return nil, errors.New("not a connect-proxy, terminating-gateway, mesh-gateway, or ingress-gateway") diff --git a/agent/proxycfg/state_test.go b/agent/proxycfg/state_test.go index 43349654f7a..d945d57ada6 100644 --- a/agent/proxycfg/state_test.go +++ b/agent/proxycfg/state_test.go @@ -26,7 +26,7 @@ import ( "github.com/hashicorp/consul/sdk/testutil" ) -func TestStateChanged(t *testing.T) { +func TestStateChangedConnectProxy(t *testing.T) { tests := []struct { name string ns *structs.NodeService @@ -108,6 +108,131 @@ func TestStateChanged(t *testing.T) { }, want: true, }, + { + name: "different proxy mesh gateway mode", + ns: structs.TestNodeServiceAPIGateway(t), + token: "foo", + mutate: func(ns structs.NodeService, token string) (*structs.NodeService, string) { + ns.Proxy.MeshGateway.Mode = structs.MeshGatewayModeLocal + return &ns, token + }, + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + proxyID := ProxyID{ServiceID: tt.ns.CompoundServiceID()} + state, err := newState(proxyID, tt.ns, testSource, tt.token, stateConfig{logger: hclog.New(nil)}, rate.NewLimiter(rate.Inf, 1)) + require.NoError(t, err) + otherNS, otherToken := tt.mutate(*tt.ns, tt.token) + require.Equal(t, tt.want, state.Changed(otherNS, otherToken)) + }) + } +} + +func TestStateChangedAPIGateway(t *testing.T) { + tests := []struct { + name string + ns *structs.NodeService + token string + mutate func(ns structs.NodeService, token string) (*structs.NodeService, string) + want bool + }{ + { + name: "nil node service", + ns: structs.TestNodeServiceAPIGateway(t), + mutate: func(ns structs.NodeService, token string) (*structs.NodeService, string) { + return nil, token + }, + want: true, + }, + { + name: "same service", + ns: structs.TestNodeServiceAPIGateway(t), + mutate: func(ns structs.NodeService, token string) (*structs.NodeService, string) { + return &ns, token + }, want: false, + }, + { + name: "same service, different token", + ns: structs.TestNodeServiceAPIGateway(t), + token: "foo", + mutate: func(ns structs.NodeService, token string) (*structs.NodeService, string) { + return &ns, "bar" + }, + want: true, + }, + { + name: "different address", + ns: structs.TestNodeServiceAPIGateway(t), + token: "foo", + mutate: func(ns structs.NodeService, token string) (*structs.NodeService, string) { + ns.Address = "10.10.10.10" + return &ns, token + }, + want: true, + }, + { + name: "different port", + ns: structs.TestNodeServiceAPIGateway(t), + token: "foo", + mutate: func(ns structs.NodeService, token string) (*structs.NodeService, string) { + ns.Port = 12345 + return &ns, token + }, + want: true, + }, + { + name: "different service kind", + ns: structs.TestNodeServiceAPIGateway(t), + token: "foo", + mutate: func(ns structs.NodeService, token string) (*structs.NodeService, string) { + ns.Kind = "" + return &ns, token + }, + want: true, + }, + { + name: "different proxy target", + ns: structs.TestNodeServiceAPIGateway(t), + token: "foo", + mutate: func(ns structs.NodeService, token string) (*structs.NodeService, string) { + ns.Proxy.DestinationServiceName = "badger" + return &ns, token + }, + want: true, + }, + { + name: "different proxy upstreams", + ns: structs.TestNodeServiceAPIGateway(t), + token: "foo", + mutate: func(ns structs.NodeService, token string) (*structs.NodeService, string) { + ns.Proxy.Upstreams = nil + return &ns, token + }, + want: true, + }, + { + name: "different mesh gateway mode (local)", + ns: structs.TestNodeServiceAPIGateway(t), + token: "foo", + mutate: func(ns structs.NodeService, token string) (*structs.NodeService, string) { + ns.Proxy.MeshGateway.Mode = structs.MeshGatewayModeLocal + return &ns, token + }, + want: true, + }, + { + name: "different mesh gateway mode (remote)", + ns: structs.TestNodeServiceAPIGateway(t), + token: "foo", + mutate: func(ns structs.NodeService, token string) (*structs.NodeService, string) { + ns.Proxy.MeshGateway.Mode = structs.MeshGatewayModeRemote + return &ns, token + }, + want: true, + }, } for _, tt := range tests { diff --git a/agent/structs/testing_catalog.go b/agent/structs/testing_catalog.go index c90af67d061..5241ecfadef 100644 --- a/agent/structs/testing_catalog.go +++ b/agent/structs/testing_catalog.go @@ -176,10 +176,35 @@ func TestNodeServiceMeshGateway(t testing.T) *NodeService { } func TestNodeServiceAPIGateway(t testing.T) *NodeService { + entMeta := DefaultEnterpriseMetaInPartition("") return &NodeService{ Kind: ServiceKindAPIGateway, Service: "api-gateway", Address: "1.1.1.1", + + // --------------------------------------- + // Adding TestConnectProxyConfig to the proxy field here within TestNodeServiceAPIGateway + // to test whether APIGateway is able to handle state changes within ConnectProxyConfig (TestStateChangedAPIGateway). + // Please note: + // The naming may suggest that ConnectProxyConfig should only be used for ConnectProxy, + // but "APIGateway state" uses serviceInstance, which embeds ConnectProxyConfig as part of its state, + // so any changes to ConnectProxyConfig will also impact APIGateway, such as change in "mesh gateway mode". + // + // For example, let's say a user updates the mesh gateway mode of an API gateway, + // First NodeService.Proxy will be updated and then proxyCfg manager detects change in config + // and it recreates the state for api_gateway which would copy the + // NodeService.Proxy.MeshGateway to serviceInstance.proxyCfg.MeshGateway in `newServiceInstanceFromNodeService` (serviceInstance is part of state) + // and then proxyCfg manager calls the api_gateway handleUpdates method which would + // update the api_gateway upstreams with new meshGateway config. + // + // Now, this serviceInstance.proxyCfg and NodeService.Proxy + // refers to same proxy configuration, which is of type ConnectProxyConfig. + + // So, we need to test it as well. + // --------------------------------------- + + Proxy: TestConnectProxyConfig(t), + EnterpriseMeta: *entMeta, } } diff --git a/agent/xds/clusters.go b/agent/xds/clusters.go index 04f3042984c..50298a64d83 100644 --- a/agent/xds/clusters.go +++ b/agent/xds/clusters.go @@ -1656,25 +1656,47 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( for _, groupedTarget := range targetGroups { s.Logger.Debug("generating cluster for", "cluster", groupedTarget.ClusterName) + // Now this makeUpstreamClusterForDiscoveryChain, is a generic method + // and used by connect proxy, ingress gateway and api gateway. + // + // Issue: This method always make cluster (without endpoints). + // `ClusterDiscoveryType: &envoy_cluster_v3.Cluster_Type{Type: envoy_cluster_v3.Cluster_EDS},` + // + // Envoy Exception: + // As we know that any service whose upstream endpoint is of type hostname, + // envoy cannot resolve hostname as EDS. + // So, we need to use CDS to send endpoints as well along with cluster configs. + // + // Context: + // When we have 2 consul DC peered with mesh gw ON AWS and + // we have API gw on DC1 which need to access a service X which exist on DC2. + // Also, API gateway is configured to in mesh-gw remote mode. + // In this case, API gateway upstream would be DC2's mesh-gateway and + // we configure API GW envoy upstream endpoint to it. + // The problem is envoy exception and AWS mesh-gw lb type. + // AWS generates hostname based endpoints for mesh-gw lb endpoint and + // when we have hostname based endpoints envoy cannot resolve it via EDS, + // So we configure that endpoint via CDS. + // + // If not fixed, whenever any service (gateway) whose upstream endpoint is of hostname type, + // cluster endpoints will be empty and envoy will fail to route traffic to that cluster. + // + // Fix: Add logic to check if we should create a cluster config + // without upstream endpoint or with upstream endpoint (hostnames) + // based on upstream endpoint type. + // + // You can refer makeUpstreamClusterForPeerService - used by connect proxy for similar logic. + // or makeGatewayCluster - used by mesh gw for peering services. + c := &envoy_cluster_v3.Cluster{ - Name: groupedTarget.ClusterName, - AltStatName: groupedTarget.ClusterName, - ConnectTimeout: durationpb.New(node.Resolver.ConnectTimeout), - ClusterDiscoveryType: &envoy_cluster_v3.Cluster_Type{Type: envoy_cluster_v3.Cluster_EDS}, + Name: groupedTarget.ClusterName, + AltStatName: groupedTarget.ClusterName, + ConnectTimeout: durationpb.New(node.Resolver.ConnectTimeout), CommonLbConfig: &envoy_cluster_v3.Cluster_CommonLbConfig{ HealthyPanicThreshold: &envoy_type_v3.Percent{ Value: 0, // disable panic threshold }, }, - EdsClusterConfig: &envoy_cluster_v3.Cluster_EdsClusterConfig{ - EdsConfig: &envoy_core_v3.ConfigSource{ - InitialFetchTimeout: cfgSnap.GetXDSCommonConfig(s.Logger).GetXDSFetchTimeout(), - ResourceApiVersion: envoy_core_v3.ApiVersion_V3, - ConfigSourceSpecifier: &envoy_core_v3.ConfigSource_Ads{ - Ads: &envoy_core_v3.AggregatedConfigSource{}, - }, - }, - }, // TODO(peering): make circuit breakers or outlier detection work? CircuitBreakers: &envoy_cluster_v3.CircuitBreakers{ Thresholds: makeThresholdsIfNeeded(upstreamConfig.Limits), @@ -1704,13 +1726,67 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( default: return nil, fmt.Errorf("cannot have more than one target") } + + targetInfo := groupedTarget.Targets[0] + targetUID := proxycfg.NewUpstreamIDFromTargetID(targetInfo.TargetID) + + meshGatewayMode, err := s.getMeshGatewayMode(cfgSnap, upstream, targetUID, groupedTarget.ClusterName) + if err != nil { + s.Logger.Error(err.Error(), "cluster", groupedTarget.ClusterName) + } + + // Check if cluster need to be configured with hostnames or not. + useEDS := true + if targetUID.Peer != "" { + if _, ok := upstreamsSnapshot.PeerUpstreamEndpointsUseHostnames[targetUID]; ok { + // If we're using local mesh gw, the fact that upstreams use hostnames doesn't matter. + // If we're not using local mesh gw, then resort to CDS/DNS. + if meshGatewayMode != structs.MeshGatewayModeLocal { + useEDS = false + } + } + } + + if useEDS { + c.ClusterDiscoveryType = &envoy_cluster_v3.Cluster_Type{Type: envoy_cluster_v3.Cluster_EDS} + c.EdsClusterConfig = &envoy_cluster_v3.Cluster_EdsClusterConfig{ + EdsConfig: &envoy_core_v3.ConfigSource{ + InitialFetchTimeout: cfgSnap.GetXDSCommonConfig(s.Logger).GetXDSFetchTimeout(), + ResourceApiVersion: envoy_core_v3.ApiVersion_V3, + ConfigSourceSpecifier: &envoy_core_v3.ConfigSource_Ads{ + Ads: &envoy_core_v3.AggregatedConfigSource{}, + }, + }, + } + } else { + hostnameEndpoints, ok := upstreamsSnapshot.PeerUpstreamEndpoints.Get(targetUID) + if !ok || len(hostnameEndpoints) == 0 { + // The upstream snapshot should deliver hostname endpoints soon; skip this cluster until then. + s.Logger.Debug("peer hostname endpoints not ready for discovery chain target", + "target", targetInfo.TargetID, + "upstream", targetUID, + "cluster", groupedTarget.ClusterName, + ) + continue + } + c.EdsClusterConfig = nil + configureClusterWithHostnames( + s.Logger, + c, + "", /*TODO: should make configurable ? */ + hostnameEndpoints, + true, /*isRemote*/ + false, /*onlyPassing*/ + ) + } + var handled bool out, handled, err = s.appendEntDiscoveryChainTargetClusters(out, cfgSnap, upstreamsSnapshot, uid, chain, groupedTarget, c, forMeshGateway) if err != nil { return nil, err } - if !handled { + if !handled { if targetInfo := groupedTarget.Targets[0]; targetInfo.TLSContext != nil { transportSocket, err := makeUpstreamTLSTransportSocket(targetInfo.TLSContext) if err != nil { @@ -1739,6 +1815,32 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( return out, nil } +func (s *ResourceGenerator) getMeshGatewayMode( + cfgSnap *proxycfg.ConfigSnapshot, upstream *structs.Upstream, + targetUID proxycfg.UpstreamID, clusterName string, +) (structs.MeshGatewayMode, error) { + defaultMode := structs.MeshGatewayModeDefault + switch cfgSnap.Kind { + case structs.ServiceKindConnectProxy: + upstreamConfig, _ := cfgSnap.ConnectProxy. + GetUpstream(targetUID, &cfgSnap.ProxyID.EnterpriseMeta) + if upstreamConfig != nil { + return upstreamConfig.MeshGateway.Mode, nil + } + return defaultMode, nil + case structs.ServiceKindAPIGateway, + structs.ServiceKindIngressGateway: + if upstream != nil { + return upstream.MeshGateway.Mode, nil + } + return defaultMode, nil + case structs.ServiceKindMeshGateway: + // Mesh Gateway mesh mode will always be remote. + return structs.MeshGatewayModeRemote, nil + } + return structs.MeshGatewayModeDefault, fmt.Errorf("unexpected service kind %q when determining mesh gateway mode for cluster %q", cfgSnap.Kind, clusterName) +} + func (s *ResourceGenerator) makeExportedUpstreamClustersForMeshGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) { // NOTE: Despite the mesh gateway already having one cluster per service // (and subset) in the local datacenter we cannot reliably use those to diff --git a/agent/xds/endpoints.go b/agent/xds/endpoints.go index 1856443c4cc..6021fb7bd28 100644 --- a/agent/xds/endpoints.go +++ b/agent/xds/endpoints.go @@ -68,17 +68,12 @@ func (s *ResourceGenerator) endpointsFromSnapshotConnectProxy(cfgSnap *proxycfg. continue } - var upstreamConfigMap map[string]interface{} - if upstream != nil { - upstreamConfigMap = upstream.Config - } - es, err := s.endpointsFromDiscoveryChain( uid, chain, cfgSnap, cfgSnap.Locality, - upstreamConfigMap, + upstream, cfgSnap.ConnectProxy.WatchedUpstreamEndpoints[uid], cfgSnap.ConnectProxy.WatchedGatewayEndpoints[uid], false, @@ -533,7 +528,7 @@ func (s *ResourceGenerator) endpointsFromSnapshotIngressGateway(cfgSnap *proxycf cfgSnap.IngressGateway.DiscoveryChain[uid], cfgSnap, proxycfg.GatewayKey{Datacenter: cfgSnap.Datacenter, Partition: u.DestinationPartition}, - u.Config, + &u, cfgSnap.IngressGateway.WatchedUpstreamEndpoints[uid], cfgSnap.IngressGateway.WatchedGatewayEndpoints[uid], false, @@ -555,8 +550,8 @@ func (s *ResourceGenerator) endpointsFromSnapshotAPIGateway(cfgSnap *proxycfg.Co readyListeners := getReadyListeners(cfgSnap) for _, readyListener := range readyListeners { - for _, u := range readyListener.upstreams { - uid := proxycfg.NewUpstreamID(&u) + for _, upstream := range readyListener.upstreams { + uid := proxycfg.NewUpstreamID(&upstream) // If we've already created endpoints for this upstream, skip it. Multiple listeners may // reference the same upstream, so we don't need to create duplicate endpoints in that case. @@ -569,8 +564,8 @@ func (s *ResourceGenerator) endpointsFromSnapshotAPIGateway(cfgSnap *proxycfg.Co uid, cfgSnap.APIGateway.DiscoveryChain[uid], cfgSnap, - proxycfg.GatewayKey{Datacenter: cfgSnap.Datacenter, Partition: u.DestinationPartition}, - u.Config, + proxycfg.GatewayKey{Datacenter: cfgSnap.Datacenter, Partition: upstream.DestinationPartition}, + &upstream, cfgSnap.APIGateway.WatchedUpstreamEndpoints[uid], cfgSnap.APIGateway.WatchedGatewayEndpoints[uid], false, @@ -627,9 +622,25 @@ func (s *ResourceGenerator) makeUpstreamLoadAssignmentForPeerService( // If an upstream is configured with local mesh gw mode, we make a load assignment // from the gateway endpoints instead of those of the upstreams. if upstreamGatewayMode == structs.MeshGatewayModeLocal { - localGw, ok := cfgSnap.ConnectProxy.WatchedLocalGWEndpoints.Get(cfgSnap.Locality.String()) - if !ok { - // local GW is not ready; return early + + // This makeUpstreamLoadAssignmentForPeerService is a generic method + // and used by both connect-proxy and API-GW. + // So, whenever this method is invoked for API Gateway (api gateway peered in local mesh mode), + // below, localGw would be nil because the existing statement fetches endpoints from cfg.ConnectProxy. + // + // Fix: generate endpoints conditionally based on the kind of cfgSnap. + + var localGatewayEndpoint structs.CheckServiceNodes + ready := false + if cfgSnap.Kind == structs.ServiceKindConnectProxy { + localGatewayEndpoint, ready = cfgSnap.ConnectProxy.WatchedLocalGWEndpoints.Get(cfgSnap.Locality.String()) + } + if cfgSnap.Kind == structs.ServiceKindAPIGateway { + localGatewayEndpoint, ready = cfgSnap.APIGateway.WatchedLocalGWEndpoints.Get(cfgSnap.Locality.String()) + } + if !ready { + // local mesh GW is not ready; skip load assignment; return early + s.Logger.Trace("local mesh GW is not ready; skipping load assignment", "cluster", clusterName) return la, nil } la = makeLoadAssignment( @@ -638,7 +649,7 @@ func (s *ResourceGenerator) makeUpstreamLoadAssignmentForPeerService( clusterName, nil, []loadAssignmentEndpointGroup{ - {Endpoints: localGw}, + {Endpoints: localGatewayEndpoint}, }, cfgSnap.Locality, ) @@ -653,6 +664,7 @@ func (s *ResourceGenerator) makeUpstreamLoadAssignmentForPeerService( endpoints, ok := upstreamsSnapshot.PeerUpstreamEndpoints.Get(uid) if !ok { + s.Logger.Trace("skipping load assignment for peer instances with hostname as their address", "upstream", uid, "cluster", clusterName) return nil, nil } la = makeLoadAssignment( @@ -673,7 +685,7 @@ func (s *ResourceGenerator) endpointsFromDiscoveryChain( chain *structs.CompiledDiscoveryChain, cfgSnap *proxycfg.ConfigSnapshot, gatewayKey proxycfg.GatewayKey, - upstreamConfigMap map[string]interface{}, + upstream *structs.Upstream, upstreamEndpoints map[string]structs.CheckServiceNodes, gatewayEndpoints map[string]structs.CheckServiceNodes, forMeshGateway bool, @@ -685,8 +697,9 @@ func (s *ResourceGenerator) endpointsFromDiscoveryChain( return nil, nil } - if upstreamConfigMap == nil { - upstreamConfigMap = make(map[string]interface{}) // TODO:needed? + upstreamConfigMap := make(map[string]interface{}) + if upstream != nil { + upstreamConfigMap = upstream.Config } var resources []proto.Message @@ -718,8 +731,25 @@ func (s *ResourceGenerator) endpointsFromDiscoveryChain( } } + // This endpointsFromDiscoveryChain is a generic method + // and used by both connect-proxy and API-GW. + // So, whenever this method is invoked for API Gateway, + // Existing `GetUpstream` method is not defined on cfgSnap.APIGateway, + // and would return empty object for upstream, + // resulting, upstream.MeshGateway.Mode to be "" and + // finally mgwMode will remain to MeshGatewayModeDefault (& Default is always treated as remote mode in peering) + // which is incorrect because API GW can be configured in local mesh mode as well. + // + // Fix: generate mgwMode conditionally based on the kind of cfgSnap. + mgwMode := structs.MeshGatewayModeDefault - if upstream, _ := cfgSnap.ConnectProxy.GetUpstream(uid, &cfgSnap.ProxyID.EnterpriseMeta); upstream != nil { + if cfgSnap.Kind == structs.ServiceKindConnectProxy { + upstreamConfig, _ := cfgSnap.ConnectProxy.GetUpstream(uid, &cfgSnap.ProxyID.EnterpriseMeta) + if upstreamConfig != nil { + mgwMode = upstreamConfig.MeshGateway.Mode + } + } + if cfgSnap.Kind == structs.ServiceKindAPIGateway { mgwMode = upstream.MeshGateway.Mode } diff --git a/agent/xds/resources_test.go b/agent/xds/resources_test.go index fed4cc8f383..121ae2f8676 100644 --- a/agent/xds/resources_test.go +++ b/agent/xds/resources_test.go @@ -19,6 +19,7 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" + "github.com/hashicorp/consul/agent/configentry" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/consul/discoverychain" "github.com/hashicorp/consul/agent/netutil" @@ -27,6 +28,7 @@ import ( "github.com/hashicorp/consul/agent/xds/response" "github.com/hashicorp/consul/agent/xds/testcommon" "github.com/hashicorp/consul/envoyextensions/xdscommon" + "github.com/hashicorp/consul/proto/private/pbpeering" "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/types" ) @@ -306,6 +308,7 @@ func TestAllResourcesFromSnapshot(t *testing.T) { tests = append(tests, getTrafficControlPeeringGoldenTestCases(false)...) tests = append(tests, getEnterpriseGoldenTestCases(t)...) tests = append(tests, getAPIGatewayGoldenTestCases(t)...) + tests = append(tests, getAPIGatewayPeeringGoldenTestCases(t)...) tests = append(tests, getExposePathGoldenTestCases()...) tests = append(tests, getCustomConfigurationGoldenTestCases(false)...) tests = append(tests, getConnectProxyJWTProviderGoldenTestCases()...) @@ -1738,6 +1741,247 @@ func getAPIGatewayGoldenTestCases(t *testing.T) []goldenTestCase { } } +func getAPIGatewayPeeringGoldenTestCases(t *testing.T) []goldenTestCase { + // Test checks if API Gateway with peering, correctly generates + // the xDS resources for the upstream service in peer cluster. + + t.Helper() + const peerTrustDomain = "1c053652-8512-4373-90cf-5a7f6263a994.consul" + + // paymentService is the upstream service in peer cluster for gateway. + paymentService := structs.NewServiceName("paymentService", nil) + paymentServiceUID := proxycfg.NewUpstreamIDFromServiceName(paymentService) + paymentServiceUID.Peer = "paymentpeer" + paymentServiceDC := "paymentdc" + paymentServicePartition := "default" + paymentServiceNamespace := "default" + + // Base entries for paymentService discovery chain. + // + // Discovery chain is required in case of API Gateway with peering, + // because we need service resolver to redirect request to peer. + // If paymentServiceSet is not provided, then api-gateway will work as simple api-gw + // without knowledge of peering and service resolver (no redirection to peer) + paymentServiceSet := configentry.NewDiscoveryChainSet() + paymentServiceSet.AddEntries( + &structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + Config: map[string]interface{}{"protocol": "http"}, + }, + &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: paymentService.Name, + Redirect: &structs.ServiceResolverRedirect{ + Peer: paymentServiceUID.Peer, // Redirect to peer + }, + }, + ) + paymentServiceChain := discoverychain.TestCompileConfigEntries( + t, + paymentService.Name, + "default", + "default", + "dc1", + connect.TestClusterID+".consul", + // Below discovery chain (re)compile request is sent, so that + // we could get the updated localGatewayEndpoint. + // + // API Gateway does not directly update WatchedLocalGWEndpoints. + // It watches route config entries and upstream chains. + // So, after every update, DC recompile happens for API GW. + // Within recompile,it synthesize the listeners/routes, etc & + // then we would be able to get localGatewayEndpoint. + // + // Also, since we are recompiling the discovery chain, + // it prefix the clusterName with customizationHash + // while generating the cluster configs. + // + // Please note that: + // API Gateway, do not recomplile when "OverrideMeshGateway" changes. + // It do not set "OverrideMeshGateway" in discoveryChainWatchOpts. + // This is just to trigger the recompilation. + // + // MeshGateway mode is updated in TestConfigSnapshotAPIGateway, + // which updates the NodeService, and once the NodeService is modified, + // proxyCfg manager recreates the state (state config + serviceInstance). + func(req *discoverychain.CompileRequest) { + req.OverrideMeshGateway = structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeLocal} + }, + paymentServiceSet, + ) + + // generateNodeServiceTargetAddress generates tagged addresses + // for NodeService based on the upstream address type. + generateNodeServiceTargetAddress := func(peerServiceName, upstreamAddr string, upstreamAddrIsHostname bool) map[string]structs.ServiceAddress { + if upstreamAddrIsHostname { + return map[string]structs.ServiceAddress{ + structs.TaggedAddressLAN: { + Address: upstreamAddr, + Port: 8443, + }, + structs.TaggedAddressWAN: { + Address: peerServiceName + ".us-east-1.elb.notaws.com", + Port: 443, + }, + } + } + return nil + } + + newTestCase := func(name string, mgwMode structs.MeshGatewayMode, upstreamAddr string, upstreamAddrIsHostname bool) goldenTestCase { + tc := goldenTestCase{ + name: name, + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + proxyCfgUpdateEvents := []proxycfg.UpdateEvent{ + // Inject Discovery Chain Events + // (because API Gateway uses serviceResolvers) + { + CorrelationID: "discovery-chain:" + paymentService.Name, + Result: &structs.DiscoveryChainResponse{ + Chain: paymentServiceChain, + }, + }, + // Trust Bundles & Endpoints + { + CorrelationID: "peer-trust-bundle:" + paymentServiceUID.Peer, + Result: &pbpeering.TrustBundleReadResponse{ + Bundle: &pbpeering.PeeringTrustBundle{ + PeerName: paymentServiceUID.Peer, + TrustDomain: peerTrustDomain, + ExportedPartition: "default", + RootPEMs: []string{paymentServiceUID.Peer + "-root"}, + }, + }, + }, + // Upstream nodes for the payment service in peer cluster. + { + CorrelationID: "upstream-peer:" + paymentServiceUID.String(), + Result: &structs.IndexedCheckServiceNodes{ + Nodes: structs.CheckServiceNodes{ + { + Node: &structs.Node{ + ID: "test1", + Node: "test1", + Address: upstreamAddr, + Datacenter: paymentServiceDC, + }, + Service: &structs.NodeService{ + Kind: structs.ServiceKindAPIGateway, + Service: "gateway", + Port: 8443, + TaggedAddresses: generateNodeServiceTargetAddress(paymentService.Name, upstreamAddr, upstreamAddrIsHostname), + Connect: structs.ServiceConnect{ + PeerMeta: &structs.PeeringServiceMeta{ + SNI: []string{ + fmt.Sprintf("%s.%s.%s.%s.external.%s", + paymentService.Name, paymentServiceNamespace, paymentServicePartition, paymentServiceUID.Peer, peerTrustDomain), + }, + SpiffeID: []string{ + fmt.Sprintf("spiffe://%s/ns/default/dc/%s/svc/%s", peerTrustDomain, paymentServiceDC, paymentService.Name), + }, + Protocol: "tcp", + }, + }, + }, + }, + }, + }, + }, + // Local mesh gateway node service, which will be used as a target when MeshGatewayMode is Local. + { + CorrelationID: "mesh-gateway:dc1", + Result: &structs.IndexedCheckServiceNodes{ + Nodes: structs.CheckServiceNodes{ + structs.CheckServiceNode{ + Node: &structs.Node{ + ID: "mesh-gateway", + Node: "mesh-gateway", + Address: "10.45.1.1", // local mesh gateway + Datacenter: "dc1", + }, + Service: &structs.NodeService{ + Kind: structs.ServiceKindMeshGateway, + Service: "mesh-gateway", + Port: 8443, + TaggedAddresses: map[string]structs.ServiceAddress{ + structs.TaggedAddressWAN: { + Address: "172.100.0.14", + Port: 8080, + }, + }, + EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), + }, + }, + }, + }, + }, + } + + return proxycfg.TestConfigSnapshotAPIGateway(t, "default", + func(ns *structs.NodeService) { + // MeshGateway mode is updated here, which updates the NodeService, + // once the NodeService is modified, + // proxyCfg manager recreates the state (state config + serviceInstance). + // which will be populated when handling update in api_gateway.go. + // snap.APIGateway.Upstreams.set(ref, listener, set) + ns.Proxy.MeshGateway.Mode = mgwMode + }, + func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) { + entry.Listeners = []structs.APIGatewayListener{ + { + Name: "listener", + Protocol: structs.ListenerProtocolHTTP, + Port: 8080, + }, + } + bound.Listeners = []structs.BoundAPIGatewayListener{ + { + Name: "listener", + Routes: []structs.ResourceReference{ + { + Name: "http-route", + Kind: structs.HTTPRoute, + }, + }, + }, + } + }, + []structs.BoundRoute{ + &structs.HTTPRouteConfigEntry{ + Name: "http-route", + Kind: structs.HTTPRoute, + Parents: []structs.ResourceReference{ + { + Kind: structs.APIGateway, + Name: "api-gateway", + }, + }, + Rules: []structs.HTTPRouteRule{ + { + Services: []structs.HTTPService{ + {Name: paymentService.Name}, + }, + }, + }, + }, + }, + nil, + proxyCfgUpdateEvents, + ) + }, + } + return tc + } + + return []goldenTestCase{ + newTestCase("api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname", structs.MeshGatewayModeLocal, "123.us-east-1.elb.notaws.com", true), + newTestCase("api-gateway-with-peers-mesh-mode-local-and-upstream-is-static", structs.MeshGatewayModeLocal, "172.68.1.1", false), + newTestCase("api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname", structs.MeshGatewayModeRemote, "123.us-east-1.elb.notaws.com", true), + newTestCase("api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static", structs.MeshGatewayModeRemote, "172.68.1.1", false), + } +} + func getExposePathGoldenTestCases() []goldenTestCase { return []goldenTestCase{ { diff --git a/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden b/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden new file mode 100644 index 00000000000..4d9c192fbd5 --- /dev/null +++ b/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden @@ -0,0 +1,58 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "altStatName": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "circuitBreakers": {}, + "commonLbConfig": { + "healthyPanicThreshold": {} + }, + "connectTimeout": "5s", + "edsClusterConfig": { + "edsConfig": { + "ads": {}, + "resourceApiVersion": "V3" + } + }, + "name": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "outlierDetection": {}, + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", + "commonTlsContext": { + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "tlsParams": {}, + "validationContext": { + "matchTypedSubjectAltNames": [ + { + "matcher": { + "exact": "spiffe://1c053652-8512-4373-90cf-5a7f6263a994.consul/ns/default/dc/paymentdc/svc/paymentService" + }, + "sanType": "URI" + } + ], + "trustedCa": { + "inlineString": "paymentpeer-root\n" + } + } + }, + "sni": "paymentService.default.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul" + } + }, + "type": "EDS" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden b/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden new file mode 100644 index 00000000000..4d9c192fbd5 --- /dev/null +++ b/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden @@ -0,0 +1,58 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "altStatName": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "circuitBreakers": {}, + "commonLbConfig": { + "healthyPanicThreshold": {} + }, + "connectTimeout": "5s", + "edsClusterConfig": { + "edsConfig": { + "ads": {}, + "resourceApiVersion": "V3" + } + }, + "name": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "outlierDetection": {}, + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", + "commonTlsContext": { + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "tlsParams": {}, + "validationContext": { + "matchTypedSubjectAltNames": [ + { + "matcher": { + "exact": "spiffe://1c053652-8512-4373-90cf-5a7f6263a994.consul/ns/default/dc/paymentdc/svc/paymentService" + }, + "sanType": "URI" + } + ], + "trustedCa": { + "inlineString": "paymentpeer-root\n" + } + } + }, + "sni": "paymentService.default.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul" + } + }, + "type": "EDS" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden b/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden new file mode 100644 index 00000000000..c98ee23d275 --- /dev/null +++ b/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden @@ -0,0 +1,75 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "altStatName": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "circuitBreakers": {}, + "commonLbConfig": { + "healthyPanicThreshold": {} + }, + "connectTimeout": "5s", + "dnsLookupFamily": "V4_ONLY", + "dnsRefreshRate": "10s", + "loadAssignment": { + "clusterName": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "paymentService.us-east-1.elb.notaws.com", + "portValue": 443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + "name": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "outlierDetection": {}, + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", + "commonTlsContext": { + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "tlsParams": {}, + "validationContext": { + "matchTypedSubjectAltNames": [ + { + "matcher": { + "exact": "spiffe://1c053652-8512-4373-90cf-5a7f6263a994.consul/ns/default/dc/paymentdc/svc/paymentService" + }, + "sanType": "URI" + } + ], + "trustedCa": { + "inlineString": "paymentpeer-root\n" + } + } + }, + "sni": "paymentService.default.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul" + } + }, + "type": "LOGICAL_DNS" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden b/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden new file mode 100644 index 00000000000..4d9c192fbd5 --- /dev/null +++ b/agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden @@ -0,0 +1,58 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "altStatName": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "circuitBreakers": {}, + "commonLbConfig": { + "healthyPanicThreshold": {} + }, + "connectTimeout": "5s", + "edsClusterConfig": { + "edsConfig": { + "ads": {}, + "resourceApiVersion": "V3" + } + }, + "name": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "outlierDetection": {}, + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", + "commonTlsContext": { + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "tlsParams": {}, + "validationContext": { + "matchTypedSubjectAltNames": [ + { + "matcher": { + "exact": "spiffe://1c053652-8512-4373-90cf-5a7f6263a994.consul/ns/default/dc/paymentdc/svc/paymentService" + }, + "sanType": "URI" + } + ], + "trustedCa": { + "inlineString": "paymentpeer-root\n" + } + } + }, + "sni": "paymentService.default.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul" + } + }, + "type": "EDS" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden b/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden new file mode 100644 index 00000000000..6a1ebedfb71 --- /dev/null +++ b/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden @@ -0,0 +1,29 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.45.1.1", + "portValue": 8443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden b/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden new file mode 100644 index 00000000000..6a1ebedfb71 --- /dev/null +++ b/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden @@ -0,0 +1,29 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.45.1.1", + "portValue": 8443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden b/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden new file mode 100644 index 00000000000..96ee5c70946 --- /dev/null +++ b/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden @@ -0,0 +1,5 @@ +{ + "nonce": "00000001", + "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden b/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden new file mode 100644 index 00000000000..204252408a2 --- /dev/null +++ b/agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden @@ -0,0 +1,29 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "c225dc1c~paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "172.68.1.1", + "portValue": 8443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden b/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden new file mode 100644 index 00000000000..6469727f979 --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden @@ -0,0 +1,54 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8080 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "rds": { + "configSource": { + "ads": {}, + "resourceApiVersion": "V3" + }, + "routeConfigName": "8080" + }, + "statPrefix": "ingress_upstream_8080", + "tracing": { + "randomSampling": {} + }, + "upgradeConfigs": [ + { + "upgradeType": "websocket" + } + ] + } + } + ] + } + ], + "name": "http:1.2.3.4:8080", + "trafficDirection": "OUTBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden b/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden new file mode 100644 index 00000000000..6469727f979 --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden @@ -0,0 +1,54 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8080 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "rds": { + "configSource": { + "ads": {}, + "resourceApiVersion": "V3" + }, + "routeConfigName": "8080" + }, + "statPrefix": "ingress_upstream_8080", + "tracing": { + "randomSampling": {} + }, + "upgradeConfigs": [ + { + "upgradeType": "websocket" + } + ] + } + } + ] + } + ], + "name": "http:1.2.3.4:8080", + "trafficDirection": "OUTBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden b/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden new file mode 100644 index 00000000000..6469727f979 --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden @@ -0,0 +1,54 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8080 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "rds": { + "configSource": { + "ads": {}, + "resourceApiVersion": "V3" + }, + "routeConfigName": "8080" + }, + "statPrefix": "ingress_upstream_8080", + "tracing": { + "randomSampling": {} + }, + "upgradeConfigs": [ + { + "upgradeType": "websocket" + } + ] + } + } + ] + } + ], + "name": "http:1.2.3.4:8080", + "trafficDirection": "OUTBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden b/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden new file mode 100644 index 00000000000..6469727f979 --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden @@ -0,0 +1,54 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8080 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "rds": { + "configSource": { + "ads": {}, + "resourceApiVersion": "V3" + }, + "routeConfigName": "8080" + }, + "statPrefix": "ingress_upstream_8080", + "tracing": { + "randomSampling": {} + }, + "upgradeConfigs": [ + { + "upgradeType": "websocket" + } + ] + } + } + ] + } + ], + "name": "http:1.2.3.4:8080", + "trafficDirection": "OUTBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden b/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden new file mode 100644 index 00000000000..bd47ac56923 --- /dev/null +++ b/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden @@ -0,0 +1,30 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "name": "8080", + "virtualHosts": [ + { + "domains": [ + "*", + "*:8080" + ], + "name": "api-gateway-listener-9b9265b", + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul" + } + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden b/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden new file mode 100644 index 00000000000..bd47ac56923 --- /dev/null +++ b/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden @@ -0,0 +1,30 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "name": "8080", + "virtualHosts": [ + { + "domains": [ + "*", + "*:8080" + ], + "name": "api-gateway-listener-9b9265b", + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul" + } + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden b/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden new file mode 100644 index 00000000000..bd47ac56923 --- /dev/null +++ b/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden @@ -0,0 +1,30 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "name": "8080", + "virtualHosts": [ + { + "domains": [ + "*", + "*:8080" + ], + "name": "api-gateway-listener-9b9265b", + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul" + } + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden b/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden new file mode 100644 index 00000000000..bd47ac56923 --- /dev/null +++ b/agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden @@ -0,0 +1,30 @@ +{ + "nonce": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "name": "8080", + "virtualHosts": [ + { + "domains": [ + "*", + "*:8080" + ], + "name": "api-gateway-listener-9b9265b", + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "paymentService.default.paymentpeer.external.1c053652-8512-4373-90cf-5a7f6263a994.consul" + } + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden b/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden new file mode 100644 index 00000000000..82e45650658 --- /dev/null +++ b/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden @@ -0,0 +1,5 @@ +{ + "nonce": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden b/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden new file mode 100644 index 00000000000..82e45650658 --- /dev/null +++ b/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden @@ -0,0 +1,5 @@ +{ + "nonce": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden b/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden new file mode 100644 index 00000000000..82e45650658 --- /dev/null +++ b/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden @@ -0,0 +1,5 @@ +{ + "nonce": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden b/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden new file mode 100644 index 00000000000..82e45650658 --- /dev/null +++ b/agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden @@ -0,0 +1,5 @@ +{ + "nonce": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "versionInfo": "00000001" +} \ No newline at end of file diff --git a/logging/names.go b/logging/names.go index b3bf817217a..db11a495cd3 100644 --- a/logging/names.go +++ b/logging/names.go @@ -41,6 +41,7 @@ const ( License string = "license" Manager string = "manager" Memberlist string = "memberlist" + APIGateway string = "api_gateway" MeshGateway string = "mesh_gateway" Namespace string = "namespace" NetworkAreas string = "network_areas"