From d4e80b880023516e1a35fdece003b6b5b2eba01f Mon Sep 17 00:00:00 2001 From: "R.B. Boyer" <4903+rboyer@users.noreply.github.com> Date: Wed, 30 Mar 2022 10:04:18 -0500 Subject: [PATCH] server: ensure that service-defaults meta is incorporated into the discovery chain response (#12511) Also add a new "Default" field to the discovery chain response to clients --- .changelog/12511.txt | 7 + agent/consul/discovery_chain_endpoint_test.go | 8 +- agent/consul/discoverychain/compile.go | 44 ++++++ agent/consul/discoverychain/compile_test.go | 139 +++++++++++++++--- agent/discovery_chain_endpoint_test.go | 6 +- agent/proxycfg/testing_connect_proxy.go | 2 +- agent/proxycfg/testing_ingress_gateway.go | 8 +- agent/structs/discovery_chain.go | 35 +---- agent/xds/clusters.go | 2 +- agent/xds/endpoints.go | 2 +- agent/xds/listeners.go | 4 +- agent/xds/listeners_ingress.go | 2 +- agent/xds/routes.go | 2 +- api/discovery_chain.go | 8 + api/discovery_chain_test.go | 2 + .../connect/l7-traffic/discovery-chain.mdx | 6 + 16 files changed, 214 insertions(+), 63 deletions(-) create mode 100644 .changelog/12511.txt diff --git a/.changelog/12511.txt b/.changelog/12511.txt new file mode 100644 index 000000000..a7ba31633 --- /dev/null +++ b/.changelog/12511.txt @@ -0,0 +1,7 @@ +```release-note:feature +server: ensure that service-defaults meta is incorporated into the discovery chain response +``` + +```release-note:feature +server: discovery chains now include a response field named "Default" to indicate if they were not constructed from any service-resolver, service-splitter, or service-router config entries +``` diff --git a/agent/consul/discovery_chain_endpoint_test.go b/agent/consul/discovery_chain_endpoint_test.go index 174cab742..e875ec25d 100644 --- a/agent/consul/discovery_chain_endpoint_test.go +++ b/agent/consul/discovery_chain_endpoint_test.go @@ -98,6 +98,7 @@ func TestDiscoveryChainEndpoint_Get(t *testing.T) { Datacenter: "dc1", Protocol: "tcp", StartNode: "resolver:web.default.default.dc1", + Default: true, Nodes: map[string]*structs.DiscoveryGraphNode{ "resolver:web.default.default.dc1": { Type: structs.DiscoveryGraphNodeTypeResolver, @@ -286,12 +287,7 @@ func TestDiscoveryChainEndpoint_Get_BlockOnNoChange(t *testing.T) { args.QueryOptions.MinQueryIndex = minQueryIndex var out structs.DiscoveryChainResponse - errCh := channelCallRPC(s1, "DiscoveryChain.Get", &args, &out, func() error { - if !out.Chain.IsDefault() { - return fmt.Errorf("expected default chain") - } - return nil - }) + errCh := channelCallRPC(s1, "DiscoveryChain.Get", &args, &out, nil) return &out.QueryMeta, errCh }, func(i int) <-chan error { diff --git a/agent/consul/discoverychain/compile.go b/agent/consul/discoverychain/compile.go index 4f78eb8bf..0567b8b90 100644 --- a/agent/consul/discoverychain/compile.go +++ b/agent/consul/discoverychain/compile.go @@ -161,6 +161,12 @@ type compiler struct { // This is an OUTPUT field. protocol string + // serviceMeta is the Meta field from the service-defaults entry that + // shares a name with this discovery chain. + // + // This is an OUTPUT field. + serviceMeta map[string]string + // startNode is computed inside of assembleChain() // // This is an OUTPUT field. @@ -327,14 +333,47 @@ func (c *compiler) compile() (*structs.CompiledDiscoveryChain, error) { Namespace: c.evaluateInNamespace, Partition: c.evaluateInPartition, Datacenter: c.evaluateInDatacenter, + Default: c.determineIfDefaultChain(), CustomizationHash: customizationHash, Protocol: c.protocol, + ServiceMeta: c.serviceMeta, StartNode: c.startNode, Nodes: c.nodes, Targets: c.loadedTargets, }, nil } +// determineIfDefaultChain 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 applied is redirection to another resolver that is +// default, so we double check the resolver matches the requested resolver. +// +// NOTE: "default chain" mostly means that this is compatible with how things +// worked (roughly) in consul 1.5 pre-discovery chain, not that there are zero +// config entries in play (like service-defaults). +func (c *compiler) determineIfDefaultChain() bool { + if c.startNode == "" || len(c.nodes) == 0 { + return true + } + + node := c.nodes[c.startNode] + if node == nil { + panic("not possible: missing node named '" + c.startNode + "' in chain '" + c.serviceName + "'") + } + + if node.Type != structs.DiscoveryGraphNodeTypeResolver { + return false + } + if !node.Resolver.Default { + return false + } + + target := c.loadedTargets[node.Resolver.Target] + + return target.Service == c.serviceName && target.Namespace == c.evaluateInNamespace && target.Partition == c.evaluateInPartition +} + func (c *compiler) detectCircularReferences() error { var ( todo stringStack @@ -515,6 +554,11 @@ func (c *compiler) assembleChain() error { sid := structs.NewServiceID(c.serviceName, c.GetEnterpriseMeta()) + // Extract the service meta for the service named by this discovery chain. + if serviceDefault := c.entries.GetService(sid); serviceDefault != nil { + c.serviceMeta = serviceDefault.GetMeta() + } + // Check for short circuit path. if len(c.resolvers) == 0 && c.entries.IsChainEmpty() { // Materialize defaults and cache. diff --git a/agent/consul/discoverychain/compile_test.go b/agent/consul/discoverychain/compile_test.go index 94029465e..9a3dde647 100644 --- a/agent/consul/discoverychain/compile_test.go +++ b/agent/consul/discoverychain/compile_test.go @@ -12,14 +12,12 @@ import ( ) type compileTestCase struct { - entries *configentry.DiscoveryChainSet - setup func(req *CompileRequest) - expect *structs.CompiledDiscoveryChain - // expectIsDefault tests behavior of CompiledDiscoveryChain.IsDefault() - expectIsDefault bool - expectCustom bool - expectErr string - expectGraphErr bool + entries *configentry.DiscoveryChainSet + setup func(req *CompileRequest) + expect *structs.CompiledDiscoveryChain + expectCustom bool + expectErr string + expectGraphErr bool } func TestCompile(t *testing.T) { @@ -56,6 +54,8 @@ func TestCompile(t *testing.T) { "loadbalancer splitter and resolver": testcase_LBSplitterAndResolver(), "loadbalancer resolver": testcase_LBResolver(), "service redirect to service with default resolver is not a default chain": testcase_RedirectToDefaultResolverIsNotDefaultChain(), + "service meta projection": testcase_ServiceMetaProjection(), + "service meta projection with redirect": testcase_ServiceMetaProjectionWithRedirect(), "all the bells and whistles": testcase_AllBellsAndWhistles(), "multi dc canary": testcase_MultiDatacenterCanary(), @@ -141,7 +141,6 @@ func TestCompile(t *testing.T) { } require.Equal(t, tc.expect, res) - require.Equal(t, tc.expectIsDefault, res.IsDefault()) } }) } @@ -1429,6 +1428,7 @@ func testcase_DefaultResolver() compileTestCase { expect := &structs.CompiledDiscoveryChain{ Protocol: "tcp", + Default: true, StartNode: "resolver:main.default.default.dc1", Nodes: map[string]*structs.DiscoveryGraphNode{ "resolver:main.default.default.dc1": { @@ -1446,7 +1446,7 @@ func testcase_DefaultResolver() compileTestCase { "main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil), }, } - return compileTestCase{entries: entries, expect: expect, expectIsDefault: true} + return compileTestCase{entries: entries, expect: expect} } func testcase_DefaultResolver_WithProxyDefaults() compileTestCase { @@ -1465,6 +1465,7 @@ func testcase_DefaultResolver_WithProxyDefaults() compileTestCase { expect := &structs.CompiledDiscoveryChain{ Protocol: "grpc", + Default: true, StartNode: "resolver:main.default.default.dc1", Nodes: map[string]*structs.DiscoveryGraphNode{ "resolver:main.default.default.dc1": { @@ -1485,11 +1486,69 @@ func testcase_DefaultResolver_WithProxyDefaults() compileTestCase { }), }, } - return compileTestCase{entries: entries, expect: expect, expectIsDefault: true} + return compileTestCase{entries: entries, expect: expect} } -func testcase_RedirectToDefaultResolverIsNotDefaultChain() compileTestCase { +func testcase_ServiceMetaProjection() compileTestCase { entries := newEntries() + entries.AddServices( + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "main", + Meta: map[string]string{ + "foo": "bar", + "abc": "123", + }, + }, + ) + expect := &structs.CompiledDiscoveryChain{ + Protocol: "tcp", + Default: true, + ServiceMeta: map[string]string{ + "foo": "bar", + "abc": "123", + }, + StartNode: "resolver:main.default.default.dc1", + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:main.default.default.dc1": { + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "main.default.default.dc1", + Resolver: &structs.DiscoveryResolver{ + Default: true, + ConnectTimeout: 5 * time.Second, + Target: "main.default.default.dc1", + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil), + }, + } + + return compileTestCase{entries: entries, expect: expect} +} + +func testcase_ServiceMetaProjectionWithRedirect() compileTestCase { + entries := newEntries() + entries.AddServices( + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "main", + Meta: map[string]string{ + "foo": "bar", + "abc": "123", + }, + }, + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "other", + Meta: map[string]string{ + "zim": "gir", + "abc": "456", + "xyz": "999", + }, + }, + ) entries.AddResolvers( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, @@ -1501,7 +1560,12 @@ func testcase_RedirectToDefaultResolverIsNotDefaultChain() compileTestCase { ) expect := &structs.CompiledDiscoveryChain{ - Protocol: "tcp", + Protocol: "tcp", + ServiceMeta: map[string]string{ + // Note this is main's meta, not other's. + "foo": "bar", + "abc": "123", + }, StartNode: "resolver:other.default.default.dc1", Nodes: map[string]*structs.DiscoveryGraphNode{ "resolver:other.default.default.dc1": { @@ -1519,7 +1583,42 @@ func testcase_RedirectToDefaultResolverIsNotDefaultChain() compileTestCase { }, } - return compileTestCase{entries: entries, expect: expect, expectIsDefault: false /*being explicit here because this is the whole point of this test*/} + return compileTestCase{entries: entries, expect: expect} +} + +func testcase_RedirectToDefaultResolverIsNotDefaultChain() compileTestCase { + entries := newEntries() + entries.AddResolvers( + &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: "main", + Redirect: &structs.ServiceResolverRedirect{ + Service: "other", + }, + }, + ) + + expect := &structs.CompiledDiscoveryChain{ + Protocol: "tcp", + StartNode: "resolver:other.default.default.dc1", + Default: false, /*being explicit here because this is the whole point of this test*/ + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:other.default.default.dc1": { + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "other.default.default.dc1", + Resolver: &structs.DiscoveryResolver{ + Default: true, + ConnectTimeout: 5 * time.Second, + Target: "other.default.default.dc1", + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "other.default.default.dc1": newTarget("other", "", "default", "default", "dc1", nil), + }, + } + + return compileTestCase{entries: entries, expect: expect} } func testcase_Resolve_WithDefaultSubset() compileTestCase { @@ -1570,6 +1669,7 @@ func testcase_DefaultResolver_ExternalSNI() compileTestCase { expect := &structs.CompiledDiscoveryChain{ Protocol: "tcp", + Default: true, StartNode: "resolver:main.default.default.dc1", Nodes: map[string]*structs.DiscoveryGraphNode{ "resolver:main.default.default.dc1": { @@ -1589,7 +1689,7 @@ func testcase_DefaultResolver_ExternalSNI() compileTestCase { }), }, } - return compileTestCase{entries: entries, expect: expect, expectIsDefault: true} + return compileTestCase{entries: entries, expect: expect} } func testcase_Resolver_ExternalSNI_FailoverNotAllowed() compileTestCase { @@ -2249,6 +2349,7 @@ func testcase_ResolverProtocolOverride() compileTestCase { expect := &structs.CompiledDiscoveryChain{ Protocol: "http2", + Default: true, StartNode: "resolver:main.default.default.dc1", Nodes: map[string]*structs.DiscoveryGraphNode{ "resolver:main.default.default.dc1": { @@ -2266,7 +2367,7 @@ func testcase_ResolverProtocolOverride() compileTestCase { "main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil), }, } - return compileTestCase{entries: entries, expect: expect, expectIsDefault: true, + return compileTestCase{entries: entries, expect: expect, expectCustom: true, setup: func(req *CompileRequest) { req.OverrideProtocol = "http2" @@ -2282,6 +2383,7 @@ func testcase_ResolverProtocolOverrideIgnored() compileTestCase { expect := &structs.CompiledDiscoveryChain{ Protocol: "http2", + Default: true, StartNode: "resolver:main.default.default.dc1", Nodes: map[string]*structs.DiscoveryGraphNode{ "resolver:main.default.default.dc1": { @@ -2299,7 +2401,7 @@ func testcase_ResolverProtocolOverrideIgnored() compileTestCase { "main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil), }, } - return compileTestCase{entries: entries, expect: expect, expectIsDefault: true, + return compileTestCase{entries: entries, expect: expect, setup: func(req *CompileRequest) { req.OverrideProtocol = "http2" }, @@ -2320,6 +2422,7 @@ func testcase_RouterIgnored_ResolverProtocolOverride() compileTestCase { expect := &structs.CompiledDiscoveryChain{ Protocol: "tcp", StartNode: "resolver:main.default.default.dc1", + Default: true, Nodes: map[string]*structs.DiscoveryGraphNode{ "resolver:main.default.default.dc1": { Type: structs.DiscoveryGraphNodeTypeResolver, @@ -2336,7 +2439,7 @@ func testcase_RouterIgnored_ResolverProtocolOverride() compileTestCase { "main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil), }, } - return compileTestCase{entries: entries, expect: expect, expectIsDefault: true, + return compileTestCase{entries: entries, expect: expect, expectCustom: true, setup: func(req *CompileRequest) { req.OverrideProtocol = "tcp" diff --git a/agent/discovery_chain_endpoint_test.go b/agent/discovery_chain_endpoint_test.go index 78fcfe303..3db87ba52 100644 --- a/agent/discovery_chain_endpoint_test.go +++ b/agent/discovery_chain_endpoint_test.go @@ -8,11 +8,12 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/hashicorp/consul/testrpc" - "github.com/stretchr/testify/require" ) func TestDiscoveryChainRead(t *testing.T) { @@ -79,6 +80,7 @@ func TestDiscoveryChainRead(t *testing.T) { Partition: "default", Datacenter: "dc1", Protocol: "tcp", + Default: true, StartNode: "resolver:web.default.default.dc1", Nodes: map[string]*structs.DiscoveryGraphNode{ "resolver:web.default.default.dc1": { @@ -122,6 +124,7 @@ func TestDiscoveryChainRead(t *testing.T) { Namespace: "default", Partition: "default", Datacenter: "dc2", + Default: true, Protocol: "tcp", StartNode: "resolver:web.default.default.dc2", Nodes: map[string]*structs.DiscoveryGraphNode{ @@ -175,6 +178,7 @@ func TestDiscoveryChainRead(t *testing.T) { Namespace: "default", Partition: "default", Datacenter: "dc1", + Default: true, Protocol: "tcp", StartNode: "resolver:web.default.default.dc1", Nodes: map[string]*structs.DiscoveryGraphNode{ diff --git a/agent/proxycfg/testing_connect_proxy.go b/agent/proxycfg/testing_connect_proxy.go index b23f02585..35a8e6011 100644 --- a/agent/proxycfg/testing_connect_proxy.go +++ b/agent/proxycfg/testing_connect_proxy.go @@ -16,7 +16,7 @@ func TestConfigSnapshot(t testing.T, nsFn func(ns *structs.NodeService), extraUp // no entries implies we'll get a default chain dbChain := discoverychain.TestCompileConfigEntries(t, "db", "default", "default", "dc1", connect.TestClusterID+".consul", nil) - assert.True(t, dbChain.IsDefault()) + assert.True(t, dbChain.Default) var ( upstreams = structs.TestUpstreams(t) diff --git a/agent/proxycfg/testing_ingress_gateway.go b/agent/proxycfg/testing_ingress_gateway.go index c3360fd96..7686993ba 100644 --- a/agent/proxycfg/testing_ingress_gateway.go +++ b/agent/proxycfg/testing_ingress_gateway.go @@ -685,10 +685,10 @@ func TestConfigSnapshotIngress_HTTPMultipleServices(t testing.T) *ConfigSnapshot quxChain = discoverychain.TestCompileConfigEntries(t, "qux", "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...) ) - require.False(t, fooChain.IsDefault()) - require.False(t, barChain.IsDefault()) - require.True(t, bazChain.IsDefault()) - require.True(t, quxChain.IsDefault()) + require.False(t, fooChain.Default) + require.False(t, barChain.Default) + require.True(t, bazChain.Default) + require.True(t, quxChain.Default) return TestConfigSnapshotIngressGateway(t, false, "http", "default", nil, func(entry *structs.IngressGatewayConfigEntry) { entry.Listeners = []structs.IngressListener{ diff --git a/agent/structs/discovery_chain.go b/agent/structs/discovery_chain.go index 86c24515d..0dd3010e7 100644 --- a/agent/structs/discovery_chain.go +++ b/agent/structs/discovery_chain.go @@ -26,9 +26,17 @@ type CompiledDiscoveryChain struct { // non-customized versions. CustomizationHash string `json:",omitempty"` + // Default indicates if this discovery chain is based on no + // service-resolver, service-splitter, or service-router config entries. + Default bool `json:",omitempty"` + // Protocol is the overall protocol shared by everything in the chain. Protocol string `json:",omitempty"` + // ServiceMeta is the metadata from the underlying service-defaults config + // entry for the service named ServiceName. + ServiceMeta map[string]string `json:",omitempty"` + // StartNode is the first key into the Nodes map that should be followed // when walking the discovery chain. StartNode string `json:",omitempty"` @@ -62,33 +70,6 @@ func (c *CompiledDiscoveryChain) WillFailoverThroughMeshGateway(node *DiscoveryG 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 -// applied is redirection to another resolver that is default, so we double -// check the resolver matches the requested resolver. -func (c *CompiledDiscoveryChain) IsDefault() bool { - if c.StartNode == "" || len(c.Nodes) == 0 { - return true - } - - node := c.Nodes[c.StartNode] - if node == nil { - panic("not possible: missing node named '" + c.StartNode + "' in chain '" + c.ServiceName + "'") - } - - if node.Type != DiscoveryGraphNodeTypeResolver { - return false - } - if !node.Resolver.Default { - return false - } - - target := c.Targets[node.Resolver.Target] - - return target.Service == c.ServiceName && target.Namespace == c.Namespace && target.Partition == c.Partition -} - // ID returns an ID that encodes the service, namespace, partition, and datacenter. // This ID allows us to compare a discovery chain target to the chain upstream itself. func (c *CompiledDiscoveryChain) ID() string { diff --git a/agent/xds/clusters.go b/agent/xds/clusters.go index 283df4125..716c320d3 100644 --- a/agent/xds/clusters.go +++ b/agent/xds/clusters.go @@ -612,7 +612,7 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( var escapeHatchCluster *envoy_cluster_v3.Cluster if cfg.EnvoyClusterJSON != "" { - if chain.IsDefault() { + if chain.Default { // If you haven't done anything to setup the discovery chain, then // you can use the envoy_cluster_json escape hatch. escapeHatchCluster, err = makeClusterFromUserConfig(cfg.EnvoyClusterJSON) diff --git a/agent/xds/endpoints.go b/agent/xds/endpoints.go index 9981dc940..b1a38f0cd 100644 --- a/agent/xds/endpoints.go +++ b/agent/xds/endpoints.go @@ -393,7 +393,7 @@ func (s *ResourceGenerator) endpointsFromDiscoveryChain( var escapeHatchCluster *envoy_cluster_v3.Cluster if cfg.EnvoyClusterJSON != "" { - if chain.IsDefault() { + if chain.Default { // If you haven't done anything to setup the discovery chain, then // you can use the envoy_cluster_json escape hatch. escapeHatchCluster, err = makeClusterFromUserConfig(cfg.EnvoyClusterJSON) diff --git a/agent/xds/listeners.go b/agent/xds/listeners.go index 68ab9c1bf..2a671c40d 100644 --- a/agent/xds/listeners.go +++ b/agent/xds/listeners.go @@ -115,7 +115,7 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg. } // RDS, Envoy's Route Discovery Service, is only used for HTTP services with a customized discovery chain. - useRDS := chain.Protocol != "tcp" && !chain.IsDefault() + useRDS := chain.Protocol != "tcp" && !chain.Default var clusterName string if !useRDS { @@ -1303,7 +1303,7 @@ func (s *ResourceGenerator) getAndModifyUpstreamConfigForListener( if u != nil { configMap = u.Config } - if chain == nil || chain.IsDefault() { + if chain == nil || chain.Default { cfg, err = structs.ParseUpstreamConfigNoDefaults(configMap) if err != nil { // Don't hard fail on a config typo, just warn. The parse func returns diff --git a/agent/xds/listeners_ingress.go b/agent/xds/listeners_ingress.go index 3ab7de3c0..cd2023d2b 100644 --- a/agent/xds/listeners_ingress.go +++ b/agent/xds/listeners_ingress.go @@ -48,7 +48,7 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap // RDS, Envoy's Route Discovery Service, is only used for HTTP services with a customized discovery chain. // TODO(freddy): Why can the protocol of the listener be overridden here? - useRDS := cfg.Protocol != "tcp" && !chain.IsDefault() + useRDS := cfg.Protocol != "tcp" && !chain.Default var clusterName string if !useRDS { diff --git a/agent/xds/routes.go b/agent/xds/routes.go index e6ed55df8..0a772d3f5 100644 --- a/agent/xds/routes.go +++ b/agent/xds/routes.go @@ -45,7 +45,7 @@ func (s *ResourceGenerator) routesFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot) func (s *ResourceGenerator) routesForConnectProxy(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) { var resources []proto.Message for uid, chain := range cfgSnap.ConnectProxy.DiscoveryChain { - if chain.IsDefault() { + if chain.Default { continue } diff --git a/api/discovery_chain.go b/api/discovery_chain.go index 29bda8591..d198b2bb5 100644 --- a/api/discovery_chain.go +++ b/api/discovery_chain.go @@ -109,9 +109,17 @@ type CompiledDiscoveryChain struct { // non-customized versions. CustomizationHash string + // Default indicates if this discovery chain is based on no + // service-resolver, service-splitter, or service-router config entries. + Default bool + // Protocol is the overall protocol shared by everything in the chain. Protocol string + // ServiceMeta is the metadata from the underlying service-defaults config + // entry for the service named ServiceName. + ServiceMeta map[string]string + // StartNode is the first key into the Nodes map that should be followed // when walking the discovery chain. StartNode string diff --git a/api/discovery_chain_test.go b/api/discovery_chain_test.go index 99f97fa9d..049ce3963 100644 --- a/api/discovery_chain_test.go +++ b/api/discovery_chain_test.go @@ -32,6 +32,7 @@ func TestAPI_DiscoveryChain_Get(t *testing.T) { Namespace: "default", Datacenter: "dc1", Protocol: "tcp", + Default: true, StartNode: "resolver:web.default.default.dc1", Nodes: map[string]*DiscoveryGraphNode{ "resolver:web.default.default.dc1": { @@ -72,6 +73,7 @@ func TestAPI_DiscoveryChain_Get(t *testing.T) { Namespace: "default", Datacenter: "dc2", Protocol: "tcp", + Default: true, StartNode: "resolver:web.default.default.dc2", Nodes: map[string]*DiscoveryGraphNode{ "resolver:web.default.default.dc2": { diff --git a/website/content/docs/connect/l7-traffic/discovery-chain.mdx b/website/content/docs/connect/l7-traffic/discovery-chain.mdx index 807c92b98..41a32a9b5 100644 --- a/website/content/docs/connect/l7-traffic/discovery-chain.mdx +++ b/website/content/docs/connect/l7-traffic/discovery-chain.mdx @@ -121,9 +121,15 @@ resolved by name using the [`Targets`](#targets) field. balancer data plane objects to avoid sharing customized and non-customized versions. +- `Default` `(bool: )` - Indicates if this discovery chain is based on no + `service-resolver`, `service-splitter`, or `service-router` config entries. + - `Protocol` `(string)` - The overall protocol shared by everything in the chain. +- `ServiceMeta` `(map)` - The metadata from the underlying `service-defaults` config + entry for the service named `ServiceName`. + - `StartNode` `(string)` - The first key into the `Nodes` map that should be followed when traversing the discovery chain.