From 5a3590a88bfd97f73d6be8eca9c8d6ab09184ea0 Mon Sep 17 00:00:00 2001 From: Abhishek Yadav Date: Wed, 22 Apr 2026 20:58:47 +0530 Subject: [PATCH] Fixed XDS package to generate correct endpoints and cluster config for API Gateways when peered and updated the API Gateway updateHandler to propagate mesh gateway config to its upstreams. (#23454) * Add api gateway peering unit test cases. (#23366) * add unit test cases for api gateway supporting consul peering * add compiled xds config golden files after running api-gw golden testcases * fix(proxyCfg): propogate meshGatewayConfig to upstreams of API gateway (#23369) * fix(proxyCfg): propogate meshGatewayConfig to upstreams of API gateway - Fixed handleRouteConfigUpdate to properly propagate meshGatewayConfig to API gateway upstreams, which is required during XDS endpoint and cluster config generation. - Added TestStateChangedAPIGateway test cases in state_test.go to validate API gateway update handling. - Added API gateway-specific logging prefix (similar to mesh gateway) to help in debugging. * fix(xds): correct endpoint config generation for API gateway in peered setups (#23370) * fix(xds): correct endpoint config generation for API gateway in peered setups - Previously, API gateway XDS endpoint generation incorrectly relied on cfgSnap.ConnectProxy config (instead of cgfSnap.APIGateway), which caused wrong/no endpoint configuration for peered environments. - Changes made: - Updated makeUpstreamLoadAssignmentForPeerService to fetch localGatewayEndpoint based on cfgSnap kind instead of always using cfgSnap.ConnectProxy. - Updated endpointsFromDiscoveryChain to derive meshGatewayMode based on cfgSnap kind instead of always using cfgSnap.ConnectProxy. - Recompiled golden test file to reflect fix. * removed comment * fix(xds): correct cluster config generation for API gateway in peered setups (#23371) * fix(xds): correct cluster config generation for API gateway in peered setups - Updated makeUpstreamClustersForDiscoveryChain to generate cluster config based on upstream endpoint type. Before this fix, it always generated cluster configs without endpoints, which is incorrect when the upstream endpoint type is hostname and mesh-gateway mode is remote; in such cases, endpoints must also be included in the cluster config. - Added recompiled golden test file to reflect the fix. * fix lint error * add changelog * refresh golden file to remove regexRewrite from route configs --- .changelog/23454.txt | 3 + agent/proxycfg/api_gateway.go | 18 ++ agent/proxycfg/state.go | 1 + agent/proxycfg/state_test.go | 127 ++++++++- agent/structs/testing_catalog.go | 25 ++ agent/xds/clusters.go | 126 ++++++++- agent/xds/endpoints.go | 68 +++-- agent/xds/resources_test.go | 244 ++++++++++++++++++ ...cal-and-upstream-is-hostname.latest.golden | 58 +++++ ...local-and-upstream-is-static.latest.golden | 58 +++++ ...ote-and-upstream-is-hostname.latest.golden | 75 ++++++ ...emote-and-upstream-is-static.latest.golden | 58 +++++ ...cal-and-upstream-is-hostname.latest.golden | 29 +++ ...local-and-upstream-is-static.latest.golden | 29 +++ ...ote-and-upstream-is-hostname.latest.golden | 5 + ...emote-and-upstream-is-static.latest.golden | 29 +++ ...cal-and-upstream-is-hostname.latest.golden | 54 ++++ ...local-and-upstream-is-static.latest.golden | 54 ++++ ...ote-and-upstream-is-hostname.latest.golden | 54 ++++ ...emote-and-upstream-is-static.latest.golden | 54 ++++ ...cal-and-upstream-is-hostname.latest.golden | 30 +++ ...local-and-upstream-is-static.latest.golden | 30 +++ ...ote-and-upstream-is-hostname.latest.golden | 30 +++ ...emote-and-upstream-is-static.latest.golden | 30 +++ ...cal-and-upstream-is-hostname.latest.golden | 5 + ...local-and-upstream-is-static.latest.golden | 5 + ...ote-and-upstream-is-hostname.latest.golden | 5 + ...emote-and-upstream-is-static.latest.golden | 5 + logging/names.go | 1 + 29 files changed, 1277 insertions(+), 33 deletions(-) create mode 100644 .changelog/23454.txt create mode 100644 agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden create mode 100644 agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden create mode 100644 agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden create mode 100644 agent/xds/testdata/clusters/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden create mode 100644 agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden create mode 100644 agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden create mode 100644 agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden create mode 100644 agent/xds/testdata/endpoints/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden create mode 100644 agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden create mode 100644 agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden create mode 100644 agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden create mode 100644 agent/xds/testdata/listeners/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden create mode 100644 agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden create mode 100644 agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden create mode 100644 agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden create mode 100644 agent/xds/testdata/routes/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden create mode 100644 agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-local-and-upstream-is-hostname.latest.golden create mode 100644 agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-local-and-upstream-is-static.latest.golden create mode 100644 agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-hostname.latest.golden create mode 100644 agent/xds/testdata/secrets/api-gateway-with-peers-mesh-mode-remote-and-upstream-is-static.latest.golden 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 e7b6d4dcb9a..44cb05d9e7f 100644 --- a/agent/proxycfg/api_gateway.go +++ b/agent/proxycfg/api_gateway.go @@ -360,6 +360,18 @@ func (h *handlerAPIGateway) handleRouteConfigUpdate(ctx context.Context, u Updat for _, rule := range route.Rules { for _, service := range rule.Services { + // 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 { @@ -382,6 +394,10 @@ func (h *handlerAPIGateway) handleRouteConfigUpdate(ctx context.Context, u Updat Config: map[string]interface{}{ "protocol": "http", }, + // 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) @@ -410,6 +426,7 @@ func (h *handlerAPIGateway) handleRouteConfigUpdate(ctx context.Context, u Updat snap.APIGateway.TCPRoutes.Set(ref, route) for _, service := range route.Services { + meshGatewayConfig := h.proxyCfg.MeshGateway upstreamID := NewUpstreamIDFromServiceName(service.ServiceName()) seenUpstreamIDs.add(upstreamID) @@ -436,6 +453,7 @@ func (h *handlerAPIGateway) handleRouteConfigUpdate(ctx context.Context, u Updat Config: map[string]interface{}{ "protocol": "tcp", }, + MeshGateway: meshGatewayConfig, } listenerKey := APIGatewayListenerKeyFromListener(listener) diff --git a/agent/proxycfg/state.go b/agent/proxycfg/state.go index 829db71b734..d2a7aeaaafa 100644 --- a/agent/proxycfg/state.go +++ b/agent/proxycfg/state.go @@ -225,6 +225,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 83e4234e3b2..1a734587207 100644 --- a/agent/xds/clusters.go +++ b/agent/xds/clusters.go @@ -1523,25 +1523,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), @@ -1572,6 +1594,58 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( 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*/ + ) + } if targetInfo := groupedTarget.Targets[0]; targetInfo.TLSContext != nil { transportSocket, err := makeUpstreamTLSTransportSocket(targetInfo.TLSContext) if err != nil { @@ -1599,6 +1673,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 2fb0a4a1df5..d59a6bb7c0d 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, @@ -527,7 +522,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, @@ -549,8 +544,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. @@ -563,8 +558,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, @@ -621,9 +616,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( @@ -632,7 +643,7 @@ func (s *ResourceGenerator) makeUpstreamLoadAssignmentForPeerService( clusterName, nil, []loadAssignmentEndpointGroup{ - {Endpoints: localGw}, + {Endpoints: localGatewayEndpoint}, }, cfgSnap.Locality, ) @@ -647,6 +658,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( @@ -667,7 +679,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, @@ -679,8 +691,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 @@ -712,8 +725,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 58a2768dabf..9b3d242ceb6 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/proxycfg" @@ -26,6 +27,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" ) @@ -304,6 +306,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()...) @@ -1736,6 +1739,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"