Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update filter chain creation for sidecar/ingress listeners #11245

Merged
merged 16 commits into from
Nov 9, 2021

Conversation

freddygv
Copy link
Contributor

@freddygv freddygv commented Oct 7, 2021

The duo of makeUpstreamFilterChainForDiscoveryChain and makeListenerForDiscoveryChain were really hard to reason about, and led to concealing a bug in their branching logic. There were several issues here:

  • They tried to accomplish too much: determining filter name, cluster name, and whether RDS should be used.
  • They embedded logic to handle significantly different kinds of upstream listeners (passthrough, prepared query, typical services, and catch-all)
  • They needed to coalesce different data sources (Upstream and CompiledDiscoveryChain)

Rather than handling all of those tasks inside of these functions, this PR pulls out the RDS/clusterName/filterName logic.

This refactor also fixed a bug with the handling of UpstreamDefaults. These defaults get stored as UpstreamConfig in the proxy snapshot with a DestinationName of "*", since they apply to all upstreams. However, this wildcard destination name must not be used when creating the name of the associated upstream cluster. The coalescing logic in the original functions here was in some situations creating clusters with a *. prefix, which is not a valid destination.

Each commit shows the progressive untangling.

@freddygv freddygv requested review from rboyer and a team October 7, 2021 15:14
@freddygv
Copy link
Contributor Author

freddygv commented Oct 7, 2021

Looking into this test failure Fixed

@github-actions github-actions bot added the theme/envoy/xds Related to Envoy support label Oct 7, 2021
@vercel vercel bot temporarily deployed to Preview – consul-ui-staging October 7, 2021 15:16 Inactive
@vercel vercel bot temporarily deployed to Preview – consul October 7, 2021 15:16 Inactive
cfgSnap,
nil,
)
if upstreamCfg != nil && upstreamCfg.HasLocalPortOrSocket() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The outboundListener being nil doesn't really matter here. That just indicates that it's not a transparent proxy.

However, creating explicit listeners applies to all sidecar proxies: transparent or not. The only thing that matters is having a local port or socket.

@vercel vercel bot temporarily deployed to Preview – consul October 7, 2021 15:35 Inactive
@vercel vercel bot temporarily deployed to Preview – consul-ui-staging October 7, 2021 15:35 Inactive
if !useRDS {
// When not using RDS we must generate a cluster name to attach to the filter chain.
// With RDS, cluster names get attached to the dynamic routes instead.
target, err := simpleChainTarget(chain)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to stare at this a lot.

So ultimately down in the listener construction clusterName!="" is required when !useRDS and vice versa.

So up here it only makes sense to compute a clusterName if not doing RDS ✔️

I was concerned that the chain.IsDefault() code was omitted here, but after thinking about it more, if you have a default chain (and not a prepared query), then you resolved that USING the upstream naming attributes (dest/dc/ns/ap) and there was no redirect so using the SNI target name for the chain you already have is effectively doing the same thing so the conditional branch for IsDefault() isn't necessary here ✔️ ❓

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this block either the protocol is TCP or the chain is default. If the protocol is TCP and the chain is not default then there could be a redirect, but that should be OK since there should only be one node in the chain.

Say you have a service web with a redirect to web in dc2. There would be a single chain node with target web.default.default.dc2, which is what we're looking for. The cluster name needs to be for the redirect target because the xds cluster will also have that name:

targetID := node.Resolver.Target
target := chain.Targets[targetID]

If there is a resolver with failovers there would also only be a single discovery chain node, despite having multiple chain targets.

Comment on lines 204 to 207
dc := u.Datacenter
if dc == "" {
dc = cfgSnap.Datacenter
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need this here since u is block-local and created just above without a Datacenter field populated. You can just pass cfgSnap.Datacenter into Sprintf

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

filterName := fmt.Sprintf("%s.%s.%s.%s", chain.ServiceName, chain.Namespace, chain.Partition, chain.Datacenter)

l := makePortListenerWithDefault(id, address, u.LocalBindPort, envoy_core_v3.TrafficDirection_OUTBOUND)
filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By switching to the new function here you've lost your EnvoyListenerJSON escape hatch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could probably fix that by adding this blurb right after the cfg := ...

if cfg.EnvoyListenerJSON != "" {
	listener, err := makeListenerFromUserConfig(cfg.EnvoyListenerJSON)
	if err != nil {
		return nil, err
	}
	resources = append(resources, listener)
	continue
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ingress gateways never actually supported escape hatches, their upstream definitions are generated from this data:
https://www.consul.io/docs/connect/config-entries/ingress-gateway#services

@@ -45,19 +44,42 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap
id := u.Identifier()

chain := cfgSnap.IngressGateway.DiscoveryChain[id]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like the answer is yes, but is chain actually guaranteed to be non-nil here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually not so sure. If the IG config entry comes back first then you'll loop over that before all of the chains come in, so maybe the right thing in this loop is :

if chain == nil {
   continue // wait until we get the chain
   }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this if-nil-continue check doesn't appear to break anything so that should resolve the incidental nil-ness due to eventual consistency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@vercel vercel bot temporarily deployed to Preview – consul November 9, 2021 14:38 Inactive
@vercel vercel bot temporarily deployed to Preview – consul-ui-staging November 9, 2021 14:38 Inactive
@vercel vercel bot temporarily deployed to Preview – consul-ui-staging November 9, 2021 15:01 Inactive
@vercel vercel bot temporarily deployed to Preview – consul November 9, 2021 15:01 Inactive
Copy link
Member

@rboyer rboyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@vercel vercel bot temporarily deployed to Preview – consul November 9, 2021 21:39 Inactive
@vercel vercel bot temporarily deployed to Preview – consul-ui-staging November 9, 2021 21:39 Inactive
@freddygv freddygv merged commit 00b5b0a into main Nov 9, 2021
@freddygv freddygv deleted the xds/chain-refactor branch November 9, 2021 21:43
@hc-github-team-consul-core
Copy link
Collaborator

🍒 If backport labels were added before merging, cherry-picking will start automatically.

To retroactively trigger a backport after merging, add backport labels and re-run https://circleci.com/gh/hashicorp/consul/498544.

@hc-github-team-consul-core
Copy link
Collaborator

🍒❌ Cherry pick of commit 00b5b0a onto release/1.10.x failed! Build Log

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
theme/envoy/xds Related to Envoy support
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants