From 711d1389aa9ce7b5d97815128717593890212e6a Mon Sep 17 00:00:00 2001 From: Kyle Havlovitz Date: Tue, 21 Apr 2020 14:06:23 -0700 Subject: [PATCH] Support multiple listeners referencing the same service in gateway definitions --- agent/consul/state/catalog.go | 7 +- agent/consul/state/catalog_test.go | 83 +++++++++++--- agent/proxycfg/state.go | 6 +- agent/proxycfg/state_test.go | 19 +++- agent/proxycfg/testing.go | 33 ++++++ agent/xds/clusters.go | 9 ++ agent/xds/clusters_test.go | 5 + agent/xds/endpoints.go | 8 ++ agent/xds/endpoints_test.go | 5 + ...ultiple-listeners-duplicate-service.golden | 103 ++++++++++++++++++ ...ultiple-listeners-duplicate-service.golden | 75 +++++++++++++ 11 files changed, 331 insertions(+), 22 deletions(-) create mode 100644 agent/xds/testdata/clusters/ingress-multiple-listeners-duplicate-service.golden create mode 100644 agent/xds/testdata/endpoints/ingress-multiple-listeners-duplicate-service.golden diff --git a/agent/consul/state/catalog.go b/agent/consul/state/catalog.go index ad03f466b0..05db9a6e77 100644 --- a/agent/consul/state/catalog.go +++ b/agent/consul/state/catalog.go @@ -75,6 +75,9 @@ func gatewayServicesTableNameSchema() *memdb.TableSchema { &ServiceIDIndex{ Field: "Service", }, + &memdb.IntFieldIndex{ + Field: "Port", + }, }, }, }, @@ -2600,7 +2603,7 @@ func (s *Store) updateGatewayNamespace(tx *memdb.Txn, idx uint64, service *struc continue } - existing, err := tx.First(gatewayServicesTableName, "id", service.Gateway, sn.CompoundServiceName()) + existing, err := tx.First(gatewayServicesTableName, "id", service.Gateway, sn.CompoundServiceName(), service.Port) if err != nil { return fmt.Errorf("gateway service lookup failed: %s", err) } @@ -2635,7 +2638,7 @@ func (s *Store) updateGatewayNamespace(tx *memdb.Txn, idx uint64, service *struc func (s *Store) updateGatewayService(tx *memdb.Txn, idx uint64, mapping *structs.GatewayService) error { // Check if mapping already exists in table if it's already in the table // Avoid insert if nothing changed - existing, err := tx.First(gatewayServicesTableName, "id", mapping.Gateway, mapping.Service) + existing, err := tx.First(gatewayServicesTableName, "id", mapping.Gateway, mapping.Service, mapping.Port) if err != nil { return fmt.Errorf("gateway service lookup failed: %s", err) } diff --git a/agent/consul/state/catalog_test.go b/agent/consul/state/catalog_test.go index 4da987b93d..9f1e8e8fa2 100644 --- a/agent/consul/state/catalog_test.go +++ b/agent/consul/state/catalog_test.go @@ -4920,7 +4920,7 @@ func TestStateStore_CheckIngressServiceNodes(t *testing.T) { t.Run("check service1 ingress gateway", func(t *testing.T) { idx, results, err := s.CheckIngressServiceNodes(ws, "service1", nil) require.NoError(err) - require.Equal(uint64(13), idx) + require.Equal(uint64(14), idx) // Multiple instances of the ingress2 service require.Len(results, 4) @@ -4939,7 +4939,7 @@ func TestStateStore_CheckIngressServiceNodes(t *testing.T) { t.Run("check service2 ingress gateway", func(t *testing.T) { idx, results, err := s.CheckIngressServiceNodes(ws, "service2", nil) require.NoError(err) - require.Equal(uint64(12), idx) + require.Equal(uint64(14), idx) require.Len(results, 2) ids := make(map[string]struct{}) @@ -4957,7 +4957,7 @@ func TestStateStore_CheckIngressServiceNodes(t *testing.T) { ws := memdb.NewWatchSet() idx, results, err := s.CheckIngressServiceNodes(ws, "service3", nil) require.NoError(err) - require.Equal(uint64(11), idx) + require.Equal(uint64(14), idx) require.Len(results, 1) require.Equal("wildcardIngress", results[0].Service.ID) }) @@ -4968,17 +4968,17 @@ func TestStateStore_CheckIngressServiceNodes(t *testing.T) { idx, results, err := s.CheckIngressServiceNodes(ws, "service1", nil) require.NoError(err) - require.Equal(uint64(13), idx) + require.Equal(uint64(14), idx) require.Len(results, 3) idx, results, err = s.CheckIngressServiceNodes(ws, "service2", nil) require.NoError(err) - require.Equal(uint64(12), idx) + require.Equal(uint64(14), idx) require.Len(results, 1) idx, results, err = s.CheckIngressServiceNodes(ws, "service3", nil) require.NoError(err) - require.Equal(uint64(0), idx) + require.Equal(uint64(14), idx) // TODO(ingress): index goes backward when deleting last config entry // require.Equal(uint64(11), idx) require.Len(results, 0) @@ -4993,7 +4993,7 @@ func TestStateStore_GatewayServices_Ingress(t *testing.T) { t.Run("ingress1 gateway services", func(t *testing.T) { idx, results, err := s.GatewayServices(ws, "ingress1", nil) require.NoError(err) - require.Equal(uint64(14), idx) + require.Equal(uint64(15), idx) require.Len(results, 2) require.Equal("ingress1", results[0].Gateway.ID) require.Equal("service1", results[0].Service.ID) @@ -5006,7 +5006,7 @@ func TestStateStore_GatewayServices_Ingress(t *testing.T) { t.Run("ingress2 gateway services", func(t *testing.T) { idx, results, err := s.GatewayServices(ws, "ingress2", nil) require.NoError(err) - require.Equal(uint64(14), idx) + require.Equal(uint64(15), idx) require.Len(results, 1) require.Equal("ingress2", results[0].Gateway.ID) require.Equal("service1", results[0].Service.ID) @@ -5016,7 +5016,7 @@ func TestStateStore_GatewayServices_Ingress(t *testing.T) { t.Run("No gatway services associated", func(t *testing.T) { idx, results, err := s.GatewayServices(ws, "nothingIngress", nil) require.NoError(err) - require.Equal(uint64(14), idx) + require.Equal(uint64(15), idx) require.Len(results, 0) }) @@ -5024,7 +5024,7 @@ func TestStateStore_GatewayServices_Ingress(t *testing.T) { ws = memdb.NewWatchSet() idx, results, err := s.GatewayServices(ws, "wildcardIngress", nil) require.NoError(err) - require.Equal(uint64(14), idx) + require.Equal(uint64(15), idx) require.Len(results, 3) require.Equal("wildcardIngress", results[0].Gateway.ID) require.Equal("service1", results[0].Service.ID) @@ -5037,6 +5037,29 @@ func TestStateStore_GatewayServices_Ingress(t *testing.T) { require.Equal(4444, results[2].Port) }) + t.Run("gateway with duplicate service", func(t *testing.T) { + idx, results, err := s.GatewayServices(ws, "ingress3", nil) + require.NoError(err) + require.Equal(uint64(15), idx) + require.Len(results, 4) + require.Equal("ingress3", results[0].Gateway.ID) + require.Equal("service1", results[0].Service.ID) + require.Equal(6666, results[0].Port) + require.Equal("tcp", results[0].Protocol) + require.Equal("ingress3", results[1].Gateway.ID) + require.Equal("service1", results[1].Service.ID) + require.Equal(5555, results[1].Port) + require.Equal("http", results[1].Protocol) + require.Equal("ingress3", results[2].Gateway.ID) + require.Equal("service2", results[2].Service.ID) + require.Equal(5555, results[2].Port) + require.Equal("http", results[2].Protocol) + require.Equal("ingress3", results[3].Gateway.ID) + require.Equal("service3", results[3].Service.ID) + require.Equal(5555, results[3].Port) + require.Equal("http", results[3].Protocol) + }) + t.Run("deregistering a service", func(t *testing.T) { require.Nil(s.DeleteService(18, "node1", "service1", nil)) require.True(watchFired(ws)) @@ -5098,7 +5121,7 @@ func TestStateStore_GatewayServices_WildcardAssociation(t *testing.T) { t.Run("base case for wildcard", func(t *testing.T) { idx, results, err := s.GatewayServices(ws, "wildcardIngress", nil) require.NoError(err) - require.Equal(uint64(14), idx) + require.Equal(uint64(15), idx) require.Len(results, 3) }) @@ -5107,7 +5130,7 @@ func TestStateStore_GatewayServices_WildcardAssociation(t *testing.T) { require.False(watchFired(ws)) idx, results, err := s.GatewayServices(ws, "wildcardIngress", nil) require.NoError(err) - require.Equal(uint64(14), idx) + require.Equal(uint64(15), idx) require.Len(results, 3) }) @@ -5120,7 +5143,7 @@ func TestStateStore_GatewayServices_WildcardAssociation(t *testing.T) { require.False(watchFired(ws)) idx, results, err := s.GatewayServices(ws, "wildcardIngress", nil) require.NoError(err) - require.Equal(uint64(14), idx) + require.Equal(uint64(15), idx) require.Len(results, 3) }) @@ -5129,7 +5152,7 @@ func TestStateStore_GatewayServices_WildcardAssociation(t *testing.T) { require.False(watchFired(ws)) idx, results, err := s.GatewayServices(ws, "wildcardIngress", nil) require.NoError(err) - require.Equal(uint64(14), idx) + require.Equal(uint64(15), idx) require.Len(results, 3) }) @@ -5140,7 +5163,7 @@ func TestStateStore_GatewayServices_WildcardAssociation(t *testing.T) { require.False(watchFired(ws)) idx, results, err := s.GatewayServices(ws, "wildcardIngress", nil) require.NoError(err) - require.Equal(uint64(14), idx) + require.Equal(uint64(15), idx) require.Len(results, 3) }) } @@ -5228,12 +5251,40 @@ func setupIngressState(t *testing.T, s *Store) memdb.WatchSet { } assert.NoError(t, s.EnsureConfigEntry(13, ingress2, nil)) + ingress3 := &structs.IngressGatewayConfigEntry{ + Kind: "ingress-gateway", + Name: "ingress3", + Listeners: []structs.IngressListener{ + { + Port: 5555, + Protocol: "http", + Services: []structs.IngressService{ + { + Name: "*", + }, + }, + }, + { + Port: 6666, + Protocol: "tcp", + Services: []structs.IngressService{ + { + Name: "service1", + }, + }, + }, + }, + } + assert.NoError(t, s.EnsureConfigEntry(14, ingress3, nil)) + assert.True(t, watchFired(ws)) + nothingIngress := &structs.IngressGatewayConfigEntry{ Kind: "ingress-gateway", Name: "nothingIngress", Listeners: []structs.IngressListener{}, } - assert.NoError(t, s.EnsureConfigEntry(14, nothingIngress, nil)) + assert.NoError(t, s.EnsureConfigEntry(15, nothingIngress, nil)) + assert.True(t, watchFired(ws)) return ws } diff --git a/agent/proxycfg/state.go b/agent/proxycfg/state.go index d87988448e..1fbe102c46 100644 --- a/agent/proxycfg/state.go +++ b/agent/proxycfg/state.go @@ -1355,6 +1355,11 @@ func makeUpstream(g *structs.GatewayService, bindAddr string) structs.Upstream { DestinationName: g.Service.ID, DestinationNamespace: g.Service.NamespaceOrDefault(), LocalBindPort: g.Port, + // Pass the protocol that was configured on the ingress listener in order + // to force that protocol on the Envoy listener. + Config: map[string]interface{}{ + "protocol": g.Protocol, + }, } upstream.LocalBindAddress = bindAddr if bindAddr == "" { @@ -1376,7 +1381,6 @@ func (s *state) watchIngressDiscoveryChain(snap *ConfigSnapshot, u structs.Upstr Name: u.DestinationName, EvaluateInDatacenter: s.source.Datacenter, EvaluateInNamespace: u.DestinationNamespace, - // TODO(ingress): Deal with MeshGateway and Protocol overrides here }, "discovery-chain:"+u.Identifier(), s.ch) if err != nil { cancel() diff --git a/agent/proxycfg/state_test.go b/agent/proxycfg/state_test.go index 5c4292c94c..fe451f8e7f 100644 --- a/agent/proxycfg/state_test.go +++ b/agent/proxycfg/state_test.go @@ -725,9 +725,10 @@ func TestState_WatchesAndUpdates(t *testing.T) { Result: &structs.IndexedGatewayServices{ Services: structs.GatewayServices{ { - Gateway: structs.NewServiceID("ingress-gateway", nil), - Service: structs.NewServiceID("api", nil), - Port: 9999, + Gateway: structs.NewServiceID("ingress-gateway", nil), + Service: structs.NewServiceID("api", nil), + Port: 9999, + Protocol: "http", }, }, }, @@ -736,6 +737,18 @@ func TestState_WatchesAndUpdates(t *testing.T) { }, verifySnapshot: func(t testing.TB, snap *ConfigSnapshot) { require.Len(t, snap.IngressGateway.Upstreams, 1) + key := IngressListenerKey{Protocol: "http", Port: 9999} + require.Equal(t, snap.IngressGateway.Upstreams[key], structs.Upstreams{ + { + DestinationNamespace: "default", + DestinationName: "api", + LocalBindAddress: "10.0.1.1", + LocalBindPort: 9999, + Config: map[string]interface{}{ + "protocol": "http", + }, + }, + }) require.Len(t, snap.IngressGateway.WatchedDiscoveryChains, 1) require.Contains(t, snap.IngressGateway.WatchedDiscoveryChains, "api") }, diff --git a/agent/proxycfg/testing.go b/agent/proxycfg/testing.go index 7c5d478f4e..516f1c2b67 100644 --- a/agent/proxycfg/testing.go +++ b/agent/proxycfg/testing.go @@ -1567,6 +1567,39 @@ func TestConfigSnapshotGRPCExposeHTTP1(t testing.T) *ConfigSnapshot { } } +func TestConfigSnapshotIngress_MultipleListenersDuplicateService(t testing.T) *ConfigSnapshot { + snap := TestConfigSnapshotIngress_HTTPMultipleServices(t) + + snap.IngressGateway.Upstreams = map[IngressListenerKey]structs.Upstreams{ + IngressListenerKey{Protocol: "http", Port: 8080}: structs.Upstreams{ + { + DestinationName: "foo", + LocalBindPort: 8080, + }, + { + DestinationName: "bar", + LocalBindPort: 8080, + }, + }, + IngressListenerKey{Protocol: "http", Port: 443}: structs.Upstreams{ + { + DestinationName: "foo", + LocalBindPort: 443, + }, + }, + } + + fooChain := discoverychain.TestCompileConfigEntries(t, "foo", "default", "dc1", connect.TestClusterID+".consul", "dc1", nil) + barChain := discoverychain.TestCompileConfigEntries(t, "bar", "default", "dc1", connect.TestClusterID+".consul", "dc1", nil) + + snap.IngressGateway.DiscoveryChain = map[string]*structs.CompiledDiscoveryChain{ + "foo": fooChain, + "bar": barChain, + } + + return snap +} + func httpMatch(http *structs.ServiceRouteHTTPMatch) *structs.ServiceRouteMatch { return &structs.ServiceRouteMatch{HTTP: http} } diff --git a/agent/xds/clusters.go b/agent/xds/clusters.go index 55ebe54eea..5cb2bff43e 100644 --- a/agent/xds/clusters.go +++ b/agent/xds/clusters.go @@ -236,9 +236,17 @@ func (s *Server) makeGatewayServiceClusters(cfgSnap *proxycfg.ConfigSnapshot) ([ func (s *Server) clustersFromSnapshotIngressGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) { var clusters []proto.Message + createdClusters := make(map[string]bool) for _, upstreams := range cfgSnap.IngressGateway.Upstreams { for _, u := range upstreams { id := u.Identifier() + + // If we've already created a cluster for this upstream, skip it. Multiple listeners may + // reference the same upstream, so we don't need to create duplicate clusters in that case. + if createdClusters[id] { + continue + } + chain, ok := cfgSnap.IngressGateway.DiscoveryChain[id] if !ok { // this should not happen @@ -259,6 +267,7 @@ func (s *Server) clustersFromSnapshotIngressGateway(cfgSnap *proxycfg.ConfigSnap for _, c := range upstreamClusters { clusters = append(clusters, c) } + createdClusters[id] = true } } return clusters, nil diff --git a/agent/xds/clusters_test.go b/agent/xds/clusters_test.go index 0e4bb264f1..09b6f37620 100644 --- a/agent/xds/clusters_test.go +++ b/agent/xds/clusters_test.go @@ -485,6 +485,11 @@ func TestClustersFromSnapshot(t *testing.T) { } }, }, + { + name: "ingress-multiple-listeners-duplicate-service", + create: proxycfg.TestConfigSnapshotIngress_MultipleListenersDuplicateService, + setup: nil, + }, } for _, tt := range tests { diff --git a/agent/xds/endpoints.go b/agent/xds/endpoints.go index f5dc0517fa..6af502b218 100644 --- a/agent/xds/endpoints.go +++ b/agent/xds/endpoints.go @@ -255,10 +255,17 @@ func (s *Server) endpointsFromServicesAndResolvers( func (s *Server) endpointsFromSnapshotIngressGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) { var resources []proto.Message + createdClusters := make(map[string]bool) for _, upstreams := range cfgSnap.IngressGateway.Upstreams { for _, u := range upstreams { id := u.Identifier() + // 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. + if createdClusters[id] { + continue + } + es := s.endpointsFromDiscoveryChain( cfgSnap.IngressGateway.DiscoveryChain[id], cfgSnap.Datacenter, @@ -266,6 +273,7 @@ func (s *Server) endpointsFromSnapshotIngressGateway(cfgSnap *proxycfg.ConfigSna cfgSnap.IngressGateway.WatchedGatewayEndpoints[id], ) resources = append(resources, es...) + createdClusters[id] = true } } return resources, nil diff --git a/agent/xds/endpoints_test.go b/agent/xds/endpoints_test.go index e5c08c1638..caad447c32 100644 --- a/agent/xds/endpoints_test.go +++ b/agent/xds/endpoints_test.go @@ -536,6 +536,11 @@ func Test_endpointsFromSnapshot(t *testing.T) { } }, }, + { + name: "ingress-multiple-listeners-duplicate-service", + create: proxycfg.TestConfigSnapshotIngress_MultipleListenersDuplicateService, + setup: nil, + }, } for _, tt := range tests { diff --git a/agent/xds/testdata/clusters/ingress-multiple-listeners-duplicate-service.golden b/agent/xds/testdata/clusters/ingress-multiple-listeners-duplicate-service.golden new file mode 100644 index 0000000000..d0a1ce534d --- /dev/null +++ b/agent/xds/testdata/clusters/ingress-multiple-listeners-duplicate-service.golden @@ -0,0 +1,103 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + + }, + "tlsContext": { + "commonTlsContext": { + "tlsParams": { + + }, + "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" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "sni": "bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + + }, + "tlsContext": { + "commonTlsContext": { + "tlsParams": { + + }, + "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" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "sni": "foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/ingress-multiple-listeners-duplicate-service.golden b/agent/xds/testdata/endpoints/ingress-multiple-listeners-duplicate-service.golden new file mode 100644 index 0000000000..eca90cb65e --- /dev/null +++ b/agent/xds/testdata/endpoints/ingress-multiple-listeners-duplicate-service.golden @@ -0,0 +1,75 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "clusterName": "bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.20.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.20.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "clusterName": "foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "nonce": "00000001" +} \ No newline at end of file