Implement support for multiple filter chains, SNI with multiple certs#4975
Implement support for multiple filter chains, SNI with multiple certs#4975rshriram merged 11 commits intoistio:masterfrom
Conversation
…gateways; this is required because we resolve gateway names now after merging gateways
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: Assign the PR to them by writing The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
pilot/pkg/model/config.go
Outdated
| } else { | ||
| for _, ruleGateway := range rule.Gateways { | ||
| if gatewayRequested[ruleGateway] { | ||
| log.Infof("service %v has gateways %v, comparing against %v", config.Name, rule.Gateways, gateways) |
There was a problem hiding this comment.
I assume you are going to get rid of these printfs?
There was a problem hiding this comment.
Ah, missed that one. Tried to move them all to Debugf at least.
| return listeners, nil | ||
| } | ||
|
|
||
| func createHTTPFilterChainOpts(env model.Environment, servers []*networking.Server, gatewayNames map[string]bool) []*filterChainOpts { |
There was a problem hiding this comment.
createGatewayHTTPFilterChainOpts (qualify with gateway)
| } | ||
| } | ||
|
|
||
| func createTCPFilterChainOpts(env model.Environment, servers []*networking.Server, gatewayNames map[string]bool) []*filterChainOpts { |
There was a problem hiding this comment.
createGatewayTCPFilterChainOpts...
Codecov Report
@@ Coverage Diff @@
## master #4975 +/- ##
=======================================
- Coverage 74% 74% -<1%
=======================================
Files 307 307
Lines 25588 25914 +326
=======================================
+ Hits 18724 18937 +213
- Misses 6115 6225 +110
- Partials 749 752 +3
Continue to review full report at Codecov.
|
|
/retest |
pilot/pkg/model/gateway.go
Outdated
| log.Debugf("MergeGateways: merging gateway %q into %v:\n%v", name, names, gateway) | ||
| for _, s := range gateway.Servers { | ||
| log.Debugf("MergeGateways: gateway %q processing server %v", name, s.Hosts) | ||
| if ss, exists := servers[s.Port.Number]; exists { |
There was a problem hiding this comment.
nit: for maps of ptrs you can just use if servers[x] != nil. otherwise it's idiomatic to always use "ok" when testing for presence (rather than exists etc).
There was a problem hiding this comment.
This isn't actually a map of pointers, it's a map of arrays of pointers. By construction the key will either not exist in the map or it will exist and the value array will have a least one element in it (the else case below).
Either way, included a comment denoting why this is safe.
| log.Debugf("MergeGateways: gateway %q processing server %v", name, s.Hosts) | ||
| if ss, exists := servers[s.Port.Number]; exists { | ||
| // TODO: remove this check when Envoy supports filter chain matching so we can expose multiple protocols on the same physical port | ||
| if ss[0].Port.Protocol != s.Port.Protocol { |
There was a problem hiding this comment.
it's not clear that ss couldn't exist and be empty here. suggest comment or better just check for len and return error.
There was a problem hiding this comment.
See above; included a comment too.
| newListener := buildListener(opts) | ||
|
|
||
| var httpFilters []*http_conn.HttpFilter | ||
| listenerType := plugin.ModelProtocolToListenerType(protocol) |
There was a problem hiding this comment.
👍
could we also simplify the long case lists with a similar helper e.g. case isL7Proto(protocol): or something like that? ModelProtocolToListenerType could be written in terms of that base function.
There was a problem hiding this comment.
We already have that method on model.Protocol. In writing this PR I'm not convinced that ListenerType should exist at all, I think we can replace it with model.Protocol just fine. I just didn't want to include that change in this PR too.
| l := buildListener(opts) | ||
| mutable := &plugin.MutableObjects{ | ||
| Listener: l, | ||
| FilterChains: make([]plugin.FilterChain, len(l.FilterChains)), |
There was a problem hiding this comment.
this is not obvious and could use a comment somewhere e.g. buildListener sets the number of FilterChains but does not create any filters.
There was a problem hiding this comment.
Done. I think, given the current usage, buildListener should return a plugin.MutableObjects that's constructed correctly. See my comment in listeners.go about wanting to combine listener, mutable objects, and opts; I think consuming opts to produce a mutable objects (with listener inline) is probably what we want. But I didn't want to include that change in this PR, especially since it'd likely include moving mutable objects from pkg plugin to pkg core.
| return []*filterChainOpts{} | ||
| } | ||
|
|
||
| nameToServiceMap := make(map[string]*model.Service) |
There was a problem hiding this comment.
optional: make(map[string]*model.Service, len(services))
| l := buildListener(listenerOpts) | ||
| if err := marshalFilters(l, listenerOpts, buildInboundNetworkFilters(instance), nil); err != nil { | ||
| log.Warn(err.Error()) | ||
| // TODO: should we call plugins for the admin port listeners too? We do everywhere else we contruct listeners. |
There was a problem hiding this comment.
yes, we should. maybe set listener type to ListenerTypeADMIN to make life easy for plugins? i can take this in a followup PR.
| &http_conn.HttpFilter{Name: xdsutil.Router}, | ||
| // TODO: need alphav3 fault filters. | ||
| //buildFaultFilters(opts.config, opts.env, opts.proxy)... | ||
| ) |
| protocolPrefix = "http" | ||
| } else { | ||
| protoPrefix = "tcp" | ||
| protocolPrefix = "tcp" |
There was a problem hiding this comment.
put this block in helper for better readability?
| "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" | ||
| "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" | ||
| "github.com/gogo/protobuf/types" | ||
| "istio.io/istio/pkg/log" |
|
|
||
| // FilterChain describes a set of filters (HTTP or TCP) with a shared TLS context. | ||
| type FilterChain struct { | ||
| HTTP []*http_conn.HttpFilter |
|
could you pls check visually that mixer config still looks reasonable since we still don't have a test for this. |
| l := buildListener(opts) | ||
| mutable := &plugin.MutableObjects{ | ||
| Listener: l, | ||
| FilterChains: make([]plugin.FilterChain, len(l.FilterChains)), |
| newListener := buildListener(opts) | ||
|
|
||
| var httpFilters []*http_conn.HttpFilter | ||
| listenerType := plugin.ModelProtocolToListenerType(protocol) |
|
@costinm can you provide LGTM for tests/ dir. |
This wound up being a bit larger than anticipated, plumbing support for multiple filter chains everywhere required a decent bit of work.
I'm writing up unit tests and an explicit SNI e2e test right now, but as-is all pilotv2 tests pass against this branch locally, so I think review can start while I get more testing written.