Skip to content

Commit

Permalink
refactoring: introduce FilterChainBuilder in addition to ListenerBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
yskopets committed Feb 15, 2020
1 parent 9c76d04 commit 9675229
Show file tree
Hide file tree
Showing 29 changed files with 365 additions and 310 deletions.
67 changes: 67 additions & 0 deletions pkg/xds/envoy/listeners/filter_chain_builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package listeners

import (
envoy_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener"
)

// FilterChainConfigurer is responsible for configuring a single aspect of the entire Envoy filter chain,
// such as TcpProxy filter, RBAC filter, access log, etc.
type FilterChainConfigurer interface {
// Configure configures a single aspect on a given Envoy filter chain.
Configure(filterChain *envoy_listener.FilterChain) error
}

// FilterChainBuilderOpt is a configuration option for FilterChainBuilder.
//
// The goal of FilterChainBuilderOpt is to facilitate fluent FilterChainBuilder API.
type FilterChainBuilderOpt interface {
// ApplyTo adds FilterChainConfigurer(s) to the FilterChainBuilder.
ApplyTo(config *FilterChainBuilderConfig)
}

func NewFilterChainBuilder() *FilterChainBuilder {
return &FilterChainBuilder{}
}

// FilterChainBuilder is responsible for generating an Envoy filter chain
// by applying a series of FilterChainConfigurers.
type FilterChainBuilder struct {
config FilterChainBuilderConfig
}

// Configure configures FilterChainBuilder by adding individual FilterChainConfigurers.
func (b *FilterChainBuilder) Configure(opts ...FilterChainBuilderOpt) *FilterChainBuilder {
for _, opt := range opts {
opt.ApplyTo(&b.config)
}
return b
}

// Build generates an Envoy filter chain by applying a series of FilterChainConfigurers.
func (b *FilterChainBuilder) Build() (*envoy_listener.FilterChain, error) {
filterChain := envoy_listener.FilterChain{}
for _, configurer := range b.config.Configurers {
if err := configurer.Configure(&filterChain); err != nil {
return nil, err
}
}
return &filterChain, nil
}

// FilterChainBuilderConfig holds configuration of a FilterChainBuilder.
type FilterChainBuilderConfig struct {
// A series of FilterChainConfigurers to apply to Envoy filter chain.
Configurers []FilterChainConfigurer
}

// Add appends a given FilterChainConfigurer to the end of the chain.
func (c *FilterChainBuilderConfig) Add(configurer FilterChainConfigurer) {
c.Configurers = append(c.Configurers, configurer)
}

// FilterChainBuilderOptFunc is a convenience type adapter.
type FilterChainBuilderOptFunc func(config *FilterChainBuilderConfig)

func (f FilterChainBuilderOptFunc) ApplyTo(config *FilterChainBuilderConfig) {
f(config)
}
26 changes: 26 additions & 0 deletions pkg/xds/envoy/listeners/filter_chain_configurer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package listeners

import (
v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
)

func FilterChain(builder *FilterChainBuilder) ListenerBuilderOpt {
return ListenerBuilderOptFunc(func(config *ListenerBuilderConfig) {
config.Add(&ListenerFilterChainConfigurer{
builder: builder,
})
})
}

type ListenerFilterChainConfigurer struct {
builder *FilterChainBuilder
}

func (c ListenerFilterChainConfigurer) Configure(listener *v2.Listener) error {
filterChain, err := c.builder.Build()
if err != nil {
return err
}
listener.FilterChains = append(listener.FilterChains, filterChain)
return nil
}
54 changes: 54 additions & 0 deletions pkg/xds/envoy/listeners/filter_chain_configurer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package listeners_test

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"

. "github.com/Kong/kuma/pkg/xds/envoy/listeners"

util_proto "github.com/Kong/kuma/pkg/util/proto"
)

var _ = Describe("ListenerFilterChainConfigurer", func() {

type testCase struct {
listenerName string
listenerAddress string
listenerPort uint32
expected string
}

DescribeTable("should generate proper Envoy config",
func(given testCase) {
// when
listener, err := NewListenerBuilder().
Configure(InboundListener(given.listenerName, given.listenerAddress, given.listenerPort)).
Configure(FilterChain(NewFilterChainBuilder())).
Build()
// then
Expect(err).ToNot(HaveOccurred())

// when
actual, err := util_proto.ToYAML(listener)
// then
Expect(err).ToNot(HaveOccurred())
// and
Expect(actual).To(MatchYAML(given.expected))
},
Entry("basic listener with an empty filter chain", testCase{
listenerName: "inbound:192.168.0.1:8080",
listenerAddress: "192.168.0.1",
listenerPort: 8080,
expected: `
name: inbound:192.168.0.1:8080
address:
socketAddress:
address: 192.168.0.1
portValue: 8080
filterChains:
- {}
`,
}),
)
})
22 changes: 9 additions & 13 deletions pkg/xds/envoy/listeners/http_connection_manager_configurer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ package listeners
import (
"github.com/golang/protobuf/ptypes"

v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
envoy_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener"
envoy_hcm "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2"
envoy_wellknown "github.com/envoyproxy/go-control-plane/pkg/wellknown"

util_xds "github.com/Kong/kuma/pkg/util/xds"
)

func HttpConnectionManager(statsName string) ListenerBuilderOpt {
return ListenerBuilderOptFunc(func(config *ListenerBuilderConfig) {
func HttpConnectionManager(statsName string) FilterChainBuilderOpt {
return FilterChainBuilderOptFunc(func(config *FilterChainBuilderConfig) {
config.Add(&HttpConnectionManagerConfigurer{
statsName: statsName,
})
Expand All @@ -23,7 +22,7 @@ type HttpConnectionManagerConfigurer struct {
statsName string
}

func (c *HttpConnectionManagerConfigurer) Configure(l *v2.Listener) error {
func (c *HttpConnectionManagerConfigurer) Configure(filterChain *envoy_listener.FilterChain) error {
config := &envoy_hcm.HttpConnectionManager{
StatPrefix: util_xds.SanitizeMetric(c.statsName),
CodecType: envoy_hcm.HttpConnectionManager_AUTO,
Expand All @@ -38,14 +37,11 @@ func (c *HttpConnectionManagerConfigurer) Configure(l *v2.Listener) error {
return err
}

for i := range l.FilterChains {
l.FilterChains[i].Filters = append(l.FilterChains[i].Filters, &envoy_listener.Filter{
Name: envoy_wellknown.HTTPConnectionManager,
ConfigType: &envoy_listener.Filter_TypedConfig{
TypedConfig: pbst,
},
})
}

filterChain.Filters = append(filterChain.Filters, &envoy_listener.Filter{
Name: envoy_wellknown.HTTPConnectionManager,
ConfigType: &envoy_listener.Filter_TypedConfig{
TypedConfig: pbst,
},
})
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ var _ = Describe("HttpConnectionManagerConfigurer", func() {
// when
listener, err := NewListenerBuilder().
Configure(InboundListener(given.listenerName, given.listenerAddress, given.listenerPort)).
Configure(HttpConnectionManager(given.statsName)).
Configure(FilterChain(NewFilterChainBuilder().
Configure(HttpConnectionManager(given.statsName)))).
Build()
// then
Expect(err).ToNot(HaveOccurred())
Expand Down
13 changes: 8 additions & 5 deletions pkg/xds/envoy/listeners/http_inbound_route_configurer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import (
wrappers "github.com/golang/protobuf/ptypes/wrappers"

v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
envoy_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener"
envoy_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route"
envoy_hcm "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2"
envoy_wellknown "github.com/envoyproxy/go-control-plane/pkg/wellknown"

envoy_common "github.com/Kong/kuma/pkg/xds/envoy"
)

func HttpInboundRoute(service string, cluster ClusterInfo) ListenerBuilderOpt {
return ListenerBuilderOptFunc(func(config *ListenerBuilderConfig) {
func HttpInboundRoute(service string, cluster envoy_common.ClusterInfo) FilterChainBuilderOpt {
return FilterChainBuilderOptFunc(func(config *FilterChainBuilderConfig) {
config.Add(&HttpInboundRouteConfigurer{
service: service,
cluster: cluster,
Expand All @@ -24,13 +27,13 @@ func HttpInboundRoute(service string, cluster ClusterInfo) ListenerBuilderOpt {
type HttpInboundRouteConfigurer struct {
service string
// Cluster to forward traffic to.
cluster ClusterInfo
cluster envoy_common.ClusterInfo
}

func (c *HttpInboundRouteConfigurer) Configure(l *v2.Listener) error {
func (c *HttpInboundRouteConfigurer) Configure(filterChain *envoy_listener.FilterChain) error {
routeConfig := c.routeConfiguration()

return UpdateFilterConfig(l, envoy_wellknown.HTTPConnectionManager, func(filterConfig proto.Message) error {
return UpdateFilterConfig(filterChain, envoy_wellknown.HTTPConnectionManager, func(filterConfig proto.Message) error {
hcm, ok := filterConfig.(*envoy_hcm.HttpConnectionManager)
if !ok {
return NewUnexpectedFilterConfigTypeError(filterConfig, &envoy_hcm.HttpConnectionManager{})
Expand Down
10 changes: 6 additions & 4 deletions pkg/xds/envoy/listeners/http_inbound_route_configurer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
. "github.com/Kong/kuma/pkg/xds/envoy/listeners"

util_proto "github.com/Kong/kuma/pkg/util/proto"
envoy_common "github.com/Kong/kuma/pkg/xds/envoy"
)

var _ = Describe("HttpInboundRouteConfigurer", func() {
Expand All @@ -18,7 +19,7 @@ var _ = Describe("HttpInboundRouteConfigurer", func() {
listenerPort uint32
statsName string
service string
cluster ClusterInfo
cluster envoy_common.ClusterInfo
expected string
}

Expand All @@ -27,8 +28,9 @@ var _ = Describe("HttpInboundRouteConfigurer", func() {
// when
listener, err := NewListenerBuilder().
Configure(InboundListener(given.listenerName, given.listenerAddress, given.listenerPort)).
Configure(HttpConnectionManager(given.statsName)).
Configure(HttpInboundRoute(given.service, given.cluster)).
Configure(FilterChain(NewFilterChainBuilder().
Configure(HttpConnectionManager(given.statsName)).
Configure(HttpInboundRoute(given.service, given.cluster)))).
Build()
// then
Expect(err).ToNot(HaveOccurred())
Expand All @@ -45,7 +47,7 @@ var _ = Describe("HttpInboundRouteConfigurer", func() {
listenerPort: 8080,
statsName: "localhost:8080",
service: "backend",
cluster: ClusterInfo{Name: "localhost:8080", Weight: 200},
cluster: envoy_common.ClusterInfo{Name: "localhost:8080", Weight: 200},
expected: `
name: inbound:192.168.0.1:8080
address:
Expand Down
5 changes: 1 addition & 4 deletions pkg/xds/envoy/listeners/inbound_listener_configurer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package listeners
import (
v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
envoy_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
envoy_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener"
)

func InboundListener(listenerName string, address string, port uint32) ListenerBuilderOpt {
Expand Down Expand Up @@ -35,9 +34,7 @@ func (c *InboundListenerConfigurer) Configure(l *v2.Listener) error {
},
},
}
l.FilterChains = []*envoy_listener.FilterChain{
{}, // 1 filter chain that will be configured later on
}
// notice that filter chain configuration is left up to other configurers

return nil
}
2 changes: 0 additions & 2 deletions pkg/xds/envoy/listeners/inbound_listener_configurer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ var _ = Describe("InboundListenerConfigurer", func() {
socketAddress:
address: 192.168.0.1
portValue: 8080
filterChains:
- {}
`,
}),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
)

// ListenerConfigurer is responsible for configuring a single aspect of the entire Envoy listener,
// such as TcpProxy filter, RBAC filter, access log, etc.
// such as filter chain, transparent proxying, etc.
type ListenerConfigurer interface {
// Configure configures a single aspect on a given Envoy listener.
Configure(listener *v2.Listener) error
Expand Down
10 changes: 5 additions & 5 deletions pkg/xds/envoy/listeners/network_access_log_configurer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"

v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
envoy_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
envoy_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener"
accesslog "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v2"
filter_accesslog "github.com/envoyproxy/go-control-plane/envoy/config/filter/accesslog/v2"
envoy_tcp "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/tcp_proxy/v2"
Expand All @@ -20,8 +20,8 @@ import (
core_xds "github.com/Kong/kuma/pkg/core/xds"
)

func NetworkAccessLog(sourceService string, destinationService string, backend *v1alpha1.LoggingBackend, proxy *core_xds.Proxy) ListenerBuilderOpt {
return ListenerBuilderOptFunc(func(config *ListenerBuilderConfig) {
func NetworkAccessLog(sourceService string, destinationService string, backend *v1alpha1.LoggingBackend, proxy *core_xds.Proxy) FilterChainBuilderOpt {
return FilterChainBuilderOptFunc(func(config *FilterChainBuilderConfig) {
if backend != nil {
config.Add(&NetworkAccessLogConfigurer{
sourceService: sourceService,
Expand All @@ -40,13 +40,13 @@ type NetworkAccessLogConfigurer struct {
proxy *core_xds.Proxy
}

func (c *NetworkAccessLogConfigurer) Configure(l *v2.Listener) error {
func (c *NetworkAccessLogConfigurer) Configure(filterChain *envoy_listener.FilterChain) error {
accessLog, err := convertLoggingBackend(c.sourceService, c.destinationService, c.backend, c.proxy)
if err != nil {
return err
}

return UpdateFilterConfig(l, envoy_wellknown.TCPProxy, func(filterConfig proto.Message) error {
return UpdateFilterConfig(filterChain, envoy_wellknown.TCPProxy, func(filterConfig proto.Message) error {
proxy, ok := filterConfig.(*envoy_tcp.TcpProxy)
if !ok {
return NewUnexpectedFilterConfigTypeError(filterConfig, &envoy_tcp.TcpProxy{})
Expand Down
Loading

0 comments on commit 9675229

Please sign in to comment.