Skip to content

Implement support for multiple filter chains, SNI with multiple certs#4975

Merged
rshriram merged 11 commits intoistio:masterfrom
ZackButcher:sni
Apr 17, 2018
Merged

Implement support for multiple filter chains, SNI with multiple certs#4975
rshriram merged 11 commits intoistio:masterfrom
ZackButcher:sni

Conversation

@ZackButcher
Copy link
Copy Markdown
Contributor

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.

@istio-testing
Copy link
Copy Markdown
Collaborator

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
To fully approve this pull request, please assign additional approvers.
We suggest the following additional approver: costinm

Assign the PR to them by writing /assign @costinm in a comment when ready.

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

} else {
for _, ruleGateway := range rule.Gateways {
if gatewayRequested[ruleGateway] {
log.Infof("service %v has gateways %v, comparing against %v", config.Name, rule.Gateways, gateways)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I assume you are going to get rid of these printfs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

createGatewayHTTPFilterChainOpts (qualify with gateway)

}
}

func createTCPFilterChainOpts(env model.Environment, servers []*networking.Server, gatewayNames map[string]bool) []*filterChainOpts {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

createGatewayTCPFilterChainOpts...

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 16, 2018

Codecov Report

Merging #4975 into master will decrease coverage by 1%.
The diff coverage is 0%.

Impacted file tree graph

@@           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
Impacted Files Coverage Δ
pilot/pkg/model/gateway.go 0% <0%> (-100%) ⬇️
pilot/pkg/networking/core/v1alpha3/listener.go 0% <0%> (ø) ⬆️
...ilot/pkg/networking/plugin/authn/authentication.go 68% <0%> (ø) ⬇️
pilot/pkg/networking/core/v1alpha3/gateway.go 0% <0%> (ø) ⬆️
pilot/pkg/networking/core/v1alpha3/httproute.go 28% <0%> (ø) ⬇️
pilot/pkg/model/config.go 51% <0%> (ø) ⬇️
...olarwinds/internal/papertrail/papertrail_logger.go 59% <0%> (-21%) ⬇️
mixer/adapter/prometheus/server.go 97% <0%> (-3%) ⬇️
mixer/adapter/kubernetesenv/kubernetesenv.go 68% <0%> (-2%) ⬇️
mixer/adapter/servicecontrol/testhelper.go 72% <0%> (-1%) ⬇️
... and 14 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e373621...31bfa70. Read the comment docs.

@ZackButcher
Copy link
Copy Markdown
Contributor Author

/retest

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 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it's not clear that ss couldn't exist and be empty here. suggest comment or better just check for len and return error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

See above; included a comment too.

newListener := buildListener(opts)

var httpFilters []*http_conn.HttpFilter
listenerType := plugin.ModelProtocolToListenerType(protocol)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👍
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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

sg

l := buildListener(opts)
mutable := &plugin.MutableObjects{
Listener: l,
FilterChains: make([]plugin.FilterChain, len(l.FilterChains)),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this is not obvious and could use a comment somewhere e.g. buildListener sets the number of FilterChains but does not create any filters.

Copy link
Copy Markdown
Contributor Author

@ZackButcher ZackButcher Apr 16, 2018

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

makes sense

return []*filterChainOpts{}
}

nameToServiceMap := make(map[string]*model.Service)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

yes, we should. maybe set listener type to ListenerTypeADMIN to make life easy for plugins? i can take this in a followup PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

SGTM

&http_conn.HttpFilter{Name: xdsutil.Router},
// TODO: need alphav3 fault filters.
//buildFaultFilters(opts.config, opts.env, opts.proxy)...
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👍

protocolPrefix = "http"
} else {
protoPrefix = "tcp"
protocolPrefix = "tcp"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

put this block in helper for better readability?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

"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"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lint


// FilterChain describes a set of filters (HTTP or TCP) with a shared TLS context.
type FilterChain struct {
HTTP []*http_conn.HttpFilter
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lint (comments)

@ostromart
Copy link
Copy Markdown
Contributor

could you pls check visually that mixer config still looks reasonable since we still don't have a test for this.

@ZackButcher ZackButcher changed the title Implement support for multiple filter chains, SNI Implement support for multiple filter chains, SNI with multiple certs Apr 16, 2018
l := buildListener(opts)
mutable := &plugin.MutableObjects{
Listener: l,
FilterChains: make([]plugin.FilterChain, len(l.FilterChains)),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

makes sense

newListener := buildListener(opts)

var httpFilters []*http_conn.HttpFilter
listenerType := plugin.ModelProtocolToListenerType(protocol)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

sg

@ZackButcher
Copy link
Copy Markdown
Contributor Author

@costinm can you provide LGTM for tests/ dir.

@rshriram rshriram merged commit 7b26e4a into istio:master Apr 17, 2018
@ostromart ostromart mentioned this pull request Apr 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants