Skip to content

Commit

Permalink
kuma-cp: generate HTTP-specific outbound listeners for services tagge…
Browse files Browse the repository at this point in the history
…d with `protocol: http`
  • Loading branch information
yskopets committed Feb 15, 2020
1 parent 9675229 commit 676917a
Show file tree
Hide file tree
Showing 23 changed files with 1,602 additions and 79 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

Changes:

* feature: generate HTTP-specific outbound listeners for services tagged with `protocol: http`
[#585](https://github.com/Kong/kuma/pull/585)
* feature: validate value of `protocol` tag on a Dataplane resource
[#576](https://github.com/Kong/kuma/pull/576)
* feature: support `<port>.service.kuma.io/protocol` annotation on k8s as a way for users to indicate protocol of a service
Expand Down
42 changes: 11 additions & 31 deletions pkg/xds/envoy/listeners/http_inbound_route_configurer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ import (
"fmt"

"github.com/golang/protobuf/proto"
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"
envoy_routes "github.com/Kong/kuma/pkg/xds/envoy/routes"
)

func HttpInboundRoute(service string, cluster envoy_common.ClusterInfo) FilterChainBuilderOpt {
Expand All @@ -31,7 +29,16 @@ type HttpInboundRouteConfigurer struct {
}

func (c *HttpInboundRouteConfigurer) Configure(filterChain *envoy_listener.FilterChain) error {
routeConfig := c.routeConfiguration()
routeName := fmt.Sprintf("inbound:%s", c.service)
routeConfig, err := envoy_routes.NewRouteConfigurationBuilder().
Configure(envoy_routes.CommonRouteConfiguration(routeName)).
Configure(envoy_routes.VirtualHost(envoy_routes.NewVirtualHostBuilder().
Configure(envoy_routes.CommonVirtualHost(c.service)).
Configure(envoy_routes.DefaultRoute(c.cluster)))).
Build()
if err != nil {
return err
}

return UpdateFilterConfig(filterChain, envoy_wellknown.HTTPConnectionManager, func(filterConfig proto.Message) error {
hcm, ok := filterConfig.(*envoy_hcm.HttpConnectionManager)
Expand All @@ -44,30 +51,3 @@ func (c *HttpInboundRouteConfigurer) Configure(filterChain *envoy_listener.Filte
return nil
})
}

func (c *HttpInboundRouteConfigurer) routeConfiguration() *v2.RouteConfiguration {
return &v2.RouteConfiguration{
Name: fmt.Sprintf("inbound:%s", c.service),
VirtualHosts: []*envoy_route.VirtualHost{{
Name: c.service,
Domains: []string{"*"},
Routes: []*envoy_route.Route{{
Match: &envoy_route.RouteMatch{
PathSpecifier: &envoy_route.RouteMatch_Prefix{
Prefix: "/",
},
},
Action: &envoy_route.Route_Route{
Route: &envoy_route.RouteAction{
ClusterSpecifier: &envoy_route.RouteAction_Cluster{
Cluster: c.cluster.Name,
},
},
},
}},
}},
ValidateClusters: &wrappers.BoolValue{
Value: true,
},
}
}
43 changes: 43 additions & 0 deletions pkg/xds/envoy/listeners/http_outbound_route_configurer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package listeners

import (
"github.com/golang/protobuf/proto"

envoy_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
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"
)

func HttpOutboundRoute(routeName string) FilterChainBuilderOpt {
return FilterChainBuilderOptFunc(func(config *FilterChainBuilderConfig) {
config.Add(&HttpOutboundRouteConfigurer{
routeName: routeName,
})
})
}

type HttpOutboundRouteConfigurer struct {
routeName string
}

func (c *HttpOutboundRouteConfigurer) Configure(filterChain *envoy_listener.FilterChain) 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{})
}

hcm.RouteSpecifier = &envoy_hcm.HttpConnectionManager_Rds{
Rds: &envoy_hcm.Rds{
ConfigSource: &envoy_core.ConfigSource{
ConfigSourceSpecifier: &envoy_core.ConfigSource_Ads{
Ads: &envoy_core.AggregatedConfigSource{},
},
},
RouteConfigName: c.routeName,
},
}
return nil
})
}
69 changes: 69 additions & 0 deletions pkg/xds/envoy/listeners/http_outbound_route_configurer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
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("HttpOutboundRouteConfigurer", func() {

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

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

// when
actual, err := util_proto.ToYAML(listener)
Expect(err).ToNot(HaveOccurred())
// and
Expect(actual).To(MatchYAML(given.expected))
},
Entry("basic http_connection_manager with an outbound route", testCase{
listenerName: "outbound:127.0.0.1:18080",
listenerAddress: "127.0.0.1",
listenerPort: 18080,
statsName: "127.0.0.1:18080",
routeName: "outbound:backend",
expected: `
name: outbound:127.0.0.1:18080
address:
socketAddress:
address: 127.0.0.1
portValue: 18080
filterChains:
- filters:
- name: envoy.http_connection_manager
typedConfig:
'@type': type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
httpFilters:
- name: envoy.router
rds:
configSource:
ads: {}
routeConfigName: outbound:backend
statPrefix: "127_0_0_1_18080"
`,
}),
)
})
1 change: 0 additions & 1 deletion pkg/xds/envoy/listeners/network_rbac_configurer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
mesh_core "github.com/Kong/kuma/pkg/core/resources/apis/mesh"

test_model "github.com/Kong/kuma/pkg/test/resources/model"

util_proto "github.com/Kong/kuma/pkg/util/proto"
envoy_common "github.com/Kong/kuma/pkg/xds/envoy"
)
Expand Down
27 changes: 27 additions & 0 deletions pkg/xds/envoy/routes/common_route_configuration_configurer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package routes

import (
"github.com/golang/protobuf/ptypes/wrappers"

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

func CommonRouteConfiguration(name string) RouteConfigurationBuilderOpt {
return RouteConfigurationBuilderOptFunc(func(config *RouteConfigurationBuilderConfig) {
config.Add(&CommonRouteConfigurationConfigurer{
name: name,
})
})
}

type CommonRouteConfigurationConfigurer struct {
name string
}

func (c CommonRouteConfigurationConfigurer) Configure(routeConfiguration *v2.RouteConfiguration) error {
routeConfiguration.Name = c.name
routeConfiguration.ValidateClusters = &wrappers.BoolValue{
Value: true,
}
return nil
}
44 changes: 44 additions & 0 deletions pkg/xds/envoy/routes/common_route_configuration_configurer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package routes_test

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

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

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

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

type testCase struct {
routeName string
expected string
}

DescribeTable("should generate proper Envoy config",
func(given testCase) {
// when
routeConfiguration, err := NewRouteConfigurationBuilder().
Configure(CommonRouteConfiguration(given.routeName)).
Build()
// then
Expect(err).ToNot(HaveOccurred())

// when
actual, err := util_proto.ToYAML(routeConfiguration)
// then
Expect(err).ToNot(HaveOccurred())
// and
Expect(actual).To(MatchYAML(given.expected))
},
Entry("basic RouteConfiguration", testCase{
routeName: "outbound:backend",
expected: `
name: outbound:backend
validateClusters: true
`,
}),
)
})
23 changes: 23 additions & 0 deletions pkg/xds/envoy/routes/common_virtual_host_configurer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package routes

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

func CommonVirtualHost(name string) VirtualHostBuilderOpt {
return VirtualHostBuilderOptFunc(func(config *VirtualHostBuilderConfig) {
config.Add(&CommonVirtualHostConfigurer{
name: name,
})
})
}

type CommonVirtualHostConfigurer struct {
name string
}

func (c CommonVirtualHostConfigurer) Configure(virtualHost *envoy_route.VirtualHost) error {
virtualHost.Name = c.name
virtualHost.Domains = []string{"*"}
return nil
}
45 changes: 45 additions & 0 deletions pkg/xds/envoy/routes/common_virtual_host_configurer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package routes_test

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

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

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

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

type testCase struct {
virtualHostName string
expected string
}

DescribeTable("should generate proper Envoy config",
func(given testCase) {
// when
routeConfiguration, err := NewVirtualHostBuilder().
Configure(CommonVirtualHost(given.virtualHostName)).
Build()
// then
Expect(err).ToNot(HaveOccurred())

// when
actual, err := util_proto.ToYAML(routeConfiguration)
// then
Expect(err).ToNot(HaveOccurred())
// and
Expect(actual).To(MatchYAML(given.expected))
},
Entry("basic VirtualHost", testCase{
virtualHostName: "backend",
expected: `
name: backend
domains:
- '*'
`,
}),
)
})
Loading

0 comments on commit 676917a

Please sign in to comment.