diff --git a/agent/cache-types/discovery_chain_test.go b/agent/cache-types/discovery_chain_test.go index a5c5d465d3..535f2e2a7a 100644 --- a/agent/cache-types/discovery_chain_test.go +++ b/agent/cache-types/discovery_chain_test.go @@ -16,7 +16,7 @@ func TestCompiledDiscoveryChain(t *testing.T) { typ := &CompiledDiscoveryChain{RPC: rpc} // just do the default chain - chain := discoverychain.TestCompileConfigEntries(t, "web", "default", "dc1", nil) + chain := discoverychain.TestCompileConfigEntries(t, "web", "default", "dc1", "dc1", nil) // Expect the proper RPC call. This also sets the expected value // since that is return-by-pointer in the arguments. diff --git a/agent/consul/discovery_chain_endpoint.go b/agent/consul/discovery_chain_endpoint.go index e79a5039a8..d6e8ab1f39 100644 --- a/agent/consul/discovery_chain_endpoint.go +++ b/agent/consul/discovery_chain_endpoint.go @@ -58,8 +58,9 @@ func (c *DiscoveryChain) Get(args *structs.DiscoveryChainRequest, reply *structs // Then we compile it into something useful. chain, err := discoverychain.Compile(discoverychain.CompileRequest{ ServiceName: args.Name, - CurrentNamespace: evalNS, - CurrentDatacenter: evalDC, + EvaluateInNamespace: evalNS, + EvaluateInDatacenter: evalDC, + UseInDatacenter: c.srv.config.Datacenter, OverrideMeshGateway: args.OverrideMeshGateway, OverrideProtocol: args.OverrideProtocol, OverrideConnectTimeout: args.OverrideConnectTimeout, diff --git a/agent/consul/discoverychain/compile.go b/agent/consul/discoverychain/compile.go index 7fc311563e..3f7ba6dc8f 100644 --- a/agent/consul/discoverychain/compile.go +++ b/agent/consul/discoverychain/compile.go @@ -11,9 +11,10 @@ import ( ) type CompileRequest struct { - ServiceName string - CurrentNamespace string - CurrentDatacenter string + ServiceName string + EvaluateInNamespace string + EvaluateInDatacenter string + UseInDatacenter string // where the results will be used from // OverrideMeshGateway allows for the setting to be overridden for any // resolver in the compiled chain. @@ -52,19 +53,23 @@ type CompileRequest struct { // valid. func Compile(req CompileRequest) (*structs.CompiledDiscoveryChain, error) { var ( - serviceName = req.ServiceName - currentNamespace = req.CurrentNamespace - currentDatacenter = req.CurrentDatacenter - entries = req.Entries + serviceName = req.ServiceName + evaluateInNamespace = req.EvaluateInNamespace + evaluateInDatacenter = req.EvaluateInDatacenter + useInDatacenter = req.UseInDatacenter + entries = req.Entries ) if serviceName == "" { return nil, fmt.Errorf("serviceName is required") } - if currentNamespace == "" { - return nil, fmt.Errorf("currentNamespace is required") + if evaluateInNamespace == "" { + return nil, fmt.Errorf("evaluateInNamespace is required") } - if currentDatacenter == "" { - return nil, fmt.Errorf("currentDatacenter is required") + if evaluateInDatacenter == "" { + return nil, fmt.Errorf("evaluateInDatacenter is required") + } + if useInDatacenter == "" { + return nil, fmt.Errorf("useInDatacenter is required") } if entries == nil { return nil, fmt.Errorf("entries is required") @@ -72,8 +77,9 @@ func Compile(req CompileRequest) (*structs.CompiledDiscoveryChain, error) { c := &compiler{ serviceName: serviceName, - currentNamespace: currentNamespace, - currentDatacenter: currentDatacenter, + evaluateInNamespace: evaluateInNamespace, + evaluateInDatacenter: evaluateInDatacenter, + useInDatacenter: useInDatacenter, overrideMeshGateway: req.OverrideMeshGateway, overrideProtocol: req.OverrideProtocol, overrideConnectTimeout: req.OverrideConnectTimeout, @@ -106,8 +112,9 @@ func Compile(req CompileRequest) (*structs.CompiledDiscoveryChain, error) { // for assembling a discovery chain from raw config entries. type compiler struct { serviceName string - currentNamespace string - currentDatacenter string + evaluateInNamespace string + evaluateInDatacenter string + useInDatacenter string overrideMeshGateway structs.MeshGatewayConfig overrideProtocol string overrideConnectTimeout time.Duration @@ -298,8 +305,8 @@ func (c *compiler) compile() (*structs.CompiledDiscoveryChain, error) { return &structs.CompiledDiscoveryChain{ ServiceName: c.serviceName, - Namespace: c.currentNamespace, - Datacenter: c.currentDatacenter, + Namespace: c.evaluateInNamespace, + Datacenter: c.evaluateInDatacenter, CustomizationHash: customizationHash, Protocol: c.protocol, StartNode: c.startNode, @@ -590,8 +597,8 @@ func (c *compiler) newTarget(service, serviceSubset, namespace, datacenter strin t := structs.NewDiscoveryTarget( service, serviceSubset, - defaultIfEmpty(namespace, c.currentNamespace), - defaultIfEmpty(datacenter, c.currentDatacenter), + defaultIfEmpty(namespace, c.evaluateInNamespace), + defaultIfEmpty(datacenter, c.evaluateInDatacenter), ) prev, ok := c.loadedTargets[t.ID] @@ -806,19 +813,24 @@ RESOLVE_AGAIN: target.Subset = resolver.Subsets[target.ServiceSubset] - // Default mesh gateway settings - if serviceDefault := c.entries.GetService(target.Service); serviceDefault != nil { - target.MeshGateway = serviceDefault.MeshGateway - } + // TODO (mesh-gateway)- maybe allow using a gateway within a datacenter at some point + if target.Datacenter == c.useInDatacenter { + target.MeshGateway.Mode = structs.MeshGatewayModeDefault + } else { + // Default mesh gateway settings + if serviceDefault := c.entries.GetService(target.Service); serviceDefault != nil { + target.MeshGateway = serviceDefault.MeshGateway + } - if c.entries.GlobalProxy != nil && target.MeshGateway.Mode == structs.MeshGatewayModeDefault { - target.MeshGateway.Mode = c.entries.GlobalProxy.MeshGateway.Mode - } + if c.entries.GlobalProxy != nil && target.MeshGateway.Mode == structs.MeshGatewayModeDefault { + target.MeshGateway.Mode = c.entries.GlobalProxy.MeshGateway.Mode + } - if c.overrideMeshGateway.Mode != structs.MeshGatewayModeDefault { - if target.MeshGateway.Mode != c.overrideMeshGateway.Mode { - target.MeshGateway.Mode = c.overrideMeshGateway.Mode - c.customizedBy.MeshGateway = true + if c.overrideMeshGateway.Mode != structs.MeshGatewayModeDefault { + if target.MeshGateway.Mode != c.overrideMeshGateway.Mode { + target.MeshGateway.Mode = c.overrideMeshGateway.Mode + c.customizedBy.MeshGateway = true + } } } diff --git a/agent/consul/discoverychain/compile_test.go b/agent/consul/discoverychain/compile_test.go index 261c32f90f..1afcbfa64d 100644 --- a/agent/consul/discoverychain/compile_test.go +++ b/agent/consul/discoverychain/compile_test.go @@ -37,12 +37,13 @@ func TestCompile(t *testing.T) { "service redirect": testcase_ServiceRedirect(), "service and subset redirect": testcase_ServiceAndSubsetRedirect(), "datacenter redirect": testcase_DatacenterRedirect(), + "datacenter redirect with mesh gateways": testcase_DatacenterRedirect_WithMeshGateways(), "service failover": testcase_ServiceFailover(), "service failover through redirect": testcase_ServiceFailoverThroughRedirect(), "circular resolver failover": testcase_Resolver_CircularFailover(), "service and subset failover": testcase_ServiceAndSubsetFailover(), "datacenter failover": testcase_DatacenterFailover(), - "service failover with mesh gateways": testcase_ServiceFailover_WithMeshGateways(), + "datacenter failover with mesh gateways": testcase_DatacenterFailover_WithMeshGateways(), "noop split to resolver with default subset": testcase_NoopSplit_WithDefaultSubset(), "resolver with default subset": testcase_Resolve_WithDefaultSubset(), "resolver with no entries and inferring defaults": testcase_DefaultResolver(), @@ -91,10 +92,11 @@ func TestCompile(t *testing.T) { } req := CompileRequest{ - ServiceName: "main", - CurrentNamespace: "default", - CurrentDatacenter: "dc1", - Entries: tc.entries, + ServiceName: "main", + EvaluateInNamespace: "default", + EvaluateInDatacenter: "dc1", + UseInDatacenter: "dc1", + Entries: tc.entries, } if tc.setup != nil { tc.setup(&req) @@ -941,6 +943,49 @@ func testcase_DatacenterRedirect() compileTestCase { return compileTestCase{entries: entries, expect: expect} } +func testcase_DatacenterRedirect_WithMeshGateways() compileTestCase { + entries := newEntries() + entries.GlobalProxy = &structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + MeshGateway: structs.MeshGatewayConfig{ + Mode: structs.MeshGatewayModeRemote, + }, + } + entries.AddResolvers( + &structs.ServiceResolverConfigEntry{ + Kind: "service-resolver", + Name: "main", + Redirect: &structs.ServiceResolverRedirect{ + Datacenter: "dc9", + }, + }, + ) + + expect := &structs.CompiledDiscoveryChain{ + Protocol: "tcp", + StartNode: "resolver:main.default.dc9", + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:main.default.dc9": &structs.DiscoveryGraphNode{ + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "main.default.dc9", + Resolver: &structs.DiscoveryResolver{ + ConnectTimeout: 5 * time.Second, + Target: "main.default.dc9", + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "main.default.dc9": newTarget("main", "", "default", "dc9", func(t *structs.DiscoveryTarget) { + t.MeshGateway = structs.MeshGatewayConfig{ + Mode: structs.MeshGatewayModeRemote, + } + }), + }, + } + return compileTestCase{entries: entries, expect: expect} +} + func testcase_ServiceFailover() compileTestCase { entries := newEntries() entries.AddResolvers( @@ -1145,7 +1190,7 @@ func testcase_DatacenterFailover() compileTestCase { return compileTestCase{entries: entries, expect: expect} } -func testcase_ServiceFailover_WithMeshGateways() compileTestCase { +func testcase_DatacenterFailover_WithMeshGateways() compileTestCase { entries := newEntries() entries.GlobalProxy = &structs.ProxyConfigEntry{ Kind: structs.ProxyDefaults, @@ -1159,7 +1204,7 @@ func testcase_ServiceFailover_WithMeshGateways() compileTestCase { Kind: "service-resolver", Name: "main", Failover: map[string]structs.ServiceResolverFailover{ - "*": {Service: "backup"}, + "*": {Datacenters: []string{"dc2", "dc4"}}, }, }, ) @@ -1175,18 +1220,22 @@ func testcase_ServiceFailover_WithMeshGateways() compileTestCase { ConnectTimeout: 5 * time.Second, Target: "main.default.dc1", Failover: &structs.DiscoveryFailover{ - Targets: []string{"backup.default.dc1"}, + Targets: []string{ + "main.default.dc2", + "main.default.dc4", + }, }, }, }, }, Targets: map[string]*structs.DiscoveryTarget{ - "main.default.dc1": newTarget("main", "", "default", "dc1", func(t *structs.DiscoveryTarget) { + "main.default.dc1": newTarget("main", "", "default", "dc1", nil), + "main.default.dc2": newTarget("main", "", "default", "dc2", func(t *structs.DiscoveryTarget) { t.MeshGateway = structs.MeshGatewayConfig{ Mode: structs.MeshGatewayModeRemote, } }), - "backup.default.dc1": newTarget("backup", "", "default", "dc1", func(t *structs.DiscoveryTarget) { + "main.default.dc4": newTarget("main", "", "default", "dc4", func(t *structs.DiscoveryTarget) { t.MeshGateway = structs.MeshGatewayConfig{ Mode: structs.MeshGatewayModeRemote, } @@ -1308,11 +1357,7 @@ func testcase_DefaultResolver_WithProxyDefaults() compileTestCase { }, }, Targets: map[string]*structs.DiscoveryTarget{ - "main.default.dc1": newTarget("main", "", "default", "dc1", func(t *structs.DiscoveryTarget) { - t.MeshGateway = structs.MeshGatewayConfig{ - Mode: structs.MeshGatewayModeRemote, - } - }), + "main.default.dc1": newTarget("main", "", "default", "dc1", nil), }, } return compileTestCase{entries: entries, expect: expect, expectIsDefault: true} diff --git a/agent/consul/discoverychain/testing.go b/agent/consul/discoverychain/testing.go index 8dbed12540..3520c7bd3c 100644 --- a/agent/consul/discoverychain/testing.go +++ b/agent/consul/discoverychain/testing.go @@ -9,8 +9,9 @@ import ( func TestCompileConfigEntries( t testing.T, serviceName string, - currentNamespace string, - currentDatacenter string, + evaluateInNamespace string, + evaluateInDatacenter string, + useInDatacenter string, setup func(req *CompileRequest), entries ...structs.ConfigEntry, ) *structs.CompiledDiscoveryChain { @@ -19,10 +20,11 @@ func TestCompileConfigEntries( set.AddEntries(entries...) req := CompileRequest{ - ServiceName: serviceName, - CurrentNamespace: currentNamespace, - CurrentDatacenter: currentDatacenter, - Entries: set, + ServiceName: serviceName, + EvaluateInNamespace: evaluateInNamespace, + EvaluateInDatacenter: evaluateInDatacenter, + UseInDatacenter: useInDatacenter, + Entries: set, } if setup != nil { setup(&req) diff --git a/agent/consul/state/config_entry.go b/agent/consul/state/config_entry.go index 916a50a83a..1f9fcc2b3f 100644 --- a/agent/consul/state/config_entry.go +++ b/agent/consul/state/config_entry.go @@ -444,11 +444,14 @@ func (s *Store) testCompileDiscoveryChain( // Note we use an arbitrary namespace and datacenter as those would not // currently affect the graph compilation in ways that matter here. + // + // TODO(rb): we should thread a better value than "dc1" down here as that is going to sometimes show up in user facing errors req := discoverychain.CompileRequest{ - ServiceName: chainName, - CurrentNamespace: "default", - CurrentDatacenter: "dc1", - Entries: speculativeEntries, + ServiceName: chainName, + EvaluateInNamespace: "default", + EvaluateInDatacenter: "dc1", + UseInDatacenter: "dc1", + Entries: speculativeEntries, } _, err = discoverychain.Compile(req) return err diff --git a/agent/discovery_chain_endpoint_test.go b/agent/discovery_chain_endpoint_test.go index c05bc15daa..2b5f98c6dd 100644 --- a/agent/discovery_chain_endpoint_test.go +++ b/agent/discovery_chain_endpoint_test.go @@ -3,6 +3,7 @@ package agent import ( "net/http" "net/http/httptest" + "reflect" "strings" "testing" "time" @@ -188,6 +189,11 @@ func TestDiscoveryChainRead(t *testing.T) { Kind: structs.ServiceResolver, Name: "web", ConnectTimeout: 33 * time.Second, + Failover: map[string]structs.ServiceResolverFailover{ + "*": { + Datacenters: []string{"dc2"}, + }, + }, }, }, &out)) require.True(t, out) @@ -203,31 +209,49 @@ func TestDiscoveryChainRead(t *testing.T) { obj, err := a.srv.DiscoveryChainRead(resp, req) r.Check(err) - value := obj.(discoveryChainReadResponse) - chain := value.Chain - - // light comparison - node := chain.Nodes["resolver:web.default.dc1"] - if node == nil { - r.Fatalf("missing node") - } - if node.Resolver.Default { - r.Fatalf("not refreshed yet") - } - // Should be a cache hit! The data should've updated in the cache // in the background so this should've been fetched directly from // the cache. if resp.Header().Get("X-Cache") != "HIT" { r.Fatalf("should be a cache hit") } + + value := obj.(discoveryChainReadResponse) + + expect := &structs.CompiledDiscoveryChain{ + ServiceName: "web", + Namespace: "default", + Datacenter: "dc1", + Protocol: "tcp", + StartNode: "resolver:web.default.dc1", + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:web.default.dc1": &structs.DiscoveryGraphNode{ + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "web.default.dc1", + Resolver: &structs.DiscoveryResolver{ + ConnectTimeout: 33 * time.Second, + Target: "web.default.dc1", + Failover: &structs.DiscoveryFailover{ + Targets: []string{"web.default.dc2"}, + }, + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "web.default.dc1": structs.NewDiscoveryTarget("web", "", "default", "dc1"), + "web.default.dc2": structs.NewDiscoveryTarget("web", "", "default", "dc2"), + }, + } + if !reflect.DeepEqual(expect, value.Chain) { + r.Fatalf("should be equal: expected=%+v, got=%+v", expect, value.Chain) + } }) })) // TODO(namespaces): add a test - expectTarget := structs.NewDiscoveryTarget("web", "", "default", "dc1") - expectTarget.MeshGateway = structs.MeshGatewayConfig{ + expectTarget_DC2 := structs.NewDiscoveryTarget("web", "", "default", "dc2") + expectTarget_DC2.MeshGateway = structs.MeshGatewayConfig{ Mode: structs.MeshGatewayModeLocal, } @@ -245,11 +269,15 @@ func TestDiscoveryChainRead(t *testing.T) { Resolver: &structs.DiscoveryResolver{ ConnectTimeout: 22 * time.Second, Target: "web.default.dc1", + Failover: &structs.DiscoveryFailover{ + Targets: []string{"web.default.dc2"}, + }, }, }, }, Targets: map[string]*structs.DiscoveryTarget{ - expectTarget.ID: expectTarget, + "web.default.dc1": structs.NewDiscoveryTarget("web", "", "default", "dc1"), + expectTarget_DC2.ID: expectTarget_DC2, }, } diff --git a/agent/proxycfg/manager_test.go b/agent/proxycfg/manager_test.go index 013eb7e4f7..2dff6f48a2 100644 --- a/agent/proxycfg/manager_test.go +++ b/agent/proxycfg/manager_test.go @@ -46,7 +46,7 @@ func TestManager_BasicLifecycle(t *testing.T) { roots, leaf := TestCerts(t) dbDefaultChain := func() *structs.CompiledDiscoveryChain { - return discoverychain.TestCompileConfigEntries(t, "db", "default", "dc1", + return discoverychain.TestCompileConfigEntries(t, "db", "default", "dc1", "dc1", func(req *discoverychain.CompileRequest) { // This is because structs.TestUpstreams uses an opaque config // to override connect timeouts. @@ -59,7 +59,7 @@ func TestManager_BasicLifecycle(t *testing.T) { ) } dbSplitChain := func() *structs.CompiledDiscoveryChain { - return discoverychain.TestCompileConfigEntries(t, "db", "default", "dc1", + return discoverychain.TestCompileConfigEntries(t, "db", "default", "dc1", "dc1", func(req *discoverychain.CompileRequest) { // This is because structs.TestUpstreams uses an opaque config // to override connect timeouts. @@ -201,6 +201,10 @@ func TestManager_BasicLifecycle(t *testing.T) { "db.default.dc1": TestUpstreamNodes(t), }, }, + WatchedGateways: nil, // Clone() clears this out + WatchedGatewayEndpoints: map[string]map[string]structs.CheckServiceNodes{ + "db": {}, + }, UpstreamEndpoints: map[string]structs.CheckServiceNodes{}, }, Datacenter: "dc1", @@ -241,6 +245,10 @@ func TestManager_BasicLifecycle(t *testing.T) { "v2.db.default.dc1": TestUpstreamNodesAlternate(t), }, }, + WatchedGateways: nil, // Clone() clears this out + WatchedGatewayEndpoints: map[string]map[string]structs.CheckServiceNodes{ + "db": {}, + }, UpstreamEndpoints: map[string]structs.CheckServiceNodes{}, }, Datacenter: "dc1", diff --git a/agent/proxycfg/snapshot.go b/agent/proxycfg/snapshot.go index 1a99c12838..37b8bf5749 100644 --- a/agent/proxycfg/snapshot.go +++ b/agent/proxycfg/snapshot.go @@ -12,7 +12,10 @@ type configSnapshotConnectProxy struct { DiscoveryChain map[string]*structs.CompiledDiscoveryChain // this is keyed by the Upstream.Identifier(), not the chain name WatchedUpstreams map[string]map[string]context.CancelFunc WatchedUpstreamEndpoints map[string]map[string]structs.CheckServiceNodes - UpstreamEndpoints map[string]structs.CheckServiceNodes // DEPRECATED:see:WatchedUpstreamEndpoints + WatchedGateways map[string]map[string]context.CancelFunc + WatchedGatewayEndpoints map[string]map[string]structs.CheckServiceNodes + + UpstreamEndpoints map[string]structs.CheckServiceNodes // DEPRECATED:see:WatchedUpstreamEndpoints } type configSnapshotMeshGateway struct { @@ -74,6 +77,7 @@ func (s *ConfigSnapshot) Clone() (*ConfigSnapshot, error) { switch s.Kind { case structs.ServiceKindConnectProxy: snap.ConnectProxy.WatchedUpstreams = nil + snap.ConnectProxy.WatchedGateways = nil case structs.ServiceKindMeshGateway: snap.MeshGateway.WatchedDatacenters = nil snap.MeshGateway.WatchedServices = nil diff --git a/agent/proxycfg/state.go b/agent/proxycfg/state.go index 27f85af4ae..eea31d100f 100644 --- a/agent/proxycfg/state.go +++ b/agent/proxycfg/state.go @@ -148,40 +148,30 @@ func (s *state) initWatches() error { } } -func (s *state) watchConnectProxyService(ctx context.Context, correlationId string, service string, dc string, filter string, meshGatewayMode structs.MeshGatewayMode) error { - switch meshGatewayMode { - case structs.MeshGatewayModeRemote: - return s.cache.Notify(ctx, cachetype.InternalServiceDumpName, &structs.ServiceDumpRequest{ - Datacenter: dc, - QueryOptions: structs.QueryOptions{Token: s.token}, - ServiceKind: structs.ServiceKindMeshGateway, - UseServiceKind: true, - Source: *s.source, - }, correlationId, s.ch) - case structs.MeshGatewayModeLocal: - return s.cache.Notify(ctx, cachetype.InternalServiceDumpName, &structs.ServiceDumpRequest{ - Datacenter: s.source.Datacenter, - QueryOptions: structs.QueryOptions{Token: s.token}, - ServiceKind: structs.ServiceKindMeshGateway, - UseServiceKind: true, - Source: *s.source, - }, correlationId, s.ch) - default: - // This includes both the None and Default modes on purpose - return s.cache.Notify(ctx, cachetype.HealthServicesName, &structs.ServiceSpecificRequest{ - Datacenter: dc, - QueryOptions: structs.QueryOptions{ - Token: s.token, - Filter: filter, - }, - ServiceName: service, - Connect: true, - // Note that Identifier doesn't type-prefix for service any more as it's - // the default and makes metrics and other things much cleaner. It's - // simpler for us if we have the type to make things unambiguous. - Source: *s.source, - }, correlationId, s.ch) - } +func (s *state) watchMeshGateway(ctx context.Context, dc string, upstreamID string) error { + return s.cache.Notify(ctx, cachetype.InternalServiceDumpName, &structs.ServiceDumpRequest{ + Datacenter: dc, + QueryOptions: structs.QueryOptions{Token: s.token}, + ServiceKind: structs.ServiceKindMeshGateway, + UseServiceKind: true, + Source: *s.source, + }, "mesh-gateway:"+dc+":"+upstreamID, s.ch) +} + +func (s *state) watchConnectProxyService(ctx context.Context, correlationId string, service string, dc string, filter string) error { + return s.cache.Notify(ctx, cachetype.HealthServicesName, &structs.ServiceSpecificRequest{ + Datacenter: dc, + QueryOptions: structs.QueryOptions{ + Token: s.token, + Filter: filter, + }, + ServiceName: service, + Connect: true, + // Note that Identifier doesn't type-prefix for service any more as it's + // the default and makes metrics and other things much cleaner. It's + // simpler for us if we have the type to make things unambiguous. + Source: *s.source, + }, correlationId, s.ch) } // initWatchesConnectProxy sets up the watches needed based on current proxy registration @@ -361,6 +351,9 @@ func (s *state) initialConfigSnapshot() ConfigSnapshot { snap.ConnectProxy.DiscoveryChain = make(map[string]*structs.CompiledDiscoveryChain) snap.ConnectProxy.WatchedUpstreams = make(map[string]map[string]context.CancelFunc) snap.ConnectProxy.WatchedUpstreamEndpoints = make(map[string]map[string]structs.CheckServiceNodes) + snap.ConnectProxy.WatchedGateways = make(map[string]map[string]context.CancelFunc) + snap.ConnectProxy.WatchedGatewayEndpoints = make(map[string]map[string]structs.CheckServiceNodes) + snap.ConnectProxy.UpstreamEndpoints = make(map[string]structs.CheckServiceNodes) // TODO(rb): deprecated case structs.ServiceKindMeshGateway: snap.MeshGateway.WatchedServices = make(map[string]context.CancelFunc) @@ -515,6 +508,23 @@ func (s *state) handleUpdateConnectProxy(u cache.UpdateEvent, snap *ConfigSnapsh } snap.ConnectProxy.WatchedUpstreamEndpoints[svc][targetID] = resp.Nodes + case strings.HasPrefix(u.CorrelationID, "mesh-gateway:"): + resp, ok := u.Result.(*structs.IndexedCheckServiceNodes) + if !ok { + return fmt.Errorf("invalid type for service response: %T", u.Result) + } + correlationID := strings.TrimPrefix(u.CorrelationID, "mesh-gateway:") + dc, svc, ok := removeColonPrefix(correlationID) + if !ok { + return fmt.Errorf("invalid correlation id %q", u.CorrelationID) + } + m, ok := snap.ConnectProxy.WatchedGatewayEndpoints[svc] + if !ok { + m = make(map[string]structs.CheckServiceNodes) + snap.ConnectProxy.WatchedGatewayEndpoints[svc] = m + } + snap.ConnectProxy.WatchedGatewayEndpoints[svc][dc] = resp.Nodes + case strings.HasPrefix(u.CorrelationID, "upstream:"+serviceIDPrefix): resp, ok := u.Result.(*structs.IndexedCheckServiceNodes) if !ok { @@ -561,6 +571,12 @@ func (s *state) resetWatchesFromChain( if _, ok := snap.ConnectProxy.WatchedUpstreamEndpoints[id]; !ok { snap.ConnectProxy.WatchedUpstreamEndpoints[id] = make(map[string]structs.CheckServiceNodes) } + if _, ok := snap.ConnectProxy.WatchedGateways[id]; !ok { + snap.ConnectProxy.WatchedGateways[id] = make(map[string]context.CancelFunc) + } + if _, ok := snap.ConnectProxy.WatchedGatewayEndpoints[id]; !ok { + snap.ConnectProxy.WatchedGatewayEndpoints[id] = make(map[string]structs.CheckServiceNodes) + } // We could invalidate this selectively based on a hash of the relevant // resolver information, but for now just reset anything about this @@ -574,29 +590,26 @@ func (s *state) resetWatchesFromChain( cancelFn() } + needGateways := make(map[string]struct{}) for _, target := range chain.Targets { s.logger.Printf("[TRACE] proxycfg: upstream=%q:chain=%q: initializing watch of target %s", id, chain.ServiceName, target.ID) + // We'll get endpoints from the gateway query, but the health still has + // to come from the backing service query. + switch target.MeshGateway.Mode { + case structs.MeshGatewayModeRemote: + needGateways[target.Datacenter] = struct{}{} + case structs.MeshGatewayModeLocal: + needGateways[s.source.Datacenter] = struct{}{} + } + ctx, cancel := context.WithCancel(s.ctx) - - // TODO (mesh-gateway)- maybe allow using a gateway within a datacenter at some point - meshGateway := structs.MeshGatewayModeDefault - if target.Datacenter != s.source.Datacenter { - meshGateway = target.MeshGateway.Mode - } - - // if the default mode - if meshGateway == structs.MeshGatewayModeDefault { - meshGateway = structs.MeshGatewayModeNone - } - err := s.watchConnectProxyService( ctx, "upstream-target:"+target.ID+":"+id, target.Service, target.Datacenter, target.Subset.Filter, - meshGateway, ) if err != nil { cancel() @@ -606,6 +619,33 @@ func (s *state) resetWatchesFromChain( snap.ConnectProxy.WatchedUpstreams[id][target.ID] = cancel } + for dc, _ := range needGateways { + if _, ok := snap.ConnectProxy.WatchedGateways[id][dc]; ok { + continue + } + + s.logger.Printf("[TRACE] proxycfg: upstream=%q:chain=%q: initializing watch of mesh gateway in dc %s", id, chain.ServiceName, dc) + + ctx, cancel := context.WithCancel(s.ctx) + err := s.watchMeshGateway(ctx, dc, id) + if err != nil { + cancel() + return err + } + + snap.ConnectProxy.WatchedGateways[id][dc] = cancel + } + + for dc, cancelFn := range snap.ConnectProxy.WatchedGateways[id] { + if _, ok := needGateways[dc]; ok { + continue + } + s.logger.Printf("[TRACE] proxycfg: upstream=%q:chain=%q: stopping watch of mesh gateway in dc %s", id, chain.ServiceName, dc) + delete(snap.ConnectProxy.WatchedGateways[id], dc) + delete(snap.ConnectProxy.WatchedGatewayEndpoints[id], dc) + cancelFn() + } + return nil } diff --git a/agent/proxycfg/state_test.go b/agent/proxycfg/state_test.go index 66d5f02b2c..65da26e69e 100644 --- a/agent/proxycfg/state_test.go +++ b/agent/proxycfg/state_test.go @@ -420,7 +420,7 @@ func TestState_WatchesAndUpdates(t *testing.T) { cache.UpdateEvent{ CorrelationID: "discovery-chain:api", Result: &structs.DiscoveryChainResponse{ - Chain: discoverychain.TestCompileConfigEntries(t, "api", "default", "dc1", + Chain: discoverychain.TestCompileConfigEntries(t, "api", "default", "dc1", "dc1", func(req *discoverychain.CompileRequest) { req.OverrideMeshGateway.Mode = meshGatewayProxyConfigValue }), @@ -430,7 +430,7 @@ func TestState_WatchesAndUpdates(t *testing.T) { cache.UpdateEvent{ CorrelationID: "discovery-chain:api-failover-remote?dc=dc2", Result: &structs.DiscoveryChainResponse{ - Chain: discoverychain.TestCompileConfigEntries(t, "api-failover-remote", "default", "dc2", + Chain: discoverychain.TestCompileConfigEntries(t, "api-failover-remote", "default", "dc2", "dc1", func(req *discoverychain.CompileRequest) { req.OverrideMeshGateway.Mode = structs.MeshGatewayModeRemote }), @@ -440,7 +440,7 @@ func TestState_WatchesAndUpdates(t *testing.T) { cache.UpdateEvent{ CorrelationID: "discovery-chain:api-failover-local?dc=dc2", Result: &structs.DiscoveryChainResponse{ - Chain: discoverychain.TestCompileConfigEntries(t, "api-failover-local", "default", "dc2", + Chain: discoverychain.TestCompileConfigEntries(t, "api-failover-local", "default", "dc2", "dc1", func(req *discoverychain.CompileRequest) { req.OverrideMeshGateway.Mode = structs.MeshGatewayModeLocal }), @@ -450,7 +450,7 @@ func TestState_WatchesAndUpdates(t *testing.T) { cache.UpdateEvent{ CorrelationID: "discovery-chain:api-failover-direct?dc=dc2", Result: &structs.DiscoveryChainResponse{ - Chain: discoverychain.TestCompileConfigEntries(t, "api-failover-direct", "default", "dc2", + Chain: discoverychain.TestCompileConfigEntries(t, "api-failover-direct", "default", "dc2", "dc1", func(req *discoverychain.CompileRequest) { req.OverrideMeshGateway.Mode = structs.MeshGatewayModeNone }), @@ -460,7 +460,7 @@ func TestState_WatchesAndUpdates(t *testing.T) { cache.UpdateEvent{ CorrelationID: "discovery-chain:api-dc2", Result: &structs.DiscoveryChainResponse{ - Chain: discoverychain.TestCompileConfigEntries(t, "api-dc2", "default", "dc1", + Chain: discoverychain.TestCompileConfigEntries(t, "api-dc2", "default", "dc1", "dc1", func(req *discoverychain.CompileRequest) { req.OverrideMeshGateway.Mode = meshGatewayProxyConfigValue }, @@ -482,16 +482,16 @@ func TestState_WatchesAndUpdates(t *testing.T) { stage1 := verificationStage{ requiredWatches: map[string]verifyWatchRequest{ "upstream-target:api.default.dc1:api": genVerifyServiceWatch("api", "", "dc1", true), - "upstream-target:api-failover-remote.default.dc2:api-failover-remote?dc=dc2": genVerifyGatewayWatch("dc2"), - "upstream-target:api-failover-local.default.dc2:api-failover-local?dc=dc2": genVerifyGatewayWatch("dc1"), + "upstream-target:api-failover-remote.default.dc2:api-failover-remote?dc=dc2": genVerifyServiceWatch("api-failover-remote", "", "dc2", true), + "upstream-target:api-failover-local.default.dc2:api-failover-local?dc=dc2": genVerifyServiceWatch("api-failover-local", "", "dc2", true), "upstream-target:api-failover-direct.default.dc2:api-failover-direct?dc=dc2": genVerifyServiceWatch("api-failover-direct", "", "dc2", true), + "mesh-gateway:dc2:api-failover-remote?dc=dc2": genVerifyGatewayWatch("dc2"), + "mesh-gateway:dc1:api-failover-local?dc=dc2": genVerifyGatewayWatch("dc1"), }, } - if meshGatewayProxyConfigValue == structs.MeshGatewayModeDefault { - stage1.requiredWatches["upstream-target:api.default.dc2:api-dc2"] = genVerifyServiceWatch("api", "", "dc2", true) - } else { - stage1.requiredWatches["upstream-target:api.default.dc2:api-dc2"] = genVerifyGatewayWatch("dc1") + if meshGatewayProxyConfigValue == structs.MeshGatewayModeLocal { + stage1.requiredWatches["mesh-gateway:dc1:api-dc2"] = genVerifyGatewayWatch("dc1") } return testCase{ diff --git a/agent/proxycfg/testing.go b/agent/proxycfg/testing.go index 167123e8d1..7e97f4e3ff 100644 --- a/agent/proxycfg/testing.go +++ b/agent/proxycfg/testing.go @@ -157,6 +157,45 @@ func TestUpstreamNodes(t testing.T) structs.CheckServiceNodes { } } +func TestUpstreamNodesInStatus(t testing.T, status string) structs.CheckServiceNodes { + return structs.CheckServiceNodes{ + structs.CheckServiceNode{ + Node: &structs.Node{ + ID: "test1", + Node: "test1", + Address: "10.10.1.1", + Datacenter: "dc1", + }, + Service: structs.TestNodeService(t), + Checks: structs.HealthChecks{ + &structs.HealthCheck{ + Node: "test1", + ServiceName: "web", + Name: "force", + Status: status, + }, + }, + }, + structs.CheckServiceNode{ + Node: &structs.Node{ + ID: "test2", + Node: "test2", + Address: "10.10.1.2", + Datacenter: "dc1", + }, + Service: structs.TestNodeService(t), + Checks: structs.HealthChecks{ + &structs.HealthCheck{ + Node: "test2", + ServiceName: "web", + Name: "force", + Status: status, + }, + }, + }, + } +} + func TestUpstreamNodesDC2(t testing.T) structs.CheckServiceNodes { return structs.CheckServiceNodes{ structs.CheckServiceNode{ @@ -180,6 +219,68 @@ func TestUpstreamNodesDC2(t testing.T) structs.CheckServiceNodes { } } +func TestUpstreamNodesInStatusDC2(t testing.T, status string) structs.CheckServiceNodes { + return structs.CheckServiceNodes{ + structs.CheckServiceNode{ + Node: &structs.Node{ + ID: "test1", + Node: "test1", + Address: "10.20.1.1", + Datacenter: "dc2", + }, + Service: structs.TestNodeService(t), + Checks: structs.HealthChecks{ + &structs.HealthCheck{ + Node: "test1", + ServiceName: "web", + Name: "force", + Status: status, + }, + }, + }, + structs.CheckServiceNode{ + Node: &structs.Node{ + ID: "test2", + Node: "test2", + Address: "10.20.1.2", + Datacenter: "dc2", + }, + Service: structs.TestNodeService(t), + Checks: structs.HealthChecks{ + &structs.HealthCheck{ + Node: "test2", + ServiceName: "web", + Name: "force", + Status: status, + }, + }, + }, + } +} + +func TestUpstreamNodesDC3(t testing.T) structs.CheckServiceNodes { + return structs.CheckServiceNodes{ + structs.CheckServiceNode{ + Node: &structs.Node{ + ID: "test1", + Node: "test1", + Address: "10.30.1.1", + Datacenter: "dc3", + }, + Service: structs.TestNodeService(t), + }, + structs.CheckServiceNode{ + Node: &structs.Node{ + ID: "test2", + Node: "test2", + Address: "10.30.1.2", + Datacenter: "dc3", + }, + Service: structs.TestNodeService(t), + }, + } +} + func TestUpstreamNodesAlternate(t testing.T) structs.CheckServiceNodes { return structs.CheckServiceNodes{ structs.CheckServiceNode{ @@ -203,6 +304,35 @@ func TestUpstreamNodesAlternate(t testing.T) structs.CheckServiceNodes { } } +func TestGatewayNodesDC1(t testing.T) structs.CheckServiceNodes { + return structs.CheckServiceNodes{ + structs.CheckServiceNode{ + Node: &structs.Node{ + ID: "mesh-gateway-1", + Node: "mesh-gateway", + Address: "10.10.1.1", + Datacenter: "dc1", + }, + Service: structs.TestNodeServiceMeshGatewayWithAddrs(t, + "10.10.1.1", 8443, + structs.ServiceAddress{Address: "10.10.1.1", Port: 8443}, + structs.ServiceAddress{Address: "198.118.1.1", Port: 443}), + }, + structs.CheckServiceNode{ + Node: &structs.Node{ + ID: "mesh-gateway-2", + Node: "mesh-gateway", + Address: "10.10.1.2", + Datacenter: "dc1", + }, + Service: structs.TestNodeServiceMeshGatewayWithAddrs(t, + "10.10.1.2", 8443, + structs.ServiceAddress{Address: "10.0.1.2", Port: 8443}, + structs.ServiceAddress{Address: "198.118.1.2", Port: 443}), + }, + } +} + func TestGatewayNodesDC2(t testing.T) structs.CheckServiceNodes { return structs.CheckServiceNodes{ structs.CheckServiceNode{ @@ -232,6 +362,35 @@ func TestGatewayNodesDC2(t testing.T) structs.CheckServiceNodes { } } +func TestGatewayNodesDC3(t testing.T) structs.CheckServiceNodes { + return structs.CheckServiceNodes{ + structs.CheckServiceNode{ + Node: &structs.Node{ + ID: "mesh-gateway-1", + Node: "mesh-gateway", + Address: "10.30.1.1", + Datacenter: "dc3", + }, + Service: structs.TestNodeServiceMeshGatewayWithAddrs(t, + "10.30.1.1", 8443, + structs.ServiceAddress{Address: "10.0.1.1", Port: 8443}, + structs.ServiceAddress{Address: "198.38.1.1", Port: 443}), + }, + structs.CheckServiceNode{ + Node: &structs.Node{ + ID: "mesh-gateway-2", + Node: "mesh-gateway", + Address: "10.30.1.2", + Datacenter: "dc3", + }, + Service: structs.TestNodeServiceMeshGatewayWithAddrs(t, + "10.30.1.2", 8443, + structs.ServiceAddress{Address: "10.30.1.2", Port: 8443}, + structs.ServiceAddress{Address: "198.38.1.2", Port: 443}), + }, + } +} + func TestGatewayServiceGroupBarDC1(t testing.T) structs.CheckServiceNodes { return structs.CheckServiceNodes{ structs.CheckServiceNode{ @@ -441,6 +600,38 @@ func TestConfigSnapshotDiscoveryChainWithFailover(t testing.T) *ConfigSnapshot { return testConfigSnapshotDiscoveryChain(t, "failover") } +func TestConfigSnapshotDiscoveryChainWithFailoverThroughRemoteGateway(t testing.T) *ConfigSnapshot { + return testConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway") +} + +func TestConfigSnapshotDiscoveryChainWithFailoverThroughRemoteGatewayTriggered(t testing.T) *ConfigSnapshot { + return testConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway-triggered") +} + +func TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughRemoteGateway(t testing.T) *ConfigSnapshot { + return testConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway") +} + +func TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughRemoteGatewayTriggered(t testing.T) *ConfigSnapshot { + return testConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway-triggered") +} + +func TestConfigSnapshotDiscoveryChainWithFailoverThroughLocalGateway(t testing.T) *ConfigSnapshot { + return testConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway") +} + +func TestConfigSnapshotDiscoveryChainWithFailoverThroughLocalGatewayTriggered(t testing.T) *ConfigSnapshot { + return testConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway-triggered") +} + +func TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughLocalGateway(t testing.T) *ConfigSnapshot { + return testConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway") +} + +func TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughLocalGatewayTriggered(t testing.T) *ConfigSnapshot { + return testConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway-triggered") +} + func TestConfigSnapshotDiscoveryChain_SplitterWithResolverRedirectMultiDC(t testing.T) *ConfigSnapshot { return testConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc") } @@ -486,6 +677,94 @@ func testConfigSnapshotDiscoveryChain(t testing.T, variation string, additionalE }, }, ) + case "failover-through-remote-gateway-triggered": + fallthrough + case "failover-through-remote-gateway": + entries = append(entries, + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "db", + MeshGateway: structs.MeshGatewayConfig{ + Mode: structs.MeshGatewayModeRemote, + }, + }, + &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: "db", + ConnectTimeout: 33 * time.Second, + Failover: map[string]structs.ServiceResolverFailover{ + "*": { + Datacenters: []string{"dc2"}, + }, + }, + }, + ) + case "failover-through-double-remote-gateway-triggered": + fallthrough + case "failover-through-double-remote-gateway": + entries = append(entries, + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "db", + MeshGateway: structs.MeshGatewayConfig{ + Mode: structs.MeshGatewayModeRemote, + }, + }, + &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: "db", + ConnectTimeout: 33 * time.Second, + Failover: map[string]structs.ServiceResolverFailover{ + "*": { + Datacenters: []string{"dc2", "dc3"}, + }, + }, + }, + ) + case "failover-through-local-gateway-triggered": + fallthrough + case "failover-through-local-gateway": + entries = append(entries, + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "db", + MeshGateway: structs.MeshGatewayConfig{ + Mode: structs.MeshGatewayModeLocal, + }, + }, + &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: "db", + ConnectTimeout: 33 * time.Second, + Failover: map[string]structs.ServiceResolverFailover{ + "*": { + Datacenters: []string{"dc2"}, + }, + }, + }, + ) + case "failover-through-double-local-gateway-triggered": + fallthrough + case "failover-through-double-local-gateway": + entries = append(entries, + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "db", + MeshGateway: structs.MeshGatewayConfig{ + Mode: structs.MeshGatewayModeLocal, + }, + }, + &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: "db", + ConnectTimeout: 33 * time.Second, + Failover: map[string]structs.ServiceResolverFailover{ + "*": { + Datacenters: []string{"dc2", "dc3"}, + }, + }, + }, + ) case "splitter-with-resolver-redirect-multidc": entries = append(entries, &structs.ProxyConfigEntry{ @@ -543,7 +822,7 @@ func testConfigSnapshotDiscoveryChain(t testing.T, variation string, additionalE entries = append(entries, additionalEntries...) } - dbChain := discoverychain.TestCompileConfigEntries(t, "db", "default", "dc1", compileSetup, entries...) + dbChain := discoverychain.TestCompileConfigEntries(t, "db", "default", "dc1", "dc1", compileSetup, entries...) snap := &ConfigSnapshot{ Kind: structs.ServiceKindConnectProxy, @@ -582,6 +861,57 @@ func testConfigSnapshotDiscoveryChain(t testing.T, variation string, additionalE case "failover": snap.ConnectProxy.WatchedUpstreamEndpoints["db"]["fail.default.dc1"] = TestUpstreamNodesAlternate(t) + case "failover-through-remote-gateway-triggered": + snap.ConnectProxy.WatchedUpstreamEndpoints["db"]["db.default.dc1"] = + TestUpstreamNodesInStatus(t, "critical") + fallthrough + case "failover-through-remote-gateway": + snap.ConnectProxy.WatchedUpstreamEndpoints["db"]["db.default.dc2"] = + TestUpstreamNodesDC2(t) + snap.ConnectProxy.WatchedGatewayEndpoints = map[string]map[string]structs.CheckServiceNodes{ + "db": map[string]structs.CheckServiceNodes{ + "dc2": TestGatewayNodesDC2(t), + }, + } + case "failover-through-double-remote-gateway-triggered": + snap.ConnectProxy.WatchedUpstreamEndpoints["db"]["db.default.dc1"] = + TestUpstreamNodesInStatus(t, "critical") + snap.ConnectProxy.WatchedUpstreamEndpoints["db"]["db.default.dc2"] = + TestUpstreamNodesInStatusDC2(t, "critical") + fallthrough + case "failover-through-double-remote-gateway": + snap.ConnectProxy.WatchedUpstreamEndpoints["db"]["db.default.dc3"] = TestUpstreamNodesDC2(t) + snap.ConnectProxy.WatchedGatewayEndpoints = map[string]map[string]structs.CheckServiceNodes{ + "db": map[string]structs.CheckServiceNodes{ + "dc2": TestGatewayNodesDC2(t), + "dc3": TestGatewayNodesDC3(t), + }, + } + case "failover-through-local-gateway-triggered": + snap.ConnectProxy.WatchedUpstreamEndpoints["db"]["db.default.dc1"] = + TestUpstreamNodesInStatus(t, "critical") + fallthrough + case "failover-through-local-gateway": + snap.ConnectProxy.WatchedUpstreamEndpoints["db"]["db.default.dc2"] = + TestUpstreamNodesDC2(t) + snap.ConnectProxy.WatchedGatewayEndpoints = map[string]map[string]structs.CheckServiceNodes{ + "db": map[string]structs.CheckServiceNodes{ + "dc1": TestGatewayNodesDC1(t), + }, + } + case "failover-through-double-local-gateway-triggered": + snap.ConnectProxy.WatchedUpstreamEndpoints["db"]["db.default.dc1"] = + TestUpstreamNodesInStatus(t, "critical") + snap.ConnectProxy.WatchedUpstreamEndpoints["db"]["db.default.dc2"] = + TestUpstreamNodesInStatusDC2(t, "critical") + fallthrough + case "failover-through-double-local-gateway": + snap.ConnectProxy.WatchedUpstreamEndpoints["db"]["db.default.dc3"] = TestUpstreamNodesDC2(t) + snap.ConnectProxy.WatchedGatewayEndpoints = map[string]map[string]structs.CheckServiceNodes{ + "db": map[string]structs.CheckServiceNodes{ + "dc1": TestGatewayNodesDC1(t), + }, + } case "splitter-with-resolver-redirect-multidc": snap.ConnectProxy.WatchedUpstreamEndpoints["db"] = map[string]structs.CheckServiceNodes{ "v1.db.default.dc1": TestUpstreamNodes(t), diff --git a/agent/structs/discovery_chain.go b/agent/structs/discovery_chain.go index 80f44bde88..a99ff805a8 100644 --- a/agent/structs/discovery_chain.go +++ b/agent/structs/discovery_chain.go @@ -40,6 +40,24 @@ type CompiledDiscoveryChain struct { Targets map[string]*DiscoveryTarget `json:",omitempty"` } +func (c *CompiledDiscoveryChain) WillFailoverThroughMeshGateway(node *DiscoveryGraphNode) bool { + if node.Type != DiscoveryGraphNodeTypeResolver { + return false + } + failover := node.Resolver.Failover + + if failover != nil && len(failover.Targets) > 0 { + for _, failTargetID := range failover.Targets { + failTarget := c.Targets[failTargetID] + switch failTarget.MeshGateway.Mode { + case MeshGatewayModeLocal, MeshGatewayModeRemote: + return true + } + } + } + return false +} + // IsDefault returns true if the compiled chain represents no routing, no // splitting, and only the default resolution. We have to be careful here to // avoid returning "yep this is default" when the only resolver action being diff --git a/agent/xds/clusters.go b/agent/xds/clusters.go index 78009aa258..2725fa97bf 100644 --- a/agent/xds/clusters.go +++ b/agent/xds/clusters.go @@ -246,6 +246,13 @@ func (s *Server) makeUpstreamClustersForDiscoveryChain( panic("chain must be provided") } + id := upstream.Identifier() + chainEndpointMap, ok := cfgSnap.ConnectProxy.WatchedUpstreamEndpoints[id] + if !ok { + // this should not happen + return nil, fmt.Errorf("no endpoint map for upstream %q", id) + } + // TODO(rb): make escape hatches work with chains var out []*envoy.Cluster @@ -254,13 +261,31 @@ func (s *Server) makeUpstreamClustersForDiscoveryChain( if node.Type != structs.DiscoveryGraphNodeTypeResolver { continue } + failover := node.Resolver.Failover targetID := node.Resolver.Target target := chain.Targets[targetID] + // Determine if we have to generate the entire cluster differently. + failoverThroughMeshGateway := chain.WillFailoverThroughMeshGateway(node) + sni := TargetSNI(target, cfgSnap) clusterName := CustomizeClusterName(sni, chain) + if failoverThroughMeshGateway { + actualTargetID := firstHealthyTarget( + chain.Targets, + chainEndpointMap, + targetID, + failover.Targets, + ) + + if actualTargetID != targetID { + actualTarget := chain.Targets[actualTargetID] + sni = TargetSNI(actualTarget, cfgSnap) + } + } + s.Logger.Printf("[DEBUG] xds.clusters - generating cluster for %s", clusterName) c := &envoy.Cluster{ Name: clusterName, diff --git a/agent/xds/clusters_test.go b/agent/xds/clusters_test.go index c11181fd98..e71a138dc1 100644 --- a/agent/xds/clusters_test.go +++ b/agent/xds/clusters_test.go @@ -115,6 +115,46 @@ func TestClustersFromSnapshot(t *testing.T) { create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailover, setup: nil, }, + { + name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughRemoteGateway, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughRemoteGatewayTriggered, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughRemoteGateway, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughRemoteGatewayTriggered, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-local-gateway", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughLocalGateway, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughLocalGatewayTriggered, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughLocalGateway, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughLocalGatewayTriggered, + setup: nil, + }, { name: "splitter-with-resolver-redirect", create: proxycfg.TestConfigSnapshotDiscoveryChain_SplitterWithResolverRedirectMultiDC, diff --git a/agent/xds/endpoints.go b/agent/xds/endpoints.go index 25529d14c3..3635de7c98 100644 --- a/agent/xds/endpoints.go +++ b/agent/xds/endpoints.go @@ -35,8 +35,8 @@ func (s *Server) endpointsFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot, token s // endpointsFromSnapshotConnectProxy returns the xDS API representation of the "endpoints" // (upstream instances) in the snapshot. func (s *Server) endpointsFromSnapshotConnectProxy(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) { - // TODO(rb): this sizing is a low bound. - resources := make([]proto.Message, 0, len(cfgSnap.ConnectProxy.UpstreamEndpoints)) + resources := make([]proto.Message, 0, + len(cfgSnap.ConnectProxy.UpstreamEndpoints)+len(cfgSnap.ConnectProxy.WatchedUpstreamEndpoints)) // TODO(rb): should naming from 1.5 -> 1.6 for clusters remain unchanged? @@ -67,11 +67,6 @@ func (s *Server) endpointsFromSnapshotConnectProxy(cfgSnap *proxycfg.ConfigSnaps } else { // Newfangled discovery chain plumbing. - chainEndpointMap, ok := cfgSnap.ConnectProxy.WatchedUpstreamEndpoints[id] - if !ok { - continue // skip the upstream (should not happen) - } - // Find all resolver nodes. for _, node := range chain.Nodes { if node.Type != structs.DiscoveryGraphNodeTypeResolver { @@ -82,43 +77,62 @@ func (s *Server) endpointsFromSnapshotConnectProxy(cfgSnap *proxycfg.ConfigSnaps target := chain.Targets[targetID] - endpoints, ok := chainEndpointMap[targetID] - if !ok { - continue // skip the cluster (should not happen) + sni := TargetSNI(target, cfgSnap) + clusterName := CustomizeClusterName(sni, chain) + + // Determine if we have to generate the entire cluster differently. + failoverThroughMeshGateway := chain.WillFailoverThroughMeshGateway(node) + + if failoverThroughMeshGateway { + actualTargetID := firstHealthyTarget( + chain.Targets, + cfgSnap.ConnectProxy.WatchedUpstreamEndpoints[id], + targetID, + failover.Targets, + ) + if actualTargetID != targetID { + targetID = actualTargetID + target = chain.Targets[actualTargetID] + } + + failover = nil + } + + primaryGroup, valid := makeLoadAssignmentEndpointGroup( + chain.Targets, + cfgSnap.ConnectProxy.WatchedUpstreamEndpoints[id], + cfgSnap.ConnectProxy.WatchedGatewayEndpoints[id], + targetID, + cfgSnap.Datacenter, + ) + if !valid { + continue // skip the cluster if we're still populating the snapshot } var endpointGroups []loadAssignmentEndpointGroup - primaryGroup := loadAssignmentEndpointGroup{ - Endpoints: endpoints, - OnlyPassing: target.Subset.OnlyPassing, - } - if failover != nil && len(failover.Targets) > 0 { endpointGroups = make([]loadAssignmentEndpointGroup, 0, len(failover.Targets)+1) endpointGroups = append(endpointGroups, primaryGroup) for _, failTargetID := range failover.Targets { - failEndpoints, ok := chainEndpointMap[failTargetID] - if !ok { - continue // skip the failover target (should not happen) + failoverGroup, valid := makeLoadAssignmentEndpointGroup( + chain.Targets, + cfgSnap.ConnectProxy.WatchedUpstreamEndpoints[id], + cfgSnap.ConnectProxy.WatchedGatewayEndpoints[id], + failTargetID, + cfgSnap.Datacenter, + ) + if !valid { + continue // skip the failover target if we're still populating the snapshot } - - failTarget := chain.Targets[failTargetID] - - endpointGroups = append(endpointGroups, loadAssignmentEndpointGroup{ - Endpoints: failEndpoints, - OnlyPassing: failTarget.Subset.OnlyPassing, - }) + endpointGroups = append(endpointGroups, failoverGroup) } } else { endpointGroups = append(endpointGroups, primaryGroup) } - sni := TargetSNI(target, cfgSnap) - clusterName := CustomizeClusterName(sni, chain) - la := makeLoadAssignment( clusterName, endpointGroups, @@ -210,8 +224,9 @@ func makeEndpoint(clusterName, host string, port int) envoyendpoint.LbEndpoint { } type loadAssignmentEndpointGroup struct { - Endpoints structs.CheckServiceNodes - OnlyPassing bool + Endpoints structs.CheckServiceNodes + OnlyPassing bool + OverrideHealth envoycore.HealthStatus } func makeLoadAssignment(clusterName string, endpointGroups []loadAssignmentEndpointGroup, localDatacenter string) *envoy.ClusterLoadAssignment { @@ -235,33 +250,12 @@ func makeLoadAssignment(clusterName string, endpointGroups []loadAssignmentEndpo for _, ep := range endpoints { // TODO (mesh-gateway) - should we respect the translate_wan_addrs configuration here or just always use the wan for cross-dc? addr, port := ep.BestAddress(localDatacenter != ep.Node.Datacenter) - healthStatus := envoycore.HealthStatus_HEALTHY - weight := 1 - if ep.Service.Weights != nil { - weight = ep.Service.Weights.Passing + healthStatus, weight := calculateEndpointHealthAndWeight(ep, endpointGroup.OnlyPassing) + + if endpointGroup.OverrideHealth != envoycore.HealthStatus_UNKNOWN { + healthStatus = endpointGroup.OverrideHealth } - for _, chk := range ep.Checks { - if chk.Status == api.HealthCritical { - healthStatus = envoycore.HealthStatus_UNHEALTHY - } - if endpointGroup.OnlyPassing && chk.Status != api.HealthPassing { - healthStatus = envoycore.HealthStatus_UNHEALTHY - } - if chk.Status == api.HealthWarning && ep.Service.Weights != nil { - weight = ep.Service.Weights.Warning - } - } - // Make weights fit Envoy's limits. A zero weight means that either Warning - // (likely) or Passing (weirdly) weight has been set to 0 effectively making - // this instance unhealthy and should not be sent traffic. - if weight < 1 { - healthStatus = envoycore.HealthStatus_UNHEALTHY - weight = 1 - } - if weight > 128 { - weight = 128 - } es = append(es, envoyendpoint.LbEndpoint{ HostIdentifier: &envoyendpoint.LbEndpoint_Endpoint{ Endpoint: &envoyendpoint.Endpoint{ @@ -281,3 +275,89 @@ func makeLoadAssignment(clusterName string, endpointGroups []loadAssignmentEndpo return cla } + +func makeLoadAssignmentEndpointGroup( + targets map[string]*structs.DiscoveryTarget, + targetHealth map[string]structs.CheckServiceNodes, + gatewayHealth map[string]structs.CheckServiceNodes, + targetID string, + currentDatacenter string, +) (loadAssignmentEndpointGroup, bool) { + realEndpoints, ok := targetHealth[targetID] + if !ok { + // skip the cluster if we're still populating the snapshot + return loadAssignmentEndpointGroup{}, false + } + target := targets[targetID] + + var gatewayDatacenter string + switch target.MeshGateway.Mode { + case structs.MeshGatewayModeRemote: + gatewayDatacenter = target.Datacenter + case structs.MeshGatewayModeLocal: + gatewayDatacenter = currentDatacenter + } + + if gatewayDatacenter == "" { + return loadAssignmentEndpointGroup{ + Endpoints: realEndpoints, + OnlyPassing: target.Subset.OnlyPassing, + }, true + } + + // If using a mesh gateway we need to pull those endpoints instead. + gatewayEndpoints, ok := gatewayHealth[gatewayDatacenter] + if !ok { + // skip the cluster if we're still populating the snapshot + return loadAssignmentEndpointGroup{}, false + } + + // But we will use the health from the actual backend service. + overallHealth := envoycore.HealthStatus_UNHEALTHY + for _, ep := range realEndpoints { + health, _ := calculateEndpointHealthAndWeight(ep, target.Subset.OnlyPassing) + if health == envoycore.HealthStatus_HEALTHY { + overallHealth = envoycore.HealthStatus_HEALTHY + break + } + } + + return loadAssignmentEndpointGroup{ + Endpoints: gatewayEndpoints, + OverrideHealth: overallHealth, + }, true +} + +func calculateEndpointHealthAndWeight( + ep structs.CheckServiceNode, + onlyPassing bool, +) (envoycore.HealthStatus, int) { + healthStatus := envoycore.HealthStatus_HEALTHY + weight := 1 + if ep.Service.Weights != nil { + weight = ep.Service.Weights.Passing + } + + for _, chk := range ep.Checks { + if chk.Status == api.HealthCritical { + healthStatus = envoycore.HealthStatus_UNHEALTHY + } + if onlyPassing && chk.Status != api.HealthPassing { + healthStatus = envoycore.HealthStatus_UNHEALTHY + } + if chk.Status == api.HealthWarning && ep.Service.Weights != nil { + weight = ep.Service.Weights.Warning + } + } + // Make weights fit Envoy's limits. A zero weight means that either Warning + // (likely) or Passing (weirdly) weight has been set to 0 effectively making + // this instance unhealthy and should not be sent traffic. + if weight < 1 { + healthStatus = envoycore.HealthStatus_UNHEALTHY + weight = 1 + } + if weight > 128 { + weight = 128 + } + return healthStatus, weight +} diff --git a/agent/xds/endpoints_test.go b/agent/xds/endpoints_test.go index 019da29859..bfe1eafd3a 100644 --- a/agent/xds/endpoints_test.go +++ b/agent/xds/endpoints_test.go @@ -253,6 +253,46 @@ func Test_endpointsFromSnapshot(t *testing.T) { create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailover, setup: nil, }, + { + name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughRemoteGateway, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughRemoteGatewayTriggered, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughRemoteGateway, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughRemoteGatewayTriggered, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-local-gateway", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughLocalGateway, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughLocalGatewayTriggered, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughLocalGateway, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithDoubleFailoverThroughLocalGatewayTriggered, + setup: nil, + }, { name: "splitter-with-resolver-redirect", create: proxycfg.TestConfigSnapshotDiscoveryChain_SplitterWithResolverRedirectMultiDC, diff --git a/agent/xds/failover_math.go b/agent/xds/failover_math.go new file mode 100644 index 0000000000..78a8288d56 --- /dev/null +++ b/agent/xds/failover_math.go @@ -0,0 +1,37 @@ +package xds + +import ( + envoycore "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" + "github.com/hashicorp/consul/agent/structs" +) + +func firstHealthyTarget( + targets map[string]*structs.DiscoveryTarget, + targetHealth map[string]structs.CheckServiceNodes, + primaryTarget string, + secondaryTargets []string, +) string { + series := make([]string, 0, len(secondaryTargets)+1) + series = append(series, primaryTarget) + series = append(series, secondaryTargets...) + + for _, targetID := range series { + target, ok := targets[targetID] + if !ok { + continue + } + + endpoints, ok := targetHealth[targetID] + if !ok { + continue + } + for _, ep := range endpoints { + healthStatus, _ := calculateEndpointHealthAndWeight(ep, target.Subset.OnlyPassing) + if healthStatus == envoycore.HealthStatus_HEALTHY { + return targetID + } + } + } + + return primaryTarget // if everything is broken just use the primary for now +} diff --git a/agent/xds/failover_math_test.go b/agent/xds/failover_math_test.go new file mode 100644 index 0000000000..3cf87512fe --- /dev/null +++ b/agent/xds/failover_math_test.go @@ -0,0 +1,116 @@ +package xds + +import ( + "fmt" + "testing" + + "github.com/hashicorp/consul/agent/proxycfg" + "github.com/hashicorp/consul/agent/structs" + "github.com/stretchr/testify/require" +) + +func TestFirstHealthyTarget(t *testing.T) { + passing := proxycfg.TestUpstreamNodesInStatus(t, "passing") + warning := proxycfg.TestUpstreamNodesInStatus(t, "warning") + critical := proxycfg.TestUpstreamNodesInStatus(t, "critical") + + warnOnlyPassingTarget := structs.NewDiscoveryTarget("all-warn", "", "default", "dc1") + warnOnlyPassingTarget.Subset.OnlyPassing = true + failOnlyPassingTarget := structs.NewDiscoveryTarget("all-fail", "", "default", "dc1") + failOnlyPassingTarget.Subset.OnlyPassing = true + + targets := map[string]*structs.DiscoveryTarget{ + "all-ok.default.dc1": structs.NewDiscoveryTarget("all-ok", "", "default", "dc1"), + "all-warn.default.dc1": structs.NewDiscoveryTarget("all-warn", "", "default", "dc1"), + "all-fail.default.dc1": structs.NewDiscoveryTarget("all-fail", "", "default", "dc1"), + "all-warn-onlypassing.default.dc1": warnOnlyPassingTarget, + "all-fail-onlypassing.default.dc1": failOnlyPassingTarget, + } + targetHealth := map[string]structs.CheckServiceNodes{ + "all-ok.default.dc1": passing, + "all-warn.default.dc1": warning, + "all-fail.default.dc1": critical, + "all-warn-onlypassing.default.dc1": warning, + "all-fail-onlypassing.default.dc1": critical, + } + + cases := []struct { + primary string + secondary []string + expect string + }{ + { + primary: "all-ok.default.dc1", + expect: "all-ok.default.dc1", + }, + { + primary: "all-warn.default.dc1", + expect: "all-warn.default.dc1", + }, + { + primary: "all-fail.default.dc1", + expect: "all-fail.default.dc1", + }, + { + primary: "all-warn-onlypassing.default.dc1", + expect: "all-warn-onlypassing.default.dc1", + }, + { + primary: "all-fail-onlypassing.default.dc1", + expect: "all-fail-onlypassing.default.dc1", + }, + { + primary: "all-ok.default.dc1", + secondary: []string{ + "all-warn.default.dc1", + }, + expect: "all-ok.default.dc1", + }, + { + primary: "all-warn.default.dc1", + secondary: []string{ + "all-ok.default.dc1", + }, + expect: "all-warn.default.dc1", + }, + { + primary: "all-warn-onlypassing.default.dc1", + secondary: []string{ + "all-ok.default.dc1", + }, + expect: "all-ok.default.dc1", + }, + { + primary: "all-fail.default.dc1", + secondary: []string{ + "all-ok.default.dc1", + }, + expect: "all-ok.default.dc1", + }, + { + primary: "all-fail-onlypassing.default.dc1", + secondary: []string{ + "all-ok.default.dc1", + }, + expect: "all-ok.default.dc1", + }, + { + primary: "all-fail.default.dc1", + secondary: []string{ + "all-warn-onlypassing.default.dc1", + "all-warn.default.dc1", + "all-ok.default.dc1", + }, + expect: "all-warn.default.dc1", + }, + } + + for _, tc := range cases { + tc := tc + name := fmt.Sprintf("%s and %v", tc.primary, tc.secondary) + t.Run(name, func(t *testing.T) { + targetID := firstHealthyTarget(targets, targetHealth, tc.primary, tc.secondary) + require.Equal(t, tc.expect, targetID) + }) + } +} diff --git a/agent/xds/listeners_test.go b/agent/xds/listeners_test.go index acf5998308..dddbd06058 100644 --- a/agent/xds/listeners_test.go +++ b/agent/xds/listeners_test.go @@ -189,6 +189,16 @@ func TestListenersFromSnapshot(t *testing.T) { create: proxycfg.TestConfigSnapshotDiscoveryChainWithOverrides, setup: nil, }, + { + name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughRemoteGateway, + setup: nil, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-local-gateway", + create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughLocalGateway, + setup: nil, + }, { name: "mesh-gateway", create: proxycfg.TestConfigSnapshotMeshGateway, diff --git a/agent/xds/testdata/clusters/connect-proxy-with-chain-and-overrides.golden b/agent/xds/testdata/clusters/connect-proxy-with-chain-and-overrides.golden index 7105cbefe3..7af4313cd1 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-chain-and-overrides.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-chain-and-overrides.golden @@ -3,8 +3,8 @@ "resources": [ { "@type": "type.googleapis.com/envoy.api.v2.Cluster", - "name": "78ebd528:db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", - "altStatName": "78ebd528:db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "name": "a236e964:db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "a236e964:db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "type": "EDS", "edsClusterConfig": { "edsConfig": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered.golden new file mode 100644 index 0000000000..aacd258621 --- /dev/null +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered.golden @@ -0,0 +1,116 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "33s", + "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": "db.default.dc3.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "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": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway.golden new file mode 100644 index 0000000000..316e7780ff --- /dev/null +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway.golden @@ -0,0 +1,116 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "33s", + "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": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "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": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered.golden new file mode 100644 index 0000000000..aacd258621 --- /dev/null +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered.golden @@ -0,0 +1,116 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "33s", + "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": "db.default.dc3.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "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": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway.golden new file mode 100644 index 0000000000..316e7780ff --- /dev/null +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway.golden @@ -0,0 +1,116 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "33s", + "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": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "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": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered.golden new file mode 100644 index 0000000000..29d573108f --- /dev/null +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered.golden @@ -0,0 +1,116 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "33s", + "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": "db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "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": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden new file mode 100644 index 0000000000..316e7780ff --- /dev/null +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden @@ -0,0 +1,116 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "33s", + "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": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "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": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered.golden new file mode 100644 index 0000000000..29d573108f --- /dev/null +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered.golden @@ -0,0 +1,116 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "33s", + "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": "db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "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": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden new file mode 100644 index 0000000000..316e7780ff --- /dev/null +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden @@ -0,0 +1,116 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "33s", + "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": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "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": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/connect-proxy-with-chain-and-overrides.golden b/agent/xds/testdata/endpoints/connect-proxy-with-chain-and-overrides.golden index 4388b199eb..ee46d0933a 100644 --- a/agent/xds/testdata/endpoints/connect-proxy-with-chain-and-overrides.golden +++ b/agent/xds/testdata/endpoints/connect-proxy-with-chain-and-overrides.golden @@ -3,7 +3,7 @@ "resources": [ { "@type": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", - "clusterName": "78ebd528:db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "clusterName": "a236e964:db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "endpoints": [ { "lbEndpoints": [ diff --git a/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered.golden b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered.golden new file mode 100644 index 0000000000..5b9210ee92 --- /dev/null +++ b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered.golden @@ -0,0 +1,41 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "clusterName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-local-gateway.golden b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-local-gateway.golden new file mode 100644 index 0000000000..2acef4c0aa --- /dev/null +++ b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-local-gateway.golden @@ -0,0 +1,41 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "clusterName": "db.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 diff --git a/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered.golden b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered.golden new file mode 100644 index 0000000000..26e985cacc --- /dev/null +++ b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered.golden @@ -0,0 +1,41 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "clusterName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "198.38.1.1", + "portValue": 443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "198.38.1.2", + "portValue": 443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway.golden b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway.golden new file mode 100644 index 0000000000..2acef4c0aa --- /dev/null +++ b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway.golden @@ -0,0 +1,41 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "clusterName": "db.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 diff --git a/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered.golden b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered.golden new file mode 100644 index 0000000000..5b9210ee92 --- /dev/null +++ b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered.golden @@ -0,0 +1,41 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "clusterName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden new file mode 100644 index 0000000000..2acef4c0aa --- /dev/null +++ b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden @@ -0,0 +1,41 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "clusterName": "db.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 diff --git a/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered.golden b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered.golden new file mode 100644 index 0000000000..11f798f292 --- /dev/null +++ b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered.golden @@ -0,0 +1,41 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "clusterName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "198.18.1.1", + "portValue": 443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "198.18.1.2", + "portValue": 443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden new file mode 100644 index 0000000000..2acef4c0aa --- /dev/null +++ b/agent/xds/testdata/endpoints/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden @@ -0,0 +1,41 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment", + "clusterName": "db.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 diff --git a/agent/xds/testdata/listeners/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden b/agent/xds/testdata/listeners/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden new file mode 100644 index 0000000000..e83b237dfb --- /dev/null +++ b/agent/xds/testdata/listeners/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden @@ -0,0 +1,116 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Listener", + "name": "db:127.0.0.1:9191", + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 9191 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.tcp_proxy", + "config": { + "cluster": "", + "stat_prefix": "upstream_db_tcp" + } + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Listener", + "name": "prepared_query:geo-cache:127.10.10.10:8181", + "address": { + "socketAddress": { + "address": "127.10.10.10", + "portValue": 8181 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.tcp_proxy", + "config": { + "cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "stat_prefix": "upstream_prepared_query_geo-cache_tcp" + } + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Listener", + "name": "public_listener:0.0.0.0:9999", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 9999 + } + }, + "filterChains": [ + { + "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" + } + } + }, + "requireClientCertificate": true + }, + "filters": [ + { + "name": "envoy.ext_authz", + "config": { + "grpc_service": { + "envoy_grpc": { + "cluster_name": "local_agent" + }, + "initial_metadata": [ + { + "key": "x-consul-token", + "value": "my-token" + } + ] + }, + "stat_prefix": "connect_authz" + } + }, + { + "name": "envoy.tcp_proxy", + "config": { + "cluster": "local_app", + "stat_prefix": "public_listener_tcp" + } + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden b/agent/xds/testdata/listeners/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden new file mode 100644 index 0000000000..e83b237dfb --- /dev/null +++ b/agent/xds/testdata/listeners/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden @@ -0,0 +1,116 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Listener", + "name": "db:127.0.0.1:9191", + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 9191 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.tcp_proxy", + "config": { + "cluster": "", + "stat_prefix": "upstream_db_tcp" + } + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Listener", + "name": "prepared_query:geo-cache:127.10.10.10:8181", + "address": { + "socketAddress": { + "address": "127.10.10.10", + "portValue": 8181 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.tcp_proxy", + "config": { + "cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "stat_prefix": "upstream_prepared_query_geo-cache_tcp" + } + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Listener", + "name": "public_listener:0.0.0.0:9999", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 9999 + } + }, + "filterChains": [ + { + "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" + } + } + }, + "requireClientCertificate": true + }, + "filters": [ + { + "name": "envoy.ext_authz", + "config": { + "grpc_service": { + "envoy_grpc": { + "cluster_name": "local_agent" + }, + "initial_metadata": [ + { + "key": "x-consul-token", + "value": "my-token" + } + ] + }, + "stat_prefix": "connect_authz" + } + }, + { + "name": "envoy.tcp_proxy", + "config": { + "cluster": "local_app", + "stat_prefix": "public_listener_tcp" + } + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/routes/connect-proxy-with-chain-and-overrides.golden b/agent/xds/testdata/routes/connect-proxy-with-chain-and-overrides.golden index 6f7af19589..b07e87e3ad 100644 --- a/agent/xds/testdata/routes/connect-proxy-with-chain-and-overrides.golden +++ b/agent/xds/testdata/routes/connect-proxy-with-chain-and-overrides.golden @@ -16,7 +16,7 @@ "prefix": "/" }, "route": { - "cluster": "78ebd528:db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "cluster": "a236e964:db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } ] diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/bind.hcl b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/bind.hcl new file mode 100644 index 0000000000..f54393f03e --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/bind.hcl @@ -0,0 +1,2 @@ +bind_addr = "0.0.0.0" +advertise_addr = "{{ GetInterfaceIP \"eth0\" }}" \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/capture.sh b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/capture.sh new file mode 100644 index 0000000000..7726004914 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/capture.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +snapshot_envoy_admin localhost:19000 s1 primary || true +snapshot_envoy_admin localhost:19001 s2 primary || true +snapshot_envoy_admin localhost:19002 s2 secondary || true +snapshot_envoy_admin localhost:19003 mesh-gateway secondary || true diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/primary/config_entries.hcl b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/primary/config_entries.hcl new file mode 100644 index 0000000000..89b7c4c1ea --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/primary/config_entries.hcl @@ -0,0 +1,25 @@ +enable_central_service_config = true + +config_entries { + bootstrap { + kind = "service-defaults" + name = "s2" + + protocol = "http" + + mesh_gateway { + mode = "none" + } + } + + bootstrap { + kind = "service-resolver" + name = "s2" + + failover = { + "*" = { + datacenters = ["secondary"] + } + } + } +} diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/primary/setup.sh b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/primary/setup.sh new file mode 100644 index 0000000000..44289c54dc --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/primary/setup.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -eEuo pipefail + +# wait for bootstrap to apply config entries +wait_for_config_entry service-defaults s2 +wait_for_config_entry service-resolver s2 + +# also wait for replication to make it to the remote dc +wait_for_config_entry service-defaults s2 secondary +wait_for_config_entry service-resolver s2 secondary + +gen_envoy_bootstrap s1 19000 primary +gen_envoy_bootstrap s2 19001 primary diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/primary/verify.bats b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/primary/verify.bats new file mode 100644 index 0000000000..9d5c8e60d9 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/primary/verify.bats @@ -0,0 +1,72 @@ +#!/usr/bin/env bats + +load helpers + +@test "s1 proxy is running correct version" { + assert_envoy_version 19000 +} + +@test "s1 proxy admin is up on :19000" { + retry_default curl -f -s localhost:19000/stats -o /dev/null +} + +@test "s2 proxy admin is up on :19001" { + retry_default curl -f -s localhost:19001/stats -o /dev/null +} + +@test "s1 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21000 s1 +} + +@test "s2 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21001 s2 +} + +@test "s2 proxies should be healthy in primary" { + assert_service_has_healthy_instances s2 1 primary +} + +@test "s2 proxies should be healthy in secondary" { + assert_service_has_healthy_instances s2 1 secondary +} + +################ +# PHASE 1: we show that by default requests are served from the primary + +# Note: when failover is configured the cluster is named for the original +# service not any destination related to failover. +@test "s1 upstream should have healthy endpoints for s2 in both primary and failover" { + assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.primary HEALTHY 2 +} + +@test "s1 upstream should be able to connect to s2 via upstream s2 to start" { + assert_expected_fortio_name s2 +} + +@test "s1 upstream made 1 connection" { + assert_envoy_metric 127.0.0.1:19000 "cluster.s2.default.primary.*cx_total" 1 +} + +################ +# PHASE 2: we show that in failover requests are served from the secondary +# +@test "terminate instance of s2 primary envoy which should trigger failover to s2 secondary when tcp check fails" { + kill_envoy s2 primary +} + +@test "s2 proxies should be unhealthy in primary" { + assert_service_has_healthy_instances s2 0 primary +} + +@test "s1 upstream should have healthy endpoints for s2 secondary and unhealthy endpoints for s2 primary" { + assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.primary HEALTHY 1 + assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.primary UNHEALTHY 1 +} + +@test "s1 upstream should be able to connect to s2 in secondary now" { + assert_expected_fortio_name s2-secondary +} + +@test "s1 upstream made 2 connections" { + assert_envoy_metric 127.0.0.1:19000 "cluster.s2.default.primary.*cx_total" 2 +} diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/gateway.hcl b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/gateway.hcl new file mode 100644 index 0000000000..55f03ac050 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/gateway.hcl @@ -0,0 +1,5 @@ +services { + name = "mesh-gateway" + kind = "mesh-gateway" + port = 4432 +} \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/join.hcl b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/join.hcl new file mode 100644 index 0000000000..fb1307d62a --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/join.hcl @@ -0,0 +1 @@ +retry_join_wan = ["consul-primary"] \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/s1.hcl b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/s1.hcl new file mode 100644 index 0000000000..eff93eb6b5 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/s1.hcl @@ -0,0 +1 @@ +# we don't want an s1 service in the secondary dc \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/setup.sh b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/setup.sh new file mode 100644 index 0000000000..a3d6260210 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/setup.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -eEuo pipefail + +# wait for bootstrap to apply config entries +wait_for_config_entry service-defaults s2 secondary +wait_for_config_entry service-resolver s2 secondary + +gen_envoy_bootstrap s2 19002 secondary +gen_envoy_bootstrap mesh-gateway 19003 secondary true +retry_default docker_consul secondary curl -s "http://localhost:8500/v1/catalog/service/consul?dc=primary" >/dev/null diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/verify.bats b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/verify.bats new file mode 100644 index 0000000000..e6b28cfc9b --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/secondary/verify.bats @@ -0,0 +1,27 @@ +#!/usr/bin/env bats + +load helpers + +@test "s2 proxy is running correct version" { + assert_envoy_version 19002 +} + +@test "s2 proxy admin is up on :19002" { + retry_default curl -f -s localhost:19002/stats -o /dev/null +} + +@test "gateway-secondary proxy admin is up on :19003" { + retry_default curl -f -s localhost:19003/stats -o /dev/null +} + +@test "s2 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21000 s2 secondary +} + +@test "s2 proxy should be healthy" { + assert_service_has_healthy_instances s2 1 secondary +} + +@test "gateway-secondary is NOT used for the upstream connection" { + assert_envoy_metric 127.0.0.1:19003 "cluster.s2.default.secondary.*cx_total" 0 +} diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/vars.sh b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/vars.sh new file mode 100644 index 0000000000..1e2ad55da9 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-none/vars.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +export REQUIRED_SERVICES=" +s1 s1-sidecar-proxy +s2 s2-sidecar-proxy +s2-secondary s2-sidecar-proxy-secondary +gateway-secondary +" +export REQUIRE_SECONDARY=1 diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/bind.hcl b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/bind.hcl new file mode 100644 index 0000000000..f54393f03e --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/bind.hcl @@ -0,0 +1,2 @@ +bind_addr = "0.0.0.0" +advertise_addr = "{{ GetInterfaceIP \"eth0\" }}" \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/capture.sh b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/capture.sh new file mode 100644 index 0000000000..7726004914 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/capture.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +snapshot_envoy_admin localhost:19000 s1 primary || true +snapshot_envoy_admin localhost:19001 s2 primary || true +snapshot_envoy_admin localhost:19002 s2 secondary || true +snapshot_envoy_admin localhost:19003 mesh-gateway secondary || true diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/primary/config_entries.hcl b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/primary/config_entries.hcl new file mode 100644 index 0000000000..9f0653fc77 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/primary/config_entries.hcl @@ -0,0 +1,25 @@ +enable_central_service_config = true + +config_entries { + bootstrap { + kind = "service-defaults" + name = "s2" + + protocol = "http" + + mesh_gateway { + mode = "remote" + } + } + + bootstrap { + kind = "service-resolver" + name = "s2" + + failover = { + "*" = { + datacenters = ["secondary"] + } + } + } +} diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/primary/setup.sh b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/primary/setup.sh new file mode 100644 index 0000000000..44289c54dc --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/primary/setup.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -eEuo pipefail + +# wait for bootstrap to apply config entries +wait_for_config_entry service-defaults s2 +wait_for_config_entry service-resolver s2 + +# also wait for replication to make it to the remote dc +wait_for_config_entry service-defaults s2 secondary +wait_for_config_entry service-resolver s2 secondary + +gen_envoy_bootstrap s1 19000 primary +gen_envoy_bootstrap s2 19001 primary diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/primary/verify.bats b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/primary/verify.bats new file mode 100644 index 0000000000..db99c8ddf8 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/primary/verify.bats @@ -0,0 +1,75 @@ +#!/usr/bin/env bats + +load helpers + +@test "s1 proxy is running correct version" { + assert_envoy_version 19000 +} + +@test "s1 proxy admin is up on :19000" { + retry_default curl -f -s localhost:19000/stats -o /dev/null +} + +@test "s2 proxy admin is up on :19001" { + retry_default curl -f -s localhost:19001/stats -o /dev/null +} + +@test "s1 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21000 s1 +} + +@test "s2 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21001 s2 +} + +@test "s2 proxies should be healthy in primary" { + assert_service_has_healthy_instances s2 1 primary +} + +@test "s2 proxies should be healthy in secondary" { + assert_service_has_healthy_instances s2 1 secondary +} + +################ +# PHASE 1: we show that by default requests are served from the primary + +# Note: when failover is configured the cluster is named for the original +# service not any destination related to failover. +@test "s1 upstream should have healthy endpoints for s2 in both primary and failover" { + # in mesh gateway remote or local mode only the current leg of failover manifests in the load assignments + assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.primary HEALTHY 1 + assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.primary UNHEALTHY 0 +} + +@test "s1 upstream should be able to connect to s2 via upstream s2 to start" { + assert_expected_fortio_name s2 +} + +@test "s1 upstream made 1 connection" { + assert_envoy_metric 127.0.0.1:19000 "cluster.s2.default.primary.*cx_total" 1 +} + +################ +# PHASE 2: we show that in failover requests are served from the secondary +# +@test "terminate instance of s2 primary envoy which should trigger failover to s2 secondary when tcp check fails" { + kill_envoy s2 primary +} + +@test "s2 proxies should be unhealthy in primary" { + assert_service_has_healthy_instances s2 0 primary +} + +@test "s1 upstream should have healthy endpoints for s2 secondary" { + # in mesh gateway remote or local mode only the current leg of failover manifests in the load assignments + assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.primary HEALTHY 1 + assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.primary UNHEALTHY 0 +} + +@test "s1 upstream should be able to connect to s2 in secondary now" { + assert_expected_fortio_name s2-secondary +} + +@test "s1 upstream made 2 connections" { + assert_envoy_metric 127.0.0.1:19000 "cluster.s2.default.primary.*cx_total" 2 +} diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/gateway.hcl b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/gateway.hcl new file mode 100644 index 0000000000..55f03ac050 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/gateway.hcl @@ -0,0 +1,5 @@ +services { + name = "mesh-gateway" + kind = "mesh-gateway" + port = 4432 +} \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/join.hcl b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/join.hcl new file mode 100644 index 0000000000..fb1307d62a --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/join.hcl @@ -0,0 +1 @@ +retry_join_wan = ["consul-primary"] \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/s1.hcl b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/s1.hcl new file mode 100644 index 0000000000..eff93eb6b5 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/s1.hcl @@ -0,0 +1 @@ +# we don't want an s1 service in the secondary dc \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/setup.sh b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/setup.sh new file mode 100644 index 0000000000..a3d6260210 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/setup.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -eEuo pipefail + +# wait for bootstrap to apply config entries +wait_for_config_entry service-defaults s2 secondary +wait_for_config_entry service-resolver s2 secondary + +gen_envoy_bootstrap s2 19002 secondary +gen_envoy_bootstrap mesh-gateway 19003 secondary true +retry_default docker_consul secondary curl -s "http://localhost:8500/v1/catalog/service/consul?dc=primary" >/dev/null diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/verify.bats b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/verify.bats new file mode 100644 index 0000000000..8bd0a91b6f --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/secondary/verify.bats @@ -0,0 +1,27 @@ +#!/usr/bin/env bats + +load helpers + +@test "s2 proxy is running correct version" { + assert_envoy_version 19002 +} + +@test "s2 proxy admin is up on :19002" { + retry_default curl -f -s localhost:19002/stats -o /dev/null +} + +@test "gateway-secondary proxy admin is up on :19003" { + retry_default curl -f -s localhost:19003/stats -o /dev/null +} + +@test "s2 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21000 s2 secondary +} + +@test "s2 proxy should be healthy" { + assert_service_has_healthy_instances s2 1 secondary +} + +@test "gateway-secondary is used for the upstream connection" { + assert_envoy_metric 127.0.0.1:19003 "cluster.s2.default.secondary.*cx_total" 1 +} diff --git a/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/vars.sh b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/vars.sh new file mode 100644 index 0000000000..1e2ad55da9 --- /dev/null +++ b/test/integration/connect/envoy/case-cfg-resolver-dc-failover-gateways-remote/vars.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +export REQUIRED_SERVICES=" +s1 s1-sidecar-proxy +s2 s2-sidecar-proxy +s2-secondary s2-sidecar-proxy-secondary +gateway-secondary +" +export REQUIRE_SECONDARY=1 diff --git a/test/integration/connect/envoy/case-gateways-local/secondary/verify.bats b/test/integration/connect/envoy/case-gateways-local/secondary/verify.bats index 1c8260888b..b4f92b07a7 100644 --- a/test/integration/connect/envoy/case-gateways-local/secondary/verify.bats +++ b/test/integration/connect/envoy/case-gateways-local/secondary/verify.bats @@ -19,9 +19,9 @@ load helpers } @test "s2 proxy should be healthy" { - assert_service_has_healthy_instances s2 1 + assert_service_has_healthy_instances s2 1 secondary } @test "gateway-secondary is used for the upstream connection" { assert_envoy_metric 127.0.0.1:19003 "cluster.s2.default.secondary.*cx_total" 1 -} \ No newline at end of file +} diff --git a/test/integration/connect/envoy/case-gateways-remote/secondary/verify.bats b/test/integration/connect/envoy/case-gateways-remote/secondary/verify.bats index 1c8260888b..b4f92b07a7 100644 --- a/test/integration/connect/envoy/case-gateways-remote/secondary/verify.bats +++ b/test/integration/connect/envoy/case-gateways-remote/secondary/verify.bats @@ -19,9 +19,9 @@ load helpers } @test "s2 proxy should be healthy" { - assert_service_has_healthy_instances s2 1 + assert_service_has_healthy_instances s2 1 secondary } @test "gateway-secondary is used for the upstream connection" { assert_envoy_metric 127.0.0.1:19003 "cluster.s2.default.secondary.*cx_total" 1 -} \ No newline at end of file +} diff --git a/test/integration/connect/envoy/docker-compose.yml b/test/integration/connect/envoy/docker-compose.yml index 0de22df129..635827c627 100644 --- a/test/integration/connect/envoy/docker-compose.yml +++ b/test/integration/connect/envoy/docker-compose.yml @@ -413,7 +413,7 @@ services: - consul-secondary image: "fortio/fortio" environment: - - "FORTIO_NAME=s1" + - "FORTIO_NAME=s1-secondary" command: - "server" - "-http-port" @@ -429,7 +429,7 @@ services: - consul-secondary image: "fortio/fortio" environment: - - "FORTIO_NAME=s2" + - "FORTIO_NAME=s2-secondary" command: - "server" - "-http-port" @@ -556,4 +556,4 @@ services: volumes: - *workdir-volume network_mode: service:consul-secondary - pid: host \ No newline at end of file + pid: host diff --git a/test/integration/connect/envoy/helpers.bash b/test/integration/connect/envoy/helpers.bash index a69e119974..44bf1a237a 100755 --- a/test/integration/connect/envoy/helpers.bash +++ b/test/integration/connect/envoy/helpers.bash @@ -246,7 +246,8 @@ function assert_envoy_metric { function get_healthy_service_count { local SERVICE_NAME=$1 - run retry_default curl -s -f 127.0.0.1:8500/v1/health/connect/${SERVICE_NAME}?passing + local DC=$2 + run retry_default curl -s -f "127.0.0.1:8500/v1/health/connect/${SERVICE_NAME}?dc=${DC}&passing" [ "$status" -eq 0 ] echo "$output" | jq --raw-output '. | length' } @@ -254,8 +255,9 @@ function get_healthy_service_count { function assert_service_has_healthy_instances_once { local SERVICE_NAME=$1 local EXPECT_COUNT=$2 + local DC=${3:-primary} - GOT_COUNT=$(get_healthy_service_count $SERVICE_NAME) + GOT_COUNT=$(get_healthy_service_count $SERVICE_NAME $DC) [ "$GOT_COUNT" -eq $EXPECT_COUNT ] } @@ -263,8 +265,9 @@ function assert_service_has_healthy_instances_once { function assert_service_has_healthy_instances { local SERVICE_NAME=$1 local EXPECT_COUNT=$2 + local DC=${3:-primary} - run retry_long assert_service_has_healthy_instances_once $SERVICE_NAME $EXPECT_COUNT + run retry_long assert_service_has_healthy_instances_once $SERVICE_NAME $EXPECT_COUNT $DC [ "$status" -eq 0 ] } @@ -444,7 +447,9 @@ function assert_expected_fortio_name { local EXPECT_NAME=$1 GOT=$(get_upstream_fortio_name) - echo "GOT $GOT" - [ "$GOT" == "FORTIO_NAME=${EXPECT_NAME}" ] + if [ "$GOT" != "FORTIO_NAME=${EXPECT_NAME}" ]; then + echo "expected name: $EXPECT_NAME, actual name: $GOT" 1>&2 + return 1 + fi }