From 8b69b8849fcd3d891f33c69bbb34e8957c13c280 Mon Sep 17 00:00:00 2001 From: Steve Sloka Date: Thu, 17 Sep 2020 18:02:41 -0400 Subject: [PATCH] internal: Refactor Envoy into v2 package Refactors the envoy package into a v2 package for Envoy API V2 types. Common items are kept in the envoy package for use by other versions. Updates: #1898 Signed-off-by: Steve Sloka --- cmd/contour/contour.go | 5 +- cmd/contour/servecontext.go | 3 +- cmd/contour/servecontext_test.go | 1 + internal/contour/cluster.go | 23 +- internal/contour/cluster_test.go | 93 +- internal/contour/endpointstranslator.go | 7 +- internal/contour/endpointstranslator_test.go | 129 +-- internal/contour/listener.go | 52 +- internal/contour/listener_test.go | 441 +++++----- internal/contour/route.go | 39 +- internal/contour/route_test.go | 213 ++--- internal/contour/secret.go | 7 +- internal/contour/visitor_test.go | 16 +- internal/debug/dot.go | 3 +- internal/envoy/accesslog.go | 60 -- internal/envoy/auth.go | 90 +- internal/envoy/bootstrap.go | 322 +------ internal/envoy/cluster.go | 218 +---- internal/envoy/cluster_test.go | 624 +------------- internal/envoy/healthcheck.go | 65 +- internal/envoy/listener.go | 516 +---------- internal/envoy/listener_test.go | 789 ----------------- internal/envoy/route.go | 304 +------ internal/envoy/secret.go | 38 +- internal/envoy/tcp_keepalive.go | 50 +- internal/envoy/v2/accesslog.go | 75 ++ internal/envoy/{ => v2}/accesslog_test.go | 8 +- internal/envoy/v2/auth.go | 101 +++ internal/envoy/{ => v2}/auth_test.go | 2 +- internal/envoy/v2/bootstrap.go | 319 +++++++ internal/envoy/{ => v2}/bootstrap_test.go | 26 +- internal/envoy/v2/cluster.go | 227 +++++ internal/envoy/v2/cluster_test.go | 585 +++++++++++++ internal/envoy/{ => v2}/endpoint.go | 2 +- internal/envoy/{ => v2}/endpoint_test.go | 2 +- internal/envoy/v2/healthcheck.go | 70 ++ internal/envoy/{ => v2}/healthcheck_test.go | 12 +- internal/envoy/v2/listener.go | 516 +++++++++++ internal/envoy/v2/listener_test.go | 798 ++++++++++++++++++ internal/envoy/v2/route.go | 314 +++++++ internal/envoy/{ => v2}/route_test.go | 12 +- internal/envoy/v2/secret.go | 44 + internal/envoy/{ => v2}/secret_test.go | 6 +- internal/envoy/{ => v2}/socket.go | 2 +- internal/envoy/{ => v2}/socket_test.go | 2 +- internal/envoy/{ => v2}/stats.go | 2 +- internal/envoy/{ => v2}/stats_test.go | 2 +- internal/envoy/v2/tcp_keepalive.go | 62 ++ internal/featuretests/authorization_test.go | 49 +- .../featuretests/backendcavalidation_test.go | 27 +- internal/featuretests/cluster_test.go | 19 +- .../featuretests/downstreamvalidation_test.go | 19 +- internal/featuretests/endpoints_test.go | 37 +- internal/featuretests/envoy.go | 63 +- .../featuretests/extensionservice_test.go | 11 +- internal/featuretests/externalname_test.go | 31 +- internal/featuretests/fallbackcert_test.go | 35 +- internal/featuretests/headercondition_test.go | 31 +- internal/featuretests/headerpolicy_test.go | 22 +- internal/featuretests/ingressclass_test.go | 69 +- internal/featuretests/listeners_test.go | 227 ++--- .../featuretests/loadbalancerpolicy_test.go | 11 +- internal/featuretests/mirrorpolicy_test.go | 7 +- internal/featuretests/replaceprefix_test.go | 51 +- internal/featuretests/retrypolicy_test.go | 19 +- internal/featuretests/rootnamespaces_test.go | 17 +- internal/featuretests/route_test.go | 171 ++-- internal/featuretests/secrets_test.go | 5 +- internal/featuretests/tcpproxy_test.go | 133 +-- internal/featuretests/timeoutpolicy_test.go | 39 +- internal/featuretests/timeouts_test.go | 19 +- .../tlscertificatedelegation_test.go | 19 +- .../featuretests/tlsprotocolversion_test.go | 25 +- internal/featuretests/websockets_test.go | 19 +- 74 files changed, 4350 insertions(+), 4122 deletions(-) create mode 100644 internal/envoy/v2/accesslog.go rename internal/envoy/{ => v2}/accesslog_test.go (94%) create mode 100644 internal/envoy/v2/auth.go rename internal/envoy/{ => v2}/auth_test.go (99%) create mode 100644 internal/envoy/v2/bootstrap.go rename internal/envoy/{ => v2}/bootstrap_test.go (97%) create mode 100644 internal/envoy/v2/cluster.go create mode 100644 internal/envoy/v2/cluster_test.go rename internal/envoy/{ => v2}/endpoint.go (99%) rename internal/envoy/{ => v2}/endpoint_test.go (99%) create mode 100644 internal/envoy/v2/healthcheck.go rename internal/envoy/{ => v2}/healthcheck_test.go (91%) create mode 100644 internal/envoy/v2/listener.go create mode 100644 internal/envoy/v2/listener_test.go create mode 100644 internal/envoy/v2/route.go rename internal/envoy/{ => v2}/route_test.go (98%) create mode 100644 internal/envoy/v2/secret.go rename internal/envoy/{ => v2}/secret_test.go (96%) rename internal/envoy/{ => v2}/socket.go (99%) rename internal/envoy/{ => v2}/socket_test.go (99%) rename internal/envoy/{ => v2}/stats.go (99%) rename internal/envoy/{ => v2}/stats_test.go (99%) create mode 100644 internal/envoy/v2/tcp_keepalive.go diff --git a/cmd/contour/contour.go b/cmd/contour/contour.go index ea74d6187f1..7833372a2e0 100644 --- a/cmd/contour/contour.go +++ b/cmd/contour/contour.go @@ -16,9 +16,10 @@ package main import ( "os" + v2 "github.com/projectcontour/contour/internal/envoy/v2" + resource "github.com/envoyproxy/go-control-plane/pkg/resource/v2" "github.com/projectcontour/contour/internal/build" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/k8s" "github.com/sirupsen/logrus" kingpin "gopkg.in/alecthomas/kingpin.v2" @@ -69,7 +70,7 @@ func main() { case sdmShutdown.FullCommand(): sdmShutdownCtx.shutdownHandler() case bootstrap.FullCommand(): - if err := envoy.WriteBootstrap(bootstrapCtx); err != nil { + if err := v2.WriteBootstrap(bootstrapCtx); err != nil { log.WithError(err).Fatal("failed to write bootstrap configuration") } case certgenApp.FullCommand(): diff --git a/cmd/contour/servecontext.go b/cmd/contour/servecontext.go index df2db712968..96df449a90a 100644 --- a/cmd/contour/servecontext.go +++ b/cmd/contour/servecontext.go @@ -25,8 +25,9 @@ import ( "strings" "time" - "github.com/projectcontour/contour/internal/contour" "github.com/projectcontour/contour/internal/envoy" + + "github.com/projectcontour/contour/internal/contour" "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/credentials" diff --git a/cmd/contour/servecontext_test.go b/cmd/contour/servecontext_test.go index caff5b3f614..1ee13a450b5 100644 --- a/cmd/contour/servecontext_test.go +++ b/cmd/contour/servecontext_test.go @@ -28,6 +28,7 @@ import ( "time" "github.com/projectcontour/contour/internal/envoy" + "github.com/projectcontour/contour/internal/fixture" "k8s.io/apimachinery/pkg/types" diff --git a/internal/contour/cluster.go b/internal/contour/cluster.go index a26abb59d88..29f33f3f57c 100644 --- a/internal/contour/cluster.go +++ b/internal/contour/cluster.go @@ -17,11 +17,12 @@ import ( "sort" "sync" - v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" + envoy_api_v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" resource "github.com/envoyproxy/go-control-plane/pkg/resource/v2" "github.com/golang/protobuf/proto" "github.com/projectcontour/contour/internal/dag" "github.com/projectcontour/contour/internal/envoy" + v2 "github.com/projectcontour/contour/internal/envoy/v2" "github.com/projectcontour/contour/internal/protobuf" "github.com/projectcontour/contour/internal/sorter" ) @@ -29,12 +30,12 @@ import ( // ClusterCache manages the contents of the gRPC CDS cache. type ClusterCache struct { mu sync.Mutex - values map[string]*v2.Cluster + values map[string]*envoy_api_v2.Cluster Cond } // Update replaces the contents of the cache with the supplied map. -func (c *ClusterCache) Update(v map[string]*v2.Cluster) { +func (c *ClusterCache) Update(v map[string]*envoy_api_v2.Cluster) { c.mu.Lock() defer c.mu.Unlock() @@ -46,7 +47,7 @@ func (c *ClusterCache) Update(v map[string]*v2.Cluster) { func (c *ClusterCache) Contents() []proto.Message { c.mu.Lock() defer c.mu.Unlock() - var values []*v2.Cluster + var values []*envoy_api_v2.Cluster for _, v := range c.values { values = append(values, v) } @@ -57,7 +58,7 @@ func (c *ClusterCache) Contents() []proto.Message { func (c *ClusterCache) Query(names []string) []proto.Message { c.mu.Lock() defer c.mu.Unlock() - var values []*v2.Cluster + var values []*envoy_api_v2.Cluster for _, n := range names { // if the cluster is not registered we cannot return // a blank cluster because each cluster has a required @@ -80,13 +81,13 @@ func (c *ClusterCache) OnChange(root *dag.DAG) { } type clusterVisitor struct { - clusters map[string]*v2.Cluster + clusters map[string]*envoy_api_v2.Cluster } -// visitCluster produces a map of *v2.Clusters. -func visitClusters(root dag.Vertex) map[string]*v2.Cluster { +// visitCluster produces a map of *envoy_api_v2.Clusters. +func visitClusters(root dag.Vertex) map[string]*envoy_api_v2.Cluster { cv := clusterVisitor{ - clusters: make(map[string]*v2.Cluster), + clusters: make(map[string]*envoy_api_v2.Cluster), } cv.visit(root) return cv.clusters @@ -97,12 +98,12 @@ func (v *clusterVisitor) visit(vertex dag.Vertex) { case *dag.Cluster: name := envoy.Clustername(cluster) if _, ok := v.clusters[name]; !ok { - v.clusters[name] = envoy.Cluster(cluster) + v.clusters[name] = v2.Cluster(cluster) } case *dag.ExtensionCluster: name := cluster.Name if _, ok := v.clusters[name]; !ok { - v.clusters[name] = envoy.ExtensionCluster(cluster) + v.clusters[name] = v2.ExtensionCluster(cluster) } } diff --git a/internal/contour/cluster_test.go b/internal/contour/cluster_test.go index c321b75e35e..875ec346363 100644 --- a/internal/contour/cluster_test.go +++ b/internal/contour/cluster_test.go @@ -17,13 +17,14 @@ import ( "testing" "time" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_cluster "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster" envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes/duration" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/protobuf" v1 "k8s.io/api/core/v1" "k8s.io/api/networking/v1beta1" @@ -45,9 +46,9 @@ func TestClusterCacheContents(t *testing.T) { &v2.Cluster{ Name: "default/kuard/443/da39a3ee5e", AltStatName: "default_kuard_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, }), @@ -55,9 +56,9 @@ func TestClusterCacheContents(t *testing.T) { cluster(&v2.Cluster{ Name: "default/kuard/443/da39a3ee5e", AltStatName: "default_kuard_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, }), @@ -86,9 +87,9 @@ func TestClusterCacheQuery(t *testing.T) { &v2.Cluster{ Name: "default/kuard/443/da39a3ee5e", AltStatName: "default_kuard_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, }), @@ -97,9 +98,9 @@ func TestClusterCacheQuery(t *testing.T) { cluster(&v2.Cluster{ Name: "default/kuard/443/da39a3ee5e", AltStatName: "default_kuard_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, }), @@ -110,9 +111,9 @@ func TestClusterCacheQuery(t *testing.T) { &v2.Cluster{ Name: "default/kuard/443/da39a3ee5e", AltStatName: "default_kuard_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, }), @@ -121,9 +122,9 @@ func TestClusterCacheQuery(t *testing.T) { cluster(&v2.Cluster{ Name: "default/kuard/443/da39a3ee5e", AltStatName: "default_kuard_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, }), @@ -134,9 +135,9 @@ func TestClusterCacheQuery(t *testing.T) { &v2.Cluster{ Name: "default/kuard/443/da39a3ee5e", AltStatName: "default_kuard_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, }), @@ -187,9 +188,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/kuard/443/da39a3ee5e", AltStatName: "default_kuard_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, }), @@ -221,9 +222,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/kuard/443/da39a3ee5e", AltStatName: "default_kuard_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard/https", }, }), @@ -259,9 +260,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/kuard/80/da39a3ee5e", AltStatName: "default_kuard_80", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard/http", }, Http2ProtocolOptions: &envoy_api_v2_core.Http2ProtocolOptions{}, @@ -292,9 +293,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "beurocra-7fe4b4/tiny-cog-7fe4b4/443/da39a3ee5e", AltStatName: "beurocratic-company-test-domain-1_tiny-cog-department-test-instance_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "beurocratic-company-test-domain-1/tiny-cog-department-test-instance/svc-0", }, }), @@ -340,18 +341,18 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/backend/80/da39a3ee5e", AltStatName: "default_backend_80", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/backend/http", }, }, &v2.Cluster{ Name: "default/backend/8080/da39a3ee5e", AltStatName: "default_backend_8080", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/backend/alt", }, }, @@ -393,9 +394,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/backend/80/c184349821", AltStatName: "default_backend_80", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/backend/http", }, HealthChecks: []*envoy_api_v2_core.HealthCheck{{ @@ -455,9 +456,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/backend/80/7f8051653a", AltStatName: "default_backend_80", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/backend/http", }, HealthChecks: []*envoy_api_v2_core.HealthCheck{{ @@ -512,9 +513,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/backend/80/da39a3ee5e", AltStatName: "default_backend_80", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/backend/http", }, }, @@ -556,9 +557,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/backend/80/8bf87fefba", AltStatName: "default_backend_80", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/backend/http", }, LbPolicy: v2.Cluster_LEAST_REQUEST, @@ -601,9 +602,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/backend/80/58d888c08a", AltStatName: "default_backend_80", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/backend/http", }, LbPolicy: v2.Cluster_RANDOM, @@ -648,9 +649,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/backend/80/da39a3ee5e", AltStatName: "default_backend_80", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/backend/http", }, }, @@ -690,9 +691,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/kuard/80/da39a3ee5e", AltStatName: "default_kuard_80", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard/http", }, CircuitBreakers: &envoy_api_v2_cluster.CircuitBreakers{ @@ -737,9 +738,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/kuard/443/da39a3ee5e", AltStatName: "default_kuard_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard/https", }, }), @@ -776,9 +777,9 @@ func TestClusterVisit(t *testing.T) { &v2.Cluster{ Name: "default/kuard/443/da39a3ee5e", AltStatName: "default_kuard_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard/https", }, }), @@ -815,7 +816,7 @@ func cluster(c *v2.Cluster) *v2.Cluster { // NOTE: Keep this in sync with envoy.defaultCluster(). defaults := &v2.Cluster{ ConnectTimeout: protobuf.Duration(250 * time.Millisecond), - CommonLbConfig: envoy.ClusterCommonLBConfig(), + CommonLbConfig: v22.ClusterCommonLBConfig(), LbPolicy: v2.Cluster_ROUND_ROBIN, } diff --git a/internal/contour/endpointstranslator.go b/internal/contour/endpointstranslator.go index db13078d63e..50ed65e5c84 100644 --- a/internal/contour/endpointstranslator.go +++ b/internal/contour/endpointstranslator.go @@ -18,12 +18,13 @@ import ( "sort" "sync" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_endpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint" resource "github.com/envoyproxy/go-control-plane/pkg/resource/v2" "github.com/golang/protobuf/proto" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/k8s" "github.com/projectcontour/contour/internal/protobuf" "github.com/projectcontour/contour/internal/sorter" @@ -70,8 +71,8 @@ func RecalculateEndpoints(port v1.ServicePort, ep *v1.Endpoints) []*LoadBalancin sort.Slice(addresses, func(i, j int) bool { return addresses[i].IP < addresses[j].IP }) for _, a := range addresses { - addr := envoy.SocketAddress(a.IP, int(p.Port)) - lb = append(lb, envoy.LBEndpoint(addr)) + addr := v22.SocketAddress(a.IP, int(p.Port)) + lb = append(lb, v22.LBEndpoint(addr)) } } } diff --git a/internal/contour/endpointstranslator_test.go b/internal/contour/endpointstranslator_test.go index 43753ea6a71..aa1eebb48b5 100644 --- a/internal/contour/endpointstranslator_test.go +++ b/internal/contour/endpointstranslator_test.go @@ -16,11 +16,12 @@ package contour import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_endpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint" "github.com/golang/protobuf/proto" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" "github.com/projectcontour/contour/internal/protobuf" "github.com/stretchr/testify/require" @@ -38,13 +39,13 @@ func TestEndpointsTranslatorContents(t *testing.T) { }, "simple": { contents: clusterloadassignments( - envoy.ClusterLoadAssignment("default/httpbin-org", - envoy.SocketAddress("10.10.10.10", 80), + v22.ClusterLoadAssignment("default/httpbin-org", + v22.SocketAddress("10.10.10.10", 80), ), ), want: []proto.Message{ - envoy.ClusterLoadAssignment("default/httpbin-org", - envoy.SocketAddress("10.10.10.10", 80), + v22.ClusterLoadAssignment("default/httpbin-org", + v22.SocketAddress("10.10.10.10", 80), ), }, }, @@ -68,40 +69,40 @@ func TestEndpointCacheQuery(t *testing.T) { }{ "exact match": { contents: clusterloadassignments( - envoy.ClusterLoadAssignment("default/httpbin-org", - envoy.SocketAddress("10.10.10.10", 80), + v22.ClusterLoadAssignment("default/httpbin-org", + v22.SocketAddress("10.10.10.10", 80), ), ), query: []string{"default/httpbin-org"}, want: []proto.Message{ - envoy.ClusterLoadAssignment("default/httpbin-org", - envoy.SocketAddress("10.10.10.10", 80), + v22.ClusterLoadAssignment("default/httpbin-org", + v22.SocketAddress("10.10.10.10", 80), ), }, }, "partial match": { contents: clusterloadassignments( - envoy.ClusterLoadAssignment("default/httpbin-org", - envoy.SocketAddress("10.10.10.10", 80), + v22.ClusterLoadAssignment("default/httpbin-org", + v22.SocketAddress("10.10.10.10", 80), ), ), query: []string{"default/kuard/8080", "default/httpbin-org"}, want: []proto.Message{ - envoy.ClusterLoadAssignment("default/httpbin-org", - envoy.SocketAddress("10.10.10.10", 80), + v22.ClusterLoadAssignment("default/httpbin-org", + v22.SocketAddress("10.10.10.10", 80), ), - envoy.ClusterLoadAssignment("default/kuard/8080"), + v22.ClusterLoadAssignment("default/kuard/8080"), }, }, "no match": { contents: clusterloadassignments( - envoy.ClusterLoadAssignment("default/httpbin-org", - envoy.SocketAddress("10.10.10.10", 80), + v22.ClusterLoadAssignment("default/httpbin-org", + v22.SocketAddress("10.10.10.10", 80), ), ), query: []string{"default/kuard/8080"}, want: []proto.Message{ - envoy.ClusterLoadAssignment("default/kuard/8080"), + v22.ClusterLoadAssignment("default/kuard/8080"), }, }, } @@ -169,7 +170,7 @@ func TestEndpointsTranslatorAddEndpoints(t *testing.T) { &v2.ClusterLoadAssignment{ClusterName: "default/httpbin-org/b"}, &v2.ClusterLoadAssignment{ ClusterName: "default/simple", - Endpoints: envoy.WeightedEndpoints(1, envoy.SocketAddress("192.168.183.24", 8080)), + Endpoints: v22.WeightedEndpoints(1, v22.SocketAddress("192.168.183.24", 8080)), }, }, }, @@ -190,11 +191,11 @@ func TestEndpointsTranslatorAddEndpoints(t *testing.T) { &v2.ClusterLoadAssignment{ClusterName: "default/httpbin-org/b"}, &v2.ClusterLoadAssignment{ ClusterName: "default/simple", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("23.23.247.89", 80), // addresses should be sorted - envoy.SocketAddress("50.17.192.147", 80), - envoy.SocketAddress("50.17.206.192", 80), - envoy.SocketAddress("50.19.99.160", 80), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("23.23.247.89", 80), // addresses should be sorted + v22.SocketAddress("50.17.192.147", 80), + v22.SocketAddress("50.17.206.192", 80), + v22.SocketAddress("50.19.99.160", 80), ), }, }, @@ -213,11 +214,11 @@ func TestEndpointsTranslatorAddEndpoints(t *testing.T) { // Results should be sorted by cluster name. &v2.ClusterLoadAssignment{ ClusterName: "default/httpbin-org/a", - Endpoints: envoy.WeightedEndpoints(1, envoy.SocketAddress("10.10.1.1", 8675)), + Endpoints: v22.WeightedEndpoints(1, v22.SocketAddress("10.10.1.1", 8675)), }, &v2.ClusterLoadAssignment{ ClusterName: "default/httpbin-org/b", - Endpoints: envoy.WeightedEndpoints(1, envoy.SocketAddress("10.10.1.1", 309)), + Endpoints: v22.WeightedEndpoints(1, v22.SocketAddress("10.10.1.1", 309)), }, &v2.ClusterLoadAssignment{ClusterName: "default/simple"}, }, @@ -236,16 +237,16 @@ func TestEndpointsTranslatorAddEndpoints(t *testing.T) { want: []proto.Message{ &v2.ClusterLoadAssignment{ ClusterName: "default/httpbin-org/a", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("10.10.1.1", 8675), // addresses should be sorted - envoy.SocketAddress("10.10.2.2", 8675), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("10.10.1.1", 8675), // addresses should be sorted + v22.SocketAddress("10.10.2.2", 8675), ), }, &v2.ClusterLoadAssignment{ ClusterName: "default/httpbin-org/b", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("10.10.1.1", 309), - envoy.SocketAddress("10.10.2.2", 309), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("10.10.1.1", 309), + v22.SocketAddress("10.10.2.2", 309), ), }, &v2.ClusterLoadAssignment{ClusterName: "default/simple"}, @@ -274,15 +275,15 @@ func TestEndpointsTranslatorAddEndpoints(t *testing.T) { want: []proto.Message{ &v2.ClusterLoadAssignment{ ClusterName: "default/httpbin-org/a", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("10.10.1.1", 8675), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("10.10.1.1", 8675), ), }, &v2.ClusterLoadAssignment{ ClusterName: "default/httpbin-org/b", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("10.10.1.1", 309), - envoy.SocketAddress("10.10.2.2", 309), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("10.10.1.1", 309), + v22.SocketAddress("10.10.2.2", 309), ), }, &v2.ClusterLoadAssignment{ClusterName: "default/simple"}, @@ -359,9 +360,9 @@ func TestEndpointsTranslatorRemoveEndpoints(t *testing.T) { ), }), want: []proto.Message{ - envoy.ClusterLoadAssignment("default/simple"), - envoy.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/http"), - envoy.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/https"), + v22.ClusterLoadAssignment("default/simple"), + v22.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/http"), + v22.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/https"), }, }, "remove different": { @@ -382,10 +383,10 @@ func TestEndpointsTranslatorRemoveEndpoints(t *testing.T) { want: []proto.Message{ &v2.ClusterLoadAssignment{ ClusterName: "default/simple", - Endpoints: envoy.WeightedEndpoints(1, envoy.SocketAddress("192.168.183.24", 8080)), + Endpoints: v22.WeightedEndpoints(1, v22.SocketAddress("192.168.183.24", 8080)), }, - envoy.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/http"), - envoy.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/https"), + v22.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/http"), + v22.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/https"), }, }, "remove non existent": { @@ -397,9 +398,9 @@ func TestEndpointsTranslatorRemoveEndpoints(t *testing.T) { ), }), want: []proto.Message{ - envoy.ClusterLoadAssignment("default/simple"), - envoy.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/http"), - envoy.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/https"), + v22.ClusterLoadAssignment("default/simple"), + v22.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/http"), + v22.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/https"), }, }, "remove long name": { @@ -435,9 +436,9 @@ func TestEndpointsTranslatorRemoveEndpoints(t *testing.T) { }, ), want: []proto.Message{ - envoy.ClusterLoadAssignment("default/simple"), - envoy.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/http"), - envoy.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/https"), + v22.ClusterLoadAssignment("default/simple"), + v22.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/http"), + v22.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/https"), }, }, } @@ -483,8 +484,8 @@ func TestEndpointsTranslatorRecomputeClusterLoadAssignment(t *testing.T) { want: []proto.Message{ &v2.ClusterLoadAssignment{ ClusterName: "default/simple", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("192.168.183.24", 8080)), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("192.168.183.24", 8080)), }, }, }, @@ -511,11 +512,11 @@ func TestEndpointsTranslatorRecomputeClusterLoadAssignment(t *testing.T) { want: []proto.Message{ &v2.ClusterLoadAssignment{ ClusterName: "default/httpbin-org", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("23.23.247.89", 80), - envoy.SocketAddress("50.17.192.147", 80), - envoy.SocketAddress("50.17.206.192", 80), - envoy.SocketAddress("50.19.99.160", 80), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("23.23.247.89", 80), + v22.SocketAddress("50.17.192.147", 80), + v22.SocketAddress("50.17.206.192", 80), + v22.SocketAddress("50.19.99.160", 80), ), }, }, @@ -539,8 +540,8 @@ func TestEndpointsTranslatorRecomputeClusterLoadAssignment(t *testing.T) { want: []proto.Message{ &v2.ClusterLoadAssignment{ ClusterName: "default/secure/https", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("192.168.183.24", 8443)), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("192.168.183.24", 8443)), }, }, }, @@ -585,7 +586,7 @@ func TestEndpointsTranslatorScaleToZeroEndpoints(t *testing.T) { want := []proto.Message{ &v2.ClusterLoadAssignment{ ClusterName: "default/simple", - Endpoints: envoy.WeightedEndpoints(1, envoy.SocketAddress("192.168.183.24", 8080)), + Endpoints: v22.WeightedEndpoints(1, v22.SocketAddress("192.168.183.24", 8080)), }, } @@ -646,9 +647,9 @@ func TestEndpointsTranslatorWeightedService(t *testing.T) { // Each helper builds a `LocalityLbEndpoints` with one // entry, so we can compose the final result by reaching // in an taking the first element of each slice. - w0 := envoy.Endpoints(envoy.SocketAddress("192.168.183.24", 8080)) - w1 := envoy.WeightedEndpoints(1, envoy.SocketAddress("192.168.183.24", 8080)) - w2 := envoy.WeightedEndpoints(2, envoy.SocketAddress("192.168.183.24", 8080)) + w0 := v22.Endpoints(v22.SocketAddress("192.168.183.24", 8080)) + w1 := v22.WeightedEndpoints(1, v22.SocketAddress("192.168.183.24", 8080)) + w2 := v22.WeightedEndpoints(2, v22.SocketAddress("192.168.183.24", 8080)) want := []proto.Message{ &v2.ClusterLoadAssignment{ @@ -704,9 +705,9 @@ func TestEndpointsTranslatorDefaultWeightedService(t *testing.T) { // Each helper builds a `LocalityLbEndpoints` with one // entry, so we can compose the final result by reaching // in an taking the first element of each slice. - w0 := envoy.WeightedEndpoints(1, envoy.SocketAddress("192.168.183.24", 8080)) - w1 := envoy.WeightedEndpoints(1, envoy.SocketAddress("192.168.183.24", 8080)) - w2 := envoy.WeightedEndpoints(1, envoy.SocketAddress("192.168.183.24", 8080)) + w0 := v22.WeightedEndpoints(1, v22.SocketAddress("192.168.183.24", 8080)) + w1 := v22.WeightedEndpoints(1, v22.SocketAddress("192.168.183.24", 8080)) + w2 := v22.WeightedEndpoints(1, v22.SocketAddress("192.168.183.24", 8080)) want := []proto.Message{ &v2.ClusterLoadAssignment{ diff --git a/internal/contour/listener.go b/internal/contour/listener.go index e742024325b..aeaf5ebec58 100644 --- a/internal/contour/listener.go +++ b/internal/contour/listener.go @@ -18,6 +18,9 @@ import ( "sort" "sync" + "github.com/projectcontour/contour/internal/envoy" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" @@ -26,7 +29,6 @@ import ( resource "github.com/envoyproxy/go-control-plane/pkg/resource/v2" "github.com/golang/protobuf/proto" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/protobuf" "github.com/projectcontour/contour/internal/sorter" "github.com/projectcontour/contour/internal/timeout" @@ -190,18 +192,18 @@ func (lvc *ListenerConfig) accesslogFields() []string { func (lvc *ListenerConfig) newInsecureAccessLog() []*envoy_api_v2_accesslog.AccessLog { switch lvc.accesslogType() { case "json": - return envoy.FileAccessLogJSON(lvc.httpAccessLog(), lvc.accesslogFields()) + return v22.FileAccessLogJSON(lvc.httpAccessLog(), lvc.accesslogFields()) default: - return envoy.FileAccessLogEnvoy(lvc.httpAccessLog()) + return v22.FileAccessLogEnvoy(lvc.httpAccessLog()) } } func (lvc *ListenerConfig) newSecureAccessLog() []*envoy_api_v2_accesslog.AccessLog { switch lvc.accesslogType() { case "json": - return envoy.FileAccessLogJSON(lvc.httpsAccessLog(), lvc.accesslogFields()) + return v22.FileAccessLogJSON(lvc.httpsAccessLog(), lvc.accesslogFields()) default: - return envoy.FileAccessLogEnvoy(lvc.httpsAccessLog()) + return v22.FileAccessLogEnvoy(lvc.httpsAccessLog()) } } @@ -226,7 +228,7 @@ type ListenerCache struct { // NewListenerCache returns an instance of a ListenerCache func NewListenerCache(config ListenerConfig, address string, port int) *ListenerCache { - stats := envoy.StatsListener(address, port) + stats := v22.StatsListener(address, port) return &ListenerCache{ Config: config, staticValues: map[string]*v2.Listener{ @@ -302,7 +304,7 @@ func visitListeners(root dag.Vertex, lvc *ListenerConfig) map[string]*v2.Listene lv := listenerVisitor{ ListenerConfig: lvc, listeners: map[string]*v2.Listener{ - ENVOY_HTTPS_LISTENER: envoy.Listener( + ENVOY_HTTPS_LISTENER: v22.Listener( ENVOY_HTTPS_LISTENER, lvc.httpsAddress(), lvc.httpsPort(), @@ -315,7 +317,7 @@ func visitListeners(root dag.Vertex, lvc *ListenerConfig) map[string]*v2.Listene if lv.http { // Add a listener if there are vhosts bound to http. - cm := envoy.HTTPConnectionManagerBuilder(). + cm := v22.HTTPConnectionManagerBuilder(). Codec(envoy.CodecForVersions(lv.DefaultHTTPVersions...)). DefaultFilters(). RouteConfigName(ENVOY_HTTP_LISTENER). @@ -328,7 +330,7 @@ func visitListeners(root dag.Vertex, lvc *ListenerConfig) map[string]*v2.Listene ConnectionShutdownGracePeriod(lvc.ConnectionShutdownGracePeriod). Get() - lv.listeners[ENVOY_HTTP_LISTENER] = envoy.Listener( + lv.listeners[ENVOY_HTTP_LISTENER] = v22.Listener( ENVOY_HTTP_LISTENER, lvc.httpAddress(), lvc.httpPort(), @@ -351,15 +353,15 @@ func visitListeners(root dag.Vertex, lvc *ListenerConfig) map[string]*v2.Listene func proxyProtocol(useProxy bool) []*envoy_api_v2_listener.ListenerFilter { if useProxy { - return envoy.ListenerFilters( - envoy.ProxyProtocol(), + return v22.ListenerFilters( + v22.ProxyProtocol(), ) } return nil } func secureProxyProtocol(useProxy bool) []*envoy_api_v2_listener.ListenerFilter { - return append(proxyProtocol(useProxy), envoy.TLSInspector()) + return append(proxyProtocol(useProxy), v22.TLSInspector()) } func (v *listenerVisitor) visit(vertex dag.Vertex) { @@ -384,7 +386,7 @@ func (v *listenerVisitor) visit(vertex dag.Vertex) { var authFilter *http.HttpFilter if vh.AuthorizationService != nil { - authFilter = envoy.FilterExternalAuthz( + authFilter = v22.FilterExternalAuthz( vh.AuthorizationService.Name, vh.AuthorizationFailOpen, vh.AuthorizationResponseTimeout, @@ -398,10 +400,10 @@ func (v *listenerVisitor) visit(vertex dag.Vertex) { // metrics prefix to keep compatibility with previous // Contour versions since the metrics prefix will be // coded into monitoring dashboards. - filters = envoy.Filters( - envoy.HTTPConnectionManagerBuilder(). + filters = v22.Filters( + v22.HTTPConnectionManagerBuilder(). Codec(envoy.CodecForVersions(v.DefaultHTTPVersions...)). - AddFilter(envoy.FilterMisdirectedRequests(vh.VirtualHost.Name)). + AddFilter(v22.FilterMisdirectedRequests(vh.VirtualHost.Name)). DefaultFilters(). AddFilter(authFilter). RouteConfigName(path.Join("https", vh.VirtualHost.Name)). @@ -417,8 +419,8 @@ func (v *listenerVisitor) visit(vertex dag.Vertex) { alpnProtos = envoy.ProtoNamesForVersions(v.DefaultHTTPVersions...) } else { - filters = envoy.Filters( - envoy.TCPProxy(ENVOY_HTTPS_LISTENER, + filters = v22.Filters( + v22.TCPProxy(ENVOY_HTTPS_LISTENER, vh.TCPProxy, v.ListenerConfig.newSecureAccessLog()), ) @@ -435,7 +437,7 @@ func (v *listenerVisitor) visit(vertex dag.Vertex) { // Choose the higher of the configured or requested TLS version. vers := max(v.ListenerConfig.minTLSVersion(), vh.MinTLSVersion) - downstreamTLS = envoy.DownstreamTLSContext( + downstreamTLS = v22.DownstreamTLSContext( vh.Secret, vers, vh.DownstreamValidation, @@ -443,25 +445,25 @@ func (v *listenerVisitor) visit(vertex dag.Vertex) { } v.listeners[ENVOY_HTTPS_LISTENER].FilterChains = append(v.listeners[ENVOY_HTTPS_LISTENER].FilterChains, - envoy.FilterChainTLS(vh.VirtualHost.Name, downstreamTLS, filters)) + v22.FilterChainTLS(vh.VirtualHost.Name, downstreamTLS, filters)) // If this VirtualHost has enabled the fallback certificate then set a default // FilterChain which will allow routes with this vhost to accept non-SNI TLS requests. // Note that we don't add the misdirected requests filter on this chain because at this // point we don't actually know the full set of server names that will be bound to the // filter chain through the ENVOY_FALLBACK_ROUTECONFIG route configuration. - if vh.FallbackCertificate != nil && !envoy.ContainsFallbackFilterChain(v.listeners[ENVOY_HTTPS_LISTENER].FilterChains) { + if vh.FallbackCertificate != nil && !v22.ContainsFallbackFilterChain(v.listeners[ENVOY_HTTPS_LISTENER].FilterChains) { // Construct the downstreamTLSContext passing the configured fallbackCertificate. The TLS minProtocolVersion will use // the value defined in the Contour Configuration file if defined. - downstreamTLS = envoy.DownstreamTLSContext( + downstreamTLS = v22.DownstreamTLSContext( vh.FallbackCertificate, v.ListenerConfig.minTLSVersion(), vh.DownstreamValidation, alpnProtos...) // Default filter chain - filters = envoy.Filters( - envoy.HTTPConnectionManagerBuilder(). + filters = v22.Filters( + v22.HTTPConnectionManagerBuilder(). DefaultFilters(). RouteConfigName(ENVOY_FALLBACK_ROUTECONFIG). MetricsPrefix(ENVOY_HTTPS_LISTENER). @@ -475,7 +477,7 @@ func (v *listenerVisitor) visit(vertex dag.Vertex) { ) v.listeners[ENVOY_HTTPS_LISTENER].FilterChains = append(v.listeners[ENVOY_HTTPS_LISTENER].FilterChains, - envoy.FilterChainTLSFallback(downstreamTLS, filters)) + v22.FilterChainTLSFallback(downstreamTLS, filters)) } default: diff --git a/internal/contour/listener_test.go b/internal/contour/listener_test.go index cfd3bae1a1d..e2f176ec455 100644 --- a/internal/contour/listener_test.go +++ b/internal/contour/listener_test.go @@ -18,6 +18,8 @@ import ( "testing" "time" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" @@ -25,7 +27,6 @@ import ( "github.com/golang/protobuf/proto" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/protobuf" "github.com/projectcontour/contour/internal/timeout" v1 "k8s.io/api/core/v1" @@ -46,16 +47,16 @@ func TestListenerCacheContents(t *testing.T) { "simple": { contents: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), want: []proto.Message{ &v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, }, }, @@ -80,43 +81,43 @@ func TestListenerCacheQuery(t *testing.T) { "exact match": { contents: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), query: []string{ENVOY_HTTP_LISTENER}, want: []proto.Message{ &v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, }, }, "partial match": { contents: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), query: []string{ENVOY_HTTP_LISTENER, "stats-listener"}, want: []proto.Message{ &v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, }, }, "no match": { contents: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), query: []string{"stats-listener"}, want: nil, @@ -135,20 +136,20 @@ func TestListenerCacheQuery(t *testing.T) { func TestListenerVisit(t *testing.T) { httpsFilterFor := func(vhost string) *envoy_api_v2_listener.Filter { - return envoy.HTTPConnectionManagerBuilder(). - AddFilter(envoy.FilterMisdirectedRequests(vhost)). + return v22.HTTPConnectionManagerBuilder(). + AddFilter(v22.FilterMisdirectedRequests(vhost)). DefaultFilters(). MetricsPrefix(ENVOY_HTTPS_LISTENER). RouteConfigName(path.Join("https", vhost)). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). Get() } - fallbackCertFilter := envoy.HTTPConnectionManagerBuilder(). + fallbackCertFilter := v22.HTTPConnectionManagerBuilder(). DefaultFilters(). MetricsPrefix(ENVOY_HTTPS_LISTENER). RouteConfigName(ENVOY_FALLBACK_ROUTECONFIG). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). Get() tests := map[string]struct { @@ -188,9 +189,9 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "one http only httpproxy": { @@ -231,9 +232,9 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "simple ingress with secret": { @@ -284,23 +285,23 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"whatever.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("whatever.example.com")), + Filters: v22.Filters(httpsFilterFor("whatever.example.com")), }}, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "multiple tls ingress with secrets should be sorted": { @@ -373,29 +374,29 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"sortedfirst.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("sortedfirst.example.com")), + Filters: v22.Filters(httpsFilterFor("sortedfirst.example.com")), }, { FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"sortedsecond.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("sortedsecond.example.com")), + Filters: v22.Filters(httpsFilterFor("sortedsecond.example.com")), }}, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "simple ingress with missing secret": { @@ -446,9 +447,9 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "simple httpproxy with secret": { @@ -497,23 +498,23 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"www.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("www.example.com")), + Filters: v22.Filters(httpsFilterFor("www.example.com")), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "ingress with allow-http: false": { @@ -584,18 +585,18 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"www.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("www.example.com")), + Filters: v22.Filters(httpsFilterFor("www.example.com")), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "http listener on non default port": { // issue 72 @@ -652,23 +653,23 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("127.0.0.100", 9100), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("127.0.0.100", 9100), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("127.0.0.200", 9200), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("127.0.0.200", 9200), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"whatever.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("whatever.example.com")), + Filters: v22.Filters(httpsFilterFor("whatever.example.com")), }}, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "use proxy proto": { @@ -722,27 +723,27 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - ListenerFilters: envoy.ListenerFilters( - envoy.ProxyProtocol(), + Address: v22.SocketAddress("0.0.0.0", 8080), + ListenerFilters: v22.ListenerFilters( + v22.ProxyProtocol(), ), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.ProxyProtocol(), - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.ProxyProtocol(), + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"whatever.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("whatever.example.com")), + Filters: v22.Filters(httpsFilterFor("whatever.example.com")), }}, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "--envoy-http-access-log": { @@ -797,29 +798,29 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress(DEFAULT_HTTP_LISTENER_ADDRESS, DEFAULT_HTTP_LISTENER_PORT), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy("/tmp/http_access.log"), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress(DEFAULT_HTTP_LISTENER_ADDRESS, DEFAULT_HTTP_LISTENER_PORT), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy("/tmp/http_access.log"), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress(DEFAULT_HTTPS_LISTENER_ADDRESS, DEFAULT_HTTPS_LISTENER_PORT), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress(DEFAULT_HTTPS_LISTENER_ADDRESS, DEFAULT_HTTPS_LISTENER_PORT), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"whatever.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(envoy.HTTPConnectionManagerBuilder(). - AddFilter(envoy.FilterMisdirectedRequests("whatever.example.com")). + Filters: v22.Filters(v22.HTTPConnectionManagerBuilder(). + AddFilter(v22.FilterMisdirectedRequests("whatever.example.com")). DefaultFilters(). MetricsPrefix(ENVOY_HTTPS_LISTENER). RouteConfigName(path.Join("https", "whatever.example.com")). - AccessLoggers(envoy.FileAccessLogEnvoy("/tmp/https_access.log")). + AccessLoggers(v22.FileAccessLogEnvoy("/tmp/https_access.log")). Get()), }}, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "tls-min-protocol-version from config": { @@ -873,23 +874,23 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"whatever.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_3, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("whatever.example.com")), + Filters: v22.Filters(httpsFilterFor("whatever.example.com")), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "tls-min-protocol-version from config overridden by annotation": { @@ -946,23 +947,23 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"whatever.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_3, "h2", "http/1.1"), // note, cannot downgrade from the configured version - Filters: envoy.Filters(httpsFilterFor("whatever.example.com")), + Filters: v22.Filters(httpsFilterFor("whatever.example.com")), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "tls-min-protocol-version from config overridden by legacy annotation": { @@ -1019,23 +1020,23 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"whatever.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_3, "h2", "http/1.1"), // note, cannot downgrade from the configured version - Filters: envoy.Filters(httpsFilterFor("whatever.example.com")), + Filters: v22.Filters(httpsFilterFor("whatever.example.com")), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "tls-min-protocol-version from config overridden by httpproxy": { @@ -1088,23 +1089,23 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"www.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_3, "h2", "http/1.1"), // note, cannot downgrade from the configured version - Filters: envoy.Filters(httpsFilterFor("www.example.com")), + Filters: v22.Filters(httpsFilterFor("www.example.com")), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "httpproxy with fallback certificate": { @@ -1170,30 +1171,30 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"www.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("www.example.com")), + Filters: v22.Filters(httpsFilterFor("www.example.com")), }, { FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ TransportProtocol: "tls", }, TransportSocket: transportSocket("fallbacksecret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(fallbackCertFilter), + Filters: v22.Filters(fallbackCertFilter), Name: "fallback-certificate", }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "multiple httpproxies with fallback certificate": { @@ -1284,39 +1285,39 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{ { FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"www.another.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("www.another.com")), + Filters: v22.Filters(httpsFilterFor("www.another.com")), }, { FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"www.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("www.example.com")), + Filters: v22.Filters(httpsFilterFor("www.example.com")), }, { FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ TransportProtocol: "tls", }, TransportSocket: transportSocket("fallbacksecret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(fallbackCertFilter), + Filters: v22.Filters(fallbackCertFilter), Name: "fallback-certificate", }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "httpproxy with fallback certificate - no cert passed": { @@ -1429,23 +1430,23 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager(ENVOY_HTTP_LISTENER, v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"www.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(httpsFilterFor("www.example.com")), + Filters: v22.Filters(httpsFilterFor("www.example.com")), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "httpproxy with connection idle timeout set in visitor config": { @@ -1489,17 +1490,17 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManagerBuilder(). + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManagerBuilder(). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). DefaultFilters(). ConnectionIdleTimeout(timeout.DurationSetting(90 * time.Second)). Get(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "httpproxy with stream idle timeout set in visitor config": { @@ -1543,17 +1544,17 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManagerBuilder(). + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManagerBuilder(). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). DefaultFilters(). StreamIdleTimeout(timeout.DurationSetting(90 * time.Second)). Get(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "httpproxy with max connection duration set in visitor config": { @@ -1597,17 +1598,17 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManagerBuilder(). + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManagerBuilder(). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). DefaultFilters(). MaxConnectionDuration(timeout.DurationSetting(90 * time.Second)). Get(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "httpproxy with connection shutdown grace period set in visitor config": { @@ -1651,17 +1652,17 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManagerBuilder(). + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManagerBuilder(). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). DefaultFilters(). ConnectionShutdownGracePeriod(timeout.DurationSetting(90 * time.Second)). Get(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "httpsproxy with secret with connection idle timeout set in visitor config": { @@ -1713,37 +1714,37 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManagerBuilder(). + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManagerBuilder(). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). DefaultFilters(). ConnectionIdleTimeout(timeout.DurationSetting(90 * time.Second)). Get(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"www.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(envoy.HTTPConnectionManagerBuilder(). - AddFilter(envoy.FilterMisdirectedRequests("www.example.com")). + Filters: v22.Filters(v22.HTTPConnectionManagerBuilder(). + AddFilter(v22.FilterMisdirectedRequests("www.example.com")). DefaultFilters(). MetricsPrefix(ENVOY_HTTPS_LISTENER). RouteConfigName(path.Join("https", "www.example.com")). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). ConnectionIdleTimeout(timeout.DurationSetting(90 * time.Second)). Get()), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "httpsproxy with secret with stream idle timeout set in visitor config": { @@ -1795,37 +1796,37 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManagerBuilder(). + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManagerBuilder(). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). DefaultFilters(). StreamIdleTimeout(timeout.DurationSetting(90 * time.Second)). Get(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"www.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(envoy.HTTPConnectionManagerBuilder(). - AddFilter(envoy.FilterMisdirectedRequests("www.example.com")). + Filters: v22.Filters(v22.HTTPConnectionManagerBuilder(). + AddFilter(v22.FilterMisdirectedRequests("www.example.com")). DefaultFilters(). MetricsPrefix(ENVOY_HTTPS_LISTENER). RouteConfigName(path.Join("https", "www.example.com")). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). StreamIdleTimeout(timeout.DurationSetting(90 * time.Second)). Get()), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "httpsproxy with secret with max connection duration set in visitor config": { @@ -1877,37 +1878,37 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManagerBuilder(). + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManagerBuilder(). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). DefaultFilters(). MaxConnectionDuration(timeout.DurationSetting(90 * time.Second)). Get(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"www.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(envoy.HTTPConnectionManagerBuilder(). - AddFilter(envoy.FilterMisdirectedRequests("www.example.com")). + Filters: v22.Filters(v22.HTTPConnectionManagerBuilder(). + AddFilter(v22.FilterMisdirectedRequests("www.example.com")). DefaultFilters(). MetricsPrefix(ENVOY_HTTPS_LISTENER). RouteConfigName(path.Join("https", "www.example.com")). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). MaxConnectionDuration(timeout.DurationSetting(90 * time.Second)). Get()), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, "httpsproxy with secret with connection shutdown grace period set in visitor config": { @@ -1959,37 +1960,37 @@ func TestListenerVisit(t *testing.T) { }, want: listenermap(&v2.Listener{ Name: ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManagerBuilder(). + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManagerBuilder(). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). DefaultFilters(). ConnectionShutdownGracePeriod(timeout.DurationSetting(90 * time.Second)). Get(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"www.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), - Filters: envoy.Filters(envoy.HTTPConnectionManagerBuilder(). - AddFilter(envoy.FilterMisdirectedRequests("www.example.com")). + Filters: v22.Filters(v22.HTTPConnectionManagerBuilder(). + AddFilter(v22.FilterMisdirectedRequests("www.example.com")). DefaultFilters(). MetricsPrefix(ENVOY_HTTPS_LISTENER). RouteConfigName(path.Join("https", "www.example.com")). - AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). ConnectionShutdownGracePeriod(timeout.DurationSetting(90 * time.Second)). Get()), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }), }, } @@ -2014,8 +2015,8 @@ func transportSocket(secretname string, tlsMinProtoVersion envoy_api_v2_auth.Tls Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), }, } - return envoy.DownstreamTLSTransportSocket( - envoy.DownstreamTLSContext(secret, tlsMinProtoVersion, nil, alpnprotos...), + return v22.DownstreamTLSTransportSocket( + v22.DownstreamTLSContext(secret, tlsMinProtoVersion, nil, alpnprotos...), ) } diff --git a/internal/contour/route.go b/internal/contour/route.go index d5e8530f1fa..a3c2cc3c284 100644 --- a/internal/contour/route.go +++ b/internal/contour/route.go @@ -18,13 +18,14 @@ import ( "sort" "sync" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" resource "github.com/envoyproxy/go-control-plane/pkg/resource/v2" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes/any" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/protobuf" "github.com/projectcontour/contour/internal/sorter" ) @@ -105,7 +106,7 @@ func visitRoutes(root dag.Vertex) map[string]*v2.RouteConfiguration { // SNI names disjoint when we later configure the listener. rv := routeVisitor{ routes: map[string]*v2.RouteConfiguration{ - ENVOY_HTTP_LISTENER: envoy.RouteConfiguration(ENVOY_HTTP_LISTENER), + ENVOY_HTTP_LISTENER: v22.RouteConfiguration(ENVOY_HTTP_LISTENER), }, } @@ -132,20 +133,20 @@ func (v *routeVisitor) onVirtualHost(vh *dag.VirtualHost) { // to a SecureVirtualHost that requires upgrade, this logic can move to // envoy.RouteRoute. routes = append(routes, &envoy_api_v2_route.Route{ - Match: envoy.RouteMatch(route), - Action: envoy.UpgradeHTTPS(), + Match: v22.RouteMatch(route), + Action: v22.UpgradeHTTPS(), }) } else { rt := &envoy_api_v2_route.Route{ - Match: envoy.RouteMatch(route), - Action: envoy.RouteRoute(route), + Match: v22.RouteMatch(route), + Action: v22.RouteRoute(route), } if route.RequestHeadersPolicy != nil { - rt.RequestHeadersToAdd = envoy.HeaderValueList(route.RequestHeadersPolicy.Set, false) + rt.RequestHeadersToAdd = v22.HeaderValueList(route.RequestHeadersPolicy.Set, false) rt.RequestHeadersToRemove = route.RequestHeadersPolicy.Remove } if route.ResponseHeadersPolicy != nil { - rt.ResponseHeadersToAdd = envoy.HeaderValueList(route.ResponseHeadersPolicy.Set, false) + rt.ResponseHeadersToAdd = v22.HeaderValueList(route.ResponseHeadersPolicy.Set, false) rt.ResponseHeadersToRemove = route.ResponseHeadersPolicy.Remove } routes = append(routes, rt) @@ -156,7 +157,7 @@ func (v *routeVisitor) onVirtualHost(vh *dag.VirtualHost) { sortRoutes(routes) v.routes[ENVOY_HTTP_LISTENER].VirtualHosts = append(v.routes[ENVOY_HTTP_LISTENER].VirtualHosts, - envoy.VirtualHost(vh.Name, routes...)) + v22.VirtualHost(vh.Name, routes...)) } } @@ -170,15 +171,15 @@ func (v *routeVisitor) onSecureVirtualHost(svh *dag.SecureVirtualHost) { } rt := &envoy_api_v2_route.Route{ - Match: envoy.RouteMatch(route), - Action: envoy.RouteRoute(route), + Match: v22.RouteMatch(route), + Action: v22.RouteRoute(route), } if route.RequestHeadersPolicy != nil { - rt.RequestHeadersToAdd = envoy.HeaderValueList(route.RequestHeadersPolicy.Set, false) + rt.RequestHeadersToAdd = v22.HeaderValueList(route.RequestHeadersPolicy.Set, false) rt.RequestHeadersToRemove = route.RequestHeadersPolicy.Remove } if route.ResponseHeadersPolicy != nil { - rt.ResponseHeadersToAdd = envoy.HeaderValueList(route.ResponseHeadersPolicy.Set, false) + rt.ResponseHeadersToAdd = v22.HeaderValueList(route.ResponseHeadersPolicy.Set, false) rt.ResponseHeadersToRemove = route.ResponseHeadersPolicy.Remove } @@ -187,12 +188,12 @@ func (v *routeVisitor) onSecureVirtualHost(svh *dag.SecureVirtualHost) { // Apply per-route authorization policy modifications. if route.AuthDisabled { rt.TypedPerFilterConfig = map[string]*any.Any{ - "envoy.filters.http.ext_authz": envoy.RouteAuthzDisabled(), + "envoy.filters.http.ext_authz": v22.RouteAuthzDisabled(), } } else { if len(route.AuthContext) > 0 { rt.TypedPerFilterConfig = map[string]*any.Any{ - "envoy.filters.http.ext_authz": envoy.RouteAuthzContext(route.AuthContext), + "envoy.filters.http.ext_authz": v22.RouteAuthzContext(route.AuthContext), } } } @@ -207,11 +208,11 @@ func (v *routeVisitor) onSecureVirtualHost(svh *dag.SecureVirtualHost) { name := path.Join("https", svh.VirtualHost.Name) if _, ok := v.routes[name]; !ok { - v.routes[name] = envoy.RouteConfiguration(name) + v.routes[name] = v22.RouteConfiguration(name) } v.routes[name].VirtualHosts = append(v.routes[name].VirtualHosts, - envoy.VirtualHost(svh.VirtualHost.Name, routes...)) + v22.VirtualHost(svh.VirtualHost.Name, routes...)) // A fallback route configuration contains routes for all the vhosts that have the fallback certificate enabled. // When a request is received, the default TLS filterchain will accept the connection, @@ -219,11 +220,11 @@ func (v *routeVisitor) onSecureVirtualHost(svh *dag.SecureVirtualHost) { if svh.FallbackCertificate != nil { // Add fallback route if not already if _, ok := v.routes[ENVOY_FALLBACK_ROUTECONFIG]; !ok { - v.routes[ENVOY_FALLBACK_ROUTECONFIG] = envoy.RouteConfiguration(ENVOY_FALLBACK_ROUTECONFIG) + v.routes[ENVOY_FALLBACK_ROUTECONFIG] = v22.RouteConfiguration(ENVOY_FALLBACK_ROUTECONFIG) } v.routes[ENVOY_FALLBACK_ROUTECONFIG].VirtualHosts = append(v.routes[ENVOY_FALLBACK_ROUTECONFIG].VirtualHosts, - envoy.VirtualHost(svh.Name, routes...)) + v22.VirtualHost(svh.Name, routes...)) } } } diff --git a/internal/contour/route_test.go b/internal/contour/route_test.go index 153a9edafae..a61f3b73ffb 100644 --- a/internal/contour/route_test.go +++ b/internal/contour/route_test.go @@ -17,6 +17,8 @@ import ( "testing" "time" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" @@ -24,7 +26,6 @@ import ( "github.com/golang/protobuf/ptypes/wrappers" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/protobuf" v1 "k8s.io/api/core/v1" "k8s.io/api/networking/v1beta1" @@ -141,7 +142,7 @@ func TestRouteVisit(t *testing.T) { "nothing": { objs: nil, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), }, "one http only ingress with service": { @@ -170,8 +171,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/8080/da39a3ee5e"), @@ -218,8 +219,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routeRegex("/[^/]+/invoices(/.*|/?)"), Action: routecluster("default/kuard/8080/da39a3ee5e"), @@ -262,8 +263,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/backend/80/da39a3ee5e"), @@ -310,8 +311,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/8080/da39a3ee5e"), @@ -371,16 +372,16 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/8080/da39a3ee5e"), }, ), ), - envoy.RouteConfiguration("https/www.example.com", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("https/www.example.com", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/8080/da39a3ee5e"), @@ -438,8 +439,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Redirect{ @@ -452,8 +453,8 @@ func TestRouteVisit(t *testing.T) { }, ), ), - envoy.RouteConfiguration("https/www.example.com", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("https/www.example.com", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/backend/8080/da39a3ee5e"), @@ -516,9 +517,9 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http"), - envoy.RouteConfiguration("https/www.example.com", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("https/www.example.com", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/8080/da39a3ee5e"), @@ -581,8 +582,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Redirect{ @@ -595,8 +596,8 @@ func TestRouteVisit(t *testing.T) { }, ), ), - envoy.RouteConfiguration("https/www.example.com", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("https/www.example.com", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/8080/da39a3ee5e"), @@ -654,8 +655,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/ws1"), Action: websocketroute("default/kuard/8080/da39a3ee5e"), @@ -697,8 +698,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/8080/da39a3ee5e"), @@ -736,8 +737,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routetimeout("default/kuard/8080/da39a3ee5e", 0), @@ -775,8 +776,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routetimeout("default/kuard/8080/da39a3ee5e", 90*time.Second), @@ -825,8 +826,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("my-very-very-long-service-host-name.subdomain.boring-dept.my.company", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("my-very-very-long-service-host-name.subdomain.boring-dept.my.company", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/80/da39a3ee5e"), @@ -864,8 +865,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeretry("default/kuard/8080/da39a3ee5e", "5xx,gateway-error", 0, 0), @@ -904,8 +905,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeretry("default/kuard/8080/da39a3ee5e", "5xx,gateway-error", 7, 0), @@ -945,8 +946,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeretry("default/kuard/8080/da39a3ee5e", "5xx,gateway-error", 7, 0), @@ -985,8 +986,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeretry("default/kuard/8080/da39a3ee5e", "5xx,gateway-error", 0, 150*time.Millisecond), @@ -1025,8 +1026,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeretry("default/kuard/8080/da39a3ee5e", "5xx,gateway-error", 0, 150*time.Millisecond), @@ -1089,8 +1090,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -1165,8 +1166,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -1242,8 +1243,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -1296,7 +1297,7 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http"), // should be blank, no fqdn defined. + v22.RouteConfiguration("ingress_http"), // should be blank, no fqdn defined. ), }, "httpproxy with pathPrefix": { @@ -1352,8 +1353,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -1428,8 +1429,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withMirrorPolicy(routecluster("default/backend/80/da39a3ee5e"), "default/backendtwo/80/da39a3ee5e"), @@ -1502,8 +1503,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Redirect{ @@ -1516,8 +1517,8 @@ func TestRouteVisit(t *testing.T) { }, ), ), - envoy.RouteConfiguration("https/www.example.com", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("https/www.example.com", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -1627,8 +1628,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/blog/info"), Action: routecluster("teama/backend/80/da39a3ee5e"), @@ -1695,8 +1696,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/", dag.HeaderMatchCondition{ Name: "x-header", @@ -1753,8 +1754,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/", dag.HeaderMatchCondition{ Name: "x-header", @@ -1812,8 +1813,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/", dag.HeaderMatchCondition{ Name: "x-header", @@ -1871,8 +1872,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/", dag.HeaderMatchCondition{ Name: "x-header", @@ -1930,8 +1931,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/", dag.HeaderMatchCondition{ Name: "x-header", @@ -1997,8 +1998,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -2110,8 +2111,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Redirect{ @@ -2124,8 +2125,8 @@ func TestRouteVisit(t *testing.T) { }, ), ), - envoy.RouteConfiguration("https/www.example.com", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("https/www.example.com", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -2143,8 +2144,8 @@ func TestRouteVisit(t *testing.T) { }, }, )), - envoy.RouteConfiguration(ENVOY_FALLBACK_ROUTECONFIG, - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration(ENVOY_FALLBACK_ROUTECONFIG, + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -2268,8 +2269,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Redirect{ @@ -2281,7 +2282,7 @@ func TestRouteVisit(t *testing.T) { }, }, ), - envoy.VirtualHost("www.example.com", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Redirect{ @@ -2294,8 +2295,8 @@ func TestRouteVisit(t *testing.T) { }, ), ), - envoy.RouteConfiguration("https/projectcontour.io", - envoy.VirtualHost("projectcontour.io", + v22.RouteConfiguration("https/projectcontour.io", + v22.VirtualHost("projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -2313,8 +2314,8 @@ func TestRouteVisit(t *testing.T) { }, }, )), - envoy.RouteConfiguration("https/www.example.com", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("https/www.example.com", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -2332,8 +2333,8 @@ func TestRouteVisit(t *testing.T) { }, }, )), - envoy.RouteConfiguration(ENVOY_FALLBACK_ROUTECONFIG, - envoy.VirtualHost("projectcontour.io", + v22.RouteConfiguration(ENVOY_FALLBACK_ROUTECONFIG, + v22.VirtualHost("projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -2457,8 +2458,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Redirect{ @@ -2470,7 +2471,7 @@ func TestRouteVisit(t *testing.T) { }, }, ), - envoy.VirtualHost("www.example.com", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Redirect{ @@ -2483,8 +2484,8 @@ func TestRouteVisit(t *testing.T) { }, ), ), - envoy.RouteConfiguration("https/projectcontour.io", - envoy.VirtualHost("projectcontour.io", + v22.RouteConfiguration("https/projectcontour.io", + v22.VirtualHost("projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -2502,8 +2503,8 @@ func TestRouteVisit(t *testing.T) { }, }, )), - envoy.RouteConfiguration("https/www.example.com", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("https/www.example.com", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -2521,8 +2522,8 @@ func TestRouteVisit(t *testing.T) { }, }, )), - envoy.RouteConfiguration(ENVOY_FALLBACK_ROUTECONFIG, - envoy.VirtualHost("projectcontour.io", + v22.RouteConfiguration(ENVOY_FALLBACK_ROUTECONFIG, + v22.VirtualHost("projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -2539,7 +2540,7 @@ func TestRouteVisit(t *testing.T) { }, }, }, - ), envoy.VirtualHost("www.example.com", + ), v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -2635,7 +2636,7 @@ func TestRouteVisit(t *testing.T) { }, }, }, - want: routeConfigurations(envoy.RouteConfiguration("ingress_http")), + want: routeConfigurations(v22.RouteConfiguration("ingress_http")), }, "httpproxy with fallback certificate - no fqdn enabled": { fallbackCertificate: &types.NamespacedName{ @@ -2714,8 +2715,8 @@ func TestRouteVisit(t *testing.T) { }, }, want: routeConfigurations( - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Redirect{ @@ -2728,8 +2729,8 @@ func TestRouteVisit(t *testing.T) { }, ), ), - envoy.RouteConfiguration("https/www.example.com", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("https/www.example.com", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Route{ @@ -2972,7 +2973,7 @@ func routeretry(cluster string, retryOn string, numRetries uint32, perTryTimeout } func routeRegex(regex string, headers ...dag.HeaderMatchCondition) *envoy_api_v2_route.RouteMatch { - return envoy.RouteMatch(&dag.Route{ + return v22.RouteMatch(&dag.Route{ PathMatchCondition: &dag.RegexMatchCondition{ Regex: regex, }, @@ -2981,7 +2982,7 @@ func routeRegex(regex string, headers ...dag.HeaderMatchCondition) *envoy_api_v2 } func routePrefix(prefix string, headers ...dag.HeaderMatchCondition) *envoy_api_v2_route.RouteMatch { - return envoy.RouteMatch(&dag.Route{ + return v22.RouteMatch(&dag.Route{ PathMatchCondition: &dag.PrefixMatchCondition{ Prefix: prefix, }, diff --git a/internal/contour/secret.go b/internal/contour/secret.go index 8d12a6b6711..cffeffc2946 100644 --- a/internal/contour/secret.go +++ b/internal/contour/secret.go @@ -17,11 +17,14 @@ import ( "sort" "sync" + "github.com/projectcontour/contour/internal/envoy" + + v2 "github.com/projectcontour/contour/internal/envoy/v2" + envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" resource "github.com/envoyproxy/go-control-plane/pkg/resource/v2" "github.com/golang/protobuf/proto" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/protobuf" "github.com/projectcontour/contour/internal/sorter" ) @@ -93,7 +96,7 @@ func visitSecrets(root dag.Vertex) map[string]*envoy_api_v2_auth.Secret { func (v *secretVisitor) addSecret(s *dag.Secret) { name := envoy.Secretname(s) if _, ok := v.secrets[name]; !ok { - envoySecret := envoy.Secret(s) + envoySecret := v2.Secret(s) v.secrets[envoySecret.Name] = envoySecret } } diff --git a/internal/contour/visitor_test.go b/internal/contour/visitor_test.go index 71afddee751..d141c76d431 100644 --- a/internal/contour/visitor_test.go +++ b/internal/contour/visitor_test.go @@ -21,7 +21,7 @@ import ( envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" + v2 "github.com/projectcontour/contour/internal/envoy/v2" "github.com/projectcontour/contour/internal/protobuf" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -65,9 +65,9 @@ func TestVisitClusters(t *testing.T) { &envoy_api_v2.Cluster{ Name: "default/example/443/da39a3ee5e", AltStatName: "default_example_443", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(envoy_api_v2.Cluster_EDS), + ClusterDiscoveryType: v2.ClusterDiscoveryType(envoy_api_v2.Cluster_EDS), EdsClusterConfig: &envoy_api_v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v2.ConfigSource("contour"), ServiceName: "default/example", }, }, @@ -130,18 +130,18 @@ func TestVisitListeners(t *testing.T) { want: listenermap( &envoy_api_v2.Listener{ Name: ENVOY_HTTPS_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v2.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"tcpproxy.example.com"}, }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1), - Filters: envoy.Filters(envoy.TCPProxy(ENVOY_HTTPS_LISTENER, p1, envoy.FileAccessLogEnvoy(DEFAULT_HTTPS_ACCESS_LOG))), + Filters: v2.Filters(v2.TCPProxy(ENVOY_HTTPS_LISTENER, p1, v2.FileAccessLogEnvoy(DEFAULT_HTTPS_ACCESS_LOG))), }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v2.ListenerFilters( + v2.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v2.TCPKeepaliveSocketOptions(), }, ), }, diff --git a/internal/debug/dot.go b/internal/debug/dot.go index 08597a667cc..30b7bda5e8a 100644 --- a/internal/debug/dot.go +++ b/internal/debug/dot.go @@ -17,8 +17,9 @@ import ( "fmt" "io" - "github.com/projectcontour/contour/internal/dag" "github.com/projectcontour/contour/internal/envoy" + + "github.com/projectcontour/contour/internal/dag" ) // quick and dirty dot debugging package diff --git a/internal/envoy/accesslog.go b/internal/envoy/accesslog.go index aff1616d757..06e36643267 100644 --- a/internal/envoy/accesslog.go +++ b/internal/envoy/accesslog.go @@ -13,14 +13,6 @@ package envoy -import ( - accesslogv2 "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v2" - accesslog "github.com/envoyproxy/go-control-plane/envoy/config/filter/accesslog/v2" - "github.com/envoyproxy/go-control-plane/pkg/wellknown" - _struct "github.com/golang/protobuf/ptypes/struct" - "github.com/projectcontour/contour/internal/protobuf" -) - //JSONFields is the canonical translation table for JSON fields to Envoy log template formats, //used for specifying fields for Envoy to log when JSON logging is enabled. //Only fields specified in this map may be used for JSON logging. @@ -74,55 +66,3 @@ var DefaultFields = []string{ "user_agent", "x_forwarded_for", } - -// FileAccessLogEnvoy returns a new file based access log filter -// that will output Envoy's default access logs. -func FileAccessLogEnvoy(path string) []*accesslog.AccessLog { - return []*accesslog.AccessLog{{ - Name: wellknown.FileAccessLog, - ConfigType: &accesslog.AccessLog_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&accesslogv2.FileAccessLog{ - Path: path, - // AccessLogFormat left blank to defer to Envoy's default log format. - }), - }, - }} -} - -// FileAccessLogJSON returns a new file based access log filter -// that will log in JSON format -func FileAccessLogJSON(path string, keys []string) []*accesslog.AccessLog { - - jsonformat := &_struct.Struct{ - Fields: make(map[string]*_struct.Value), - } - - for _, k := range keys { - // This will silently ignore invalid headers. - // TODO(youngnick): this should tell users if a header is not valid - // https://github.com/projectcontour/contour/issues/1507 - if template, ok := JSONFields[k]; ok { - jsonformat.Fields[k] = sv(template) - } - } - - return []*accesslog.AccessLog{{ - Name: wellknown.FileAccessLog, - ConfigType: &accesslog.AccessLog_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&accesslogv2.FileAccessLog{ - Path: path, - AccessLogFormat: &accesslogv2.FileAccessLog_JsonFormat{ - JsonFormat: jsonformat, - }, - }), - }, - }} -} - -func sv(s string) *_struct.Value { - return &_struct.Value{ - Kind: &_struct.Value_StringValue{ - StringValue: s, - }, - } -} diff --git a/internal/envoy/auth.go b/internal/envoy/auth.go index 50097bc231a..3837da69028 100644 --- a/internal/envoy/auth.go +++ b/internal/envoy/auth.go @@ -13,16 +13,8 @@ package envoy -import ( - envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" - envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" - matcher "github.com/envoyproxy/go-control-plane/envoy/type/matcher" - "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/protobuf" -) - var ( - // This is the list of default ciphers used by contour 1.9.1. A handful are + // Ciphers containers the list of default ciphers used by contour. A handful are // commented out, as they're arguably less secure. They're also unnecessary // - most of the clients that might need to use the commented ciphers are // unable to connect without TLS 1.0, which contour never enables. @@ -31,7 +23,7 @@ var ( // // The commented ciphers are left in place to simplify updating this list for future // versions of envoy. - ciphers = []string{ + Ciphers = []string{ "[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]", "[ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]", "ECDHE-ECDSA-AES128-SHA", @@ -46,81 +38,3 @@ var ( //"AES256-SHA", } ) - -// UpstreamTLSContext creates an envoy_api_v2_auth.UpstreamTlsContext. By default -// UpstreamTLSContext returns a HTTP/1.1 TLS enabled context. A list of -// additional ALPN protocols can be provided. -func UpstreamTLSContext(peerValidationContext *dag.PeerValidationContext, sni string, alpnProtocols ...string) *envoy_api_v2_auth.UpstreamTlsContext { - context := &envoy_api_v2_auth.UpstreamTlsContext{ - CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ - AlpnProtocols: alpnProtocols, - }, - Sni: sni, - } - - if peerValidationContext.GetCACertificate() != nil && len(peerValidationContext.GetSubjectName()) > 0 { - // We have to explicitly assign the value from validationContext - // to context.CommonTlsContext.ValidationContextType because the - // latter is an interface. Returning nil from validationContext - // directly into this field boxes the nil into the unexported - // type of this grpc OneOf field which causes proto marshaling - // to explode later on. - vc := validationContext(peerValidationContext.GetCACertificate(), peerValidationContext.GetSubjectName()) - if vc != nil { - context.CommonTlsContext.ValidationContextType = vc - } - } - - return context -} - -func validationContext(ca []byte, subjectName string) *envoy_api_v2_auth.CommonTlsContext_ValidationContext { - vc := &envoy_api_v2_auth.CommonTlsContext_ValidationContext{ - ValidationContext: &envoy_api_v2_auth.CertificateValidationContext{ - TrustedCa: &envoy_api_v2_core.DataSource{ - // TODO(dfc) update this for SDS - Specifier: &envoy_api_v2_core.DataSource_InlineBytes{ - InlineBytes: ca, - }, - }, - }, - } - - if len(subjectName) > 0 { - vc.ValidationContext.MatchSubjectAltNames = []*matcher.StringMatcher{{ - MatchPattern: &matcher.StringMatcher_Exact{ - Exact: subjectName, - }}, - } - } - - return vc -} - -// DownstreamTLSContext creates a new DownstreamTlsContext. -func DownstreamTLSContext(serverSecret *dag.Secret, tlsMinProtoVersion envoy_api_v2_auth.TlsParameters_TlsProtocol, peerValidationContext *dag.PeerValidationContext, alpnProtos ...string) *envoy_api_v2_auth.DownstreamTlsContext { - context := &envoy_api_v2_auth.DownstreamTlsContext{ - CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ - TlsParams: &envoy_api_v2_auth.TlsParameters{ - TlsMinimumProtocolVersion: tlsMinProtoVersion, - TlsMaximumProtocolVersion: envoy_api_v2_auth.TlsParameters_TLSv1_3, - CipherSuites: ciphers, - }, - TlsCertificateSdsSecretConfigs: []*envoy_api_v2_auth.SdsSecretConfig{{ - Name: Secretname(serverSecret), - SdsConfig: ConfigSource("contour"), - }}, - AlpnProtocols: alpnProtos, - }, - } - - if peerValidationContext.GetCACertificate() != nil { - vc := validationContext(peerValidationContext.GetCACertificate(), "") - if vc != nil { - context.CommonTlsContext.ValidationContextType = vc - context.RequireClientCertificate = protobuf.Bool(true) - } - } - - return context -} diff --git a/internal/envoy/bootstrap.go b/internal/envoy/bootstrap.go index 8eb336efa33..d83df173864 100644 --- a/internal/envoy/bootstrap.go +++ b/internal/envoy/bootstrap.go @@ -10,323 +10,29 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - +// // Package envoy contains APIs for translating between Contour // objects and Envoy configuration APIs and types. + package envoy import ( - "fmt" "os" - "path" - "strconv" - "strings" - "time" - api "github.com/envoyproxy/go-control-plane/envoy/api/v2" - envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" - clusterv2 "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster" - envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" - envoy_api_bootstrap "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v2" - matcher "github.com/envoyproxy/go-control-plane/envoy/type/matcher" "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" - "github.com/projectcontour/contour/internal/protobuf" ) -// sdsResourcesSubdirectory stores the subdirectory name where SDS path resources are stored to. -const sdsResourcesSubdirectory = "sds" +// SdsResourcesSubdirectory stores the subdirectory name where SDS path resources are stored to. +const SdsResourcesSubdirectory = "sds" -// sdsTLSCertificateFile stores the path to the SDS resource with Envoy's +// SdsTLSCertificateFile stores the path to the SDS resource with Envoy's // client certificate and key for XDS gRPC connection. -const sdsTLSCertificateFile = "xds-tls-certicate.json" +const SdsTLSCertificateFile = "xds-tls-certicate.json" // sdsValidationContextFile stores the path to the SDS resource with // CA certificates for Envoy to use for the XDS gRPC connection. -const sdsValidationContextFile = "xds-validation-context.json" - -// WriteBootstrap writes bootstrap configuration to files. -func WriteBootstrap(c *BootstrapConfig) error { - // Create Envoy bootstrap config and associated resource files. - steps, err := bootstrap(c) - if err != nil { - return err - } - - if c.ResourcesDir != "" { - if err := os.MkdirAll(path.Join(c.ResourcesDir, "sds"), 0750); err != nil { - return err - } - } - - // Write all configuration files out to filesystem. - for _, step := range steps { - if err := writeConfig(step(c)); err != nil { - return err - } - } - - return nil -} - -type bootstrapf func(*BootstrapConfig) (string, proto.Message) - -// bootstrap creates a new v2 bootstrap configuration and associated resource files. -func bootstrap(c *BootstrapConfig) ([]bootstrapf, error) { - steps := []bootstrapf{} - - if c.GrpcClientCert == "" && c.GrpcClientKey == "" && c.GrpcCABundle == "" { - steps = append(steps, - func(*BootstrapConfig) (string, proto.Message) { - return c.Path, bootstrapConfig(c) - }) - - return steps, nil - } - - for _, f := range []string{c.GrpcClientCert, c.GrpcClientKey, c.GrpcCABundle} { - // If any of of the TLS options is not empty, they all must be not empty. - if f == "" { - return nil, fmt.Errorf( - "you must supply all TLS parameters - %q, %q, %q, or none of them", - "--envoy-cafile", "--envoy-cert-file", "--envoy-key-file") - } - - if !c.SkipFilePathCheck { - // If the TLS secrets aren't set up properly, - // some files may not be present. In this case, - // envoy will reject the bootstrap configuration, - // but there is no way to detect and fix that. If - // we check and fail here, that is visible in the - // Pod lifecycle and therefore fixable. - fi, err := os.Stat(f) - if err != nil { - return nil, err - } - if fi.Size() == 0 { - return nil, fmt.Errorf("%q is empty", f) - } - } - } - - if c.ResourcesDir == "" { - // For backwards compatibility, the old behavior - // is to use direct certificate and key file paths in - // bootstrap config. Envoy does not support rotation - // of xDS certificate files in this case. - - steps = append(steps, - func(*BootstrapConfig) (string, proto.Message) { - b := bootstrapConfig(c) - b.StaticResources.Clusters[0].TransportSocket = UpstreamTLSTransportSocket( - upstreamFileTLSContext(c)) - return c.Path, b - }) - - return steps, nil - } - - // xDS certificate rotation is supported by Envoy by using SDS path based resource files. - // These files are JSON representation of the SDS protobuf messages that normally get sent over the xDS connection, - // but for xDS connection itself, bootstrapping is done by storing the SDS resources in a local filesystem. - // Envoy will monitor and reload the resource files and the certificate and key files referred from the SDS resources. - // - // Two files are written to ResourcesDir: - // - SDS resource for xDS client certificate and key for authenticating Envoy towards Contour. - // - SDS resource for trusted CA certificate for validating Contour server certificate. - sdsTLSCertificatePath := path.Join(c.ResourcesDir, sdsResourcesSubdirectory, sdsTLSCertificateFile) - sdsValidationContextPath := path.Join(c.ResourcesDir, sdsResourcesSubdirectory, sdsValidationContextFile) - - steps = append(steps, - func(*BootstrapConfig) (string, proto.Message) { - return sdsTLSCertificatePath, tlsCertificateSdsSecretConfig(c) - }, - func(*BootstrapConfig) (string, proto.Message) { - return sdsValidationContextPath, validationContextSdsSecretConfig(c) - }, - func(*BootstrapConfig) (string, proto.Message) { - b := bootstrapConfig(c) - b.StaticResources.Clusters[0].TransportSocket = UpstreamTLSTransportSocket( - upstreamSdsTLSContext(sdsTLSCertificatePath, sdsValidationContextPath)) - return c.Path, b - }, - ) - - return steps, nil -} - -func bootstrapConfig(c *BootstrapConfig) *envoy_api_bootstrap.Bootstrap { - return &envoy_api_bootstrap.Bootstrap{ - DynamicResources: &envoy_api_bootstrap.Bootstrap_DynamicResources{ - LdsConfig: ConfigSource("contour"), - CdsConfig: ConfigSource("contour"), - }, - StaticResources: &envoy_api_bootstrap.Bootstrap_StaticResources{ - Clusters: []*api.Cluster{{ - Name: "contour", - AltStatName: strings.Join([]string{c.Namespace, "contour", strconv.Itoa(c.xdsGRPCPort())}, "_"), - ConnectTimeout: protobuf.Duration(5 * time.Second), - ClusterDiscoveryType: ClusterDiscoveryType(api.Cluster_STRICT_DNS), - LbPolicy: api.Cluster_ROUND_ROBIN, - LoadAssignment: &api.ClusterLoadAssignment{ - ClusterName: "contour", - Endpoints: Endpoints( - SocketAddress(c.xdsAddress(), c.xdsGRPCPort()), - ), - }, - UpstreamConnectionOptions: &api.UpstreamConnectionOptions{ - TcpKeepalive: &envoy_api_v2_core.TcpKeepalive{ - KeepaliveProbes: protobuf.UInt32(3), - KeepaliveTime: protobuf.UInt32(30), - KeepaliveInterval: protobuf.UInt32(5), - }, - }, - Http2ProtocolOptions: new(envoy_api_v2_core.Http2ProtocolOptions), // enables http2 - CircuitBreakers: &clusterv2.CircuitBreakers{ - Thresholds: []*clusterv2.CircuitBreakers_Thresholds{{ - Priority: envoy_api_v2_core.RoutingPriority_HIGH, - MaxConnections: protobuf.UInt32(100000), - MaxPendingRequests: protobuf.UInt32(100000), - MaxRequests: protobuf.UInt32(60000000), - MaxRetries: protobuf.UInt32(50), - }, { - Priority: envoy_api_v2_core.RoutingPriority_DEFAULT, - MaxConnections: protobuf.UInt32(100000), - MaxPendingRequests: protobuf.UInt32(100000), - MaxRequests: protobuf.UInt32(60000000), - MaxRetries: protobuf.UInt32(50), - }}, - }, - }, { - Name: "service-stats", - AltStatName: strings.Join([]string{c.Namespace, "service-stats", strconv.Itoa(c.adminPort())}, "_"), - ConnectTimeout: protobuf.Duration(250 * time.Millisecond), - ClusterDiscoveryType: ClusterDiscoveryType(api.Cluster_LOGICAL_DNS), - LbPolicy: api.Cluster_ROUND_ROBIN, - LoadAssignment: &api.ClusterLoadAssignment{ - ClusterName: "service-stats", - Endpoints: Endpoints( - SocketAddress(c.adminAddress(), c.adminPort()), - ), - }, - }}, - }, - Admin: &envoy_api_bootstrap.Admin{ - AccessLogPath: c.adminAccessLogPath(), - Address: SocketAddress(c.adminAddress(), c.adminPort()), - }, - } -} - -func upstreamFileTLSContext(c *BootstrapConfig) *envoy_api_v2_auth.UpstreamTlsContext { - context := &envoy_api_v2_auth.UpstreamTlsContext{ - CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ - TlsCertificates: []*envoy_api_v2_auth.TlsCertificate{{ - CertificateChain: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcClientCert, - }, - }, - PrivateKey: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcClientKey, - }, - }, - }}, - ValidationContextType: &envoy_api_v2_auth.CommonTlsContext_ValidationContext{ - ValidationContext: &envoy_api_v2_auth.CertificateValidationContext{ - TrustedCa: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcCABundle, - }, - }, - // TODO(youngnick): Does there need to be a flag wired down to here? - MatchSubjectAltNames: []*matcher.StringMatcher{{ - MatchPattern: &matcher.StringMatcher_Exact{ - Exact: "contour", - }}, - }, - }, - }, - }, - } - return context -} - -func upstreamSdsTLSContext(certificateSdsFile, validationSdsFile string) *envoy_api_v2_auth.UpstreamTlsContext { - context := &envoy_api_v2_auth.UpstreamTlsContext{ - CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ - TlsCertificateSdsSecretConfigs: []*envoy_api_v2_auth.SdsSecretConfig{{ - SdsConfig: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_Path{ - Path: certificateSdsFile, - }, - }, - }}, - ValidationContextType: &envoy_api_v2_auth.CommonTlsContext_ValidationContextSdsSecretConfig{ - ValidationContextSdsSecretConfig: &envoy_api_v2_auth.SdsSecretConfig{ - SdsConfig: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_Path{ - Path: validationSdsFile, - }, - }, - }, - }, - }, - } - return context -} - -// tlsCertificateSdsSecretConfig creates DiscoveryResponse with file based SDS resource -// including paths to TLS certificates and key -func tlsCertificateSdsSecretConfig(c *BootstrapConfig) *api.DiscoveryResponse { - secret := &envoy_api_v2_auth.Secret{ - Type: &envoy_api_v2_auth.Secret_TlsCertificate{ - TlsCertificate: &envoy_api_v2_auth.TlsCertificate{ - CertificateChain: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcClientCert, - }, - }, - PrivateKey: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcClientKey, - }, - }, - }, - }, - } - - return &api.DiscoveryResponse{ - Resources: []*any.Any{protobuf.MustMarshalAny(secret)}, - } -} - -// validationContextSdsSecretConfig creates DiscoveryResponse with file based SDS resource -// including path to CA certificate bundle -func validationContextSdsSecretConfig(c *BootstrapConfig) *api.DiscoveryResponse { - secret := &envoy_api_v2_auth.Secret{ - Type: &envoy_api_v2_auth.Secret_ValidationContext{ - ValidationContext: &envoy_api_v2_auth.CertificateValidationContext{ - TrustedCa: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcCABundle, - }, - }, - MatchSubjectAltNames: []*matcher.StringMatcher{{ - MatchPattern: &matcher.StringMatcher_Exact{ - Exact: "contour", - }}, - }, - }, - }, - } - - return &api.DiscoveryResponse{ - Resources: []*any.Any{protobuf.MustMarshalAny(secret)}, - } -} +const SdsValidationContextFile = "xds-validation-context.json" // BootstrapConfig holds configuration values for a v2.Bootstrap. type BootstrapConfig struct { @@ -376,11 +82,13 @@ type BootstrapConfig struct { SkipFilePathCheck bool } -func (c *BootstrapConfig) xdsAddress() string { return stringOrDefault(c.XDSAddress, "127.0.0.1") } -func (c *BootstrapConfig) xdsGRPCPort() int { return intOrDefault(c.XDSGRPCPort, 8001) } -func (c *BootstrapConfig) adminAddress() string { return stringOrDefault(c.AdminAddress, "127.0.0.1") } -func (c *BootstrapConfig) adminPort() int { return intOrDefault(c.AdminPort, 9001) } -func (c *BootstrapConfig) adminAccessLogPath() string { +func (c *BootstrapConfig) GetXdsAddress() string { return stringOrDefault(c.XDSAddress, "127.0.0.1") } +func (c *BootstrapConfig) GetXdsGRPCPort() int { return intOrDefault(c.XDSGRPCPort, 8001) } +func (c *BootstrapConfig) GetAdminAddress() string { + return stringOrDefault(c.AdminAddress, "127.0.0.1") +} +func (c *BootstrapConfig) GetAdminPort() int { return intOrDefault(c.AdminPort, 9001) } +func (c *BootstrapConfig) GetAdminAccessLogPath() string { return stringOrDefault(c.AdminAccessLogPath, "/dev/null") } @@ -398,7 +106,7 @@ func intOrDefault(i, def int) int { return i } -func writeConfig(filename string, config proto.Message) (err error) { +func WriteConfig(filename string, config proto.Message) (err error) { var out *os.File if filename == "-" { diff --git a/internal/envoy/cluster.go b/internal/envoy/cluster.go index e568d577dac..2a0d998f8e1 100644 --- a/internal/envoy/cluster.go +++ b/internal/envoy/cluster.go @@ -19,182 +19,10 @@ import ( "fmt" "strconv" "strings" - "time" - v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" - envoy_cluster "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster" - envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" - envoy_type "github.com/envoyproxy/go-control-plane/envoy/type" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/protobuf" - "github.com/projectcontour/contour/internal/xds" - "k8s.io/apimachinery/pkg/types" ) -func clusterDefaults() *v2.Cluster { - return &v2.Cluster{ - ConnectTimeout: protobuf.Duration(250 * time.Millisecond), - CommonLbConfig: ClusterCommonLBConfig(), - LbPolicy: lbPolicy(""), - } -} - -// Cluster creates new v2.Cluster from dag.Cluster. -func Cluster(c *dag.Cluster) *v2.Cluster { - service := c.Upstream - cluster := clusterDefaults() - - cluster.Name = Clustername(c) - cluster.AltStatName = altStatName(service) - cluster.LbPolicy = lbPolicy(c.LoadBalancerPolicy) - cluster.HealthChecks = edshealthcheck(c) - - switch len(service.ExternalName) { - case 0: - // external name not set, cluster will be discovered via EDS - cluster.ClusterDiscoveryType = ClusterDiscoveryType(v2.Cluster_EDS) - cluster.EdsClusterConfig = edsconfig("contour", service) - default: - // external name set, use hard coded DNS name - cluster.ClusterDiscoveryType = ClusterDiscoveryType(v2.Cluster_STRICT_DNS) - cluster.LoadAssignment = StaticClusterLoadAssignment(service) - } - - // Drain connections immediately if using healthchecks and the endpoint is known to be removed - if c.HTTPHealthCheckPolicy != nil || c.TCPHealthCheckPolicy != nil { - cluster.DrainConnectionsOnHostRemoval = true - } - - if anyPositive(service.MaxConnections, service.MaxPendingRequests, service.MaxRequests, service.MaxRetries) { - cluster.CircuitBreakers = &envoy_cluster.CircuitBreakers{ - Thresholds: []*envoy_cluster.CircuitBreakers_Thresholds{{ - MaxConnections: protobuf.UInt32OrNil(service.MaxConnections), - MaxPendingRequests: protobuf.UInt32OrNil(service.MaxPendingRequests), - MaxRequests: protobuf.UInt32OrNil(service.MaxRequests), - MaxRetries: protobuf.UInt32OrNil(service.MaxRetries), - }}, - } - } - - switch c.Protocol { - case "tls": - cluster.TransportSocket = UpstreamTLSTransportSocket( - UpstreamTLSContext( - c.UpstreamValidation, - c.SNI, - ), - ) - case "h2": - cluster.Http2ProtocolOptions = &envoy_api_v2_core.Http2ProtocolOptions{} - cluster.TransportSocket = UpstreamTLSTransportSocket( - UpstreamTLSContext( - c.UpstreamValidation, - c.SNI, - "h2", - ), - ) - case "h2c": - cluster.Http2ProtocolOptions = &envoy_api_v2_core.Http2ProtocolOptions{} - } - - return cluster -} - -// ExtensionCluster builds a v2.Cluster struct for the given extension service. -func ExtensionCluster(ext *dag.ExtensionCluster) *v2.Cluster { - cluster := clusterDefaults() - - // The Envoy cluster name has already been set. - cluster.Name = ext.Name - - // The AltStatName was added to make a more readable alternative - // to the cluster name for metrics (see #827). For extension - // services, we can have multiple ports, so it doesn't make - // sense to build this the same way we build it for HTTPProxy - // service clusters. However, we know the namespaced name for - // the ExtensionCluster is globally unique, so we can use that - // to produce a stable, readable name. - cluster.AltStatName = strings.ReplaceAll(cluster.Name, "/", "_") - - cluster.LbPolicy = lbPolicy(ext.LoadBalancerPolicy) - - // Cluster will be discovered via EDS. - cluster.ClusterDiscoveryType = ClusterDiscoveryType(v2.Cluster_EDS) - cluster.EdsClusterConfig = &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: ext.Upstream.ClusterName, - } - - // TODO(jpeach): Externalname service support in https://github.com/projectcontour/contour/issues/2875 - - switch ext.Protocol { - case "h2": - cluster.Http2ProtocolOptions = &envoy_api_v2_core.Http2ProtocolOptions{} - cluster.TransportSocket = UpstreamTLSTransportSocket( - UpstreamTLSContext( - ext.UpstreamValidation, - ext.SNI, - "h2", - ), - ) - case "h2c": - cluster.Http2ProtocolOptions = &envoy_api_v2_core.Http2ProtocolOptions{} - } - - return cluster -} - -// StaticClusterLoadAssignment creates a *v2.ClusterLoadAssignment pointing to the external DNS address of the service -func StaticClusterLoadAssignment(service *dag.Service) *v2.ClusterLoadAssignment { - addr := SocketAddress(service.ExternalName, int(service.Weighted.ServicePort.Port)) - return &v2.ClusterLoadAssignment{ - Endpoints: Endpoints(addr), - ClusterName: xds.ClusterLoadAssignmentName( - types.NamespacedName{Name: service.Weighted.ServiceName, Namespace: service.Weighted.ServiceNamespace}, - service.Weighted.ServicePort.Name, - ), - } -} - -func edsconfig(cluster string, service *dag.Service) *v2.Cluster_EdsClusterConfig { - return &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource(cluster), - ServiceName: xds.ClusterLoadAssignmentName( - types.NamespacedName{Name: service.Weighted.ServiceName, Namespace: service.Weighted.ServiceNamespace}, - service.Weighted.ServicePort.Name, - ), - } -} - -func lbPolicy(strategy string) v2.Cluster_LbPolicy { - switch strategy { - case "WeightedLeastRequest": - return v2.Cluster_LEAST_REQUEST - case "Random": - return v2.Cluster_RANDOM - case "Cookie": - return v2.Cluster_RING_HASH - default: - return v2.Cluster_ROUND_ROBIN - } -} - -func edshealthcheck(c *dag.Cluster) []*envoy_api_v2_core.HealthCheck { - if c.HTTPHealthCheckPolicy == nil && c.TCPHealthCheckPolicy == nil { - return nil - } - - if c.HTTPHealthCheckPolicy != nil { - return []*envoy_api_v2_core.HealthCheck{ - httpHealthCheck(c), - } - } - - return []*envoy_api_v2_core.HealthCheck{ - tcpHealthCheck(c), - } -} - // Clustername returns the name of the CDS cluster for this service. func Clustername(cluster *dag.Cluster) string { service := cluster.Upstream @@ -224,23 +52,23 @@ func Clustername(cluster *dag.Cluster) string { ns := service.Weighted.ServiceNamespace name := service.Weighted.ServiceName - return hashname(60, ns, name, strconv.Itoa(int(service.Weighted.ServicePort.Port)), fmt.Sprintf("%x", hash[:5])) + return Hashname(60, ns, name, strconv.Itoa(int(service.Weighted.ServicePort.Port)), fmt.Sprintf("%x", hash[:5])) } -// altStatName generates an alternative stat name for the service +// AltStatName generates an alternative stat name for the service // using format ns_name_port -func altStatName(service *dag.Service) string { +func AltStatName(service *dag.Service) string { parts := []string{service.Weighted.ServiceNamespace, service.Weighted.ServiceName, strconv.Itoa(int(service.Weighted.ServicePort.Port))} return strings.Join(parts, "_") } -// hashname takes a lenth l and a varargs of strings s and returns a string whose length +// Hashname takes a length l and a varargs of strings s and returns a string whose length // which does not exceed l. Internally s is joined with strings.Join(s, "/"). If the // combined length exceeds l then hashname truncates each element in s, starting from the // end using a hash derived from the contents of s (not the current element). This process // continues until the length of s does not exceed l, or all elements have been truncated. // In which case, the entire string is replaced with a hash not exceeding the length of l. -func hashname(l int, s ...string) string { +func Hashname(l int, s ...string) string { const shorthash = 6 // the length of the shorthash r := strings.Join(s, "/") @@ -282,8 +110,8 @@ func min(a, b int) int { return a } -// anyPositive indicates if any of the values provided are greater than zero. -func anyPositive(first uint32, rest ...uint32) bool { +// AnyPositive indicates if any of the values provided are greater than zero. +func AnyPositive(first uint32, rest ...uint32) bool { if first > 0 { return true } @@ -294,35 +122,3 @@ func anyPositive(first uint32, rest ...uint32) bool { } return false } - -// ClusterCommonLBConfig creates a *v2.Cluster_CommonLbConfig with HealthyPanicThreshold disabled. -func ClusterCommonLBConfig() *v2.Cluster_CommonLbConfig { - return &v2.Cluster_CommonLbConfig{ - HealthyPanicThreshold: &envoy_type.Percent{ // Disable HealthyPanicThreshold - Value: 0, - }, - } -} - -// ConfigSource returns a *envoy_api_v2_core.ConfigSource for cluster. -func ConfigSource(cluster string) *envoy_api_v2_core.ConfigSource { - return &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ - ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ - ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, - GrpcServices: []*envoy_api_v2_core.GrpcService{{ - TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ - ClusterName: cluster, - }, - }, - }}, - }, - }, - } -} - -// ClusterDiscoveryType returns the type of a ClusterDiscovery as a Cluster_type. -func ClusterDiscoveryType(t v2.Cluster_DiscoveryType) *v2.Cluster_Type { - return &v2.Cluster_Type{Type: t} -} diff --git a/internal/envoy/cluster_test.go b/internal/envoy/cluster_test.go index 632b2249464..a2a98aa3b6a 100644 --- a/internal/envoy/cluster_test.go +++ b/internal/envoy/cluster_test.go @@ -1,584 +1,11 @@ -// Copyright Project Contour Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package envoy import ( "testing" - "time" - v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" - envoy_cluster "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster" - envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" - envoy_type "github.com/envoyproxy/go-control-plane/envoy/type" - "github.com/golang/protobuf/proto" - "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/protobuf" - "github.com/projectcontour/contour/internal/xds" "github.com/stretchr/testify/assert" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/intstr" ) -func TestCluster(t *testing.T) { - s1 := &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 443, - TargetPort: intstr.FromInt(8080), - }}, - }, - } - - s2 := &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - ExternalName: "foo.io", - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 443, - TargetPort: intstr.FromInt(8080), - }}, - }, - } - - svcExternal := &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - ExternalName: "projectcontour.local", - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 443, - TargetPort: intstr.FromInt(8080), - }}, - Type: v1.ServiceTypeExternalName, - }, - } - - secret := &dag.Secret{ - Object: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: v1.SecretTypeTLS, - Data: map[string][]byte{dag.CACertificateKey: []byte("cacert")}, - }, - } - - tests := map[string]struct { - cluster *dag.Cluster - want *v2.Cluster - }{ - "simple service": { - cluster: &dag.Cluster{ - Upstream: service(s1), - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - }, - }, - "h2c upstream": { - cluster: &dag.Cluster{ - Upstream: service(s1, "h2c"), - Protocol: "h2c", - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - Http2ProtocolOptions: &envoy_api_v2_core.Http2ProtocolOptions{}, - }, - }, - "h2 upstream": { - cluster: &dag.Cluster{ - Upstream: service(s1, "h2"), - Protocol: "h2", - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - TransportSocket: UpstreamTLSTransportSocket( - UpstreamTLSContext(nil, "", "h2"), - ), - Http2ProtocolOptions: &envoy_api_v2_core.Http2ProtocolOptions{}, - }, - }, - "externalName service": { - cluster: &dag.Cluster{ - Upstream: service(s2), - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_STRICT_DNS), - LoadAssignment: StaticClusterLoadAssignment(service(s2)), - }, - }, - "tls upstream": { - cluster: &dag.Cluster{ - Upstream: service(s1, "tls"), - Protocol: "tls", - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - TransportSocket: UpstreamTLSTransportSocket( - UpstreamTLSContext(nil, ""), - ), - }, - }, - "tls upstream - external name": { - cluster: &dag.Cluster{ - Upstream: service(svcExternal, "tls"), - Protocol: "tls", - SNI: "projectcontour.local", - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_STRICT_DNS), - LoadAssignment: StaticClusterLoadAssignment(service(svcExternal, "tls")), - TransportSocket: UpstreamTLSTransportSocket( - UpstreamTLSContext(nil, "projectcontour.local"), - ), - }, - }, - "verify tls upstream with san": { - cluster: &dag.Cluster{ - Upstream: service(s1, "tls"), - Protocol: "tls", - UpstreamValidation: &dag.PeerValidationContext{ - CACertificate: secret, - SubjectName: "foo.bar.io", - }, - }, - want: &v2.Cluster{ - Name: "default/kuard/443/3ac4e90987", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - TransportSocket: UpstreamTLSTransportSocket( - UpstreamTLSContext( - &dag.PeerValidationContext{ - CACertificate: secret, - SubjectName: "foo.bar.io", - }, - ""), - ), - }, - }, - "projectcontour.io/max-connections": { - cluster: &dag.Cluster{ - Upstream: &dag.Service{ - MaxConnections: 9000, - Weighted: dag.WeightedService{ - Weight: 1, - ServiceName: s1.Name, - ServiceNamespace: s1.Namespace, - ServicePort: s1.Spec.Ports[0], - }, - }, - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - CircuitBreakers: &envoy_cluster.CircuitBreakers{ - Thresholds: []*envoy_cluster.CircuitBreakers_Thresholds{{ - MaxConnections: protobuf.UInt32(9000), - }}, - }, - }, - }, - "projectcontour.io/max-pending-requests": { - cluster: &dag.Cluster{ - Upstream: &dag.Service{ - MaxPendingRequests: 4096, - Weighted: dag.WeightedService{ - Weight: 1, - ServiceName: s1.Name, - ServiceNamespace: s1.Namespace, - ServicePort: s1.Spec.Ports[0], - }, - }, - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - CircuitBreakers: &envoy_cluster.CircuitBreakers{ - Thresholds: []*envoy_cluster.CircuitBreakers_Thresholds{{ - MaxPendingRequests: protobuf.UInt32(4096), - }}, - }, - }, - }, - "projectcontour.io/max-requests": { - cluster: &dag.Cluster{ - Upstream: &dag.Service{ - MaxRequests: 404, - Weighted: dag.WeightedService{ - Weight: 1, - ServiceName: s1.Name, - ServiceNamespace: s1.Namespace, - ServicePort: s1.Spec.Ports[0], - }, - }, - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - CircuitBreakers: &envoy_cluster.CircuitBreakers{ - Thresholds: []*envoy_cluster.CircuitBreakers_Thresholds{{ - MaxRequests: protobuf.UInt32(404), - }}, - }, - }, - }, - "projectcontour.io/max-retries": { - cluster: &dag.Cluster{ - Upstream: &dag.Service{ - MaxRetries: 7, - Weighted: dag.WeightedService{ - Weight: 1, - ServiceName: s1.Name, - ServiceNamespace: s1.Namespace, - ServicePort: s1.Spec.Ports[0], - }, - }, - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - CircuitBreakers: &envoy_cluster.CircuitBreakers{ - Thresholds: []*envoy_cluster.CircuitBreakers_Thresholds{{ - MaxRetries: protobuf.UInt32(7), - }}, - }, - }, - }, - "cluster with random load balancer policy": { - cluster: &dag.Cluster{ - Upstream: service(s1), - LoadBalancerPolicy: "Random", - }, - want: &v2.Cluster{ - Name: "default/kuard/443/58d888c08a", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - LbPolicy: v2.Cluster_RANDOM, - }, - }, - "cluster with cookie policy": { - cluster: &dag.Cluster{ - Upstream: service(s1), - LoadBalancerPolicy: "Cookie", - }, - want: &v2.Cluster{ - Name: "default/kuard/443/e4f81994fe", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - LbPolicy: v2.Cluster_RING_HASH, - }, - }, - - "tcp service": { - cluster: &dag.Cluster{ - Upstream: service(s1), - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - }, - }, - "tcp service with healthcheck": { - cluster: &dag.Cluster{ - Upstream: service(s1), - TCPHealthCheckPolicy: &dag.TCPHealthCheckPolicy{ - Timeout: 2, - Interval: 10, - UnhealthyThreshold: 3, - HealthyThreshold: 2, - }, - }, - want: &v2.Cluster{ - Name: "default/kuard/443/da39a3ee5e", - AltStatName: "default_kuard_443", - ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), - EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: ConfigSource("contour"), - ServiceName: "default/kuard/http", - }, - DrainConnectionsOnHostRemoval: true, - HealthChecks: []*envoy_api_v2_core.HealthCheck{{ - Timeout: durationOrDefault(2, hcTimeout), - Interval: durationOrDefault(10, hcInterval), - UnhealthyThreshold: protobuf.UInt32OrDefault(3, hcUnhealthyThreshold), - HealthyThreshold: protobuf.UInt32OrDefault(2, hcHealthyThreshold), - HealthChecker: &envoy_api_v2_core.HealthCheck_TcpHealthCheck_{ - TcpHealthCheck: &envoy_api_v2_core.HealthCheck_TcpHealthCheck{}, - }, - }}, - }, - }, - } - - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - got := Cluster(tc.cluster) - want := clusterDefaults() - - proto.Merge(want, tc.want) - - protobuf.ExpectEqual(t, want, got) - }) - } -} - -func TestClusterLoadAssignmentName(t *testing.T) { - assert.Equal(t, xds.ClusterLoadAssignmentName(types.NamespacedName{Namespace: "ns", Name: "svc"}, "port"), "ns/svc/port") - assert.Equal(t, xds.ClusterLoadAssignmentName(types.NamespacedName{Namespace: "ns", Name: "svc"}, ""), "ns/svc") - assert.Equal(t, xds.ClusterLoadAssignmentName(types.NamespacedName{}, ""), "/") -} - -func TestClustername(t *testing.T) { - tests := map[string]struct { - cluster *dag.Cluster - want string - }{ - "simple": { - cluster: &dag.Cluster{ - Upstream: &dag.Service{ - Weighted: dag.WeightedService{ - Weight: 1, - ServiceName: "backend", - ServiceNamespace: "default", - ServicePort: v1.ServicePort{ - Name: "http", - Protocol: "TCP", - Port: 80, - TargetPort: intstr.FromInt(6502), - }, - }, - }, - }, - want: "default/backend/80/da39a3ee5e", - }, - "far too long": { - cluster: &dag.Cluster{ - Upstream: &dag.Service{ - Weighted: dag.WeightedService{ - Weight: 1, - ServiceName: "must-be-in-want-of-a-wife", - ServiceNamespace: "it-is-a-truth-universally-acknowledged-that-a-single-man-in-possession-of-a-good-fortune", - ServicePort: v1.ServicePort{ - Name: "http", - Protocol: "TCP", - Port: 9999, - TargetPort: intstr.FromString("http-alt"), - }, - }, - }, - }, - want: "it-is-a--dea8b0/must-be--dea8b0/9999/da39a3ee5e", - }, - "various healthcheck params": { - cluster: &dag.Cluster{ - Upstream: &dag.Service{ - Weighted: dag.WeightedService{ - Weight: 1, - ServiceName: "backend", - ServiceNamespace: "default", - ServicePort: v1.ServicePort{ - Name: "http", - Protocol: "TCP", - Port: 80, - TargetPort: intstr.FromInt(6502), - }, - }, - }, - LoadBalancerPolicy: "Random", - HTTPHealthCheckPolicy: &dag.HTTPHealthCheckPolicy{ - Path: "/healthz", - Interval: 5 * time.Second, - Timeout: 30 * time.Second, - UnhealthyThreshold: 3, - HealthyThreshold: 1, - }, - }, - want: "default/backend/80/5c26077e1d", - }, - "upstream tls validation with subject alt name": { - cluster: &dag.Cluster{ - Upstream: &dag.Service{ - Weighted: dag.WeightedService{ - Weight: 1, - ServiceName: "backend", - ServiceNamespace: "default", - ServicePort: v1.ServicePort{ - Name: "http", - Protocol: "TCP", - Port: 80, - TargetPort: intstr.FromInt(6502), - }, - }, - }, - LoadBalancerPolicy: "Random", - UpstreamValidation: &dag.PeerValidationContext{ - CACertificate: &dag.Secret{ - Object: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Data: map[string][]byte{ - dag.CACertificateKey: []byte("somethingsecret"), - }, - }, - }, - SubjectName: "foo.com", - }, - }, - want: "default/backend/80/6bf46b7b3a", - }, - } - - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - got := Clustername(tc.cluster) - assert.Equal(t, tc.want, got) - }) - } -} - -func TestLBPolicy(t *testing.T) { - tests := map[string]v2.Cluster_LbPolicy{ - "WeightedLeastRequest": v2.Cluster_LEAST_REQUEST, - "Random": v2.Cluster_RANDOM, - "RoundRobin": v2.Cluster_ROUND_ROBIN, - "": v2.Cluster_ROUND_ROBIN, - "unknown": v2.Cluster_ROUND_ROBIN, - "Cookie": v2.Cluster_RING_HASH, - - // RingHash and Maglev were removed as options in 0.13. - // See #1150 - "RingHash": v2.Cluster_ROUND_ROBIN, - "Maglev": v2.Cluster_ROUND_ROBIN, - } - - for policy, want := range tests { - t.Run(policy, func(t *testing.T) { - got := lbPolicy(policy) - assert.Equal(t, want, got) - }) - } -} - -func TestHashname(t *testing.T) { - tests := []struct { - name string - l int - s []string - want string - }{ - {name: "empty s", l: 99, s: nil, want: ""}, - {name: "single element", l: 99, s: []string{"alpha"}, want: "alpha"}, - {name: "long single element, hashed", l: 12, s: []string{"gammagammagamma"}, want: "0d350ea5c204"}, - {name: "single element, truncated", l: 4, s: []string{"alpha"}, want: "8ed3"}, - {name: "two elements, truncated", l: 19, s: []string{"gammagamma", "betabeta"}, want: "ga-edf159/betabeta"}, - {name: "three elements", l: 99, s: []string{"alpha", "beta", "gamma"}, want: "alpha/beta/gamma"}, - {name: "issue/25", l: 60, s: []string{"default", "my-service-name", "my-very-very-long-service-host-name.my.domainname"}, want: "default/my-service-name/my-very-very--c4d2d4"}, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - got := hashname(tc.l, append([]string{}, tc.s...)...) - assert.Equal(t, tc.want, got) - }) - } -} - func TestTruncate(t *testing.T) { tests := []struct { name string @@ -606,36 +33,33 @@ func TestTruncate(t *testing.T) { } func TestAnyPositive(t *testing.T) { - assert.Equal(t, false, anyPositive(0)) - assert.Equal(t, true, anyPositive(1)) - assert.Equal(t, false, anyPositive(0, 0)) - assert.Equal(t, true, anyPositive(1, 0)) - assert.Equal(t, true, anyPositive(0, 1)) + assert.Equal(t, false, AnyPositive(0)) + assert.Equal(t, true, AnyPositive(1)) + assert.Equal(t, false, AnyPositive(0, 0)) + assert.Equal(t, true, AnyPositive(1, 0)) + assert.Equal(t, true, AnyPositive(0, 1)) } -func TestClusterCommonLBConfig(t *testing.T) { - got := ClusterCommonLBConfig() - want := &v2.Cluster_CommonLbConfig{ - HealthyPanicThreshold: &envoy_type.Percent{ // Disable HealthyPanicThreshold - Value: 0, - }, +func TestHashname(t *testing.T) { + tests := []struct { + name string + l int + s []string + want string + }{ + {name: "empty s", l: 99, s: nil, want: ""}, + {name: "single element", l: 99, s: []string{"alpha"}, want: "alpha"}, + {name: "long single element, hashed", l: 12, s: []string{"gammagammagamma"}, want: "0d350ea5c204"}, + {name: "single element, truncated", l: 4, s: []string{"alpha"}, want: "8ed3"}, + {name: "two elements, truncated", l: 19, s: []string{"gammagamma", "betabeta"}, want: "ga-edf159/betabeta"}, + {name: "three elements", l: 99, s: []string{"alpha", "beta", "gamma"}, want: "alpha/beta/gamma"}, + {name: "issue/25", l: 60, s: []string{"default", "my-service-name", "my-very-very-long-service-host-name.my.domainname"}, want: "default/my-service-name/my-very-very--c4d2d4"}, } - assert.Equal(t, want, got) -} -func service(s *v1.Service, protocols ...string) *dag.Service { - protocol := "" - if len(protocols) > 0 { - protocol = protocols[0] - } - return &dag.Service{ - Weighted: dag.WeightedService{ - Weight: 1, - ServiceName: s.Name, - ServiceNamespace: s.Namespace, - ServicePort: s.Spec.Ports[0], - }, - ExternalName: s.Spec.ExternalName, - Protocol: protocol, + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := Hashname(tc.l, append([]string{}, tc.s...)...) + assert.Equal(t, tc.want, got) + }) } } diff --git a/internal/envoy/healthcheck.go b/internal/envoy/healthcheck.go index 302fd6882b4..9bac42ae126 100644 --- a/internal/envoy/healthcheck.go +++ b/internal/envoy/healthcheck.go @@ -13,66 +13,13 @@ package envoy -import ( - "time" - - envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" - "github.com/golang/protobuf/ptypes/duration" - "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/protobuf" -) +import "time" const ( // Default healthcheck / lb algorithm values - hcTimeout = 2 * time.Second - hcInterval = 10 * time.Second - hcUnhealthyThreshold = 3 - hcHealthyThreshold = 2 - hcHost = "contour-envoy-healthcheck" + HCTimeout = 2 * time.Second + HCInterval = 10 * time.Second + HCUnhealthyThreshold = 3 + HCHealthyThreshold = 2 + HCHost = "contour-envoy-healthcheck" ) - -// httpHealthCheck returns a *envoy_api_v2_core.HealthCheck value for HTTP Routes -func httpHealthCheck(cluster *dag.Cluster) *envoy_api_v2_core.HealthCheck { - hc := cluster.HTTPHealthCheckPolicy - host := hcHost - if hc.Host != "" { - host = hc.Host - } - - // TODO(dfc) why do we need to specify our own default, what is the default - // that envoy applies if these fields are left nil? - return &envoy_api_v2_core.HealthCheck{ - Timeout: durationOrDefault(hc.Timeout, hcTimeout), - Interval: durationOrDefault(hc.Interval, hcInterval), - UnhealthyThreshold: protobuf.UInt32OrDefault(hc.UnhealthyThreshold, hcUnhealthyThreshold), - HealthyThreshold: protobuf.UInt32OrDefault(hc.HealthyThreshold, hcHealthyThreshold), - HealthChecker: &envoy_api_v2_core.HealthCheck_HttpHealthCheck_{ - HttpHealthCheck: &envoy_api_v2_core.HealthCheck_HttpHealthCheck{ - Path: hc.Path, - Host: host, - }, - }, - } -} - -// tcpHealthCheck returns a *envoy_api_v2_core.HealthCheck value for TCPProxies -func tcpHealthCheck(cluster *dag.Cluster) *envoy_api_v2_core.HealthCheck { - hc := cluster.TCPHealthCheckPolicy - - return &envoy_api_v2_core.HealthCheck{ - Timeout: durationOrDefault(hc.Timeout, hcTimeout), - Interval: durationOrDefault(hc.Interval, hcInterval), - UnhealthyThreshold: protobuf.UInt32OrDefault(hc.UnhealthyThreshold, hcUnhealthyThreshold), - HealthyThreshold: protobuf.UInt32OrDefault(hc.HealthyThreshold, hcHealthyThreshold), - HealthChecker: &envoy_api_v2_core.HealthCheck_TcpHealthCheck_{ - TcpHealthCheck: &envoy_api_v2_core.HealthCheck_TcpHealthCheck{}, - }, - } -} - -func durationOrDefault(d, def time.Duration) *duration.Duration { - if d != 0 { - return protobuf.Duration(d) - } - return protobuf.Duration(def) -} diff --git a/internal/envoy/listener.go b/internal/envoy/listener.go index 57645f92932..9297683bc66 100644 --- a/internal/envoy/listener.go +++ b/internal/envoy/listener.go @@ -14,27 +14,9 @@ package envoy import ( - "fmt" "log" - "sort" - "strings" - "time" - v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" - envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" - envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" - envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" - accesslog "github.com/envoyproxy/go-control-plane/envoy/config/filter/accesslog/v2" - envoy_config_filter_http_ext_authz_v2 "github.com/envoyproxy/go-control-plane/envoy/config/filter/http/ext_authz/v2" - lua "github.com/envoyproxy/go-control-plane/envoy/config/filter/http/lua/v2" http "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2" - tcp "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/tcp_proxy/v2" - envoy_type "github.com/envoyproxy/go-control-plane/envoy/type" - "github.com/envoyproxy/go-control-plane/pkg/wellknown" - "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/protobuf" - "github.com/projectcontour/contour/internal/sorter" - "github.com/projectcontour/contour/internal/timeout" ) type HTTPVersionType = http.HttpConnectionManager_CodecType @@ -46,35 +28,6 @@ const ( HTTPVersion3 HTTPVersionType = http.HttpConnectionManager_HTTP3 ) -// TLSInspector returns a new TLS inspector listener filter. -func TLSInspector() *envoy_api_v2_listener.ListenerFilter { - return &envoy_api_v2_listener.ListenerFilter{ - Name: wellknown.TlsInspector, - } -} - -// ProxyProtocol returns a new Proxy Protocol listener filter. -func ProxyProtocol() *envoy_api_v2_listener.ListenerFilter { - return &envoy_api_v2_listener.ListenerFilter{ - Name: wellknown.ProxyProtocol, - } -} - -// CodecForVersions determines a single Envoy HTTP codec constant -// that support all the given HTTP protocol versions. -func CodecForVersions(versions ...HTTPVersionType) HTTPVersionType { - switch len(versions) { - case 1: - return versions[0] - case 0: - // Default is to autodetect. - return HTTPVersionAuto - default: - // If more than one version is allowed, autodetect and let ALPN sort it out. - return HTTPVersionAuto - } -} - // ProtoNamesForVersions returns the slice of ALPN protocol names for the give HTTP versions. func ProtoNamesForVersions(versions ...HTTPVersionType) []string { protocols := map[HTTPVersionType]string{ @@ -110,466 +63,17 @@ func ProtoNamesForVersions(versions ...HTTPVersionType) []string { return alpn } -// Listener returns a new v2.Listener for the supplied address, port, and filters. -func Listener(name, address string, port int, lf []*envoy_api_v2_listener.ListenerFilter, filters ...*envoy_api_v2_listener.Filter) *v2.Listener { - l := &v2.Listener{ - Name: name, - Address: SocketAddress(address, port), - ListenerFilters: lf, - SocketOptions: TCPKeepaliveSocketOptions(), - } - if len(filters) > 0 { - l.FilterChains = append( - l.FilterChains, - &envoy_api_v2_listener.FilterChain{ - Filters: filters, - }, - ) - } - return l -} - -type httpConnectionManagerBuilder struct { - routeConfigName string - metricsPrefix string - accessLoggers []*accesslog.AccessLog - requestTimeout timeout.Setting - connectionIdleTimeout timeout.Setting - streamIdleTimeout timeout.Setting - maxConnectionDuration timeout.Setting - connectionShutdownGracePeriod timeout.Setting - filters []*http.HttpFilter - codec HTTPVersionType // Note the zero value is AUTO, which is the default we want. -} - -// RouteConfigName sets the name of the RDS element that contains -// the routing table for this manager. -func (b *httpConnectionManagerBuilder) RouteConfigName(name string) *httpConnectionManagerBuilder { - b.routeConfigName = name - return b -} - -// MetricsPrefix sets the prefix used for emitting metrics from the -// connection manager. Note that this prefix is externally visible in -// monitoring tools, so it is subject to compatibility concerns. -// -// See https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/stats#config-http-conn-man-stats -func (b *httpConnectionManagerBuilder) MetricsPrefix(prefix string) *httpConnectionManagerBuilder { - b.metricsPrefix = prefix - return b -} - -// Codec sets the HTTP codec for the manager. The default is AUTO. -func (b *httpConnectionManagerBuilder) Codec(codecType HTTPVersionType) *httpConnectionManagerBuilder { - b.codec = codecType - return b -} - -// AccessLoggers sets the access logging configuration. -func (b *httpConnectionManagerBuilder) AccessLoggers(loggers []*accesslog.AccessLog) *httpConnectionManagerBuilder { - b.accessLoggers = loggers - return b -} - -// RequestTimeout sets the active request timeout on the connection manager. -func (b *httpConnectionManagerBuilder) RequestTimeout(timeout timeout.Setting) *httpConnectionManagerBuilder { - b.requestTimeout = timeout - return b -} - -// ConnectionIdleTimeout sets the idle timeout on the connection manager. -func (b *httpConnectionManagerBuilder) ConnectionIdleTimeout(timeout timeout.Setting) *httpConnectionManagerBuilder { - b.connectionIdleTimeout = timeout - return b -} - -// StreamIdleTimeout sets the stream idle timeout on the connection manager. -func (b *httpConnectionManagerBuilder) StreamIdleTimeout(timeout timeout.Setting) *httpConnectionManagerBuilder { - b.streamIdleTimeout = timeout - return b -} - -// MaxConnectionDuration sets the max connection duration on the connection manager. -func (b *httpConnectionManagerBuilder) MaxConnectionDuration(timeout timeout.Setting) *httpConnectionManagerBuilder { - b.maxConnectionDuration = timeout - return b -} - -// ConnectionShutdownGracePeriod sets the drain timeout on the connection manager. -func (b *httpConnectionManagerBuilder) ConnectionShutdownGracePeriod(timeout timeout.Setting) *httpConnectionManagerBuilder { - b.connectionShutdownGracePeriod = timeout - return b -} - -func (b *httpConnectionManagerBuilder) DefaultFilters() *httpConnectionManagerBuilder { - b.filters = append(b.filters, - &http.HttpFilter{ - Name: wellknown.Gzip, - }, - &http.HttpFilter{ - Name: wellknown.GRPCWeb, - }, - &http.HttpFilter{ - Name: wellknown.Router, - }, - ) - - return b -} - -// AddFilter appends f to the list of filters for this HTTPConnectionManager. f -// may by nil, in which case it is ignored. -func (b *httpConnectionManagerBuilder) AddFilter(f *http.HttpFilter) *httpConnectionManagerBuilder { - if f == nil { - return b - } - - if len(b.filters) > 0 { - lastIndex := len(b.filters) - 1 - // If the router filter is last, keep it at the end - // of the filter chain when we add the new filter. - if b.filters[lastIndex].Name == wellknown.Router { - b.filters = append(b.filters[:lastIndex], f, b.filters[lastIndex]) - return b - } - } - - b.filters = append(b.filters, f) - - return b -} - -// Validate runs builtin validation rules against the current builder state. -func (b *httpConnectionManagerBuilder) Validate() error { - filterNames := map[string]struct{}{} - - for _, f := range b.filters { - filterNames[f.Name] = struct{}{} - } - - // If there's no router filter, requests won't be forwarded. - if _, ok := filterNames[wellknown.Router]; !ok { - return fmt.Errorf("missing required filter %q", wellknown.Router) - } - - return nil -} - -// Get returns a new http.HttpConnectionManager filter, constructed -// from the builder settings. -// -// See https://www.envoyproxy.io/docs/envoy/latest/api-v2/config/filter/network/http_connection_manager/v2/http_connection_manager.proto.html -func (b *httpConnectionManagerBuilder) Get() *envoy_api_v2_listener.Filter { - // For now, failing validation is a programmer error that - // the caller can't reasonably recover from. A caller that can - // handle this should validate manually. - if err := b.Validate(); err != nil { - panic(err.Error()) - } - - cm := &http.HttpConnectionManager{ - CodecType: b.codec, - RouteSpecifier: &http.HttpConnectionManager_Rds{ - Rds: &http.Rds{ - RouteConfigName: b.routeConfigName, - ConfigSource: ConfigSource("contour"), - }, - }, - HttpFilters: b.filters, - CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{ - IdleTimeout: envoyTimeout(b.connectionIdleTimeout), - }, - HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ - // Enable support for HTTP/1.0 requests that carry - // a Host: header. See #537. - AcceptHttp_10: true, - }, - UseRemoteAddress: protobuf.Bool(true), - NormalizePath: protobuf.Bool(true), - - // issue #1487 pass through X-Request-Id if provided. - PreserveExternalRequestId: true, - MergeSlashes: true, - - RequestTimeout: envoyTimeout(b.requestTimeout), - StreamIdleTimeout: envoyTimeout(b.streamIdleTimeout), - DrainTimeout: envoyTimeout(b.connectionShutdownGracePeriod), - } - - // Max connection duration is infinite/disabled by default in Envoy, so if the timeout setting - // indicates to either disable or use default, don't pass a value at all. Note that unlike other - // Envoy timeouts, explicitly passing a 0 here *would not* disable the timeout; it needs to be - // omitted entirely. - if !b.maxConnectionDuration.IsDisabled() && !b.maxConnectionDuration.UseDefault() { - cm.CommonHttpProtocolOptions.MaxConnectionDuration = protobuf.Duration(b.maxConnectionDuration.Duration()) - } - - if len(b.accessLoggers) > 0 { - cm.AccessLog = b.accessLoggers - } - - // If there's no explicit metrics prefix, default it to the - // route config name. - if b.metricsPrefix != "" { - cm.StatPrefix = b.metricsPrefix - } else { - cm.StatPrefix = b.routeConfigName - } - - return &envoy_api_v2_listener.Filter{ - Name: wellknown.HTTPConnectionManager, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(cm), - }, - } -} - -// HTTPConnectionManager creates a new HTTP Connection Manager filter -// for the supplied route, access log, and client request timeout. -func HTTPConnectionManager(routename string, accesslogger []*accesslog.AccessLog, requestTimeout time.Duration) *envoy_api_v2_listener.Filter { - return HTTPConnectionManagerBuilder(). - RouteConfigName(routename). - MetricsPrefix(routename). - AccessLoggers(accesslogger). - RequestTimeout(timeout.DurationSetting(requestTimeout)). - DefaultFilters(). - Get() -} - -func HTTPConnectionManagerBuilder() *httpConnectionManagerBuilder { - return &httpConnectionManagerBuilder{} -} - -// TCPProxy creates a new TCPProxy filter. -func TCPProxy(statPrefix string, proxy *dag.TCPProxy, accesslogger []*accesslog.AccessLog) *envoy_api_v2_listener.Filter { - // Set the idle timeout in seconds for connections through a TCP Proxy type filter. - // The value of two and a half hours for reasons documented at - // https://github.com/projectcontour/contour/issues/1074 - // Set to 9001 because now it's OVER NINE THOUSAND. - idleTimeout := protobuf.Duration(9001 * time.Second) - - switch len(proxy.Clusters) { +// CodecForVersions determines a single Envoy HTTP codec constant +// that support all the given HTTP protocol versions. +func CodecForVersions(versions ...HTTPVersionType) HTTPVersionType { + switch len(versions) { case 1: - return &envoy_api_v2_listener.Filter{ - Name: wellknown.TCPProxy, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&tcp.TcpProxy{ - StatPrefix: statPrefix, - ClusterSpecifier: &tcp.TcpProxy_Cluster{ - Cluster: Clustername(proxy.Clusters[0]), - }, - AccessLog: accesslogger, - IdleTimeout: idleTimeout, - }), - }, - } + return versions[0] + case 0: + // Default is to autodetect. + return HTTPVersionAuto default: - var clusters []*tcp.TcpProxy_WeightedCluster_ClusterWeight - for _, c := range proxy.Clusters { - weight := c.Weight - if weight == 0 { - weight = 1 - } - clusters = append(clusters, &tcp.TcpProxy_WeightedCluster_ClusterWeight{ - Name: Clustername(c), - Weight: weight, - }) - } - sort.Stable(sorter.For(clusters)) - return &envoy_api_v2_listener.Filter{ - Name: wellknown.TCPProxy, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&tcp.TcpProxy{ - StatPrefix: statPrefix, - ClusterSpecifier: &tcp.TcpProxy_WeightedClusters{ - WeightedClusters: &tcp.TcpProxy_WeightedCluster{ - Clusters: clusters, - }, - }, - AccessLog: accesslogger, - IdleTimeout: idleTimeout, - }), - }, - } - } -} - -// SocketAddress creates a new TCP envoy_api_v2_core.Address. -func SocketAddress(address string, port int) *envoy_api_v2_core.Address { - if address == "::" { - return &envoy_api_v2_core.Address{ - Address: &envoy_api_v2_core.Address_SocketAddress{ - SocketAddress: &envoy_api_v2_core.SocketAddress{ - Protocol: envoy_api_v2_core.SocketAddress_TCP, - Address: address, - Ipv4Compat: true, - PortSpecifier: &envoy_api_v2_core.SocketAddress_PortValue{ - PortValue: uint32(port), - }, - }, - }, - } - } - return &envoy_api_v2_core.Address{ - Address: &envoy_api_v2_core.Address_SocketAddress{ - SocketAddress: &envoy_api_v2_core.SocketAddress{ - Protocol: envoy_api_v2_core.SocketAddress_TCP, - Address: address, - PortSpecifier: &envoy_api_v2_core.SocketAddress_PortValue{ - PortValue: uint32(port), - }, - }, - }, - } -} - -// Filters returns a []*envoy_api_v2_listener.Filter for the supplied filters. -func Filters(filters ...*envoy_api_v2_listener.Filter) []*envoy_api_v2_listener.Filter { - if len(filters) == 0 { - return nil - } - return filters -} - -// FilterChain retruns a *envoy_api_v2_listener.FilterChain for the supplied filters. -func FilterChain(filters ...*envoy_api_v2_listener.Filter) *envoy_api_v2_listener.FilterChain { - return &envoy_api_v2_listener.FilterChain{ - Filters: filters, - } -} - -// FilterChains returns a []*envoy_api_v2_listener.FilterChain for the supplied filters. -func FilterChains(filters ...*envoy_api_v2_listener.Filter) []*envoy_api_v2_listener.FilterChain { - if len(filters) == 0 { - return nil - } - return []*envoy_api_v2_listener.FilterChain{ - FilterChain(filters...), - } -} - -func FilterMisdirectedRequests(fqdn string) *http.HttpFilter { - // When Envoy matches on the virtual host domain, we configure - // it to match any port specifier (see envoy.VirtualHost), - // so the Host header (authority) may contain a port that - // should be ignored. This means that if we don't have a match, - // we should try again after stripping the port specifier. - - code := ` -function envoy_on_request(request_handle) - local headers = request_handle:headers() - local host = string.lower(headers:get(":authority")) - local target = "%s" - - if host ~= target then - s, e = string.find(host, ":", 1, true) - if s ~= nil then - host = string.sub(host, 1, s - 1) - end - - if host ~= target then - request_handle:respond( - {[":status"] = "421"}, - string.format("misdirected request to %%q", headers:get(":authority")) - ) - end - end -end - ` - - return &http.HttpFilter{ - Name: "envoy.filters.http.lua", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&lua.Lua{ - InlineCode: fmt.Sprintf(code, strings.ToLower(fqdn)), - }), - }, - } -} - -// FilterExternalAuthz returns an `ext_authz` filter configured with the -// requested parameters. -func FilterExternalAuthz(authzClusterName string, failOpen bool, timeout timeout.Setting) *http.HttpFilter { - authConfig := envoy_config_filter_http_ext_authz_v2.ExtAuthz{ - Services: &envoy_config_filter_http_ext_authz_v2.ExtAuthz_GrpcService{ - GrpcService: &envoy_api_v2_core.GrpcService{ - TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ - ClusterName: authzClusterName, - }, - }, - Timeout: envoyTimeout(timeout), - // We don't need to configure metadata here, since we allow - // operators to specify authorization context parameters at - // the virtual host and route. - InitialMetadata: []*envoy_api_v2_core.HeaderValue{}, - }, - }, - // Pretty sure we always want this. Why have an - // external auth service if it is not going to affect - // routing decisions? - ClearRouteCache: true, - FailureModeAllow: failOpen, - StatusOnError: &envoy_type.HttpStatus{ - Code: envoy_type.StatusCode_Forbidden, - }, - MetadataContextNamespaces: []string{}, - IncludePeerCertificate: true, - } - - // TODO(jpeach): When we move to the Envoy v3 API, propagate the - // `transport_api_version` from ExtensionServiceSpec ProtocolVersion. - - return &http.HttpFilter{ - Name: "envoy.filters.http.ext_authz", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&authConfig), - }, - } -} - -// FilterChainTLS returns a TLS enabled envoy_api_v2_listener.FilterChain. -func FilterChainTLS(domain string, downstream *envoy_api_v2_auth.DownstreamTlsContext, filters []*envoy_api_v2_listener.Filter) *envoy_api_v2_listener.FilterChain { - fc := &envoy_api_v2_listener.FilterChain{ - Filters: filters, - FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ - ServerNames: []string{domain}, - }, - } - // Attach TLS data to this listener if provided. - if downstream != nil { - fc.TransportSocket = DownstreamTLSTransportSocket(downstream) - - } - return fc -} - -// FilterChainTLSFallback returns a TLS enabled envoy_api_v2_listener.FilterChain conifgured for FallbackCertificate. -func FilterChainTLSFallback(downstream *envoy_api_v2_auth.DownstreamTlsContext, filters []*envoy_api_v2_listener.Filter) *envoy_api_v2_listener.FilterChain { - fc := &envoy_api_v2_listener.FilterChain{ - Name: "fallback-certificate", - Filters: filters, - FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ - TransportProtocol: "tls", - }, - } - // Attach TLS data to this listener if provided. - if downstream != nil { - fc.TransportSocket = DownstreamTLSTransportSocket(downstream) - } - return fc -} - -// ListenerFilters returns a []*envoy_api_v2_listener.ListenerFilter for the supplied listener filters. -func ListenerFilters(filters ...*envoy_api_v2_listener.ListenerFilter) []*envoy_api_v2_listener.ListenerFilter { - return filters -} - -func ContainsFallbackFilterChain(filterchains []*envoy_api_v2_listener.FilterChain) bool { - for _, fc := range filterchains { - if fc.Name == "fallback-certificate" { - return true - } + // If more than one version is allowed, autodetect and let ALPN sort it out. + return HTTPVersionAuto } - return false } diff --git a/internal/envoy/listener_test.go b/internal/envoy/listener_test.go index 4e010364369..741a0e76ba6 100644 --- a/internal/envoy/listener_test.go +++ b/internal/envoy/listener_test.go @@ -1,784 +1,11 @@ -// Copyright Project Contour Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package envoy import ( "testing" - "time" - v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" - envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" - envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" - envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" - envoy_api_v2_accesslog "github.com/envoyproxy/go-control-plane/envoy/config/filter/accesslog/v2" - http "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2" - envoy_config_v2_tcpproxy "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/tcp_proxy/v2" - "github.com/envoyproxy/go-control-plane/pkg/wellknown" - "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/protobuf" - "github.com/projectcontour/contour/internal/timeout" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" ) -func TestListener(t *testing.T) { - tests := map[string]struct { - name, address string - port int - lf []*envoy_api_v2_listener.ListenerFilter - f []*envoy_api_v2_listener.Filter - want *v2.Listener - }{ - "insecure listener": { - name: "http", - address: "0.0.0.0", - port: 9000, - f: []*envoy_api_v2_listener.Filter{ - HTTPConnectionManager("http", FileAccessLogEnvoy("/dev/null"), 0), - }, - want: &v2.Listener{ - Name: "http", - Address: SocketAddress("0.0.0.0", 9000), - FilterChains: FilterChains( - HTTPConnectionManager("http", FileAccessLogEnvoy("/dev/null"), 0), - ), - SocketOptions: TCPKeepaliveSocketOptions(), - }, - }, - "insecure listener w/ proxy": { - name: "http-proxy", - address: "0.0.0.0", - port: 9000, - lf: []*envoy_api_v2_listener.ListenerFilter{ - ProxyProtocol(), - }, - f: []*envoy_api_v2_listener.Filter{ - HTTPConnectionManager("http-proxy", FileAccessLogEnvoy("/dev/null"), 0), - }, - want: &v2.Listener{ - Name: "http-proxy", - Address: SocketAddress("0.0.0.0", 9000), - ListenerFilters: ListenerFilters( - ProxyProtocol(), - ), - FilterChains: FilterChains( - HTTPConnectionManager("http-proxy", FileAccessLogEnvoy("/dev/null"), 0), - ), - SocketOptions: TCPKeepaliveSocketOptions(), - }, - }, - "secure listener": { - name: "https", - address: "0.0.0.0", - port: 9000, - lf: ListenerFilters( - TLSInspector(), - ), - want: &v2.Listener{ - Name: "https", - Address: SocketAddress("0.0.0.0", 9000), - ListenerFilters: ListenerFilters( - TLSInspector(), - ), - SocketOptions: TCPKeepaliveSocketOptions(), - }, - }, - "secure listener w/ proxy": { - name: "https-proxy", - address: "0.0.0.0", - port: 9000, - lf: ListenerFilters( - ProxyProtocol(), - TLSInspector(), - ), - want: &v2.Listener{ - Name: "https-proxy", - Address: SocketAddress("0.0.0.0", 9000), - ListenerFilters: ListenerFilters( - ProxyProtocol(), - TLSInspector(), - ), - SocketOptions: TCPKeepaliveSocketOptions(), - }, - }, - } - - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - got := Listener(tc.name, tc.address, tc.port, tc.lf, tc.f...) - protobuf.ExpectEqual(t, tc.want, got) - }) - } -} - -func TestSocketAddress(t *testing.T) { - const ( - addr = "foo.example.com" - port = 8123 - ) - - got := SocketAddress(addr, port) - want := &envoy_api_v2_core.Address{ - Address: &envoy_api_v2_core.Address_SocketAddress{ - SocketAddress: &envoy_api_v2_core.SocketAddress{ - Protocol: envoy_api_v2_core.SocketAddress_TCP, - Address: addr, - PortSpecifier: &envoy_api_v2_core.SocketAddress_PortValue{ - PortValue: port, - }, - }, - }, - } - require.Equal(t, want, got) - - got = SocketAddress("::", port) - want = &envoy_api_v2_core.Address{ - Address: &envoy_api_v2_core.Address_SocketAddress{ - SocketAddress: &envoy_api_v2_core.SocketAddress{ - Protocol: envoy_api_v2_core.SocketAddress_TCP, - Address: "::", - Ipv4Compat: true, // Set only for ipv6-any "::" - PortSpecifier: &envoy_api_v2_core.SocketAddress_PortValue{ - PortValue: port, - }, - }, - }, - } - assert.Equal(t, want, got) -} - -func TestDownstreamTLSContext(t *testing.T) { - const subjectName = "client-subject-name" - ca := []byte("client-ca-cert") - - serverSecret := &dag.Secret{ - Object: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "tls-cert", - Namespace: "default", - }, - Data: map[string][]byte{ - v1.TLSCertKey: []byte("cert"), - v1.TLSPrivateKeyKey: []byte("key"), - }, - }, - } - - tlsParams := &envoy_api_v2_auth.TlsParameters{ - TlsMinimumProtocolVersion: envoy_api_v2_auth.TlsParameters_TLSv1_1, - TlsMaximumProtocolVersion: envoy_api_v2_auth.TlsParameters_TLSv1_3, - CipherSuites: []string{ - "[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]", - "[ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]", - "ECDHE-ECDSA-AES128-SHA", - "ECDHE-RSA-AES128-SHA", - "ECDHE-ECDSA-AES256-GCM-SHA384", - "ECDHE-RSA-AES256-GCM-SHA384", - "ECDHE-ECDSA-AES256-SHA", - "ECDHE-RSA-AES256-SHA", - }, - } - - tlsCertificateSdsSecretConfigs := []*envoy_api_v2_auth.SdsSecretConfig{{ - Name: Secretname(serverSecret), - SdsConfig: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ - ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ - ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, - GrpcServices: []*envoy_api_v2_core.GrpcService{{ - TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ - ClusterName: "contour", - }, - }, - }}, - }, - }, - }, - }} - - alpnProtocols := []string{"h2", "http/1.1"} - validationContext := &envoy_api_v2_auth.CommonTlsContext_ValidationContext{ - ValidationContext: &envoy_api_v2_auth.CertificateValidationContext{ - TrustedCa: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_InlineBytes{ - InlineBytes: ca, - }, - }, - }, - } - - peerValidationContext := &dag.PeerValidationContext{ - CACertificate: &dag.Secret{ - Object: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Data: map[string][]byte{ - dag.CACertificateKey: ca, - }, - }, - }, - } - - // Negative test case: downstream validation should not contain subjectname. - peerValidationContextWithSubjectName := &dag.PeerValidationContext{ - CACertificate: &dag.Secret{ - Object: &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Data: map[string][]byte{ - dag.CACertificateKey: ca, - }, - }, - }, - SubjectName: subjectName, - } - - tests := map[string]struct { - got *envoy_api_v2_auth.DownstreamTlsContext - want *envoy_api_v2_auth.DownstreamTlsContext - }{ - "TLS context without client authentication": { - DownstreamTLSContext(serverSecret, envoy_api_v2_auth.TlsParameters_TLSv1_1, nil, "h2", "http/1.1"), - &envoy_api_v2_auth.DownstreamTlsContext{ - CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ - TlsParams: tlsParams, - TlsCertificateSdsSecretConfigs: tlsCertificateSdsSecretConfigs, - AlpnProtocols: alpnProtocols, - }, - }, - }, - "TLS context with client authentication": { - DownstreamTLSContext(serverSecret, envoy_api_v2_auth.TlsParameters_TLSv1_1, peerValidationContext, "h2", "http/1.1"), - &envoy_api_v2_auth.DownstreamTlsContext{ - CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ - TlsParams: tlsParams, - TlsCertificateSdsSecretConfigs: tlsCertificateSdsSecretConfigs, - AlpnProtocols: alpnProtocols, - ValidationContextType: validationContext, - }, - RequireClientCertificate: protobuf.Bool(true), - }, - }, - "Downstream validation shall not support subjectName validation": { - DownstreamTLSContext(serverSecret, envoy_api_v2_auth.TlsParameters_TLSv1_1, peerValidationContextWithSubjectName, "h2", "http/1.1"), - &envoy_api_v2_auth.DownstreamTlsContext{ - CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ - TlsParams: tlsParams, - TlsCertificateSdsSecretConfigs: tlsCertificateSdsSecretConfigs, - AlpnProtocols: alpnProtocols, - ValidationContextType: validationContext, - }, - RequireClientCertificate: protobuf.Bool(true), - }, - }, - } - - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - protobuf.ExpectEqual(t, tc.want, tc.got) - }) - } -} - -func TestHTTPConnectionManager(t *testing.T) { - tests := map[string]struct { - routename string - accesslogger []*envoy_api_v2_accesslog.AccessLog - requestTimeout timeout.Setting - connectionIdleTimeout timeout.Setting - streamIdleTimeout timeout.Setting - maxConnectionDuration timeout.Setting - connectionShutdownGracePeriod timeout.Setting - want *envoy_api_v2_listener.Filter - }{ - "default": { - routename: "default/kuard", - accesslogger: FileAccessLogEnvoy("/dev/stdout"), - want: &envoy_api_v2_listener.Filter{ - Name: wellknown.HTTPConnectionManager, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ - StatPrefix: "default/kuard", - RouteSpecifier: &http.HttpConnectionManager_Rds{ - Rds: &http.Rds{ - RouteConfigName: "default/kuard", - ConfigSource: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ - ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ - ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, - GrpcServices: []*envoy_api_v2_core.GrpcService{{ - TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ - ClusterName: "contour", - }, - }, - }}, - }, - }, - }, - }, - }, - HttpFilters: []*http.HttpFilter{{ - Name: wellknown.Gzip, - }, { - Name: wellknown.GRPCWeb, - }, { - Name: wellknown.Router, - }}, - HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ - // Enable support for HTTP/1.0 requests that carry - // a Host: header. See #537. - AcceptHttp_10: true, - }, - CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{}, - AccessLog: FileAccessLogEnvoy("/dev/stdout"), - UseRemoteAddress: protobuf.Bool(true), - NormalizePath: protobuf.Bool(true), - PreserveExternalRequestId: true, - MergeSlashes: true, - }), - }, - }, - }, - "request timeout of 10s": { - routename: "default/kuard", - accesslogger: FileAccessLogEnvoy("/dev/stdout"), - requestTimeout: timeout.DurationSetting(10 * time.Second), - want: &envoy_api_v2_listener.Filter{ - Name: wellknown.HTTPConnectionManager, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ - StatPrefix: "default/kuard", - RouteSpecifier: &http.HttpConnectionManager_Rds{ - Rds: &http.Rds{ - RouteConfigName: "default/kuard", - ConfigSource: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ - ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ - ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, - GrpcServices: []*envoy_api_v2_core.GrpcService{{ - TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ - ClusterName: "contour", - }, - }, - }}, - }, - }, - }, - }, - }, - HttpFilters: []*http.HttpFilter{{ - Name: wellknown.Gzip, - }, { - Name: wellknown.GRPCWeb, - }, { - Name: wellknown.Router, - }}, - HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ - // Enable support for HTTP/1.0 requests that carry - // a Host: header. See #537. - AcceptHttp_10: true, - }, - CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{}, - AccessLog: FileAccessLogEnvoy("/dev/stdout"), - UseRemoteAddress: protobuf.Bool(true), - NormalizePath: protobuf.Bool(true), - RequestTimeout: protobuf.Duration(10 * time.Second), - PreserveExternalRequestId: true, - MergeSlashes: true, - }), - }, - }, - }, - "connection idle timeout of 90s": { - routename: "default/kuard", - accesslogger: FileAccessLogEnvoy("/dev/stdout"), - connectionIdleTimeout: timeout.DurationSetting(90 * time.Second), - want: &envoy_api_v2_listener.Filter{ - Name: wellknown.HTTPConnectionManager, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ - StatPrefix: "default/kuard", - RouteSpecifier: &http.HttpConnectionManager_Rds{ - Rds: &http.Rds{ - RouteConfigName: "default/kuard", - ConfigSource: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ - ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ - ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, - GrpcServices: []*envoy_api_v2_core.GrpcService{{ - TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ - ClusterName: "contour", - }, - }, - }}, - }, - }, - }, - }, - }, - HttpFilters: []*http.HttpFilter{{ - Name: wellknown.Gzip, - }, { - Name: wellknown.GRPCWeb, - }, { - Name: wellknown.Router, - }}, - HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ - // Enable support for HTTP/1.0 requests that carry - // a Host: header. See #537. - AcceptHttp_10: true, - }, - CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{ - IdleTimeout: protobuf.Duration(90 * time.Second), - }, - AccessLog: FileAccessLogEnvoy("/dev/stdout"), - UseRemoteAddress: protobuf.Bool(true), - NormalizePath: protobuf.Bool(true), - PreserveExternalRequestId: true, - MergeSlashes: true, - }), - }, - }, - }, - "stream idle timeout of 90s": { - routename: "default/kuard", - accesslogger: FileAccessLogEnvoy("/dev/stdout"), - streamIdleTimeout: timeout.DurationSetting(90 * time.Second), - want: &envoy_api_v2_listener.Filter{ - Name: wellknown.HTTPConnectionManager, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ - StatPrefix: "default/kuard", - RouteSpecifier: &http.HttpConnectionManager_Rds{ - Rds: &http.Rds{ - RouteConfigName: "default/kuard", - ConfigSource: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ - ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ - ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, - GrpcServices: []*envoy_api_v2_core.GrpcService{{ - TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ - ClusterName: "contour", - }, - }, - }}, - }, - }, - }, - }, - }, - HttpFilters: []*http.HttpFilter{{ - Name: wellknown.Gzip, - }, { - Name: wellknown.GRPCWeb, - }, { - Name: wellknown.Router, - }}, - HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ - // Enable support for HTTP/1.0 requests that carry - // a Host: header. See #537. - AcceptHttp_10: true, - }, - CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{}, - AccessLog: FileAccessLogEnvoy("/dev/stdout"), - UseRemoteAddress: protobuf.Bool(true), - NormalizePath: protobuf.Bool(true), - PreserveExternalRequestId: true, - MergeSlashes: true, - StreamIdleTimeout: protobuf.Duration(90 * time.Second), - }), - }, - }, - }, - "max connection duration of 90s": { - routename: "default/kuard", - accesslogger: FileAccessLogEnvoy("/dev/stdout"), - maxConnectionDuration: timeout.DurationSetting(90 * time.Second), - want: &envoy_api_v2_listener.Filter{ - Name: wellknown.HTTPConnectionManager, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ - StatPrefix: "default/kuard", - RouteSpecifier: &http.HttpConnectionManager_Rds{ - Rds: &http.Rds{ - RouteConfigName: "default/kuard", - ConfigSource: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ - ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ - ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, - GrpcServices: []*envoy_api_v2_core.GrpcService{{ - TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ - ClusterName: "contour", - }, - }, - }}, - }, - }, - }, - }, - }, - HttpFilters: []*http.HttpFilter{{ - Name: wellknown.Gzip, - }, { - Name: wellknown.GRPCWeb, - }, { - Name: wellknown.Router, - }}, - HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ - // Enable support for HTTP/1.0 requests that carry - // a Host: header. See #537. - AcceptHttp_10: true, - }, - CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{ - MaxConnectionDuration: protobuf.Duration(90 * time.Second), - }, - AccessLog: FileAccessLogEnvoy("/dev/stdout"), - UseRemoteAddress: protobuf.Bool(true), - NormalizePath: protobuf.Bool(true), - PreserveExternalRequestId: true, - MergeSlashes: true, - }), - }, - }, - }, - "when max connection duration is disabled, it's omitted": { - routename: "default/kuard", - accesslogger: FileAccessLogEnvoy("/dev/stdout"), - maxConnectionDuration: timeout.DisabledSetting(), - want: &envoy_api_v2_listener.Filter{ - Name: wellknown.HTTPConnectionManager, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ - StatPrefix: "default/kuard", - RouteSpecifier: &http.HttpConnectionManager_Rds{ - Rds: &http.Rds{ - RouteConfigName: "default/kuard", - ConfigSource: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ - ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ - ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, - GrpcServices: []*envoy_api_v2_core.GrpcService{{ - TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ - ClusterName: "contour", - }, - }, - }}, - }, - }, - }, - }, - }, - HttpFilters: []*http.HttpFilter{{ - Name: wellknown.Gzip, - }, { - Name: wellknown.GRPCWeb, - }, { - Name: wellknown.Router, - }}, - HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ - // Enable support for HTTP/1.0 requests that carry - // a Host: header. See #537. - AcceptHttp_10: true, - }, - CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{}, - AccessLog: FileAccessLogEnvoy("/dev/stdout"), - UseRemoteAddress: protobuf.Bool(true), - NormalizePath: protobuf.Bool(true), - PreserveExternalRequestId: true, - MergeSlashes: true, - }), - }, - }, - }, - "drain timeout of 90s": { - routename: "default/kuard", - accesslogger: FileAccessLogEnvoy("/dev/stdout"), - connectionShutdownGracePeriod: timeout.DurationSetting(90 * time.Second), - want: &envoy_api_v2_listener.Filter{ - Name: wellknown.HTTPConnectionManager, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ - StatPrefix: "default/kuard", - RouteSpecifier: &http.HttpConnectionManager_Rds{ - Rds: &http.Rds{ - RouteConfigName: "default/kuard", - ConfigSource: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ - ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ - ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, - GrpcServices: []*envoy_api_v2_core.GrpcService{{ - TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ - ClusterName: "contour", - }, - }, - }}, - }, - }, - }, - }, - }, - HttpFilters: []*http.HttpFilter{{ - Name: wellknown.Gzip, - }, { - Name: wellknown.GRPCWeb, - }, { - Name: wellknown.Router, - }}, - HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ - // Enable support for HTTP/1.0 requests that carry - // a Host: header. See #537. - AcceptHttp_10: true, - }, - CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{}, - AccessLog: FileAccessLogEnvoy("/dev/stdout"), - UseRemoteAddress: protobuf.Bool(true), - NormalizePath: protobuf.Bool(true), - PreserveExternalRequestId: true, - MergeSlashes: true, - DrainTimeout: protobuf.Duration(90 * time.Second), - }), - }, - }, - }, - } - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - got := HTTPConnectionManagerBuilder(). - RouteConfigName(tc.routename). - MetricsPrefix(tc.routename). - AccessLoggers(tc.accesslogger). - RequestTimeout(tc.requestTimeout). - ConnectionIdleTimeout(tc.connectionIdleTimeout). - StreamIdleTimeout(tc.streamIdleTimeout). - MaxConnectionDuration(tc.maxConnectionDuration). - ConnectionShutdownGracePeriod(tc.connectionShutdownGracePeriod). - DefaultFilters(). - Get() - - protobuf.ExpectEqual(t, tc.want, got) - }) - } -} - -func TestTCPProxy(t *testing.T) { - const ( - statPrefix = "ingress_https" - accessLogPath = "/dev/stdout" - ) - - c1 := &dag.Cluster{ - Upstream: &dag.Service{ - Weighted: dag.WeightedService{ - Weight: 1, - ServiceName: "example", - ServiceNamespace: "default", - ServicePort: v1.ServicePort{ - Protocol: "TCP", - Port: 443, - TargetPort: intstr.FromInt(8443), - }, - }, - }, - } - c2 := &dag.Cluster{ - Upstream: &dag.Service{ - Weighted: dag.WeightedService{ - ServiceName: "example2", - ServiceNamespace: "default", - ServicePort: v1.ServicePort{ - Protocol: "TCP", - Port: 443, - TargetPort: intstr.FromInt(8443), - }, - }, - }, - Weight: 20, - } - - tests := map[string]struct { - proxy *dag.TCPProxy - want *envoy_api_v2_listener.Filter - }{ - "single cluster": { - proxy: &dag.TCPProxy{ - Clusters: []*dag.Cluster{c1}, - }, - want: &envoy_api_v2_listener.Filter{ - Name: wellknown.TCPProxy, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_config_v2_tcpproxy.TcpProxy{ - StatPrefix: statPrefix, - ClusterSpecifier: &envoy_config_v2_tcpproxy.TcpProxy_Cluster{ - Cluster: Clustername(c1), - }, - AccessLog: FileAccessLogEnvoy(accessLogPath), - IdleTimeout: protobuf.Duration(9001 * time.Second), - }), - }, - }, - }, - "multiple cluster": { - proxy: &dag.TCPProxy{ - Clusters: []*dag.Cluster{c2, c1}, - }, - want: &envoy_api_v2_listener.Filter{ - Name: wellknown.TCPProxy, - ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_config_v2_tcpproxy.TcpProxy{ - StatPrefix: statPrefix, - ClusterSpecifier: &envoy_config_v2_tcpproxy.TcpProxy_WeightedClusters{ - WeightedClusters: &envoy_config_v2_tcpproxy.TcpProxy_WeightedCluster{ - Clusters: []*envoy_config_v2_tcpproxy.TcpProxy_WeightedCluster_ClusterWeight{{ - Name: Clustername(c1), - Weight: 1, - }, { - Name: Clustername(c2), - Weight: 20, - }}, - }, - }, - AccessLog: FileAccessLogEnvoy(accessLogPath), - IdleTimeout: protobuf.Duration(9001 * time.Second), - }), - }, - }, - }, - } - - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - got := TCPProxy(statPrefix, tc.proxy, FileAccessLogEnvoy(accessLogPath)) - protobuf.ExpectEqual(t, tc.want, got) - }) - } -} - func TestCodecForVersions(t *testing.T) { assert.Equal(t, CodecForVersions(HTTPVersionAuto), HTTPVersionAuto) assert.Equal(t, CodecForVersions(HTTPVersion1, HTTPVersion2), HTTPVersionAuto) @@ -794,19 +21,3 @@ func TestProtoNamesForVersions(t *testing.T) { assert.Equal(t, ProtoNamesForVersions(HTTPVersion3), []string(nil)) assert.Equal(t, ProtoNamesForVersions(HTTPVersion1, HTTPVersion2), []string{"h2", "http/1.1"}) } - -// TestBuilderValidation tests that validation checks that -// DefaultFilters adds the required HTTP connection manager filters. -func TestBuilderValidation(t *testing.T) { - if err := HTTPConnectionManagerBuilder().Validate(); err == nil { - t.Errorf("ConnectionManager with no filters passed validation") - } - - if err := HTTPConnectionManagerBuilder().AddFilter(&http.HttpFilter{Name: "foo"}).Validate(); err == nil { - t.Errorf("ConnectionManager with no filters passed validation") - } - - if err := HTTPConnectionManagerBuilder().DefaultFilters().Validate(); err != nil { - t.Errorf("ConnectionManager with default filters failed validation: %s", err) - } -} diff --git a/internal/envoy/route.go b/internal/envoy/route.go index d1577043290..73eaa9022f2 100644 --- a/internal/envoy/route.go +++ b/internal/envoy/route.go @@ -14,157 +14,26 @@ package envoy import ( - "fmt" - "regexp" - "sort" - - v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" - envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" - envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" - envoy_config_filter_http_ext_authz_v2 "github.com/envoyproxy/go-control-plane/envoy/config/filter/http/ext_authz/v2" - "github.com/golang/protobuf/ptypes/any" "github.com/golang/protobuf/ptypes/duration" - wrappers "github.com/golang/protobuf/ptypes/wrappers" "github.com/projectcontour/contour/internal/dag" "github.com/projectcontour/contour/internal/protobuf" - "github.com/projectcontour/contour/internal/sorter" "github.com/projectcontour/contour/internal/timeout" ) -// RouteAuthzDisabled returns a per-route config to disable authorization. -func RouteAuthzDisabled() *any.Any { - return protobuf.MustMarshalAny( - &envoy_config_filter_http_ext_authz_v2.ExtAuthzPerRoute{ - Override: &envoy_config_filter_http_ext_authz_v2.ExtAuthzPerRoute_Disabled{ - Disabled: true, - }, - }, - ) -} - -// RouteAuthzContext returns a per-route config to pass the given -// context entries in the check request. -func RouteAuthzContext(settings map[string]string) *any.Any { - return protobuf.MustMarshalAny( - &envoy_config_filter_http_ext_authz_v2.ExtAuthzPerRoute{ - Override: &envoy_config_filter_http_ext_authz_v2.ExtAuthzPerRoute_CheckSettings{ - CheckSettings: &envoy_config_filter_http_ext_authz_v2.CheckSettings{ - ContextExtensions: settings, - }, - }, - }, - ) -} - -// RouteMatch creates a *envoy_api_v2_route.RouteMatch for the supplied *dag.Route. -func RouteMatch(route *dag.Route) *envoy_api_v2_route.RouteMatch { - switch c := route.PathMatchCondition.(type) { - case *dag.RegexMatchCondition: - return &envoy_api_v2_route.RouteMatch{ - PathSpecifier: &envoy_api_v2_route.RouteMatch_SafeRegex{ - SafeRegex: SafeRegexMatch(c.Regex), - }, - Headers: headerMatcher(route.HeaderMatchConditions), - } - case *dag.PrefixMatchCondition: - return &envoy_api_v2_route.RouteMatch{ - PathSpecifier: &envoy_api_v2_route.RouteMatch_Prefix{ - Prefix: c.Prefix, - }, - Headers: headerMatcher(route.HeaderMatchConditions), - } - default: - return &envoy_api_v2_route.RouteMatch{ - Headers: headerMatcher(route.HeaderMatchConditions), - } - } -} - -// RouteRoute creates a *envoy_api_v2_route.Route_Route for the services supplied. -// If len(services) is greater than one, the route's action will be a -// weighted cluster. -func RouteRoute(r *dag.Route) *envoy_api_v2_route.Route_Route { - ra := envoy_api_v2_route.RouteAction{ - RetryPolicy: retryPolicy(r), - Timeout: envoyTimeout(r.TimeoutPolicy.ResponseTimeout), - IdleTimeout: envoyTimeout(r.TimeoutPolicy.IdleTimeout), - PrefixRewrite: r.PrefixRewrite, - HashPolicy: hashPolicy(r), - RequestMirrorPolicies: mirrorPolicy(r), - } - - // Check for host header policy and set if found - if val := hostReplaceHeader(r.RequestHeadersPolicy); val != "" { - ra.HostRewriteSpecifier = &envoy_api_v2_route.RouteAction_HostRewrite{ - HostRewrite: val, - } - } - - if r.Websocket { - ra.UpgradeConfigs = append(ra.UpgradeConfigs, - &envoy_api_v2_route.RouteAction_UpgradeConfig{ - UpgradeType: "websocket", - }, - ) - } - - if singleSimpleCluster(r.Clusters) { - ra.ClusterSpecifier = &envoy_api_v2_route.RouteAction_Cluster{ - Cluster: Clustername(r.Clusters[0]), - } - } else { - ra.ClusterSpecifier = &envoy_api_v2_route.RouteAction_WeightedClusters{ - WeightedClusters: weightedClusters(r.Clusters), - } - } - return &envoy_api_v2_route.Route_Route{ - Route: &ra, - } -} - -// hashPolicy returns a slice of hash policies iff at least one of the route's -// clusters supplied uses the `Cookie` load balancing strategy. -func hashPolicy(r *dag.Route) []*envoy_api_v2_route.RouteAction_HashPolicy { - for _, c := range r.Clusters { - if c.LoadBalancerPolicy == "Cookie" { - return []*envoy_api_v2_route.RouteAction_HashPolicy{{ - PolicySpecifier: &envoy_api_v2_route.RouteAction_HashPolicy_Cookie_{ - Cookie: &envoy_api_v2_route.RouteAction_HashPolicy_Cookie{ - Name: "X-Contour-Session-Affinity", - Ttl: protobuf.Duration(0), - Path: "/", - }, - }, - }} - } - } - return nil -} - -func mirrorPolicy(r *dag.Route) []*envoy_api_v2_route.RouteAction_RequestMirrorPolicy { - if r.MirrorPolicy == nil { - return nil - } - - return []*envoy_api_v2_route.RouteAction_RequestMirrorPolicy{{ - Cluster: Clustername(r.MirrorPolicy.Cluster), - }} -} - -func hostReplaceHeader(hp *dag.HeadersPolicy) string { +func HostReplaceHeader(hp *dag.HeadersPolicy) string { if hp == nil { return "" } return hp.HostRewrite } -// envoyTimeout converts a timeout.Setting to a protobuf.Duration +// Timeout converts a timeout.Setting to a protobuf.Duration // that's appropriate for Envoy. In general (though there are // exceptions), Envoy uses the following semantics: // - not passing a value means "use Envoy default" // - explicitly passing a 0 means "disable this timeout" // - passing a positive value uses that value -func envoyTimeout(d timeout.Setting) *duration.Duration { +func Timeout(d timeout.Setting) *duration.Duration { switch { case d.UseDefault(): // Don't pass a value to Envoy. @@ -178,63 +47,9 @@ func envoyTimeout(d timeout.Setting) *duration.Duration { } } -func retryPolicy(r *dag.Route) *envoy_api_v2_route.RetryPolicy { - if r.RetryPolicy == nil { - return nil - } - if r.RetryPolicy.RetryOn == "" { - return nil - } - - rp := &envoy_api_v2_route.RetryPolicy{ - RetryOn: r.RetryPolicy.RetryOn, - RetriableStatusCodes: r.RetryPolicy.RetriableStatusCodes, - } - if r.RetryPolicy.NumRetries > 0 { - rp.NumRetries = protobuf.UInt32(r.RetryPolicy.NumRetries) - } - rp.PerTryTimeout = envoyTimeout(r.RetryPolicy.PerTryTimeout) - - return rp -} - -// UpgradeHTTPS returns a route Action that redirects the request to HTTPS. -func UpgradeHTTPS() *envoy_api_v2_route.Route_Redirect { - return &envoy_api_v2_route.Route_Redirect{ - Redirect: &envoy_api_v2_route.RedirectAction{ - SchemeRewriteSpecifier: &envoy_api_v2_route.RedirectAction_HttpsRedirect{ - HttpsRedirect: true, - }, - }, - } -} - -// HeaderValueList creates a list of Envoy HeaderValueOptions from the provided map. -func HeaderValueList(hvm map[string]string, app bool) []*envoy_api_v2_core.HeaderValueOption { - var hvs []*envoy_api_v2_core.HeaderValueOption - - for key, value := range hvm { - hvs = append(hvs, &envoy_api_v2_core.HeaderValueOption{ - Header: &envoy_api_v2_core.HeaderValue{ - Key: key, - Value: value, - }, - Append: &wrappers.BoolValue{ - Value: app, - }, - }) - } - - sort.Slice(hvs, func(i, j int) bool { - return hvs[i].Header.Key < hvs[j].Header.Key - }) - - return hvs -} - -// singleSimpleCluster determines whether we can use a RouteAction_Cluster +// SingleSimpleCluster determines whether we can use a RouteAction_Cluster // or must use a RouteAction_WeighedCluster to encode additional routing data. -func singleSimpleCluster(clusters []*dag.Cluster) bool { +func SingleSimpleCluster(clusters []*dag.Cluster) bool { // If there are multiple clusters, than we cannot simply dispatch // to it by name. if len(clusters) != 1 { @@ -260,112 +75,3 @@ func singleSimpleCluster(clusters []*dag.Cluster) bool { return true } - -// weightedClusters returns a route.WeightedCluster for multiple services. -func weightedClusters(clusters []*dag.Cluster) *envoy_api_v2_route.WeightedCluster { - var wc envoy_api_v2_route.WeightedCluster - var total uint32 - for _, cluster := range clusters { - total += cluster.Weight - - c := &envoy_api_v2_route.WeightedCluster_ClusterWeight{ - Name: Clustername(cluster), - Weight: protobuf.UInt32(cluster.Weight), - } - if cluster.RequestHeadersPolicy != nil { - c.RequestHeadersToAdd = HeaderValueList(cluster.RequestHeadersPolicy.Set, false) - c.RequestHeadersToRemove = cluster.RequestHeadersPolicy.Remove - } - if cluster.ResponseHeadersPolicy != nil { - c.ResponseHeadersToAdd = HeaderValueList(cluster.ResponseHeadersPolicy.Set, false) - c.ResponseHeadersToRemove = cluster.ResponseHeadersPolicy.Remove - } - wc.Clusters = append(wc.Clusters, c) - } - // Check if no weights were defined, if not default to even distribution - if total == 0 { - for _, c := range wc.Clusters { - c.Weight.Value = 1 - } - total = uint32(len(clusters)) - } - wc.TotalWeight = protobuf.UInt32(total) - - sort.Stable(sorter.For(wc.Clusters)) - return &wc -} - -// VirtualHost creates a new route.VirtualHost. -func VirtualHost(hostname string, routes ...*envoy_api_v2_route.Route) *envoy_api_v2_route.VirtualHost { - domains := []string{hostname} - if hostname != "*" { - // NOTE(jpeach) see also envoy.FilterMisdirectedRequests(). - domains = append(domains, hostname+":*") - } - - return &envoy_api_v2_route.VirtualHost{ - Name: hashname(60, hostname), - Domains: domains, - Routes: routes, - } -} - -// RouteConfiguration returns a *v2.RouteConfiguration. -func RouteConfiguration(name string, virtualhosts ...*envoy_api_v2_route.VirtualHost) *v2.RouteConfiguration { - return &v2.RouteConfiguration{ - Name: name, - VirtualHosts: virtualhosts, - RequestHeadersToAdd: Headers( - AppendHeader("x-request-start", "t=%START_TIME(%s.%3f)%"), - ), - } -} - -func Headers(first *envoy_api_v2_core.HeaderValueOption, rest ...*envoy_api_v2_core.HeaderValueOption) []*envoy_api_v2_core.HeaderValueOption { - return append([]*envoy_api_v2_core.HeaderValueOption{first}, rest...) -} - -func AppendHeader(key, value string) *envoy_api_v2_core.HeaderValueOption { - return &envoy_api_v2_core.HeaderValueOption{ - Header: &envoy_api_v2_core.HeaderValue{ - Key: key, - Value: value, - }, - Append: protobuf.Bool(true), - } -} - -func headerMatcher(headers []dag.HeaderMatchCondition) []*envoy_api_v2_route.HeaderMatcher { - var envoyHeaders []*envoy_api_v2_route.HeaderMatcher - - for _, h := range headers { - header := &envoy_api_v2_route.HeaderMatcher{ - Name: h.Name, - InvertMatch: h.Invert, - } - - switch h.MatchType { - case "exact": - header.HeaderMatchSpecifier = &envoy_api_v2_route.HeaderMatcher_ExactMatch{ExactMatch: h.Value} - case "contains": - header.HeaderMatchSpecifier = containsMatch(h.Value) - case "present": - header.HeaderMatchSpecifier = &envoy_api_v2_route.HeaderMatcher_PresentMatch{PresentMatch: true} - } - envoyHeaders = append(envoyHeaders, header) - } - return envoyHeaders -} - -// containsMatch returns a HeaderMatchSpecifier which will match the -// supplied substring -func containsMatch(s string) *envoy_api_v2_route.HeaderMatcher_SafeRegexMatch { - // convert the substring s into a regular expression that matches s. - // note that Envoy expects the expression to match the entire string, not just the substring - // formed from s. see [projectcontour/contour/#1751 & envoyproxy/envoy#8283] - regex := fmt.Sprintf(".*%s.*", regexp.QuoteMeta(s)) - - return &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ - SafeRegexMatch: SafeRegexMatch(regex), - } -} diff --git a/internal/envoy/secret.go b/internal/envoy/secret.go index 6d3397063c1..625f2d0606c 100644 --- a/internal/envoy/secret.go +++ b/internal/envoy/secret.go @@ -1,24 +1,9 @@ -// Copyright Project Contour Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package envoy import ( "crypto/sha1" // nolint:gosec "fmt" - envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" - envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" "github.com/projectcontour/contour/internal/dag" ) @@ -28,26 +13,5 @@ func Secretname(s *dag.Secret) string { hash := sha1.Sum(s.Cert()) // nolint:gosec ns := s.Namespace() name := s.Name() - return hashname(60, ns, name, fmt.Sprintf("%x", hash[:5])) -} - -// Secret creates new envoy_api_v2_auth.Secret from secret. -func Secret(s *dag.Secret) *envoy_api_v2_auth.Secret { - return &envoy_api_v2_auth.Secret{ - Name: Secretname(s), - Type: &envoy_api_v2_auth.Secret_TlsCertificate{ - TlsCertificate: &envoy_api_v2_auth.TlsCertificate{ - PrivateKey: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_InlineBytes{ - InlineBytes: s.PrivateKey(), - }, - }, - CertificateChain: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_InlineBytes{ - InlineBytes: s.Cert(), - }, - }, - }, - }, - } + return Hashname(60, ns, name, fmt.Sprintf("%x", hash[:5])) } diff --git a/internal/envoy/tcp_keepalive.go b/internal/envoy/tcp_keepalive.go index e4230f265a7..1dd38a5819f 100644 --- a/internal/envoy/tcp_keepalive.go +++ b/internal/envoy/tcp_keepalive.go @@ -12,11 +12,7 @@ package envoy -import ( - "syscall" - - envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" -) +import "syscall" // We only support Envoy on Linux so always configure Linux TCP keep-alive // socket options regardless of the platform that Contour is running on. @@ -34,47 +30,3 @@ const ( // is defined here for consistency. IPPROTO_TCP = syscall.IPPROTO_TCP ) - -func TCPKeepaliveSocketOptions() []*envoy_api_v2_core.SocketOption { - - // Note: TCP_KEEPIDLE + (TCP_KEEPINTVL * TCP_KEEPCNT) must be greater than - // the grpc.KeepaliveParams time + timeout (currently 60 + 20 = 80 seconds) - // otherwise TestGRPC/StreamClusters fails. - return []*envoy_api_v2_core.SocketOption{ - // Enable TCP keep-alive. - { - Description: "Enable TCP keep-alive", - Level: SOL_SOCKET, - Name: SO_KEEPALIVE, - Value: &envoy_api_v2_core.SocketOption_IntValue{IntValue: 1}, - State: envoy_api_v2_core.SocketOption_STATE_LISTENING, - }, - // The time (in seconds) the connection needs to remain idle - // before TCP starts sending keepalive probes. - { - Description: "TCP keep-alive initial idle time", - Level: IPPROTO_TCP, - Name: TCP_KEEPIDLE, - Value: &envoy_api_v2_core.SocketOption_IntValue{IntValue: 45}, - State: envoy_api_v2_core.SocketOption_STATE_LISTENING, - }, - // The time (in seconds) between individual keepalive probes. - { - Description: "TCP keep-alive time between probes", - Level: IPPROTO_TCP, - Name: TCP_KEEPINTVL, - Value: &envoy_api_v2_core.SocketOption_IntValue{IntValue: 5}, - State: envoy_api_v2_core.SocketOption_STATE_LISTENING, - }, - // The maximum number of TCP keep-alive probes to send before - // giving up and killing the connection if no response is - // obtained from the other end. - { - Description: "TCP keep-alive probe count", - Level: IPPROTO_TCP, - Name: TCP_KEEPCNT, - Value: &envoy_api_v2_core.SocketOption_IntValue{IntValue: 9}, - State: envoy_api_v2_core.SocketOption_STATE_LISTENING, - }, - } -} diff --git a/internal/envoy/v2/accesslog.go b/internal/envoy/v2/accesslog.go new file mode 100644 index 00000000000..d1793f35e49 --- /dev/null +++ b/internal/envoy/v2/accesslog.go @@ -0,0 +1,75 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v2 + +import ( + accesslogv2 "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v2" + accesslog "github.com/envoyproxy/go-control-plane/envoy/config/filter/accesslog/v2" + "github.com/envoyproxy/go-control-plane/pkg/wellknown" + _struct "github.com/golang/protobuf/ptypes/struct" + "github.com/projectcontour/contour/internal/envoy" + "github.com/projectcontour/contour/internal/protobuf" +) + +// FileAccessLogEnvoy returns a new file based access log filter +// that will output Envoy's default access logs. +func FileAccessLogEnvoy(path string) []*accesslog.AccessLog { + return []*accesslog.AccessLog{{ + Name: wellknown.FileAccessLog, + ConfigType: &accesslog.AccessLog_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&accesslogv2.FileAccessLog{ + Path: path, + // AccessLogFormat left blank to defer to Envoy's default log format. + }), + }, + }} +} + +// FileAccessLogJSON returns a new file based access log filter +// that will log in JSON format +func FileAccessLogJSON(path string, keys []string) []*accesslog.AccessLog { + + jsonformat := &_struct.Struct{ + Fields: make(map[string]*_struct.Value), + } + + for _, k := range keys { + // This will silently ignore invalid headers. + // TODO(youngnick): this should tell users if a header is not valid + // https://github.com/projectcontour/contour/issues/1507 + if template, ok := envoy.JSONFields[k]; ok { + jsonformat.Fields[k] = sv(template) + } + } + + return []*accesslog.AccessLog{{ + Name: wellknown.FileAccessLog, + ConfigType: &accesslog.AccessLog_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&accesslogv2.FileAccessLog{ + Path: path, + AccessLogFormat: &accesslogv2.FileAccessLog_JsonFormat{ + JsonFormat: jsonformat, + }, + }), + }, + }} +} + +func sv(s string) *_struct.Value { + return &_struct.Value{ + Kind: &_struct.Value_StringValue{ + StringValue: s, + }, + } +} diff --git a/internal/envoy/accesslog_test.go b/internal/envoy/v2/accesslog_test.go similarity index 94% rename from internal/envoy/accesslog_test.go rename to internal/envoy/v2/accesslog_test.go index 144f9096be1..7a44e3e3fc7 100644 --- a/internal/envoy/accesslog_test.go +++ b/internal/envoy/v2/accesslog_test.go @@ -11,11 +11,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( "testing" + "github.com/projectcontour/contour/internal/envoy" + accesslog_v2 "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v2" envoy_accesslog "github.com/envoyproxy/go-control-plane/envoy/config/filter/accesslog/v2" "github.com/envoyproxy/go-control-plane/pkg/wellknown" @@ -89,8 +91,8 @@ func TestJSONFileAccessLog(t *testing.T) { AccessLogFormat: &accesslog_v2.FileAccessLog_JsonFormat{ JsonFormat: &_struct.Struct{ Fields: map[string]*_struct.Value{ - "@timestamp": sv(JSONFields["@timestamp"]), - "method": sv(JSONFields["method"]), + "@timestamp": sv(envoy.JSONFields["@timestamp"]), + "method": sv(envoy.JSONFields["method"]), }, }, }, diff --git a/internal/envoy/v2/auth.go b/internal/envoy/v2/auth.go new file mode 100644 index 00000000000..914534d3bb5 --- /dev/null +++ b/internal/envoy/v2/auth.go @@ -0,0 +1,101 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v2 + +import ( + envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" + envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" + matcher "github.com/envoyproxy/go-control-plane/envoy/type/matcher" + "github.com/projectcontour/contour/internal/dag" + "github.com/projectcontour/contour/internal/envoy" + "github.com/projectcontour/contour/internal/protobuf" +) + +// UpstreamTLSContext creates an envoy_api_v2_auth.UpstreamTlsContext. By default +// UpstreamTLSContext returns a HTTP/1.1 TLS enabled context. A list of +// additional ALPN protocols can be provided. +func UpstreamTLSContext(peerValidationContext *dag.PeerValidationContext, sni string, alpnProtocols ...string) *envoy_api_v2_auth.UpstreamTlsContext { + context := &envoy_api_v2_auth.UpstreamTlsContext{ + CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ + AlpnProtocols: alpnProtocols, + }, + Sni: sni, + } + + if peerValidationContext.GetCACertificate() != nil && len(peerValidationContext.GetSubjectName()) > 0 { + // We have to explicitly assign the value from validationContext + // to context.CommonTlsContext.ValidationContextType because the + // latter is an interface. Returning nil from validationContext + // directly into this field boxes the nil into the unexported + // type of this grpc OneOf field which causes proto marshaling + // to explode later on. + vc := validationContext(peerValidationContext.GetCACertificate(), peerValidationContext.GetSubjectName()) + if vc != nil { + context.CommonTlsContext.ValidationContextType = vc + } + } + + return context +} + +func validationContext(ca []byte, subjectName string) *envoy_api_v2_auth.CommonTlsContext_ValidationContext { + vc := &envoy_api_v2_auth.CommonTlsContext_ValidationContext{ + ValidationContext: &envoy_api_v2_auth.CertificateValidationContext{ + TrustedCa: &envoy_api_v2_core.DataSource{ + // TODO(dfc) update this for SDS + Specifier: &envoy_api_v2_core.DataSource_InlineBytes{ + InlineBytes: ca, + }, + }, + }, + } + + if len(subjectName) > 0 { + vc.ValidationContext.MatchSubjectAltNames = []*matcher.StringMatcher{{ + MatchPattern: &matcher.StringMatcher_Exact{ + Exact: subjectName, + }}, + } + } + + return vc +} + +// DownstreamTLSContext creates a new DownstreamTlsContext. +func DownstreamTLSContext(serverSecret *dag.Secret, tlsMinProtoVersion envoy_api_v2_auth.TlsParameters_TlsProtocol, peerValidationContext *dag.PeerValidationContext, alpnProtos ...string) *envoy_api_v2_auth.DownstreamTlsContext { + context := &envoy_api_v2_auth.DownstreamTlsContext{ + CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ + TlsParams: &envoy_api_v2_auth.TlsParameters{ + TlsMinimumProtocolVersion: tlsMinProtoVersion, + TlsMaximumProtocolVersion: envoy_api_v2_auth.TlsParameters_TLSv1_3, + CipherSuites: envoy.Ciphers, + }, + TlsCertificateSdsSecretConfigs: []*envoy_api_v2_auth.SdsSecretConfig{{ + Name: envoy.Secretname(serverSecret), + SdsConfig: ConfigSource("contour"), + }}, + AlpnProtocols: alpnProtos, + }, + } + + if peerValidationContext.GetCACertificate() != nil { + vc := validationContext(peerValidationContext.GetCACertificate(), "") + if vc != nil { + context.CommonTlsContext.ValidationContextType = vc + context.RequireClientCertificate = protobuf.Bool(true) + } + } + + return context +} diff --git a/internal/envoy/auth_test.go b/internal/envoy/v2/auth_test.go similarity index 99% rename from internal/envoy/auth_test.go rename to internal/envoy/v2/auth_test.go index 467feefcad4..eca2d43c3e1 100644 --- a/internal/envoy/auth_test.go +++ b/internal/envoy/v2/auth_test.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( "testing" diff --git a/internal/envoy/v2/bootstrap.go b/internal/envoy/v2/bootstrap.go new file mode 100644 index 00000000000..d2fba26cfe0 --- /dev/null +++ b/internal/envoy/v2/bootstrap.go @@ -0,0 +1,319 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package envoy contains APIs for translating between Contour +// objects and Envoy configuration APIs and types. + +package v2 + +import ( + "fmt" + "os" + "path" + "strconv" + "strings" + "time" + + api "github.com/envoyproxy/go-control-plane/envoy/api/v2" + envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" + clusterv2 "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster" + envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" + envoy_api_bootstrap "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v2" + matcher "github.com/envoyproxy/go-control-plane/envoy/type/matcher" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" + "github.com/projectcontour/contour/internal/envoy" + "github.com/projectcontour/contour/internal/protobuf" +) + +// WriteBootstrap writes bootstrap configuration to files. +func WriteBootstrap(c *envoy.BootstrapConfig) error { + // Create Envoy bootstrap config and associated resource files. + steps, err := bootstrap(c) + if err != nil { + return err + } + + if c.ResourcesDir != "" { + if err := os.MkdirAll(path.Join(c.ResourcesDir, "sds"), 0750); err != nil { + return err + } + } + + // Write all configuration files out to filesystem. + for _, step := range steps { + if err := envoy.WriteConfig(step(c)); err != nil { + return err + } + } + + return nil +} + +type bootstrapf func(*envoy.BootstrapConfig) (string, proto.Message) + +// bootstrap creates a new v2 bootstrap configuration and associated resource files. +func bootstrap(c *envoy.BootstrapConfig) ([]bootstrapf, error) { + steps := []bootstrapf{} + + if c.GrpcClientCert == "" && c.GrpcClientKey == "" && c.GrpcCABundle == "" { + steps = append(steps, + func(*envoy.BootstrapConfig) (string, proto.Message) { + return c.Path, bootstrapConfig(c) + }) + + return steps, nil + } + + for _, f := range []string{c.GrpcClientCert, c.GrpcClientKey, c.GrpcCABundle} { + // If any of of the TLS options is not empty, they all must be not empty. + if f == "" { + return nil, fmt.Errorf( + "you must supply all TLS parameters - %q, %q, %q, or none of them", + "--envoy-cafile", "--envoy-cert-file", "--envoy-key-file") + } + + if !c.SkipFilePathCheck { + // If the TLS secrets aren't set up properly, + // some files may not be present. In this case, + // envoy will reject the bootstrap configuration, + // but there is no way to detect and fix that. If + // we check and fail here, that is visible in the + // Pod lifecycle and therefore fixable. + fi, err := os.Stat(f) + if err != nil { + return nil, err + } + if fi.Size() == 0 { + return nil, fmt.Errorf("%q is empty", f) + } + } + } + + if c.ResourcesDir == "" { + // For backwards compatibility, the old behavior + // is to use direct certificate and key file paths in + // bootstrap config. Envoy does not support rotation + // of xDS certificate files in this case. + + steps = append(steps, + func(*envoy.BootstrapConfig) (string, proto.Message) { + b := bootstrapConfig(c) + b.StaticResources.Clusters[0].TransportSocket = UpstreamTLSTransportSocket( + upstreamFileTLSContext(c)) + return c.Path, b + }) + + return steps, nil + } + + // xDS certificate rotation is supported by Envoy by using SDS path based resource files. + // These files are JSON representation of the SDS protobuf messages that normally get sent over the xDS connection, + // but for xDS connection itself, bootstrapping is done by storing the SDS resources in a local filesystem. + // Envoy will monitor and reload the resource files and the certificate and key files referred from the SDS resources. + // + // Two files are written to ResourcesDir: + // - SDS resource for xDS client certificate and key for authenticating Envoy towards Contour. + // - SDS resource for trusted CA certificate for validating Contour server certificate. + sdsTLSCertificatePath := path.Join(c.ResourcesDir, envoy.SdsResourcesSubdirectory, envoy.SdsTLSCertificateFile) + sdsValidationContextPath := path.Join(c.ResourcesDir, envoy.SdsResourcesSubdirectory, envoy.SdsValidationContextFile) + + steps = append(steps, + func(*envoy.BootstrapConfig) (string, proto.Message) { + return sdsTLSCertificatePath, tlsCertificateSdsSecretConfig(c) + }, + func(*envoy.BootstrapConfig) (string, proto.Message) { + return sdsValidationContextPath, validationContextSdsSecretConfig(c) + }, + func(*envoy.BootstrapConfig) (string, proto.Message) { + b := bootstrapConfig(c) + b.StaticResources.Clusters[0].TransportSocket = UpstreamTLSTransportSocket( + upstreamSdsTLSContext(sdsTLSCertificatePath, sdsValidationContextPath)) + return c.Path, b + }, + ) + + return steps, nil +} + +func bootstrapConfig(c *envoy.BootstrapConfig) *envoy_api_bootstrap.Bootstrap { + return &envoy_api_bootstrap.Bootstrap{ + DynamicResources: &envoy_api_bootstrap.Bootstrap_DynamicResources{ + LdsConfig: ConfigSource("contour"), + CdsConfig: ConfigSource("contour"), + }, + StaticResources: &envoy_api_bootstrap.Bootstrap_StaticResources{ + Clusters: []*api.Cluster{{ + Name: "contour", + AltStatName: strings.Join([]string{c.Namespace, "contour", strconv.Itoa(c.GetXdsGRPCPort())}, "_"), + ConnectTimeout: protobuf.Duration(5 * time.Second), + ClusterDiscoveryType: ClusterDiscoveryType(api.Cluster_STRICT_DNS), + LbPolicy: api.Cluster_ROUND_ROBIN, + LoadAssignment: &api.ClusterLoadAssignment{ + ClusterName: "contour", + Endpoints: Endpoints( + SocketAddress(c.GetXdsAddress(), c.GetXdsGRPCPort()), + ), + }, + UpstreamConnectionOptions: &api.UpstreamConnectionOptions{ + TcpKeepalive: &envoy_api_v2_core.TcpKeepalive{ + KeepaliveProbes: protobuf.UInt32(3), + KeepaliveTime: protobuf.UInt32(30), + KeepaliveInterval: protobuf.UInt32(5), + }, + }, + Http2ProtocolOptions: new(envoy_api_v2_core.Http2ProtocolOptions), // enables http2 + CircuitBreakers: &clusterv2.CircuitBreakers{ + Thresholds: []*clusterv2.CircuitBreakers_Thresholds{{ + Priority: envoy_api_v2_core.RoutingPriority_HIGH, + MaxConnections: protobuf.UInt32(100000), + MaxPendingRequests: protobuf.UInt32(100000), + MaxRequests: protobuf.UInt32(60000000), + MaxRetries: protobuf.UInt32(50), + }, { + Priority: envoy_api_v2_core.RoutingPriority_DEFAULT, + MaxConnections: protobuf.UInt32(100000), + MaxPendingRequests: protobuf.UInt32(100000), + MaxRequests: protobuf.UInt32(60000000), + MaxRetries: protobuf.UInt32(50), + }}, + }, + }, { + Name: "service-stats", + AltStatName: strings.Join([]string{c.Namespace, "service-stats", strconv.Itoa(c.GetAdminPort())}, "_"), + ConnectTimeout: protobuf.Duration(250 * time.Millisecond), + ClusterDiscoveryType: ClusterDiscoveryType(api.Cluster_LOGICAL_DNS), + LbPolicy: api.Cluster_ROUND_ROBIN, + LoadAssignment: &api.ClusterLoadAssignment{ + ClusterName: "service-stats", + Endpoints: Endpoints( + SocketAddress(c.GetAdminAddress(), c.GetAdminPort()), + ), + }, + }}, + }, + Admin: &envoy_api_bootstrap.Admin{ + AccessLogPath: c.GetAdminAccessLogPath(), + Address: SocketAddress(c.GetAdminAddress(), c.GetAdminPort()), + }, + } +} + +func upstreamFileTLSContext(c *envoy.BootstrapConfig) *envoy_api_v2_auth.UpstreamTlsContext { + context := &envoy_api_v2_auth.UpstreamTlsContext{ + CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ + TlsCertificates: []*envoy_api_v2_auth.TlsCertificate{{ + CertificateChain: &envoy_api_v2_core.DataSource{ + Specifier: &envoy_api_v2_core.DataSource_Filename{ + Filename: c.GrpcClientCert, + }, + }, + PrivateKey: &envoy_api_v2_core.DataSource{ + Specifier: &envoy_api_v2_core.DataSource_Filename{ + Filename: c.GrpcClientKey, + }, + }, + }}, + ValidationContextType: &envoy_api_v2_auth.CommonTlsContext_ValidationContext{ + ValidationContext: &envoy_api_v2_auth.CertificateValidationContext{ + TrustedCa: &envoy_api_v2_core.DataSource{ + Specifier: &envoy_api_v2_core.DataSource_Filename{ + Filename: c.GrpcCABundle, + }, + }, + // TODO(youngnick): Does there need to be a flag wired down to here? + MatchSubjectAltNames: []*matcher.StringMatcher{{ + MatchPattern: &matcher.StringMatcher_Exact{ + Exact: "contour", + }}, + }, + }, + }, + }, + } + return context +} + +func upstreamSdsTLSContext(certificateSdsFile, validationSdsFile string) *envoy_api_v2_auth.UpstreamTlsContext { + context := &envoy_api_v2_auth.UpstreamTlsContext{ + CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ + TlsCertificateSdsSecretConfigs: []*envoy_api_v2_auth.SdsSecretConfig{{ + SdsConfig: &envoy_api_v2_core.ConfigSource{ + ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_Path{ + Path: certificateSdsFile, + }, + }, + }}, + ValidationContextType: &envoy_api_v2_auth.CommonTlsContext_ValidationContextSdsSecretConfig{ + ValidationContextSdsSecretConfig: &envoy_api_v2_auth.SdsSecretConfig{ + SdsConfig: &envoy_api_v2_core.ConfigSource{ + ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_Path{ + Path: validationSdsFile, + }, + }, + }, + }, + }, + } + return context +} + +// tlsCertificateSdsSecretConfig creates DiscoveryResponse with file based SDS resource +// including paths to TLS certificates and key +func tlsCertificateSdsSecretConfig(c *envoy.BootstrapConfig) *api.DiscoveryResponse { + secret := &envoy_api_v2_auth.Secret{ + Type: &envoy_api_v2_auth.Secret_TlsCertificate{ + TlsCertificate: &envoy_api_v2_auth.TlsCertificate{ + CertificateChain: &envoy_api_v2_core.DataSource{ + Specifier: &envoy_api_v2_core.DataSource_Filename{ + Filename: c.GrpcClientCert, + }, + }, + PrivateKey: &envoy_api_v2_core.DataSource{ + Specifier: &envoy_api_v2_core.DataSource_Filename{ + Filename: c.GrpcClientKey, + }, + }, + }, + }, + } + + return &api.DiscoveryResponse{ + Resources: []*any.Any{protobuf.MustMarshalAny(secret)}, + } +} + +// validationContextSdsSecretConfig creates DiscoveryResponse with file based SDS resource +// including path to CA certificate bundle +func validationContextSdsSecretConfig(c *envoy.BootstrapConfig) *api.DiscoveryResponse { + secret := &envoy_api_v2_auth.Secret{ + Type: &envoy_api_v2_auth.Secret_ValidationContext{ + ValidationContext: &envoy_api_v2_auth.CertificateValidationContext{ + TrustedCa: &envoy_api_v2_core.DataSource{ + Specifier: &envoy_api_v2_core.DataSource_Filename{ + Filename: c.GrpcCABundle, + }, + }, + MatchSubjectAltNames: []*matcher.StringMatcher{{ + MatchPattern: &matcher.StringMatcher_Exact{ + Exact: "contour", + }}, + }, + }, + }, + } + + return &api.DiscoveryResponse{ + Resources: []*any.Any{protobuf.MustMarshalAny(secret)}, + } +} diff --git a/internal/envoy/bootstrap_test.go b/internal/envoy/v2/bootstrap_test.go similarity index 97% rename from internal/envoy/bootstrap_test.go rename to internal/envoy/v2/bootstrap_test.go index 8f82a9d3056..2e1a30c44ae 100644 --- a/internal/envoy/bootstrap_test.go +++ b/internal/envoy/v2/bootstrap_test.go @@ -11,12 +11,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( "path" "testing" + "github.com/projectcontour/contour/internal/envoy" + api "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_bootstrap "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v2" "github.com/golang/protobuf/jsonpb" @@ -27,14 +29,14 @@ import ( func TestBootstrap(t *testing.T) { tests := map[string]struct { - config BootstrapConfig + config envoy.BootstrapConfig wantedBootstrapConfig string wantedTLSCertificateConfig string wantedValidationContextConfig string wantedError bool }{ "default configuration": { - config: BootstrapConfig{ + config: envoy.BootstrapConfig{ Path: "envoy.json", Namespace: "testing-ns"}, wantedBootstrapConfig: `{ @@ -155,7 +157,7 @@ func TestBootstrap(t *testing.T) { }`, }, "--admin-address=8.8.8.8 --admin-port=9200": { - config: BootstrapConfig{ + config: envoy.BootstrapConfig{ Path: "envoy.json", AdminAddress: "8.8.8.8", AdminPort: 9200, @@ -279,7 +281,7 @@ func TestBootstrap(t *testing.T) { }`, }, "AdminAccessLogPath": { // TODO(dfc) doesn't appear to be exposed via contour bootstrap - config: BootstrapConfig{ + config: envoy.BootstrapConfig{ Path: "envoy.json", AdminAccessLogPath: "/var/log/admin.log", Namespace: "testing-ns", @@ -402,7 +404,7 @@ func TestBootstrap(t *testing.T) { }`, }, "--xds-address=8.8.8.8 --xds-port=9200": { - config: BootstrapConfig{ + config: envoy.BootstrapConfig{ Path: "envoy.json", XDSAddress: "8.8.8.8", XDSGRPCPort: 9200, @@ -526,7 +528,7 @@ func TestBootstrap(t *testing.T) { }`, }, "--stats-address=8.8.8.8 --stats-port=9200": { - config: BootstrapConfig{ + config: envoy.BootstrapConfig{ Path: "envoy.json", Namespace: "testing-ns", }, @@ -648,7 +650,7 @@ func TestBootstrap(t *testing.T) { }`, }, "--envoy-cafile=CA.cert --envoy-client-cert=client.cert --envoy-client-key=client.key": { - config: BootstrapConfig{ + config: envoy.BootstrapConfig{ Path: "envoy.json", Namespace: "testing-ns", GrpcCABundle: "CA.cert", @@ -802,7 +804,7 @@ func TestBootstrap(t *testing.T) { }`, }, "--resources-dir tmp --envoy-cafile=CA.cert --envoy-client-cert=client.cert --envoy-client-key=client.key": { - config: BootstrapConfig{ + config: envoy.BootstrapConfig{ Path: "envoy.json", Namespace: "testing-ns", ResourcesDir: "resources", @@ -981,7 +983,7 @@ func TestBootstrap(t *testing.T) { }`, }, "return error when not providing all certificate related parameters": { - config: BootstrapConfig{ + config: envoy.BootstrapConfig{ Path: "envoy.json", Namespace: "testing-ns", ResourcesDir: "resources", @@ -1002,8 +1004,8 @@ func TestBootstrap(t *testing.T) { gotConfigs[path] = config } - sdsTLSCertificatePath := path.Join(tc.config.ResourcesDir, sdsResourcesSubdirectory, sdsTLSCertificateFile) - sdsValidationContextPath := path.Join(tc.config.ResourcesDir, sdsResourcesSubdirectory, sdsValidationContextFile) + sdsTLSCertificatePath := path.Join(tc.config.ResourcesDir, envoy.SdsResourcesSubdirectory, envoy.SdsTLSCertificateFile) + sdsValidationContextPath := path.Join(tc.config.ResourcesDir, envoy.SdsResourcesSubdirectory, envoy.SdsValidationContextFile) if tc.wantedBootstrapConfig != "" { want := new(envoy_api_bootstrap.Bootstrap) diff --git a/internal/envoy/v2/cluster.go b/internal/envoy/v2/cluster.go new file mode 100644 index 00000000000..08f98af6d0a --- /dev/null +++ b/internal/envoy/v2/cluster.go @@ -0,0 +1,227 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v2 + +import ( + // nolint:gosec + + "strings" + "time" + + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" + envoy_cluster "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster" + envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" + envoy_type "github.com/envoyproxy/go-control-plane/envoy/type" + "github.com/projectcontour/contour/internal/dag" + "github.com/projectcontour/contour/internal/envoy" + "github.com/projectcontour/contour/internal/protobuf" + "github.com/projectcontour/contour/internal/xds" + "k8s.io/apimachinery/pkg/types" +) + +func clusterDefaults() *v2.Cluster { + return &v2.Cluster{ + ConnectTimeout: protobuf.Duration(250 * time.Millisecond), + CommonLbConfig: ClusterCommonLBConfig(), + LbPolicy: lbPolicy(""), + } +} + +// Cluster creates new v2.Cluster from dag.Cluster. +func Cluster(c *dag.Cluster) *v2.Cluster { + service := c.Upstream + cluster := clusterDefaults() + + cluster.Name = envoy.Clustername(c) + cluster.AltStatName = envoy.AltStatName(service) + cluster.LbPolicy = lbPolicy(c.LoadBalancerPolicy) + cluster.HealthChecks = edshealthcheck(c) + + switch len(service.ExternalName) { + case 0: + // external name not set, cluster will be discovered via EDS + cluster.ClusterDiscoveryType = ClusterDiscoveryType(v2.Cluster_EDS) + cluster.EdsClusterConfig = edsconfig("contour", service) + default: + // external name set, use hard coded DNS name + cluster.ClusterDiscoveryType = ClusterDiscoveryType(v2.Cluster_STRICT_DNS) + cluster.LoadAssignment = StaticClusterLoadAssignment(service) + } + + // Drain connections immediately if using healthchecks and the endpoint is known to be removed + if c.HTTPHealthCheckPolicy != nil || c.TCPHealthCheckPolicy != nil { + cluster.DrainConnectionsOnHostRemoval = true + } + + if envoy.AnyPositive(service.MaxConnections, service.MaxPendingRequests, service.MaxRequests, service.MaxRetries) { + cluster.CircuitBreakers = &envoy_cluster.CircuitBreakers{ + Thresholds: []*envoy_cluster.CircuitBreakers_Thresholds{{ + MaxConnections: protobuf.UInt32OrNil(service.MaxConnections), + MaxPendingRequests: protobuf.UInt32OrNil(service.MaxPendingRequests), + MaxRequests: protobuf.UInt32OrNil(service.MaxRequests), + MaxRetries: protobuf.UInt32OrNil(service.MaxRetries), + }}, + } + } + + switch c.Protocol { + case "tls": + cluster.TransportSocket = UpstreamTLSTransportSocket( + UpstreamTLSContext( + c.UpstreamValidation, + c.SNI, + ), + ) + case "h2": + cluster.Http2ProtocolOptions = &envoy_api_v2_core.Http2ProtocolOptions{} + cluster.TransportSocket = UpstreamTLSTransportSocket( + UpstreamTLSContext( + c.UpstreamValidation, + c.SNI, + "h2", + ), + ) + case "h2c": + cluster.Http2ProtocolOptions = &envoy_api_v2_core.Http2ProtocolOptions{} + } + + return cluster +} + +// ExtensionCluster builds a v2.Cluster struct for the given extension service. +func ExtensionCluster(ext *dag.ExtensionCluster) *v2.Cluster { + cluster := clusterDefaults() + + // The Envoy cluster name has already been set. + cluster.Name = ext.Name + + // The AltStatName was added to make a more readable alternative + // to the cluster name for metrics (see #827). For extension + // services, we can have multiple ports, so it doesn't make + // sense to build this the same way we build it for HTTPProxy + // service clusters. However, we know the namespaced name for + // the ExtensionCluster is globally unique, so we can use that + // to produce a stable, readable name. + cluster.AltStatName = strings.ReplaceAll(cluster.Name, "/", "_") + + cluster.LbPolicy = lbPolicy(ext.LoadBalancerPolicy) + + // Cluster will be discovered via EDS. + cluster.ClusterDiscoveryType = ClusterDiscoveryType(v2.Cluster_EDS) + cluster.EdsClusterConfig = &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: ext.Upstream.ClusterName, + } + + // TODO(jpeach): Externalname service support in https://github.com/projectcontour/contour/issues/2875 + + switch ext.Protocol { + case "h2": + cluster.Http2ProtocolOptions = &envoy_api_v2_core.Http2ProtocolOptions{} + cluster.TransportSocket = UpstreamTLSTransportSocket( + UpstreamTLSContext( + ext.UpstreamValidation, + ext.SNI, + "h2", + ), + ) + case "h2c": + cluster.Http2ProtocolOptions = &envoy_api_v2_core.Http2ProtocolOptions{} + } + + return cluster +} + +// StaticClusterLoadAssignment creates a *v2.ClusterLoadAssignment pointing to the external DNS address of the service +func StaticClusterLoadAssignment(service *dag.Service) *v2.ClusterLoadAssignment { + addr := SocketAddress(service.ExternalName, int(service.Weighted.ServicePort.Port)) + return &v2.ClusterLoadAssignment{ + Endpoints: Endpoints(addr), + ClusterName: xds.ClusterLoadAssignmentName( + types.NamespacedName{Name: service.Weighted.ServiceName, Namespace: service.Weighted.ServiceNamespace}, + service.Weighted.ServicePort.Name, + ), + } +} + +func edsconfig(cluster string, service *dag.Service) *v2.Cluster_EdsClusterConfig { + return &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource(cluster), + ServiceName: xds.ClusterLoadAssignmentName( + types.NamespacedName{Name: service.Weighted.ServiceName, Namespace: service.Weighted.ServiceNamespace}, + service.Weighted.ServicePort.Name, + ), + } +} + +func lbPolicy(strategy string) v2.Cluster_LbPolicy { + switch strategy { + case "WeightedLeastRequest": + return v2.Cluster_LEAST_REQUEST + case "Random": + return v2.Cluster_RANDOM + case "Cookie": + return v2.Cluster_RING_HASH + default: + return v2.Cluster_ROUND_ROBIN + } +} + +func edshealthcheck(c *dag.Cluster) []*envoy_api_v2_core.HealthCheck { + if c.HTTPHealthCheckPolicy == nil && c.TCPHealthCheckPolicy == nil { + return nil + } + + if c.HTTPHealthCheckPolicy != nil { + return []*envoy_api_v2_core.HealthCheck{ + httpHealthCheck(c), + } + } + + return []*envoy_api_v2_core.HealthCheck{ + tcpHealthCheck(c), + } +} + +// ClusterCommonLBConfig creates a *v2.Cluster_CommonLbConfig with HealthyPanicThreshold disabled. +func ClusterCommonLBConfig() *v2.Cluster_CommonLbConfig { + return &v2.Cluster_CommonLbConfig{ + HealthyPanicThreshold: &envoy_type.Percent{ // Disable HealthyPanicThreshold + Value: 0, + }, + } +} + +// ConfigSource returns a *envoy_api_v2_core.ConfigSource for cluster. +func ConfigSource(cluster string) *envoy_api_v2_core.ConfigSource { + return &envoy_api_v2_core.ConfigSource{ + ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ + ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ + ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, + GrpcServices: []*envoy_api_v2_core.GrpcService{{ + TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ + ClusterName: cluster, + }, + }, + }}, + }, + }, + } +} + +// ClusterDiscoveryType returns the type of a ClusterDiscovery as a Cluster_type. +func ClusterDiscoveryType(t v2.Cluster_DiscoveryType) *v2.Cluster_Type { + return &v2.Cluster_Type{Type: t} +} diff --git a/internal/envoy/v2/cluster_test.go b/internal/envoy/v2/cluster_test.go new file mode 100644 index 00000000000..d542ed296e6 --- /dev/null +++ b/internal/envoy/v2/cluster_test.go @@ -0,0 +1,585 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v2 + +import ( + "testing" + "time" + + "github.com/projectcontour/contour/internal/envoy" + + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" + envoy_cluster "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster" + envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" + envoy_type "github.com/envoyproxy/go-control-plane/envoy/type" + "github.com/golang/protobuf/proto" + "github.com/projectcontour/contour/internal/dag" + "github.com/projectcontour/contour/internal/protobuf" + "github.com/projectcontour/contour/internal/xds" + "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" +) + +func TestCluster(t *testing.T) { + s1 := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kuard", + Namespace: "default", + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{{ + Name: "http", + Protocol: "TCP", + Port: 443, + TargetPort: intstr.FromInt(8080), + }}, + }, + } + + s2 := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kuard", + Namespace: "default", + }, + Spec: v1.ServiceSpec{ + ExternalName: "foo.io", + Ports: []v1.ServicePort{{ + Name: "http", + Protocol: "TCP", + Port: 443, + TargetPort: intstr.FromInt(8080), + }}, + }, + } + + svcExternal := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kuard", + Namespace: "default", + }, + Spec: v1.ServiceSpec{ + ExternalName: "projectcontour.local", + Ports: []v1.ServicePort{{ + Name: "http", + Protocol: "TCP", + Port: 443, + TargetPort: intstr.FromInt(8080), + }}, + Type: v1.ServiceTypeExternalName, + }, + } + + secret := &dag.Secret{ + Object: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "secret", + Namespace: "default", + }, + Type: v1.SecretTypeTLS, + Data: map[string][]byte{dag.CACertificateKey: []byte("cacert")}, + }, + } + + tests := map[string]struct { + cluster *dag.Cluster + want *v2.Cluster + }{ + "simple service": { + cluster: &dag.Cluster{ + Upstream: service(s1), + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + }, + }, + "h2c upstream": { + cluster: &dag.Cluster{ + Upstream: service(s1, "h2c"), + Protocol: "h2c", + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + Http2ProtocolOptions: &envoy_api_v2_core.Http2ProtocolOptions{}, + }, + }, + "h2 upstream": { + cluster: &dag.Cluster{ + Upstream: service(s1, "h2"), + Protocol: "h2", + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + TransportSocket: UpstreamTLSTransportSocket( + UpstreamTLSContext(nil, "", "h2"), + ), + Http2ProtocolOptions: &envoy_api_v2_core.Http2ProtocolOptions{}, + }, + }, + "externalName service": { + cluster: &dag.Cluster{ + Upstream: service(s2), + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_STRICT_DNS), + LoadAssignment: StaticClusterLoadAssignment(service(s2)), + }, + }, + "tls upstream": { + cluster: &dag.Cluster{ + Upstream: service(s1, "tls"), + Protocol: "tls", + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + TransportSocket: UpstreamTLSTransportSocket( + UpstreamTLSContext(nil, ""), + ), + }, + }, + "tls upstream - external name": { + cluster: &dag.Cluster{ + Upstream: service(svcExternal, "tls"), + Protocol: "tls", + SNI: "projectcontour.local", + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_STRICT_DNS), + LoadAssignment: StaticClusterLoadAssignment(service(svcExternal, "tls")), + TransportSocket: UpstreamTLSTransportSocket( + UpstreamTLSContext(nil, "projectcontour.local"), + ), + }, + }, + "verify tls upstream with san": { + cluster: &dag.Cluster{ + Upstream: service(s1, "tls"), + Protocol: "tls", + UpstreamValidation: &dag.PeerValidationContext{ + CACertificate: secret, + SubjectName: "foo.bar.io", + }, + }, + want: &v2.Cluster{ + Name: "default/kuard/443/3ac4e90987", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + TransportSocket: UpstreamTLSTransportSocket( + UpstreamTLSContext( + &dag.PeerValidationContext{ + CACertificate: secret, + SubjectName: "foo.bar.io", + }, + ""), + ), + }, + }, + "projectcontour.io/max-connections": { + cluster: &dag.Cluster{ + Upstream: &dag.Service{ + MaxConnections: 9000, + Weighted: dag.WeightedService{ + Weight: 1, + ServiceName: s1.Name, + ServiceNamespace: s1.Namespace, + ServicePort: s1.Spec.Ports[0], + }, + }, + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + CircuitBreakers: &envoy_cluster.CircuitBreakers{ + Thresholds: []*envoy_cluster.CircuitBreakers_Thresholds{{ + MaxConnections: protobuf.UInt32(9000), + }}, + }, + }, + }, + "projectcontour.io/max-pending-requests": { + cluster: &dag.Cluster{ + Upstream: &dag.Service{ + MaxPendingRequests: 4096, + Weighted: dag.WeightedService{ + Weight: 1, + ServiceName: s1.Name, + ServiceNamespace: s1.Namespace, + ServicePort: s1.Spec.Ports[0], + }, + }, + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + CircuitBreakers: &envoy_cluster.CircuitBreakers{ + Thresholds: []*envoy_cluster.CircuitBreakers_Thresholds{{ + MaxPendingRequests: protobuf.UInt32(4096), + }}, + }, + }, + }, + "projectcontour.io/max-requests": { + cluster: &dag.Cluster{ + Upstream: &dag.Service{ + MaxRequests: 404, + Weighted: dag.WeightedService{ + Weight: 1, + ServiceName: s1.Name, + ServiceNamespace: s1.Namespace, + ServicePort: s1.Spec.Ports[0], + }, + }, + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + CircuitBreakers: &envoy_cluster.CircuitBreakers{ + Thresholds: []*envoy_cluster.CircuitBreakers_Thresholds{{ + MaxRequests: protobuf.UInt32(404), + }}, + }, + }, + }, + "projectcontour.io/max-retries": { + cluster: &dag.Cluster{ + Upstream: &dag.Service{ + MaxRetries: 7, + Weighted: dag.WeightedService{ + Weight: 1, + ServiceName: s1.Name, + ServiceNamespace: s1.Namespace, + ServicePort: s1.Spec.Ports[0], + }, + }, + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + CircuitBreakers: &envoy_cluster.CircuitBreakers{ + Thresholds: []*envoy_cluster.CircuitBreakers_Thresholds{{ + MaxRetries: protobuf.UInt32(7), + }}, + }, + }, + }, + "cluster with random load balancer policy": { + cluster: &dag.Cluster{ + Upstream: service(s1), + LoadBalancerPolicy: "Random", + }, + want: &v2.Cluster{ + Name: "default/kuard/443/58d888c08a", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + LbPolicy: v2.Cluster_RANDOM, + }, + }, + "cluster with cookie policy": { + cluster: &dag.Cluster{ + Upstream: service(s1), + LoadBalancerPolicy: "Cookie", + }, + want: &v2.Cluster{ + Name: "default/kuard/443/e4f81994fe", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + LbPolicy: v2.Cluster_RING_HASH, + }, + }, + + "tcp service": { + cluster: &dag.Cluster{ + Upstream: service(s1), + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + }, + }, + "tcp service with healthcheck": { + cluster: &dag.Cluster{ + Upstream: service(s1), + TCPHealthCheckPolicy: &dag.TCPHealthCheckPolicy{ + Timeout: 2, + Interval: 10, + UnhealthyThreshold: 3, + HealthyThreshold: 2, + }, + }, + want: &v2.Cluster{ + Name: "default/kuard/443/da39a3ee5e", + AltStatName: "default_kuard_443", + ClusterDiscoveryType: ClusterDiscoveryType(v2.Cluster_EDS), + EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ + EdsConfig: ConfigSource("contour"), + ServiceName: "default/kuard/http", + }, + DrainConnectionsOnHostRemoval: true, + HealthChecks: []*envoy_api_v2_core.HealthCheck{{ + Timeout: durationOrDefault(2, envoy.HCTimeout), + Interval: durationOrDefault(10, envoy.HCInterval), + UnhealthyThreshold: protobuf.UInt32OrDefault(3, envoy.HCUnhealthyThreshold), + HealthyThreshold: protobuf.UInt32OrDefault(2, envoy.HCHealthyThreshold), + HealthChecker: &envoy_api_v2_core.HealthCheck_TcpHealthCheck_{ + TcpHealthCheck: &envoy_api_v2_core.HealthCheck_TcpHealthCheck{}, + }, + }}, + }, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := Cluster(tc.cluster) + want := clusterDefaults() + + proto.Merge(want, tc.want) + + protobuf.ExpectEqual(t, want, got) + }) + } +} + +func TestClusterLoadAssignmentName(t *testing.T) { + assert.Equal(t, xds.ClusterLoadAssignmentName(types.NamespacedName{Namespace: "ns", Name: "svc"}, "port"), "ns/svc/port") + assert.Equal(t, xds.ClusterLoadAssignmentName(types.NamespacedName{Namespace: "ns", Name: "svc"}, ""), "ns/svc") + assert.Equal(t, xds.ClusterLoadAssignmentName(types.NamespacedName{}, ""), "/") +} + +func TestClustername(t *testing.T) { + tests := map[string]struct { + cluster *dag.Cluster + want string + }{ + "simple": { + cluster: &dag.Cluster{ + Upstream: &dag.Service{ + Weighted: dag.WeightedService{ + Weight: 1, + ServiceName: "backend", + ServiceNamespace: "default", + ServicePort: v1.ServicePort{ + Name: "http", + Protocol: "TCP", + Port: 80, + TargetPort: intstr.FromInt(6502), + }, + }, + }, + }, + want: "default/backend/80/da39a3ee5e", + }, + "far too long": { + cluster: &dag.Cluster{ + Upstream: &dag.Service{ + Weighted: dag.WeightedService{ + Weight: 1, + ServiceName: "must-be-in-want-of-a-wife", + ServiceNamespace: "it-is-a-truth-universally-acknowledged-that-a-single-man-in-possession-of-a-good-fortune", + ServicePort: v1.ServicePort{ + Name: "http", + Protocol: "TCP", + Port: 9999, + TargetPort: intstr.FromString("http-alt"), + }, + }, + }, + }, + want: "it-is-a--dea8b0/must-be--dea8b0/9999/da39a3ee5e", + }, + "various healthcheck params": { + cluster: &dag.Cluster{ + Upstream: &dag.Service{ + Weighted: dag.WeightedService{ + Weight: 1, + ServiceName: "backend", + ServiceNamespace: "default", + ServicePort: v1.ServicePort{ + Name: "http", + Protocol: "TCP", + Port: 80, + TargetPort: intstr.FromInt(6502), + }, + }, + }, + LoadBalancerPolicy: "Random", + HTTPHealthCheckPolicy: &dag.HTTPHealthCheckPolicy{ + Path: "/healthz", + Interval: 5 * time.Second, + Timeout: 30 * time.Second, + UnhealthyThreshold: 3, + HealthyThreshold: 1, + }, + }, + want: "default/backend/80/5c26077e1d", + }, + "upstream tls validation with subject alt name": { + cluster: &dag.Cluster{ + Upstream: &dag.Service{ + Weighted: dag.WeightedService{ + Weight: 1, + ServiceName: "backend", + ServiceNamespace: "default", + ServicePort: v1.ServicePort{ + Name: "http", + Protocol: "TCP", + Port: 80, + TargetPort: intstr.FromInt(6502), + }, + }, + }, + LoadBalancerPolicy: "Random", + UpstreamValidation: &dag.PeerValidationContext{ + CACertificate: &dag.Secret{ + Object: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "secret", + Namespace: "default", + }, + Data: map[string][]byte{ + dag.CACertificateKey: []byte("somethingsecret"), + }, + }, + }, + SubjectName: "foo.com", + }, + }, + want: "default/backend/80/6bf46b7b3a", + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := envoy.Clustername(tc.cluster) + assert.Equal(t, tc.want, got) + }) + } +} + +func TestLBPolicy(t *testing.T) { + tests := map[string]v2.Cluster_LbPolicy{ + "WeightedLeastRequest": v2.Cluster_LEAST_REQUEST, + "Random": v2.Cluster_RANDOM, + "RoundRobin": v2.Cluster_ROUND_ROBIN, + "": v2.Cluster_ROUND_ROBIN, + "unknown": v2.Cluster_ROUND_ROBIN, + "Cookie": v2.Cluster_RING_HASH, + + // RingHash and Maglev were removed as options in 0.13. + // See #1150 + "RingHash": v2.Cluster_ROUND_ROBIN, + "Maglev": v2.Cluster_ROUND_ROBIN, + } + + for policy, want := range tests { + t.Run(policy, func(t *testing.T) { + got := lbPolicy(policy) + assert.Equal(t, want, got) + }) + } +} + +func TestClusterCommonLBConfig(t *testing.T) { + got := ClusterCommonLBConfig() + want := &v2.Cluster_CommonLbConfig{ + HealthyPanicThreshold: &envoy_type.Percent{ // Disable HealthyPanicThreshold + Value: 0, + }, + } + assert.Equal(t, want, got) +} + +func service(s *v1.Service, protocols ...string) *dag.Service { + protocol := "" + if len(protocols) > 0 { + protocol = protocols[0] + } + return &dag.Service{ + Weighted: dag.WeightedService{ + Weight: 1, + ServiceName: s.Name, + ServiceNamespace: s.Namespace, + ServicePort: s.Spec.Ports[0], + }, + ExternalName: s.Spec.ExternalName, + Protocol: protocol, + } +} diff --git a/internal/envoy/endpoint.go b/internal/envoy/v2/endpoint.go similarity index 99% rename from internal/envoy/endpoint.go rename to internal/envoy/v2/endpoint.go index a1b4906afb0..5c7783f682e 100644 --- a/internal/envoy/endpoint.go +++ b/internal/envoy/v2/endpoint.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" diff --git a/internal/envoy/endpoint_test.go b/internal/envoy/v2/endpoint_test.go similarity index 99% rename from internal/envoy/endpoint_test.go rename to internal/envoy/v2/endpoint_test.go index eb2b41e800f..d0a0c8a4abc 100644 --- a/internal/envoy/endpoint_test.go +++ b/internal/envoy/v2/endpoint_test.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( "testing" diff --git a/internal/envoy/v2/healthcheck.go b/internal/envoy/v2/healthcheck.go new file mode 100644 index 00000000000..35e2e572c99 --- /dev/null +++ b/internal/envoy/v2/healthcheck.go @@ -0,0 +1,70 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v2 + +import ( + "time" + + envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" + "github.com/golang/protobuf/ptypes/duration" + "github.com/projectcontour/contour/internal/dag" + "github.com/projectcontour/contour/internal/envoy" + "github.com/projectcontour/contour/internal/protobuf" +) + +// httpHealthCheck returns a *envoy_api_v2_core.HealthCheck value for HTTP Routes +func httpHealthCheck(cluster *dag.Cluster) *envoy_api_v2_core.HealthCheck { + hc := cluster.HTTPHealthCheckPolicy + host := envoy.HCHost + if hc.Host != "" { + host = hc.Host + } + + // TODO(dfc) why do we need to specify our own default, what is the default + // that envoy applies if these fields are left nil? + return &envoy_api_v2_core.HealthCheck{ + Timeout: durationOrDefault(hc.Timeout, envoy.HCTimeout), + Interval: durationOrDefault(hc.Interval, envoy.HCInterval), + UnhealthyThreshold: protobuf.UInt32OrDefault(hc.UnhealthyThreshold, envoy.HCUnhealthyThreshold), + HealthyThreshold: protobuf.UInt32OrDefault(hc.HealthyThreshold, envoy.HCHealthyThreshold), + HealthChecker: &envoy_api_v2_core.HealthCheck_HttpHealthCheck_{ + HttpHealthCheck: &envoy_api_v2_core.HealthCheck_HttpHealthCheck{ + Path: hc.Path, + Host: host, + }, + }, + } +} + +// tcpHealthCheck returns a *envoy_api_v2_core.HealthCheck value for TCPProxies +func tcpHealthCheck(cluster *dag.Cluster) *envoy_api_v2_core.HealthCheck { + hc := cluster.TCPHealthCheckPolicy + + return &envoy_api_v2_core.HealthCheck{ + Timeout: durationOrDefault(hc.Timeout, envoy.HCTimeout), + Interval: durationOrDefault(hc.Interval, envoy.HCInterval), + UnhealthyThreshold: protobuf.UInt32OrDefault(hc.UnhealthyThreshold, envoy.HCUnhealthyThreshold), + HealthyThreshold: protobuf.UInt32OrDefault(hc.HealthyThreshold, envoy.HCHealthyThreshold), + HealthChecker: &envoy_api_v2_core.HealthCheck_TcpHealthCheck_{ + TcpHealthCheck: &envoy_api_v2_core.HealthCheck_TcpHealthCheck{}, + }, + } +} + +func durationOrDefault(d, def time.Duration) *duration.Duration { + if d != 0 { + return protobuf.Duration(d) + } + return protobuf.Duration(def) +} diff --git a/internal/envoy/healthcheck_test.go b/internal/envoy/v2/healthcheck_test.go similarity index 91% rename from internal/envoy/healthcheck_test.go rename to internal/envoy/v2/healthcheck_test.go index 5f762f6b32c..ab79464630c 100644 --- a/internal/envoy/healthcheck_test.go +++ b/internal/envoy/v2/healthcheck_test.go @@ -11,12 +11,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( "testing" "time" + "github.com/projectcontour/contour/internal/envoy" + envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" "github.com/projectcontour/contour/internal/dag" "github.com/projectcontour/contour/internal/protobuf" @@ -34,8 +36,8 @@ func TestHealthCheck(t *testing.T) { HTTPHealthCheckPolicy: new(dag.HTTPHealthCheckPolicy), }, want: &envoy_api_v2_core.HealthCheck{ - Timeout: protobuf.Duration(hcTimeout), - Interval: protobuf.Duration(hcInterval), + Timeout: protobuf.Duration(envoy.HCTimeout), + Interval: protobuf.Duration(envoy.HCInterval), UnhealthyThreshold: protobuf.UInt32(3), HealthyThreshold: protobuf.UInt32(2), HealthChecker: &envoy_api_v2_core.HealthCheck_HttpHealthCheck_{ @@ -53,8 +55,8 @@ func TestHealthCheck(t *testing.T) { }, }, want: &envoy_api_v2_core.HealthCheck{ - Timeout: protobuf.Duration(hcTimeout), - Interval: protobuf.Duration(hcInterval), + Timeout: protobuf.Duration(envoy.HCTimeout), + Interval: protobuf.Duration(envoy.HCInterval), UnhealthyThreshold: protobuf.UInt32(3), HealthyThreshold: protobuf.UInt32(2), HealthChecker: &envoy_api_v2_core.HealthCheck_HttpHealthCheck_{ diff --git a/internal/envoy/v2/listener.go b/internal/envoy/v2/listener.go new file mode 100644 index 00000000000..79441c7a6a2 --- /dev/null +++ b/internal/envoy/v2/listener.go @@ -0,0 +1,516 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v2 + +import ( + "fmt" + "sort" + "strings" + "time" + + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" + envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" + envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" + envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" + accesslog "github.com/envoyproxy/go-control-plane/envoy/config/filter/accesslog/v2" + envoy_config_filter_http_ext_authz_v2 "github.com/envoyproxy/go-control-plane/envoy/config/filter/http/ext_authz/v2" + lua "github.com/envoyproxy/go-control-plane/envoy/config/filter/http/lua/v2" + http "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2" + tcp "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/tcp_proxy/v2" + envoy_type "github.com/envoyproxy/go-control-plane/envoy/type" + "github.com/envoyproxy/go-control-plane/pkg/wellknown" + "github.com/projectcontour/contour/internal/dag" + "github.com/projectcontour/contour/internal/envoy" + "github.com/projectcontour/contour/internal/protobuf" + "github.com/projectcontour/contour/internal/sorter" + "github.com/projectcontour/contour/internal/timeout" +) + +// TLSInspector returns a new TLS inspector listener filter. +func TLSInspector() *envoy_api_v2_listener.ListenerFilter { + return &envoy_api_v2_listener.ListenerFilter{ + Name: wellknown.TlsInspector, + } +} + +// ProxyProtocol returns a new Proxy Protocol listener filter. +func ProxyProtocol() *envoy_api_v2_listener.ListenerFilter { + return &envoy_api_v2_listener.ListenerFilter{ + Name: wellknown.ProxyProtocol, + } +} + +// Listener returns a new v2.Listener for the supplied address, port, and filters. +func Listener(name, address string, port int, lf []*envoy_api_v2_listener.ListenerFilter, filters ...*envoy_api_v2_listener.Filter) *v2.Listener { + l := &v2.Listener{ + Name: name, + Address: SocketAddress(address, port), + ListenerFilters: lf, + SocketOptions: TCPKeepaliveSocketOptions(), + } + if len(filters) > 0 { + l.FilterChains = append( + l.FilterChains, + &envoy_api_v2_listener.FilterChain{ + Filters: filters, + }, + ) + } + return l +} + +type httpConnectionManagerBuilder struct { + routeConfigName string + metricsPrefix string + accessLoggers []*accesslog.AccessLog + requestTimeout timeout.Setting + connectionIdleTimeout timeout.Setting + streamIdleTimeout timeout.Setting + maxConnectionDuration timeout.Setting + connectionShutdownGracePeriod timeout.Setting + filters []*http.HttpFilter + codec envoy.HTTPVersionType // Note the zero value is AUTO, which is the default we want. +} + +// RouteConfigName sets the name of the RDS element that contains +// the routing table for this manager. +func (b *httpConnectionManagerBuilder) RouteConfigName(name string) *httpConnectionManagerBuilder { + b.routeConfigName = name + return b +} + +// MetricsPrefix sets the prefix used for emitting metrics from the +// connection manager. Note that this prefix is externally visible in +// monitoring tools, so it is subject to compatibility concerns. +// +// See https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/stats#config-http-conn-man-stats +func (b *httpConnectionManagerBuilder) MetricsPrefix(prefix string) *httpConnectionManagerBuilder { + b.metricsPrefix = prefix + return b +} + +// Codec sets the HTTP codec for the manager. The default is AUTO. +func (b *httpConnectionManagerBuilder) Codec(codecType envoy.HTTPVersionType) *httpConnectionManagerBuilder { + b.codec = codecType + return b +} + +// AccessLoggers sets the access logging configuration. +func (b *httpConnectionManagerBuilder) AccessLoggers(loggers []*accesslog.AccessLog) *httpConnectionManagerBuilder { + b.accessLoggers = loggers + return b +} + +// RequestTimeout sets the active request timeout on the connection manager. +func (b *httpConnectionManagerBuilder) RequestTimeout(timeout timeout.Setting) *httpConnectionManagerBuilder { + b.requestTimeout = timeout + return b +} + +// ConnectionIdleTimeout sets the idle timeout on the connection manager. +func (b *httpConnectionManagerBuilder) ConnectionIdleTimeout(timeout timeout.Setting) *httpConnectionManagerBuilder { + b.connectionIdleTimeout = timeout + return b +} + +// StreamIdleTimeout sets the stream idle timeout on the connection manager. +func (b *httpConnectionManagerBuilder) StreamIdleTimeout(timeout timeout.Setting) *httpConnectionManagerBuilder { + b.streamIdleTimeout = timeout + return b +} + +// MaxConnectionDuration sets the max connection duration on the connection manager. +func (b *httpConnectionManagerBuilder) MaxConnectionDuration(timeout timeout.Setting) *httpConnectionManagerBuilder { + b.maxConnectionDuration = timeout + return b +} + +// ConnectionShutdownGracePeriod sets the drain timeout on the connection manager. +func (b *httpConnectionManagerBuilder) ConnectionShutdownGracePeriod(timeout timeout.Setting) *httpConnectionManagerBuilder { + b.connectionShutdownGracePeriod = timeout + return b +} + +func (b *httpConnectionManagerBuilder) DefaultFilters() *httpConnectionManagerBuilder { + b.filters = append(b.filters, + &http.HttpFilter{ + Name: wellknown.Gzip, + }, + &http.HttpFilter{ + Name: wellknown.GRPCWeb, + }, + &http.HttpFilter{ + Name: wellknown.Router, + }, + ) + + return b +} + +// AddFilter appends f to the list of filters for this HTTPConnectionManager. f +// may by nil, in which case it is ignored. +func (b *httpConnectionManagerBuilder) AddFilter(f *http.HttpFilter) *httpConnectionManagerBuilder { + if f == nil { + return b + } + + if len(b.filters) > 0 { + lastIndex := len(b.filters) - 1 + // If the router filter is last, keep it at the end + // of the filter chain when we add the new filter. + if b.filters[lastIndex].Name == wellknown.Router { + b.filters = append(b.filters[:lastIndex], f, b.filters[lastIndex]) + return b + } + } + + b.filters = append(b.filters, f) + + return b +} + +// Validate runs builtin validation rules against the current builder state. +func (b *httpConnectionManagerBuilder) Validate() error { + filterNames := map[string]struct{}{} + + for _, f := range b.filters { + filterNames[f.Name] = struct{}{} + } + + // If there's no router filter, requests won't be forwarded. + if _, ok := filterNames[wellknown.Router]; !ok { + return fmt.Errorf("missing required filter %q", wellknown.Router) + } + + return nil +} + +// Get returns a new http.HttpConnectionManager filter, constructed +// from the builder settings. +// +// See https://www.envoyproxy.io/docs/envoy/latest/api-v2/config/filter/network/http_connection_manager/v2/http_connection_manager.proto.html +func (b *httpConnectionManagerBuilder) Get() *envoy_api_v2_listener.Filter { + // For now, failing validation is a programmer error that + // the caller can't reasonably recover from. A caller that can + // handle this should validate manually. + if err := b.Validate(); err != nil { + panic(err.Error()) + } + + cm := &http.HttpConnectionManager{ + CodecType: b.codec, + RouteSpecifier: &http.HttpConnectionManager_Rds{ + Rds: &http.Rds{ + RouteConfigName: b.routeConfigName, + ConfigSource: ConfigSource("contour"), + }, + }, + HttpFilters: b.filters, + CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{ + IdleTimeout: envoy.Timeout(b.connectionIdleTimeout), + }, + HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ + // Enable support for HTTP/1.0 requests that carry + // a Host: header. See #537. + AcceptHttp_10: true, + }, + UseRemoteAddress: protobuf.Bool(true), + NormalizePath: protobuf.Bool(true), + + // issue #1487 pass through X-Request-Id if provided. + PreserveExternalRequestId: true, + MergeSlashes: true, + + RequestTimeout: envoy.Timeout(b.requestTimeout), + StreamIdleTimeout: envoy.Timeout(b.streamIdleTimeout), + DrainTimeout: envoy.Timeout(b.connectionShutdownGracePeriod), + } + + // Max connection duration is infinite/disabled by default in Envoy, so if the timeout setting + // indicates to either disable or use default, don't pass a value at all. Note that unlike other + // Envoy timeouts, explicitly passing a 0 here *would not* disable the timeout; it needs to be + // omitted entirely. + if !b.maxConnectionDuration.IsDisabled() && !b.maxConnectionDuration.UseDefault() { + cm.CommonHttpProtocolOptions.MaxConnectionDuration = protobuf.Duration(b.maxConnectionDuration.Duration()) + } + + if len(b.accessLoggers) > 0 { + cm.AccessLog = b.accessLoggers + } + + // If there's no explicit metrics prefix, default it to the + // route config name. + if b.metricsPrefix != "" { + cm.StatPrefix = b.metricsPrefix + } else { + cm.StatPrefix = b.routeConfigName + } + + return &envoy_api_v2_listener.Filter{ + Name: wellknown.HTTPConnectionManager, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(cm), + }, + } +} + +// HTTPConnectionManager creates a new HTTP Connection Manager filter +// for the supplied route, access log, and client request timeout. +func HTTPConnectionManager(routename string, accesslogger []*accesslog.AccessLog, requestTimeout time.Duration) *envoy_api_v2_listener.Filter { + return HTTPConnectionManagerBuilder(). + RouteConfigName(routename). + MetricsPrefix(routename). + AccessLoggers(accesslogger). + RequestTimeout(timeout.DurationSetting(requestTimeout)). + DefaultFilters(). + Get() +} + +func HTTPConnectionManagerBuilder() *httpConnectionManagerBuilder { + return &httpConnectionManagerBuilder{} +} + +// TCPProxy creates a new TCPProxy filter. +func TCPProxy(statPrefix string, proxy *dag.TCPProxy, accesslogger []*accesslog.AccessLog) *envoy_api_v2_listener.Filter { + // Set the idle timeout in seconds for connections through a TCP Proxy type filter. + // The value of two and a half hours for reasons documented at + // https://github.com/projectcontour/contour/issues/1074 + // Set to 9001 because now it's OVER NINE THOUSAND. + idleTimeout := protobuf.Duration(9001 * time.Second) + + switch len(proxy.Clusters) { + case 1: + return &envoy_api_v2_listener.Filter{ + Name: wellknown.TCPProxy, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&tcp.TcpProxy{ + StatPrefix: statPrefix, + ClusterSpecifier: &tcp.TcpProxy_Cluster{ + Cluster: envoy.Clustername(proxy.Clusters[0]), + }, + AccessLog: accesslogger, + IdleTimeout: idleTimeout, + }), + }, + } + default: + var clusters []*tcp.TcpProxy_WeightedCluster_ClusterWeight + for _, c := range proxy.Clusters { + weight := c.Weight + if weight == 0 { + weight = 1 + } + clusters = append(clusters, &tcp.TcpProxy_WeightedCluster_ClusterWeight{ + Name: envoy.Clustername(c), + Weight: weight, + }) + } + sort.Stable(sorter.For(clusters)) + return &envoy_api_v2_listener.Filter{ + Name: wellknown.TCPProxy, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&tcp.TcpProxy{ + StatPrefix: statPrefix, + ClusterSpecifier: &tcp.TcpProxy_WeightedClusters{ + WeightedClusters: &tcp.TcpProxy_WeightedCluster{ + Clusters: clusters, + }, + }, + AccessLog: accesslogger, + IdleTimeout: idleTimeout, + }), + }, + } + } +} + +// SocketAddress creates a new TCP envoy_api_v2_core.Address. +func SocketAddress(address string, port int) *envoy_api_v2_core.Address { + if address == "::" { + return &envoy_api_v2_core.Address{ + Address: &envoy_api_v2_core.Address_SocketAddress{ + SocketAddress: &envoy_api_v2_core.SocketAddress{ + Protocol: envoy_api_v2_core.SocketAddress_TCP, + Address: address, + Ipv4Compat: true, + PortSpecifier: &envoy_api_v2_core.SocketAddress_PortValue{ + PortValue: uint32(port), + }, + }, + }, + } + } + return &envoy_api_v2_core.Address{ + Address: &envoy_api_v2_core.Address_SocketAddress{ + SocketAddress: &envoy_api_v2_core.SocketAddress{ + Protocol: envoy_api_v2_core.SocketAddress_TCP, + Address: address, + PortSpecifier: &envoy_api_v2_core.SocketAddress_PortValue{ + PortValue: uint32(port), + }, + }, + }, + } +} + +// Filters returns a []*envoy_api_v2_listener.Filter for the supplied filters. +func Filters(filters ...*envoy_api_v2_listener.Filter) []*envoy_api_v2_listener.Filter { + if len(filters) == 0 { + return nil + } + return filters +} + +// FilterChain retruns a *envoy_api_v2_listener.FilterChain for the supplied filters. +func FilterChain(filters ...*envoy_api_v2_listener.Filter) *envoy_api_v2_listener.FilterChain { + return &envoy_api_v2_listener.FilterChain{ + Filters: filters, + } +} + +// FilterChains returns a []*envoy_api_v2_listener.FilterChain for the supplied filters. +func FilterChains(filters ...*envoy_api_v2_listener.Filter) []*envoy_api_v2_listener.FilterChain { + if len(filters) == 0 { + return nil + } + return []*envoy_api_v2_listener.FilterChain{ + FilterChain(filters...), + } +} + +func FilterMisdirectedRequests(fqdn string) *http.HttpFilter { + // When Envoy matches on the virtual host domain, we configure + // it to match any port specifier (see envoy.VirtualHost), + // so the Host header (authority) may contain a port that + // should be ignored. This means that if we don't have a match, + // we should try again after stripping the port specifier. + + code := ` +function envoy_on_request(request_handle) + local headers = request_handle:headers() + local host = string.lower(headers:get(":authority")) + local target = "%s" + + if host ~= target then + s, e = string.find(host, ":", 1, true) + if s ~= nil then + host = string.sub(host, 1, s - 1) + end + + if host ~= target then + request_handle:respond( + {[":status"] = "421"}, + string.format("misdirected request to %%q", headers:get(":authority")) + ) + end + end +end + ` + + return &http.HttpFilter{ + Name: "envoy.filters.http.lua", + ConfigType: &http.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&lua.Lua{ + InlineCode: fmt.Sprintf(code, strings.ToLower(fqdn)), + }), + }, + } +} + +// FilterExternalAuthz returns an `ext_authz` filter configured with the +// requested parameters. +func FilterExternalAuthz(authzClusterName string, failOpen bool, timeout timeout.Setting) *http.HttpFilter { + authConfig := envoy_config_filter_http_ext_authz_v2.ExtAuthz{ + Services: &envoy_config_filter_http_ext_authz_v2.ExtAuthz_GrpcService{ + GrpcService: &envoy_api_v2_core.GrpcService{ + TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ + ClusterName: authzClusterName, + }, + }, + Timeout: envoy.Timeout(timeout), + // We don't need to configure metadata here, since we allow + // operators to specify authorization context parameters at + // the virtual host and route. + InitialMetadata: []*envoy_api_v2_core.HeaderValue{}, + }, + }, + // Pretty sure we always want this. Why have an + // external auth service if it is not going to affect + // routing decisions? + ClearRouteCache: true, + FailureModeAllow: failOpen, + StatusOnError: &envoy_type.HttpStatus{ + Code: envoy_type.StatusCode_Forbidden, + }, + MetadataContextNamespaces: []string{}, + IncludePeerCertificate: true, + } + + // TODO(jpeach): When we move to the Envoy v3 API, propagate the + // `transport_api_version` from ExtensionServiceSpec ProtocolVersion. + + return &http.HttpFilter{ + Name: "envoy.filters.http.ext_authz", + ConfigType: &http.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&authConfig), + }, + } +} + +// FilterChainTLS returns a TLS enabled envoy_api_v2_listener.FilterChain. +func FilterChainTLS(domain string, downstream *envoy_api_v2_auth.DownstreamTlsContext, filters []*envoy_api_v2_listener.Filter) *envoy_api_v2_listener.FilterChain { + fc := &envoy_api_v2_listener.FilterChain{ + Filters: filters, + FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ + ServerNames: []string{domain}, + }, + } + // Attach TLS data to this listener if provided. + if downstream != nil { + fc.TransportSocket = DownstreamTLSTransportSocket(downstream) + + } + return fc +} + +// FilterChainTLSFallback returns a TLS enabled envoy_api_v2_listener.FilterChain conifgured for FallbackCertificate. +func FilterChainTLSFallback(downstream *envoy_api_v2_auth.DownstreamTlsContext, filters []*envoy_api_v2_listener.Filter) *envoy_api_v2_listener.FilterChain { + fc := &envoy_api_v2_listener.FilterChain{ + Name: "fallback-certificate", + Filters: filters, + FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ + TransportProtocol: "tls", + }, + } + // Attach TLS data to this listener if provided. + if downstream != nil { + fc.TransportSocket = DownstreamTLSTransportSocket(downstream) + } + return fc +} + +// ListenerFilters returns a []*envoy_api_v2_listener.ListenerFilter for the supplied listener filters. +func ListenerFilters(filters ...*envoy_api_v2_listener.ListenerFilter) []*envoy_api_v2_listener.ListenerFilter { + return filters +} + +func ContainsFallbackFilterChain(filterchains []*envoy_api_v2_listener.FilterChain) bool { + for _, fc := range filterchains { + if fc.Name == "fallback-certificate" { + return true + } + } + return false +} diff --git a/internal/envoy/v2/listener_test.go b/internal/envoy/v2/listener_test.go new file mode 100644 index 00000000000..19083b896a7 --- /dev/null +++ b/internal/envoy/v2/listener_test.go @@ -0,0 +1,798 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v2 + +import ( + "testing" + "time" + + "github.com/projectcontour/contour/internal/envoy" + + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" + envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" + envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" + envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" + envoy_api_v2_accesslog "github.com/envoyproxy/go-control-plane/envoy/config/filter/accesslog/v2" + http "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2" + envoy_config_v2_tcpproxy "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/tcp_proxy/v2" + "github.com/envoyproxy/go-control-plane/pkg/wellknown" + "github.com/projectcontour/contour/internal/dag" + "github.com/projectcontour/contour/internal/protobuf" + "github.com/projectcontour/contour/internal/timeout" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +func TestListener(t *testing.T) { + tests := map[string]struct { + name, address string + port int + lf []*envoy_api_v2_listener.ListenerFilter + f []*envoy_api_v2_listener.Filter + want *v2.Listener + }{ + "insecure listener": { + name: "http", + address: "0.0.0.0", + port: 9000, + f: []*envoy_api_v2_listener.Filter{ + HTTPConnectionManager("http", FileAccessLogEnvoy("/dev/null"), 0), + }, + want: &v2.Listener{ + Name: "http", + Address: SocketAddress("0.0.0.0", 9000), + FilterChains: FilterChains( + HTTPConnectionManager("http", FileAccessLogEnvoy("/dev/null"), 0), + ), + SocketOptions: TCPKeepaliveSocketOptions(), + }, + }, + "insecure listener w/ proxy": { + name: "http-proxy", + address: "0.0.0.0", + port: 9000, + lf: []*envoy_api_v2_listener.ListenerFilter{ + ProxyProtocol(), + }, + f: []*envoy_api_v2_listener.Filter{ + HTTPConnectionManager("http-proxy", FileAccessLogEnvoy("/dev/null"), 0), + }, + want: &v2.Listener{ + Name: "http-proxy", + Address: SocketAddress("0.0.0.0", 9000), + ListenerFilters: ListenerFilters( + ProxyProtocol(), + ), + FilterChains: FilterChains( + HTTPConnectionManager("http-proxy", FileAccessLogEnvoy("/dev/null"), 0), + ), + SocketOptions: TCPKeepaliveSocketOptions(), + }, + }, + "secure listener": { + name: "https", + address: "0.0.0.0", + port: 9000, + lf: ListenerFilters( + TLSInspector(), + ), + want: &v2.Listener{ + Name: "https", + Address: SocketAddress("0.0.0.0", 9000), + ListenerFilters: ListenerFilters( + TLSInspector(), + ), + SocketOptions: TCPKeepaliveSocketOptions(), + }, + }, + "secure listener w/ proxy": { + name: "https-proxy", + address: "0.0.0.0", + port: 9000, + lf: ListenerFilters( + ProxyProtocol(), + TLSInspector(), + ), + want: &v2.Listener{ + Name: "https-proxy", + Address: SocketAddress("0.0.0.0", 9000), + ListenerFilters: ListenerFilters( + ProxyProtocol(), + TLSInspector(), + ), + SocketOptions: TCPKeepaliveSocketOptions(), + }, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := Listener(tc.name, tc.address, tc.port, tc.lf, tc.f...) + protobuf.ExpectEqual(t, tc.want, got) + }) + } +} + +func TestSocketAddress(t *testing.T) { + const ( + addr = "foo.example.com" + port = 8123 + ) + + got := SocketAddress(addr, port) + want := &envoy_api_v2_core.Address{ + Address: &envoy_api_v2_core.Address_SocketAddress{ + SocketAddress: &envoy_api_v2_core.SocketAddress{ + Protocol: envoy_api_v2_core.SocketAddress_TCP, + Address: addr, + PortSpecifier: &envoy_api_v2_core.SocketAddress_PortValue{ + PortValue: port, + }, + }, + }, + } + require.Equal(t, want, got) + + got = SocketAddress("::", port) + want = &envoy_api_v2_core.Address{ + Address: &envoy_api_v2_core.Address_SocketAddress{ + SocketAddress: &envoy_api_v2_core.SocketAddress{ + Protocol: envoy_api_v2_core.SocketAddress_TCP, + Address: "::", + Ipv4Compat: true, // Set only for ipv6-any "::" + PortSpecifier: &envoy_api_v2_core.SocketAddress_PortValue{ + PortValue: port, + }, + }, + }, + } + assert.Equal(t, want, got) +} + +func TestDownstreamTLSContext(t *testing.T) { + const subjectName = "client-subject-name" + ca := []byte("client-ca-cert") + + serverSecret := &dag.Secret{ + Object: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tls-cert", + Namespace: "default", + }, + Data: map[string][]byte{ + v1.TLSCertKey: []byte("cert"), + v1.TLSPrivateKeyKey: []byte("key"), + }, + }, + } + + tlsParams := &envoy_api_v2_auth.TlsParameters{ + TlsMinimumProtocolVersion: envoy_api_v2_auth.TlsParameters_TLSv1_1, + TlsMaximumProtocolVersion: envoy_api_v2_auth.TlsParameters_TLSv1_3, + CipherSuites: []string{ + "[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]", + "[ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]", + "ECDHE-ECDSA-AES128-SHA", + "ECDHE-RSA-AES128-SHA", + "ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES256-GCM-SHA384", + "ECDHE-ECDSA-AES256-SHA", + "ECDHE-RSA-AES256-SHA", + }, + } + + tlsCertificateSdsSecretConfigs := []*envoy_api_v2_auth.SdsSecretConfig{{ + Name: envoy.Secretname(serverSecret), + SdsConfig: &envoy_api_v2_core.ConfigSource{ + ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ + ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ + ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, + GrpcServices: []*envoy_api_v2_core.GrpcService{{ + TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ + ClusterName: "contour", + }, + }, + }}, + }, + }, + }, + }} + + alpnProtocols := []string{"h2", "http/1.1"} + validationContext := &envoy_api_v2_auth.CommonTlsContext_ValidationContext{ + ValidationContext: &envoy_api_v2_auth.CertificateValidationContext{ + TrustedCa: &envoy_api_v2_core.DataSource{ + Specifier: &envoy_api_v2_core.DataSource_InlineBytes{ + InlineBytes: ca, + }, + }, + }, + } + + peerValidationContext := &dag.PeerValidationContext{ + CACertificate: &dag.Secret{ + Object: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "secret", + Namespace: "default", + }, + Data: map[string][]byte{ + dag.CACertificateKey: ca, + }, + }, + }, + } + + // Negative test case: downstream validation should not contain subjectname. + peerValidationContextWithSubjectName := &dag.PeerValidationContext{ + CACertificate: &dag.Secret{ + Object: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "secret", + Namespace: "default", + }, + Data: map[string][]byte{ + dag.CACertificateKey: ca, + }, + }, + }, + SubjectName: subjectName, + } + + tests := map[string]struct { + got *envoy_api_v2_auth.DownstreamTlsContext + want *envoy_api_v2_auth.DownstreamTlsContext + }{ + "TLS context without client authentication": { + DownstreamTLSContext(serverSecret, envoy_api_v2_auth.TlsParameters_TLSv1_1, nil, "h2", "http/1.1"), + &envoy_api_v2_auth.DownstreamTlsContext{ + CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ + TlsParams: tlsParams, + TlsCertificateSdsSecretConfigs: tlsCertificateSdsSecretConfigs, + AlpnProtocols: alpnProtocols, + }, + }, + }, + "TLS context with client authentication": { + DownstreamTLSContext(serverSecret, envoy_api_v2_auth.TlsParameters_TLSv1_1, peerValidationContext, "h2", "http/1.1"), + &envoy_api_v2_auth.DownstreamTlsContext{ + CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ + TlsParams: tlsParams, + TlsCertificateSdsSecretConfigs: tlsCertificateSdsSecretConfigs, + AlpnProtocols: alpnProtocols, + ValidationContextType: validationContext, + }, + RequireClientCertificate: protobuf.Bool(true), + }, + }, + "Downstream validation shall not support subjectName validation": { + DownstreamTLSContext(serverSecret, envoy_api_v2_auth.TlsParameters_TLSv1_1, peerValidationContextWithSubjectName, "h2", "http/1.1"), + &envoy_api_v2_auth.DownstreamTlsContext{ + CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ + TlsParams: tlsParams, + TlsCertificateSdsSecretConfigs: tlsCertificateSdsSecretConfigs, + AlpnProtocols: alpnProtocols, + ValidationContextType: validationContext, + }, + RequireClientCertificate: protobuf.Bool(true), + }, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + protobuf.ExpectEqual(t, tc.want, tc.got) + }) + } +} + +func TestHTTPConnectionManager(t *testing.T) { + tests := map[string]struct { + routename string + accesslogger []*envoy_api_v2_accesslog.AccessLog + requestTimeout timeout.Setting + connectionIdleTimeout timeout.Setting + streamIdleTimeout timeout.Setting + maxConnectionDuration timeout.Setting + connectionShutdownGracePeriod timeout.Setting + want *envoy_api_v2_listener.Filter + }{ + "default": { + routename: "default/kuard", + accesslogger: FileAccessLogEnvoy("/dev/stdout"), + want: &envoy_api_v2_listener.Filter{ + Name: wellknown.HTTPConnectionManager, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ + StatPrefix: "default/kuard", + RouteSpecifier: &http.HttpConnectionManager_Rds{ + Rds: &http.Rds{ + RouteConfigName: "default/kuard", + ConfigSource: &envoy_api_v2_core.ConfigSource{ + ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ + ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ + ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, + GrpcServices: []*envoy_api_v2_core.GrpcService{{ + TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ + ClusterName: "contour", + }, + }, + }}, + }, + }, + }, + }, + }, + HttpFilters: []*http.HttpFilter{{ + Name: wellknown.Gzip, + }, { + Name: wellknown.GRPCWeb, + }, { + Name: wellknown.Router, + }}, + HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ + // Enable support for HTTP/1.0 requests that carry + // a Host: header. See #537. + AcceptHttp_10: true, + }, + CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{}, + AccessLog: FileAccessLogEnvoy("/dev/stdout"), + UseRemoteAddress: protobuf.Bool(true), + NormalizePath: protobuf.Bool(true), + PreserveExternalRequestId: true, + MergeSlashes: true, + }), + }, + }, + }, + "request timeout of 10s": { + routename: "default/kuard", + accesslogger: FileAccessLogEnvoy("/dev/stdout"), + requestTimeout: timeout.DurationSetting(10 * time.Second), + want: &envoy_api_v2_listener.Filter{ + Name: wellknown.HTTPConnectionManager, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ + StatPrefix: "default/kuard", + RouteSpecifier: &http.HttpConnectionManager_Rds{ + Rds: &http.Rds{ + RouteConfigName: "default/kuard", + ConfigSource: &envoy_api_v2_core.ConfigSource{ + ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ + ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ + ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, + GrpcServices: []*envoy_api_v2_core.GrpcService{{ + TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ + ClusterName: "contour", + }, + }, + }}, + }, + }, + }, + }, + }, + HttpFilters: []*http.HttpFilter{{ + Name: wellknown.Gzip, + }, { + Name: wellknown.GRPCWeb, + }, { + Name: wellknown.Router, + }}, + HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ + // Enable support for HTTP/1.0 requests that carry + // a Host: header. See #537. + AcceptHttp_10: true, + }, + CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{}, + AccessLog: FileAccessLogEnvoy("/dev/stdout"), + UseRemoteAddress: protobuf.Bool(true), + NormalizePath: protobuf.Bool(true), + RequestTimeout: protobuf.Duration(10 * time.Second), + PreserveExternalRequestId: true, + MergeSlashes: true, + }), + }, + }, + }, + "connection idle timeout of 90s": { + routename: "default/kuard", + accesslogger: FileAccessLogEnvoy("/dev/stdout"), + connectionIdleTimeout: timeout.DurationSetting(90 * time.Second), + want: &envoy_api_v2_listener.Filter{ + Name: wellknown.HTTPConnectionManager, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ + StatPrefix: "default/kuard", + RouteSpecifier: &http.HttpConnectionManager_Rds{ + Rds: &http.Rds{ + RouteConfigName: "default/kuard", + ConfigSource: &envoy_api_v2_core.ConfigSource{ + ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ + ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ + ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, + GrpcServices: []*envoy_api_v2_core.GrpcService{{ + TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ + ClusterName: "contour", + }, + }, + }}, + }, + }, + }, + }, + }, + HttpFilters: []*http.HttpFilter{{ + Name: wellknown.Gzip, + }, { + Name: wellknown.GRPCWeb, + }, { + Name: wellknown.Router, + }}, + HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ + // Enable support for HTTP/1.0 requests that carry + // a Host: header. See #537. + AcceptHttp_10: true, + }, + CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{ + IdleTimeout: protobuf.Duration(90 * time.Second), + }, + AccessLog: FileAccessLogEnvoy("/dev/stdout"), + UseRemoteAddress: protobuf.Bool(true), + NormalizePath: protobuf.Bool(true), + PreserveExternalRequestId: true, + MergeSlashes: true, + }), + }, + }, + }, + "stream idle timeout of 90s": { + routename: "default/kuard", + accesslogger: FileAccessLogEnvoy("/dev/stdout"), + streamIdleTimeout: timeout.DurationSetting(90 * time.Second), + want: &envoy_api_v2_listener.Filter{ + Name: wellknown.HTTPConnectionManager, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ + StatPrefix: "default/kuard", + RouteSpecifier: &http.HttpConnectionManager_Rds{ + Rds: &http.Rds{ + RouteConfigName: "default/kuard", + ConfigSource: &envoy_api_v2_core.ConfigSource{ + ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ + ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ + ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, + GrpcServices: []*envoy_api_v2_core.GrpcService{{ + TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ + ClusterName: "contour", + }, + }, + }}, + }, + }, + }, + }, + }, + HttpFilters: []*http.HttpFilter{{ + Name: wellknown.Gzip, + }, { + Name: wellknown.GRPCWeb, + }, { + Name: wellknown.Router, + }}, + HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ + // Enable support for HTTP/1.0 requests that carry + // a Host: header. See #537. + AcceptHttp_10: true, + }, + CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{}, + AccessLog: FileAccessLogEnvoy("/dev/stdout"), + UseRemoteAddress: protobuf.Bool(true), + NormalizePath: protobuf.Bool(true), + PreserveExternalRequestId: true, + MergeSlashes: true, + StreamIdleTimeout: protobuf.Duration(90 * time.Second), + }), + }, + }, + }, + "max connection duration of 90s": { + routename: "default/kuard", + accesslogger: FileAccessLogEnvoy("/dev/stdout"), + maxConnectionDuration: timeout.DurationSetting(90 * time.Second), + want: &envoy_api_v2_listener.Filter{ + Name: wellknown.HTTPConnectionManager, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ + StatPrefix: "default/kuard", + RouteSpecifier: &http.HttpConnectionManager_Rds{ + Rds: &http.Rds{ + RouteConfigName: "default/kuard", + ConfigSource: &envoy_api_v2_core.ConfigSource{ + ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ + ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ + ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, + GrpcServices: []*envoy_api_v2_core.GrpcService{{ + TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ + ClusterName: "contour", + }, + }, + }}, + }, + }, + }, + }, + }, + HttpFilters: []*http.HttpFilter{{ + Name: wellknown.Gzip, + }, { + Name: wellknown.GRPCWeb, + }, { + Name: wellknown.Router, + }}, + HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ + // Enable support for HTTP/1.0 requests that carry + // a Host: header. See #537. + AcceptHttp_10: true, + }, + CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{ + MaxConnectionDuration: protobuf.Duration(90 * time.Second), + }, + AccessLog: FileAccessLogEnvoy("/dev/stdout"), + UseRemoteAddress: protobuf.Bool(true), + NormalizePath: protobuf.Bool(true), + PreserveExternalRequestId: true, + MergeSlashes: true, + }), + }, + }, + }, + "when max connection duration is disabled, it's omitted": { + routename: "default/kuard", + accesslogger: FileAccessLogEnvoy("/dev/stdout"), + maxConnectionDuration: timeout.DisabledSetting(), + want: &envoy_api_v2_listener.Filter{ + Name: wellknown.HTTPConnectionManager, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ + StatPrefix: "default/kuard", + RouteSpecifier: &http.HttpConnectionManager_Rds{ + Rds: &http.Rds{ + RouteConfigName: "default/kuard", + ConfigSource: &envoy_api_v2_core.ConfigSource{ + ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ + ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ + ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, + GrpcServices: []*envoy_api_v2_core.GrpcService{{ + TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ + ClusterName: "contour", + }, + }, + }}, + }, + }, + }, + }, + }, + HttpFilters: []*http.HttpFilter{{ + Name: wellknown.Gzip, + }, { + Name: wellknown.GRPCWeb, + }, { + Name: wellknown.Router, + }}, + HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ + // Enable support for HTTP/1.0 requests that carry + // a Host: header. See #537. + AcceptHttp_10: true, + }, + CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{}, + AccessLog: FileAccessLogEnvoy("/dev/stdout"), + UseRemoteAddress: protobuf.Bool(true), + NormalizePath: protobuf.Bool(true), + PreserveExternalRequestId: true, + MergeSlashes: true, + }), + }, + }, + }, + "drain timeout of 90s": { + routename: "default/kuard", + accesslogger: FileAccessLogEnvoy("/dev/stdout"), + connectionShutdownGracePeriod: timeout.DurationSetting(90 * time.Second), + want: &envoy_api_v2_listener.Filter{ + Name: wellknown.HTTPConnectionManager, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&http.HttpConnectionManager{ + StatPrefix: "default/kuard", + RouteSpecifier: &http.HttpConnectionManager_Rds{ + Rds: &http.Rds{ + RouteConfigName: "default/kuard", + ConfigSource: &envoy_api_v2_core.ConfigSource{ + ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_ApiConfigSource{ + ApiConfigSource: &envoy_api_v2_core.ApiConfigSource{ + ApiType: envoy_api_v2_core.ApiConfigSource_GRPC, + GrpcServices: []*envoy_api_v2_core.GrpcService{{ + TargetSpecifier: &envoy_api_v2_core.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &envoy_api_v2_core.GrpcService_EnvoyGrpc{ + ClusterName: "contour", + }, + }, + }}, + }, + }, + }, + }, + }, + HttpFilters: []*http.HttpFilter{{ + Name: wellknown.Gzip, + }, { + Name: wellknown.GRPCWeb, + }, { + Name: wellknown.Router, + }}, + HttpProtocolOptions: &envoy_api_v2_core.Http1ProtocolOptions{ + // Enable support for HTTP/1.0 requests that carry + // a Host: header. See #537. + AcceptHttp_10: true, + }, + CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{}, + AccessLog: FileAccessLogEnvoy("/dev/stdout"), + UseRemoteAddress: protobuf.Bool(true), + NormalizePath: protobuf.Bool(true), + PreserveExternalRequestId: true, + MergeSlashes: true, + DrainTimeout: protobuf.Duration(90 * time.Second), + }), + }, + }, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := HTTPConnectionManagerBuilder(). + RouteConfigName(tc.routename). + MetricsPrefix(tc.routename). + AccessLoggers(tc.accesslogger). + RequestTimeout(tc.requestTimeout). + ConnectionIdleTimeout(tc.connectionIdleTimeout). + StreamIdleTimeout(tc.streamIdleTimeout). + MaxConnectionDuration(tc.maxConnectionDuration). + ConnectionShutdownGracePeriod(tc.connectionShutdownGracePeriod). + DefaultFilters(). + Get() + + protobuf.ExpectEqual(t, tc.want, got) + }) + } +} + +func TestTCPProxy(t *testing.T) { + const ( + statPrefix = "ingress_https" + accessLogPath = "/dev/stdout" + ) + + c1 := &dag.Cluster{ + Upstream: &dag.Service{ + Weighted: dag.WeightedService{ + Weight: 1, + ServiceName: "example", + ServiceNamespace: "default", + ServicePort: v1.ServicePort{ + Protocol: "TCP", + Port: 443, + TargetPort: intstr.FromInt(8443), + }, + }, + }, + } + c2 := &dag.Cluster{ + Upstream: &dag.Service{ + Weighted: dag.WeightedService{ + ServiceName: "example2", + ServiceNamespace: "default", + ServicePort: v1.ServicePort{ + Protocol: "TCP", + Port: 443, + TargetPort: intstr.FromInt(8443), + }, + }, + }, + Weight: 20, + } + + tests := map[string]struct { + proxy *dag.TCPProxy + want *envoy_api_v2_listener.Filter + }{ + "single cluster": { + proxy: &dag.TCPProxy{ + Clusters: []*dag.Cluster{c1}, + }, + want: &envoy_api_v2_listener.Filter{ + Name: wellknown.TCPProxy, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&envoy_config_v2_tcpproxy.TcpProxy{ + StatPrefix: statPrefix, + ClusterSpecifier: &envoy_config_v2_tcpproxy.TcpProxy_Cluster{ + Cluster: envoy.Clustername(c1), + }, + AccessLog: FileAccessLogEnvoy(accessLogPath), + IdleTimeout: protobuf.Duration(9001 * time.Second), + }), + }, + }, + }, + "multiple cluster": { + proxy: &dag.TCPProxy{ + Clusters: []*dag.Cluster{c2, c1}, + }, + want: &envoy_api_v2_listener.Filter{ + Name: wellknown.TCPProxy, + ConfigType: &envoy_api_v2_listener.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&envoy_config_v2_tcpproxy.TcpProxy{ + StatPrefix: statPrefix, + ClusterSpecifier: &envoy_config_v2_tcpproxy.TcpProxy_WeightedClusters{ + WeightedClusters: &envoy_config_v2_tcpproxy.TcpProxy_WeightedCluster{ + Clusters: []*envoy_config_v2_tcpproxy.TcpProxy_WeightedCluster_ClusterWeight{{ + Name: envoy.Clustername(c1), + Weight: 1, + }, { + Name: envoy.Clustername(c2), + Weight: 20, + }}, + }, + }, + AccessLog: FileAccessLogEnvoy(accessLogPath), + IdleTimeout: protobuf.Duration(9001 * time.Second), + }), + }, + }, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := TCPProxy(statPrefix, tc.proxy, FileAccessLogEnvoy(accessLogPath)) + protobuf.ExpectEqual(t, tc.want, got) + }) + } +} + +// TestBuilderValidation tests that validation checks that +// DefaultFilters adds the required HTTP connection manager filters. +func TestBuilderValidation(t *testing.T) { + if err := HTTPConnectionManagerBuilder().Validate(); err == nil { + t.Errorf("ConnectionManager with no filters passed validation") + } + + if err := HTTPConnectionManagerBuilder().AddFilter(&http.HttpFilter{Name: "foo"}).Validate(); err == nil { + t.Errorf("ConnectionManager with no filters passed validation") + } + + if err := HTTPConnectionManagerBuilder().DefaultFilters().Validate(); err != nil { + t.Errorf("ConnectionManager with default filters failed validation: %s", err) + } +} diff --git a/internal/envoy/v2/route.go b/internal/envoy/v2/route.go new file mode 100644 index 00000000000..13993341b59 --- /dev/null +++ b/internal/envoy/v2/route.go @@ -0,0 +1,314 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v2 + +import ( + "fmt" + "regexp" + "sort" + + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" + envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" + envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" + envoy_config_filter_http_ext_authz_v2 "github.com/envoyproxy/go-control-plane/envoy/config/filter/http/ext_authz/v2" + "github.com/golang/protobuf/ptypes/any" + wrappers "github.com/golang/protobuf/ptypes/wrappers" + "github.com/projectcontour/contour/internal/dag" + "github.com/projectcontour/contour/internal/envoy" + "github.com/projectcontour/contour/internal/protobuf" + "github.com/projectcontour/contour/internal/sorter" +) + +// RouteAuthzDisabled returns a per-route config to disable authorization. +func RouteAuthzDisabled() *any.Any { + return protobuf.MustMarshalAny( + &envoy_config_filter_http_ext_authz_v2.ExtAuthzPerRoute{ + Override: &envoy_config_filter_http_ext_authz_v2.ExtAuthzPerRoute_Disabled{ + Disabled: true, + }, + }, + ) +} + +// RouteAuthzContext returns a per-route config to pass the given +// context entries in the check request. +func RouteAuthzContext(settings map[string]string) *any.Any { + return protobuf.MustMarshalAny( + &envoy_config_filter_http_ext_authz_v2.ExtAuthzPerRoute{ + Override: &envoy_config_filter_http_ext_authz_v2.ExtAuthzPerRoute_CheckSettings{ + CheckSettings: &envoy_config_filter_http_ext_authz_v2.CheckSettings{ + ContextExtensions: settings, + }, + }, + }, + ) +} + +// RouteMatch creates a *envoy_api_v2_route.RouteMatch for the supplied *dag.Route. +func RouteMatch(route *dag.Route) *envoy_api_v2_route.RouteMatch { + switch c := route.PathMatchCondition.(type) { + case *dag.RegexMatchCondition: + return &envoy_api_v2_route.RouteMatch{ + PathSpecifier: &envoy_api_v2_route.RouteMatch_SafeRegex{ + SafeRegex: envoy.SafeRegexMatch(c.Regex), + }, + Headers: headerMatcher(route.HeaderMatchConditions), + } + case *dag.PrefixMatchCondition: + return &envoy_api_v2_route.RouteMatch{ + PathSpecifier: &envoy_api_v2_route.RouteMatch_Prefix{ + Prefix: c.Prefix, + }, + Headers: headerMatcher(route.HeaderMatchConditions), + } + default: + return &envoy_api_v2_route.RouteMatch{ + Headers: headerMatcher(route.HeaderMatchConditions), + } + } +} + +// RouteRoute creates a *envoy_api_v2_route.Route_Route for the services supplied. +// If len(services) is greater than one, the route's action will be a +// weighted cluster. +func RouteRoute(r *dag.Route) *envoy_api_v2_route.Route_Route { + ra := envoy_api_v2_route.RouteAction{ + RetryPolicy: retryPolicy(r), + Timeout: envoy.Timeout(r.TimeoutPolicy.ResponseTimeout), + IdleTimeout: envoy.Timeout(r.TimeoutPolicy.IdleTimeout), + PrefixRewrite: r.PrefixRewrite, + HashPolicy: hashPolicy(r), + RequestMirrorPolicies: mirrorPolicy(r), + } + + // Check for host header policy and set if found + if val := envoy.HostReplaceHeader(r.RequestHeadersPolicy); val != "" { + ra.HostRewriteSpecifier = &envoy_api_v2_route.RouteAction_HostRewrite{ + HostRewrite: val, + } + } + + if r.Websocket { + ra.UpgradeConfigs = append(ra.UpgradeConfigs, + &envoy_api_v2_route.RouteAction_UpgradeConfig{ + UpgradeType: "websocket", + }, + ) + } + + if envoy.SingleSimpleCluster(r.Clusters) { + ra.ClusterSpecifier = &envoy_api_v2_route.RouteAction_Cluster{ + Cluster: envoy.Clustername(r.Clusters[0]), + } + } else { + ra.ClusterSpecifier = &envoy_api_v2_route.RouteAction_WeightedClusters{ + WeightedClusters: weightedClusters(r.Clusters), + } + } + return &envoy_api_v2_route.Route_Route{ + Route: &ra, + } +} + +// hashPolicy returns a slice of hash policies iff at least one of the route's +// clusters supplied uses the `Cookie` load balancing strategy. +func hashPolicy(r *dag.Route) []*envoy_api_v2_route.RouteAction_HashPolicy { + for _, c := range r.Clusters { + if c.LoadBalancerPolicy == "Cookie" { + return []*envoy_api_v2_route.RouteAction_HashPolicy{{ + PolicySpecifier: &envoy_api_v2_route.RouteAction_HashPolicy_Cookie_{ + Cookie: &envoy_api_v2_route.RouteAction_HashPolicy_Cookie{ + Name: "X-Contour-Session-Affinity", + Ttl: protobuf.Duration(0), + Path: "/", + }, + }, + }} + } + } + return nil +} + +func mirrorPolicy(r *dag.Route) []*envoy_api_v2_route.RouteAction_RequestMirrorPolicy { + if r.MirrorPolicy == nil { + return nil + } + + return []*envoy_api_v2_route.RouteAction_RequestMirrorPolicy{{ + Cluster: envoy.Clustername(r.MirrorPolicy.Cluster), + }} +} + +func retryPolicy(r *dag.Route) *envoy_api_v2_route.RetryPolicy { + if r.RetryPolicy == nil { + return nil + } + if r.RetryPolicy.RetryOn == "" { + return nil + } + + rp := &envoy_api_v2_route.RetryPolicy{ + RetryOn: r.RetryPolicy.RetryOn, + RetriableStatusCodes: r.RetryPolicy.RetriableStatusCodes, + } + if r.RetryPolicy.NumRetries > 0 { + rp.NumRetries = protobuf.UInt32(r.RetryPolicy.NumRetries) + } + rp.PerTryTimeout = envoy.Timeout(r.RetryPolicy.PerTryTimeout) + + return rp +} + +// UpgradeHTTPS returns a route Action that redirects the request to HTTPS. +func UpgradeHTTPS() *envoy_api_v2_route.Route_Redirect { + return &envoy_api_v2_route.Route_Redirect{ + Redirect: &envoy_api_v2_route.RedirectAction{ + SchemeRewriteSpecifier: &envoy_api_v2_route.RedirectAction_HttpsRedirect{ + HttpsRedirect: true, + }, + }, + } +} + +// HeaderValueList creates a list of Envoy HeaderValueOptions from the provided map. +func HeaderValueList(hvm map[string]string, app bool) []*envoy_api_v2_core.HeaderValueOption { + var hvs []*envoy_api_v2_core.HeaderValueOption + + for key, value := range hvm { + hvs = append(hvs, &envoy_api_v2_core.HeaderValueOption{ + Header: &envoy_api_v2_core.HeaderValue{ + Key: key, + Value: value, + }, + Append: &wrappers.BoolValue{ + Value: app, + }, + }) + } + + sort.Slice(hvs, func(i, j int) bool { + return hvs[i].Header.Key < hvs[j].Header.Key + }) + + return hvs +} + +// weightedClusters returns a route.WeightedCluster for multiple services. +func weightedClusters(clusters []*dag.Cluster) *envoy_api_v2_route.WeightedCluster { + var wc envoy_api_v2_route.WeightedCluster + var total uint32 + for _, cluster := range clusters { + total += cluster.Weight + + c := &envoy_api_v2_route.WeightedCluster_ClusterWeight{ + Name: envoy.Clustername(cluster), + Weight: protobuf.UInt32(cluster.Weight), + } + if cluster.RequestHeadersPolicy != nil { + c.RequestHeadersToAdd = HeaderValueList(cluster.RequestHeadersPolicy.Set, false) + c.RequestHeadersToRemove = cluster.RequestHeadersPolicy.Remove + } + if cluster.ResponseHeadersPolicy != nil { + c.ResponseHeadersToAdd = HeaderValueList(cluster.ResponseHeadersPolicy.Set, false) + c.ResponseHeadersToRemove = cluster.ResponseHeadersPolicy.Remove + } + wc.Clusters = append(wc.Clusters, c) + } + // Check if no weights were defined, if not default to even distribution + if total == 0 { + for _, c := range wc.Clusters { + c.Weight.Value = 1 + } + total = uint32(len(clusters)) + } + wc.TotalWeight = protobuf.UInt32(total) + + sort.Stable(sorter.For(wc.Clusters)) + return &wc +} + +// VirtualHost creates a new route.VirtualHost. +func VirtualHost(hostname string, routes ...*envoy_api_v2_route.Route) *envoy_api_v2_route.VirtualHost { + domains := []string{hostname} + if hostname != "*" { + // NOTE(jpeach) see also envoy.FilterMisdirectedRequests(). + domains = append(domains, hostname+":*") + } + + return &envoy_api_v2_route.VirtualHost{ + Name: envoy.Hashname(60, hostname), + Domains: domains, + Routes: routes, + } +} + +// RouteConfiguration returns a *v2.RouteConfiguration. +func RouteConfiguration(name string, virtualhosts ...*envoy_api_v2_route.VirtualHost) *v2.RouteConfiguration { + return &v2.RouteConfiguration{ + Name: name, + VirtualHosts: virtualhosts, + RequestHeadersToAdd: Headers( + AppendHeader("x-request-start", "t=%START_TIME(%s.%3f)%"), + ), + } +} + +func Headers(first *envoy_api_v2_core.HeaderValueOption, rest ...*envoy_api_v2_core.HeaderValueOption) []*envoy_api_v2_core.HeaderValueOption { + return append([]*envoy_api_v2_core.HeaderValueOption{first}, rest...) +} + +func AppendHeader(key, value string) *envoy_api_v2_core.HeaderValueOption { + return &envoy_api_v2_core.HeaderValueOption{ + Header: &envoy_api_v2_core.HeaderValue{ + Key: key, + Value: value, + }, + Append: protobuf.Bool(true), + } +} + +func headerMatcher(headers []dag.HeaderMatchCondition) []*envoy_api_v2_route.HeaderMatcher { + var envoyHeaders []*envoy_api_v2_route.HeaderMatcher + + for _, h := range headers { + header := &envoy_api_v2_route.HeaderMatcher{ + Name: h.Name, + InvertMatch: h.Invert, + } + + switch h.MatchType { + case "exact": + header.HeaderMatchSpecifier = &envoy_api_v2_route.HeaderMatcher_ExactMatch{ExactMatch: h.Value} + case "contains": + header.HeaderMatchSpecifier = containsMatch(h.Value) + case "present": + header.HeaderMatchSpecifier = &envoy_api_v2_route.HeaderMatcher_PresentMatch{PresentMatch: true} + } + envoyHeaders = append(envoyHeaders, header) + } + return envoyHeaders +} + +// containsMatch returns a HeaderMatchSpecifier which will match the +// supplied substring +func containsMatch(s string) *envoy_api_v2_route.HeaderMatcher_SafeRegexMatch { + // convert the substring s into a regular expression that matches s. + // note that Envoy expects the expression to match the entire string, not just the substring + // formed from s. see [projectcontour/contour/#1751 & envoyproxy/envoy#8283] + regex := fmt.Sprintf(".*%s.*", regexp.QuoteMeta(s)) + + return &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ + SafeRegexMatch: envoy.SafeRegexMatch(regex), + } +} diff --git a/internal/envoy/route_test.go b/internal/envoy/v2/route_test.go similarity index 98% rename from internal/envoy/route_test.go rename to internal/envoy/v2/route_test.go index e11c8e5ef65..758c3e6fcd0 100644 --- a/internal/envoy/route_test.go +++ b/internal/envoy/v2/route_test.go @@ -11,12 +11,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( "testing" "time" + "github.com/projectcontour/contour/internal/envoy" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" @@ -766,7 +768,7 @@ func TestRouteMatch(t *testing.T) { Name: "x-header", InvertMatch: false, HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ - SafeRegexMatch: SafeRegexMatch(".*11-22-33-44.*"), + SafeRegexMatch: envoy.SafeRegexMatch(".*11-22-33-44.*"), }, }}, }, @@ -785,7 +787,7 @@ func TestRouteMatch(t *testing.T) { Name: "x-header", InvertMatch: false, HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ - SafeRegexMatch: SafeRegexMatch(".*11\\.22\\.33\\.44.*"), + SafeRegexMatch: envoy.SafeRegexMatch(".*11\\.22\\.33\\.44.*"), }, }}, }, @@ -804,7 +806,7 @@ func TestRouteMatch(t *testing.T) { Name: "x-header", InvertMatch: false, HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ - SafeRegexMatch: SafeRegexMatch(".*11\\.\\[22\\]\\.\\*33\\.44.*"), + SafeRegexMatch: envoy.SafeRegexMatch(".*11\\.\\[22\\]\\.\\*33\\.44.*"), }, }}, }, @@ -832,7 +834,7 @@ func TestRouteMatch(t *testing.T) { // note, unlike header conditions this is not a quoted regex because // the value comes directly from the Ingress.Paths.Path value which // is permitted to be a bare regex. - SafeRegex: SafeRegexMatch("/v.1/*"), + SafeRegex: envoy.SafeRegexMatch("/v.1/*"), }, }, }, diff --git a/internal/envoy/v2/secret.go b/internal/envoy/v2/secret.go new file mode 100644 index 00000000000..64f1e9d84b6 --- /dev/null +++ b/internal/envoy/v2/secret.go @@ -0,0 +1,44 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v2 + +import ( + // nolint:gosec + + envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" + envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" + "github.com/projectcontour/contour/internal/dag" + "github.com/projectcontour/contour/internal/envoy" +) + +// Secret creates new envoy_api_v2_auth.Secret from secret. +func Secret(s *dag.Secret) *envoy_api_v2_auth.Secret { + return &envoy_api_v2_auth.Secret{ + Name: envoy.Secretname(s), + Type: &envoy_api_v2_auth.Secret_TlsCertificate{ + TlsCertificate: &envoy_api_v2_auth.TlsCertificate{ + PrivateKey: &envoy_api_v2_core.DataSource{ + Specifier: &envoy_api_v2_core.DataSource_InlineBytes{ + InlineBytes: s.PrivateKey(), + }, + }, + CertificateChain: &envoy_api_v2_core.DataSource{ + Specifier: &envoy_api_v2_core.DataSource_InlineBytes{ + InlineBytes: s.Cert(), + }, + }, + }, + }, + } +} diff --git a/internal/envoy/secret_test.go b/internal/envoy/v2/secret_test.go similarity index 96% rename from internal/envoy/secret_test.go rename to internal/envoy/v2/secret_test.go index 810646a720b..4f413a4de21 100644 --- a/internal/envoy/secret_test.go +++ b/internal/envoy/v2/secret_test.go @@ -11,11 +11,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( "testing" + "github.com/projectcontour/contour/internal/envoy" + envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" "github.com/projectcontour/contour/internal/dag" @@ -110,7 +112,7 @@ func TestSecretname(t *testing.T) { for name, tc := range tests { t.Run(name, func(t *testing.T) { - got := Secretname(tc.secret) + got := envoy.Secretname(tc.secret) assert.Equal(t, tc.want, got) }) } diff --git a/internal/envoy/socket.go b/internal/envoy/v2/socket.go similarity index 99% rename from internal/envoy/socket.go rename to internal/envoy/v2/socket.go index 93ed67198cb..ae1a2f4ffc5 100644 --- a/internal/envoy/socket.go +++ b/internal/envoy/v2/socket.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" diff --git a/internal/envoy/socket_test.go b/internal/envoy/v2/socket_test.go similarity index 99% rename from internal/envoy/socket_test.go rename to internal/envoy/v2/socket_test.go index b347fc289c7..6e8bcda9850 100644 --- a/internal/envoy/socket_test.go +++ b/internal/envoy/v2/socket_test.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( "testing" diff --git a/internal/envoy/stats.go b/internal/envoy/v2/stats.go similarity index 99% rename from internal/envoy/stats.go rename to internal/envoy/v2/stats.go index 4f7738b7a88..74dd7acee77 100644 --- a/internal/envoy/stats.go +++ b/internal/envoy/v2/stats.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" diff --git a/internal/envoy/stats_test.go b/internal/envoy/v2/stats_test.go similarity index 99% rename from internal/envoy/stats_test.go rename to internal/envoy/v2/stats_test.go index e35b2d779aa..4289ff0f948 100644 --- a/internal/envoy/stats_test.go +++ b/internal/envoy/v2/stats_test.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package envoy +package v2 import ( "testing" diff --git a/internal/envoy/v2/tcp_keepalive.go b/internal/envoy/v2/tcp_keepalive.go new file mode 100644 index 00000000000..c26f4e35d44 --- /dev/null +++ b/internal/envoy/v2/tcp_keepalive.go @@ -0,0 +1,62 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v2 + +import ( + envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" + "github.com/projectcontour/contour/internal/envoy" +) + +func TCPKeepaliveSocketOptions() []*envoy_api_v2_core.SocketOption { + + // Note: TCP_KEEPIDLE + (TCP_KEEPINTVL * TCP_KEEPCNT) must be greater than + // the grpc.KeepaliveParams time + timeout (currently 60 + 20 = 80 seconds) + // otherwise TestGRPC/StreamClusters fails. + return []*envoy_api_v2_core.SocketOption{ + // Enable TCP keep-alive. + { + Description: "Enable TCP keep-alive", + Level: envoy.SOL_SOCKET, + Name: envoy.SO_KEEPALIVE, + Value: &envoy_api_v2_core.SocketOption_IntValue{IntValue: 1}, + State: envoy_api_v2_core.SocketOption_STATE_LISTENING, + }, + // The time (in seconds) the connection needs to remain idle + // before TCP starts sending keepalive probes. + { + Description: "TCP keep-alive initial idle time", + Level: envoy.IPPROTO_TCP, + Name: envoy.TCP_KEEPIDLE, + Value: &envoy_api_v2_core.SocketOption_IntValue{IntValue: 45}, + State: envoy_api_v2_core.SocketOption_STATE_LISTENING, + }, + // The time (in seconds) between individual keepalive probes. + { + Description: "TCP keep-alive time between probes", + Level: envoy.IPPROTO_TCP, + Name: envoy.TCP_KEEPINTVL, + Value: &envoy_api_v2_core.SocketOption_IntValue{IntValue: 5}, + State: envoy_api_v2_core.SocketOption_STATE_LISTENING, + }, + // The maximum number of TCP keep-alive probes to send before + // giving up and killing the connection if no response is + // obtained from the other end. + { + Description: "TCP keep-alive probe count", + Level: envoy.IPPROTO_TCP, + Name: envoy.TCP_KEEPCNT, + Value: &envoy_api_v2_core.SocketOption_IntValue{IntValue: 9}, + State: envoy_api_v2_core.SocketOption_STATE_LISTENING, + }, + } +} diff --git a/internal/featuretests/authorization_test.go b/internal/featuretests/authorization_test.go index 29d992675ac..3a5c5312097 100644 --- a/internal/featuretests/authorization_test.go +++ b/internal/featuretests/authorization_test.go @@ -18,6 +18,8 @@ import ( "testing" "time" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" @@ -26,7 +28,6 @@ import ( envoy_type "github.com/envoyproxy/go-control-plane/envoy/type" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" "github.com/projectcontour/contour/internal/k8s" "github.com/projectcontour/contour/internal/protobuf" @@ -76,9 +77,9 @@ func authzResponseTimeout(t *testing.T, rh cache.ResourceEventHandler, c *Contou defaultHTTPListener(), &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ filterchaintls(fqdn, @@ -100,7 +101,7 @@ func authzResponseTimeout(t *testing.T, rh cache.ResourceEventHandler, c *Contou ), nil, "h2", "http/1.1"), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener()), }).Status(p).Like(projcontour.HTTPProxyStatus{ @@ -168,9 +169,9 @@ func authzFailOpen(t *testing.T, rh cache.ResourceEventHandler, c *Contour) { defaultHTTPListener(), &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ filterchaintls(fqdn, @@ -193,7 +194,7 @@ func authzFailOpen(t *testing.T, rh cache.ResourceEventHandler, c *Contour) { ), nil, "h2", "http/1.1"), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener()), }).Status(p).Like(projcontour.HTTPProxyStatus{ @@ -291,9 +292,9 @@ func authzOverrideDisabled(t *testing.T, rh cache.ResourceEventHandler, c *Conto c.Request(routeType).Equals(&v2.DiscoveryResponse{ TypeUrl: routeType, Resources: resources(t, - envoy.RouteConfiguration( + v22.RouteConfiguration( path.Join("https", disabled), - envoy.VirtualHost(disabled, + v22.VirtualHost(disabled, &envoy_api_v2_route.Route{ Match: routePrefix("/enabled"), Action: routeCluster("default/app-server/80/da39a3ee5e"), @@ -305,9 +306,9 @@ func authzOverrideDisabled(t *testing.T, rh cache.ResourceEventHandler, c *Conto }, ), ), - envoy.RouteConfiguration( + v22.RouteConfiguration( path.Join("https", enabled), - envoy.VirtualHost(enabled, + v22.VirtualHost(enabled, &envoy_api_v2_route.Route{ Match: routePrefix("/disabled"), Action: routeCluster("default/app-server/80/da39a3ee5e"), @@ -319,9 +320,9 @@ func authzOverrideDisabled(t *testing.T, rh cache.ResourceEventHandler, c *Conto }, ), ), - envoy.RouteConfiguration( + v22.RouteConfiguration( "ingress_http", - envoy.VirtualHost(disabled, + v22.VirtualHost(disabled, &envoy_api_v2_route.Route{ Match: routePrefix("/enabled"), Action: withRedirect(), @@ -331,7 +332,7 @@ func authzOverrideDisabled(t *testing.T, rh cache.ResourceEventHandler, c *Conto Action: withRedirect(), }, ), - envoy.VirtualHost(enabled, + v22.VirtualHost(enabled, &envoy_api_v2_route.Route{ Match: routePrefix("/disabled"), Action: withRedirect(), @@ -399,9 +400,9 @@ func authzMergeRouteContext(t *testing.T, rh cache.ResourceEventHandler, c *Cont c.Request(routeType).Equals(&v2.DiscoveryResponse{ TypeUrl: routeType, Resources: resources(t, - envoy.RouteConfiguration( + v22.RouteConfiguration( path.Join("https", fqdn), - envoy.VirtualHost(fqdn, + v22.VirtualHost(fqdn, &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/app-server/80/da39a3ee5e"), @@ -416,9 +417,9 @@ func authzMergeRouteContext(t *testing.T, rh cache.ResourceEventHandler, c *Cont }, ), ), - envoy.RouteConfiguration( + v22.RouteConfiguration( "ingress_http", - envoy.VirtualHost(fqdn, + v22.VirtualHost(fqdn, &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withRedirect(), @@ -493,9 +494,9 @@ func authzInvalidReference(t *testing.T, rh cache.ResourceEventHandler, c *Conto defaultHTTPListener(), &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ filterchaintls(fqdn, @@ -518,7 +519,7 @@ func authzInvalidReference(t *testing.T, rh cache.ResourceEventHandler, c *Conto ), nil, "h2", "http/1.1"), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener()), }).Status(invalid).Like(projcontour.HTTPProxyStatus{ diff --git a/internal/featuretests/backendcavalidation_test.go b/internal/featuretests/backendcavalidation_test.go index ec159754ee9..a6958e6621c 100644 --- a/internal/featuretests/backendcavalidation_test.go +++ b/internal/featuretests/backendcavalidation_test.go @@ -16,10 +16,11 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -71,11 +72,11 @@ func TestClusterServiceTLSBackendCAValidation(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -119,11 +120,11 @@ func TestClusterServiceTLSBackendCAValidation(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -176,11 +177,11 @@ func TestClusterServiceTLSBackendCAValidation(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), diff --git a/internal/featuretests/cluster_test.go b/internal/featuretests/cluster_test.go index 99d3e919908..fe8addea0c0 100644 --- a/internal/featuretests/cluster_test.go +++ b/internal/featuretests/cluster_test.go @@ -16,10 +16,11 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" envoy_cluster "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" "github.com/projectcontour/contour/internal/protobuf" @@ -426,9 +427,9 @@ func TestClusterCircuitbreakerAnnotations(t *testing.T) { DefaultCluster(&v2.Cluster{ Name: "default/kuard/8080/da39a3ee5e", AltStatName: "default_kuard_8080", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, CircuitBreakers: &envoy_cluster.CircuitBreakers{ @@ -459,9 +460,9 @@ func TestClusterCircuitbreakerAnnotations(t *testing.T) { DefaultCluster(&v2.Cluster{ Name: "default/kuard/8080/da39a3ee5e", AltStatName: "default_kuard_8080", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, CircuitBreakers: &envoy_cluster.CircuitBreakers{ @@ -571,9 +572,9 @@ func TestClusterLoadBalancerStrategyPerRoute(t *testing.T) { DefaultCluster(&v2.Cluster{ Name: "default/kuard/80/58d888c08a", AltStatName: "default_kuard_80", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, LbPolicy: v2.Cluster_RANDOM, @@ -581,9 +582,9 @@ func TestClusterLoadBalancerStrategyPerRoute(t *testing.T) { DefaultCluster(&v2.Cluster{ Name: "default/kuard/80/8bf87fefba", AltStatName: "default_kuard_80", - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: "default/kuard", }, LbPolicy: v2.Cluster_LEAST_REQUEST, diff --git a/internal/featuretests/downstreamvalidation_test.go b/internal/featuretests/downstreamvalidation_test.go index 30741627f2d..29d5d4cb767 100644 --- a/internal/featuretests/downstreamvalidation_test.go +++ b/internal/featuretests/downstreamvalidation_test.go @@ -16,10 +16,11 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" "github.com/projectcontour/contour/internal/k8s" v1 "k8s.io/api/core/v1" @@ -79,18 +80,18 @@ func TestDownstreamTLSCertificateValidation(t *testing.T) { ingress_http := &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } ingress_https := &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: appendFilterChains( filterchaintls("example.com", serverTLSSecret, @@ -103,7 +104,7 @@ func TestDownstreamTLSCertificateValidation(t *testing.T) { "h2", "http/1.1", ), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } c.Request(listenerType).Equals(&v2.DiscoveryResponse{ diff --git a/internal/featuretests/endpoints_test.go b/internal/featuretests/endpoints_test.go index 3ff8bc69bd6..8a2c1836c89 100644 --- a/internal/featuretests/endpoints_test.go +++ b/internal/featuretests/endpoints_test.go @@ -16,9 +16,10 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" ) @@ -74,16 +75,16 @@ func TestAddRemoveEndpoints(t *testing.T) { Resources: resources(t, &v2.ClusterLoadAssignment{ ClusterName: "super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/http", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("172.16.0.1", 8000), // endpoints and cluster names should be sorted - envoy.SocketAddress("172.16.0.2", 8000), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("172.16.0.1", 8000), // endpoints and cluster names should be sorted + v22.SocketAddress("172.16.0.2", 8000), ), }, &v2.ClusterLoadAssignment{ ClusterName: "super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/https", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("172.16.0.1", 8443), - envoy.SocketAddress("172.16.0.2", 8443), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("172.16.0.1", 8443), + v22.SocketAddress("172.16.0.2", 8443), ), }, ), @@ -95,8 +96,8 @@ func TestAddRemoveEndpoints(t *testing.T) { c.Request(endpointType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/http"), - envoy.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/https"), + v22.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/http"), + v22.ClusterLoadAssignment("super-long-namespace-name-oh-boy/what-a-descriptive-service-name-you-must-be-so-proud/https"), ), TypeUrl: endpointType, }) @@ -166,15 +167,15 @@ func TestAddEndpointComplicated(t *testing.T) { Resources: resources(t, &v2.ClusterLoadAssignment{ ClusterName: "default/kuard/admin", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("10.48.1.77", 9000), - envoy.SocketAddress("10.48.1.78", 9000), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("10.48.1.77", 9000), + v22.SocketAddress("10.48.1.78", 9000), ), }, &v2.ClusterLoadAssignment{ ClusterName: "default/kuard/foo", - Endpoints: envoy.WeightedEndpoints(1, - envoy.SocketAddress("10.48.1.78", 8080), + Endpoints: v22.WeightedEndpoints(1, + v22.SocketAddress("10.48.1.78", 8080), ), }, ), @@ -234,7 +235,7 @@ func TestEndpointFilter(t *testing.T) { Resources: resources(t, &v2.ClusterLoadAssignment{ ClusterName: "default/kuard/foo", - Endpoints: envoy.WeightedEndpoints(1, envoy.SocketAddress("10.48.1.78", 8080)), + Endpoints: v22.WeightedEndpoints(1, v22.SocketAddress("10.48.1.78", 8080)), }, ), }) @@ -242,7 +243,7 @@ func TestEndpointFilter(t *testing.T) { c.Request(endpointType, "default/kuard/bar").Equals(&v2.DiscoveryResponse{ TypeUrl: endpointType, Resources: resources(t, - envoy.ClusterLoadAssignment("default/kuard/bar"), + v22.ClusterLoadAssignment("default/kuard/bar"), ), }) } @@ -282,7 +283,7 @@ func TestIssue602(t *testing.T) { Resources: resources(t, &v2.ClusterLoadAssignment{ ClusterName: "default/simple", - Endpoints: envoy.WeightedEndpoints(1, envoy.SocketAddress("192.168.183.24", 8080)), + Endpoints: v22.WeightedEndpoints(1, v22.SocketAddress("192.168.183.24", 8080)), }, ), TypeUrl: endpointType, @@ -293,7 +294,7 @@ func TestIssue602(t *testing.T) { rh.OnUpdate(e1, e2) c.Request(endpointType).Equals(&v2.DiscoveryResponse{ - Resources: resources(t, envoy.ClusterLoadAssignment("default/simple")), + Resources: resources(t, v22.ClusterLoadAssignment("default/simple")), TypeUrl: endpointType, }) } diff --git a/internal/featuretests/envoy.go b/internal/featuretests/envoy.go index 14732971725..0bd99125333 100644 --- a/internal/featuretests/envoy.go +++ b/internal/featuretests/envoy.go @@ -19,6 +19,8 @@ import ( "path" "time" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" @@ -32,7 +34,6 @@ import ( "github.com/golang/protobuf/ptypes/any" "github.com/projectcontour/contour/internal/contour" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/protobuf" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -46,7 +47,7 @@ func DefaultCluster(clusters ...*v2.Cluster) *v2.Cluster { defaults := &v2.Cluster{ ConnectTimeout: protobuf.Duration(250 * time.Millisecond), LbPolicy: v2.Cluster_ROUND_ROBIN, - CommonLbConfig: envoy.ClusterCommonLBConfig(), + CommonLbConfig: v22.ClusterCommonLBConfig(), } for _, c := range clusters { @@ -77,12 +78,12 @@ func clusterWithHealthCheck(name, servicename, statName, healthCheckPath string, func externalNameCluster(name, servicename, statName, externalName string, port int) *v2.Cluster { return DefaultCluster(&v2.Cluster{ Name: name, - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_STRICT_DNS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_STRICT_DNS), AltStatName: statName, LoadAssignment: &v2.ClusterLoadAssignment{ ClusterName: servicename, - Endpoints: envoy.Endpoints( - envoy.SocketAddress(externalName, port), + Endpoints: v22.Endpoints( + v22.SocketAddress(externalName, port), ), }, }) @@ -99,7 +100,7 @@ func routeCluster(cluster string) *envoy_api_v2_route.Route_Route { } func routePrefix(prefix string, headers ...dag.HeaderMatchCondition) *envoy_api_v2_route.RouteMatch { - return envoy.RouteMatch(&dag.Route{ + return v22.RouteMatch(&dag.Route{ PathMatchCondition: &dag.PrefixMatchCondition{ Prefix: prefix, }, @@ -119,25 +120,25 @@ func routeHostRewrite(cluster, newHostName string) *envoy_api_v2_route.Route_Rou func upgradeHTTPS(match *envoy_api_v2_route.RouteMatch) *envoy_api_v2_route.Route { return &envoy_api_v2_route.Route{ Match: match, - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), } } func cluster(name, servicename, statName string) *v2.Cluster { return DefaultCluster(&v2.Cluster{ Name: name, - ClusterDiscoveryType: envoy.ClusterDiscoveryType(v2.Cluster_EDS), + ClusterDiscoveryType: v22.ClusterDiscoveryType(v2.Cluster_EDS), AltStatName: statName, EdsClusterConfig: &v2.Cluster_EdsClusterConfig{ - EdsConfig: envoy.ConfigSource("contour"), + EdsConfig: v22.ConfigSource("contour"), ServiceName: servicename, }, }) } func tlsCluster(c *v2.Cluster, ca []byte, subjectName string, sni string, alpnProtocols ...string) *v2.Cluster { - c.TransportSocket = envoy.UpstreamTLSTransportSocket( - envoy.UpstreamTLSContext( + c.TransportSocket = v22.UpstreamTLSTransportSocket( + v22.UpstreamTLSContext( &dag.PeerValidationContext{ CACertificate: &dag.Secret{Object: &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ @@ -269,43 +270,43 @@ func appendFilterChains(chains ...*envoy_api_v2_listener.FilterChain) []*envoy_a // filterchaintls returns a FilterChain wrapping the given virtual host. func filterchaintls(domain string, secret *v1.Secret, filter *envoy_api_v2_listener.Filter, peerValidationContext *dag.PeerValidationContext, alpn ...string) *envoy_api_v2_listener.FilterChain { - return envoy.FilterChainTLS( + return v22.FilterChainTLS( domain, - envoy.DownstreamTLSContext( + v22.DownstreamTLSContext( &dag.Secret{Object: secret}, envoy_api_v2_auth.TlsParameters_TLSv1_1, peerValidationContext, alpn...), - envoy.Filters(filter), + v22.Filters(filter), ) } // filterchaintlsfallback returns a FilterChain for the given TLS fallback certificate. func filterchaintlsfallback(fallbackSecret *v1.Secret, peerValidationContext *dag.PeerValidationContext, alpn ...string) *envoy_api_v2_listener.FilterChain { - return envoy.FilterChainTLSFallback( - envoy.DownstreamTLSContext( + return v22.FilterChainTLSFallback( + v22.DownstreamTLSContext( &dag.Secret{Object: fallbackSecret}, envoy_api_v2_auth.TlsParameters_TLSv1_1, peerValidationContext, alpn...), - envoy.Filters( - envoy.HTTPConnectionManagerBuilder(). + v22.Filters( + v22.HTTPConnectionManagerBuilder(). DefaultFilters(). RouteConfigName(contour.ENVOY_FALLBACK_ROUTECONFIG). MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). + AccessLoggers(v22.FileAccessLogEnvoy("/dev/stdout")). Get(), ), ) } func httpsFilterFor(vhost string) *envoy_api_v2_listener.Filter { - return envoy.HTTPConnectionManagerBuilder(). - AddFilter(envoy.FilterMisdirectedRequests(vhost)). + return v22.HTTPConnectionManagerBuilder(). + AddFilter(v22.FilterMisdirectedRequests(vhost)). DefaultFilters(). RouteConfigName(path.Join("https", vhost)). MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). + AccessLoggers(v22.FileAccessLogEnvoy("/dev/stdout")). Get() } @@ -316,8 +317,8 @@ func authzFilterFor( vhost string, authz *envoy_config_filter_http_ext_authz_v2.ExtAuthz, ) *envoy_api_v2_listener.Filter { - return envoy.HTTPConnectionManagerBuilder(). - AddFilter(envoy.FilterMisdirectedRequests(vhost)). + return v22.HTTPConnectionManagerBuilder(). + AddFilter(v22.FilterMisdirectedRequests(vhost)). DefaultFilters(). AddFilter(&http.HttpFilter{ Name: "envoy.filters.http.ext_authz", @@ -327,7 +328,7 @@ func authzFilterFor( }). RouteConfigName(path.Join("https", vhost)). MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). + AccessLoggers(v22.FileAccessLogEnvoy("/dev/stdout")). Get() } @@ -340,7 +341,7 @@ func tcpproxy(statPrefix, cluster string) *envoy_api_v2_listener.Filter { ClusterSpecifier: &envoy_config_v2_tcpproxy.TcpProxy_Cluster{ Cluster: cluster, }, - AccessLog: envoy.FileAccessLogEnvoy("/dev/stdout"), + AccessLog: v22.FileAccessLogEnvoy("/dev/stdout"), IdleTimeout: protobuf.Duration(9001 * time.Second), }), }, @@ -348,16 +349,16 @@ func tcpproxy(statPrefix, cluster string) *envoy_api_v2_listener.Filter { } func staticListener() *v2.Listener { - return envoy.StatsListener("0.0.0.0", 8002) + return v22.StatsListener("0.0.0.0", 8002) } func defaultHTTPListener() *v2.Listener { return &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } } diff --git a/internal/featuretests/extensionservice_test.go b/internal/featuretests/extensionservice_test.go index fc0f508fa6d..cfb319a7ac2 100644 --- a/internal/featuretests/extensionservice_test.go +++ b/internal/featuretests/extensionservice_test.go @@ -16,6 +16,8 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" @@ -24,7 +26,6 @@ import ( projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" corev1 "k8s.io/api/core/v1" "k8s.io/client-go/tools/cache" @@ -48,7 +49,7 @@ func extBasic(t *testing.T, rh cache.ResourceEventHandler, c *Contour) { DefaultCluster( h2cCluster(cluster("extension/ns/ext", "extension/ns/ext", "extension_ns_ext")), &v2.Cluster{ - TransportSocket: envoy.UpstreamTLSTransportSocket( + TransportSocket: v22.UpstreamTLSTransportSocket( &envoy_api_v2_auth.UpstreamTlsContext{ CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ AlpnProtocols: []string{"h2"}, @@ -66,8 +67,8 @@ func extBasic(t *testing.T, rh cache.ResourceEventHandler, c *Contour) { Resources: resources(t, &v2.ClusterLoadAssignment{ ClusterName: "extension/ns/ext", Endpoints: []*envoy_api_v2_endpoint.LocalityLbEndpoints{ - envoy.WeightedEndpoints(1, envoy.SocketAddress("192.168.183.20", 8081))[0], - envoy.WeightedEndpoints(1, envoy.SocketAddress("192.168.183.21", 8082))[0], + v22.WeightedEndpoints(1, v22.SocketAddress("192.168.183.20", 8081))[0], + v22.WeightedEndpoints(1, v22.SocketAddress("192.168.183.21", 8082))[0], }, }), }) @@ -112,7 +113,7 @@ func extUpstreamValidation(t *testing.T, rh cache.ResourceEventHandler, c *Conto rh.OnAdd(ext) // Enabling validation add SNI as well as CA and server altname validation. - tlsSocket := envoy.UpstreamTLSTransportSocket( + tlsSocket := v22.UpstreamTLSTransportSocket( &envoy_api_v2_auth.UpstreamTlsContext{ Sni: "ext.projectcontour.io", CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ diff --git a/internal/featuretests/externalname_test.go b/internal/featuretests/externalname_test.go index dc99d58e104..3622cf3c979 100644 --- a/internal/featuretests/externalname_test.go +++ b/internal/featuretests/externalname_test.go @@ -16,11 +16,12 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" "k8s.io/api/networking/v1beta1" @@ -62,8 +63,8 @@ func TestExternalNameService(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/80/da39a3ee5e"), @@ -97,8 +98,8 @@ func TestExternalNameService(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/80/da39a3ee5e"), @@ -140,8 +141,8 @@ func TestExternalNameService(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ TypeUrl: routeType, Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeHostRewrite("default/kuard/80/da39a3ee5e", "external.address"), @@ -185,8 +186,8 @@ func TestExternalNameService(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ TypeUrl: routeType, Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeHostRewrite("default/kuard/80/da39a3ee5e", "external.address"), @@ -205,8 +206,8 @@ func TestExternalNameService(t *testing.T) { Http2ProtocolOptions: &envoy_api_v2_core.Http2ProtocolOptions{}, }, &v2.Cluster{ - TransportSocket: envoy.UpstreamTLSTransportSocket( - envoy.UpstreamTLSContext(nil, "external.address", "h2"), + TransportSocket: v22.UpstreamTLSTransportSocket( + v22.UpstreamTLSContext(nil, "external.address", "h2"), ), }, ), @@ -240,8 +241,8 @@ func TestExternalNameService(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ TypeUrl: routeType, Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeHostRewrite("default/kuard/80/da39a3ee5e", "external.address"), @@ -257,8 +258,8 @@ func TestExternalNameService(t *testing.T) { DefaultCluster( externalNameCluster("default/kuard/80/da39a3ee5e", "default/kuard", "default_kuard_80", "foo.io", 80), &v2.Cluster{ - TransportSocket: envoy.UpstreamTLSTransportSocket( - envoy.UpstreamTLSContext(nil, "external.address"), + TransportSocket: v22.UpstreamTLSTransportSocket( + v22.UpstreamTLSContext(nil, "external.address"), ), }, ), diff --git a/internal/featuretests/fallbackcert_test.go b/internal/featuretests/fallbackcert_test.go index ce4dc542dfd..fb4787d995b 100644 --- a/internal/featuretests/fallbackcert_test.go +++ b/internal/featuretests/fallbackcert_test.go @@ -16,13 +16,14 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/contour" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -95,16 +96,16 @@ func TestFallbackCertificate(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: appendFilterChains( filterchaintls("fallback.example.com", sec1, httpsFilterFor("fallback.example.com"), nil, "h2", "http/1.1"), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, ), }) @@ -157,9 +158,9 @@ func TestFallbackCertificate(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: appendFilterChains( filterchaintls("fallback.example.com", sec1, @@ -167,7 +168,7 @@ func TestFallbackCertificate(t *testing.T) { nil, "h2", "http/1.1"), filterchaintlsfallback(fallbackSecret, nil, "h2", "http/1.1"), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, ), }) @@ -199,9 +200,9 @@ func TestFallbackCertificate(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: appendFilterChains( filterchaintls("fallback.example.com", sec1, @@ -209,7 +210,7 @@ func TestFallbackCertificate(t *testing.T) { nil, "h2", "http/1.1"), filterchaintlsfallback(fallbackSecret, nil, "h2", "http/1.1"), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, ), }) @@ -268,9 +269,9 @@ func TestFallbackCertificate(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: appendFilterChains( filterchaintls("anotherfallback.example.com", sec1, @@ -281,7 +282,7 @@ func TestFallbackCertificate(t *testing.T) { nil, "h2", "http/1.1"), filterchaintlsfallback(fallbackSecret, nil, "h2", "http/1.1"), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, ), }) diff --git a/internal/featuretests/headercondition_test.go b/internal/featuretests/headercondition_test.go index d6b545c2d8a..99f8f6d0474 100644 --- a/internal/featuretests/headercondition_test.go +++ b/internal/featuretests/headercondition_test.go @@ -16,11 +16,12 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -80,8 +81,8 @@ func TestConditions_ContainsHeader_HTTProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/blog", dag.HeaderMatchCondition{ Name: "x-header", @@ -143,8 +144,8 @@ func TestConditions_ContainsHeader_HTTProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/blog", dag.HeaderMatchCondition{ Name: "x-header", @@ -206,8 +207,8 @@ func TestConditions_ContainsHeader_HTTProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/blog", dag.HeaderMatchCondition{ Name: "x-header", @@ -269,8 +270,8 @@ func TestConditions_ContainsHeader_HTTProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/blog", dag.HeaderMatchCondition{ Name: "x-header", @@ -332,8 +333,8 @@ func TestConditions_ContainsHeader_HTTProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/blog", dag.HeaderMatchCondition{ Name: "x-header", @@ -393,8 +394,8 @@ func TestConditions_ContainsHeader_HTTProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/", dag.HeaderMatchCondition{ Name: "x-header", @@ -452,8 +453,8 @@ func TestConditions_ContainsHeader_HTTProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/", dag.HeaderMatchCondition{ Name: "x-header", diff --git a/internal/featuretests/headerpolicy_test.go b/internal/featuretests/headerpolicy_test.go index c4d40ffa551..68ffda21028 100644 --- a/internal/featuretests/headerpolicy_test.go +++ b/internal/featuretests/headerpolicy_test.go @@ -17,7 +17,7 @@ import ( envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" "github.com/golang/protobuf/ptypes/wrappers" - "github.com/projectcontour/contour/internal/envoy" + v22 "github.com/projectcontour/contour/internal/envoy/v2" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" @@ -57,8 +57,8 @@ func TestHeaderPolicy_ReplaceHeader_HTTProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeHostRewrite("default/svc1/80/da39a3ee5e", "goodbye.planet"), @@ -90,8 +90,8 @@ func TestHeaderPolicy_ReplaceHeader_HTTProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/svc1/80/da39a3ee5e"), @@ -131,8 +131,8 @@ func TestHeaderPolicy_ReplaceHeader_HTTProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/svc1/80/da39a3ee5e"), @@ -188,8 +188,8 @@ func TestHeaderPolicy_ReplaceHeader_HTTProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: &envoy_api_v2_route.Route_Redirect{ @@ -201,8 +201,8 @@ func TestHeaderPolicy_ReplaceHeader_HTTProxy(t *testing.T) { }, }), ), - envoy.RouteConfiguration("https/hello.world", - envoy.VirtualHost("hello.world", + v22.RouteConfiguration("https/hello.world", + v22.VirtualHost("hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeHostRewrite("default/externalname/443/da39a3ee5e", "goodbye.planet"), diff --git a/internal/featuretests/ingressclass_test.go b/internal/featuretests/ingressclass_test.go index 717da672c5f..6150034741e 100644 --- a/internal/featuretests/ingressclass_test.go +++ b/internal/featuretests/ingressclass_test.go @@ -16,11 +16,12 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/contour" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" "github.com/projectcontour/contour/internal/k8s" v1 "k8s.io/api/core/v1" @@ -65,8 +66,8 @@ func TestIngressClassAnnotation_Configured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -95,7 +96,7 @@ func TestIngressClassAnnotation_Configured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -114,7 +115,7 @@ func TestIngressClassAnnotation_Configured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -124,8 +125,8 @@ func TestIngressClassAnnotation_Configured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -141,7 +142,7 @@ func TestIngressClassAnnotation_Configured(t *testing.T) { // verify ingress is gone c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -168,8 +169,8 @@ func TestIngressClassAnnotation_Configured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -200,7 +201,7 @@ func TestIngressClassAnnotation_Configured(t *testing.T) { // ingress class does not match ingress controller, ignored. c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -224,7 +225,7 @@ func TestIngressClassAnnotation_Configured(t *testing.T) { // ingress class does not match ingress controller, ignored. c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -234,8 +235,8 @@ func TestIngressClassAnnotation_Configured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -251,7 +252,7 @@ func TestIngressClassAnnotation_Configured(t *testing.T) { // verify ingress is gone c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -287,8 +288,8 @@ func TestIngressClassAnnotation_NotConfigured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -317,8 +318,8 @@ func TestIngressClassAnnotation_NotConfigured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -346,7 +347,7 @@ func TestIngressClassAnnotation_NotConfigured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -356,8 +357,8 @@ func TestIngressClassAnnotation_NotConfigured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -373,7 +374,7 @@ func TestIngressClassAnnotation_NotConfigured(t *testing.T) { // verify ingress is gone c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -399,8 +400,8 @@ func TestIngressClassAnnotation_NotConfigured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -430,8 +431,8 @@ func TestIngressClassAnnotation_NotConfigured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -462,7 +463,7 @@ func TestIngressClassAnnotation_NotConfigured(t *testing.T) { // ingress class does not match ingress controller, ignored. c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -472,8 +473,8 @@ func TestIngressClassAnnotation_NotConfigured(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -489,7 +490,7 @@ func TestIngressClassAnnotation_NotConfigured(t *testing.T) { // verify ingress is gone c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -532,8 +533,8 @@ func TestIngressClassUpdate(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -557,7 +558,7 @@ func TestIngressClassUpdate(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }).NoStatus(vhost) diff --git a/internal/featuretests/listeners_test.go b/internal/featuretests/listeners_test.go index 64f49518467..b23a6ba78f7 100644 --- a/internal/featuretests/listeners_test.go +++ b/internal/featuretests/listeners_test.go @@ -16,13 +16,14 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/contour" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" "k8s.io/api/networking/v1beta1" @@ -68,9 +69,9 @@ func TestNonTLSListener(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -127,9 +128,9 @@ func TestNonTLSListener(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -198,22 +199,22 @@ func TestTLSListener(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ filterchaintls("kuard.example.com", s1, httpsFilterFor("kuard.example.com"), nil, "h2", "http/1.1"), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -256,16 +257,16 @@ func TestTLSListener(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ filterchaintls("kuard.example.com", s1, httpsFilterFor("kuard.example.com"), nil, "h2", "http/1.1"), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -364,16 +365,16 @@ func TestHTTPProxyTLSListener(t *testing.T) { l1 := &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ filterchaintls("kuard.example.com", secret1, httpsFilterFor("kuard.example.com"), nil, "h2", "http/1.1"), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } // add service @@ -386,11 +387,11 @@ func TestHTTPProxyTLSListener(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, l1, staticListener(), @@ -413,22 +414,22 @@ func TestHTTPProxyTLSListener(t *testing.T) { rh.OnAdd(secret1) l2 := &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ - envoy.FilterChainTLS( + v22.FilterChainTLS( "kuard.example.com", - envoy.DownstreamTLSContext( + v22.DownstreamTLSContext( &dag.Secret{Object: secret1}, envoy_api_v2_auth.TlsParameters_TLSv1_3, nil, "h2", "http/1.1"), - envoy.Filters(httpsFilterFor("kuard.example.com")), + v22.Filters(httpsFilterFor("kuard.example.com")), ), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } // add ingress and assert the existence of ingress_http and ingres_https @@ -437,11 +438,11 @@ func TestHTTPProxyTLSListener(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, l2, staticListener(), @@ -503,16 +504,16 @@ func TestLDSFilter(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ filterchaintls("kuard.example.com", s1, httpsFilterFor("kuard.example.com"), nil, "h2", "http/1.1"), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, ), TypeUrl: listenerType, @@ -523,11 +524,11 @@ func TestLDSFilter(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, ), TypeUrl: listenerType, @@ -593,12 +594,12 @@ func TestLDSIngressHTTPUseProxyProtocol(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - ListenerFilters: envoy.ListenerFilters( - envoy.ProxyProtocol(), + Address: v22.SocketAddress("0.0.0.0", 8080), + ListenerFilters: v22.ListenerFilters( + v22.ProxyProtocol(), ), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -670,28 +671,28 @@ func TestLDSIngressHTTPSUseProxyProtocol(t *testing.T) { ingress_https := &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.ProxyProtocol(), - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.ProxyProtocol(), + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ filterchaintls("kuard.example.com", s1, httpsFilterFor("kuard.example.com"), nil, "h2", "http/1.1"), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } c.Request(listenerType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - ListenerFilters: envoy.ListenerFilters( - envoy.ProxyProtocol(), + Address: v22.SocketAddress("0.0.0.0", 8080), + ListenerFilters: v22.ListenerFilters( + v22.ProxyProtocol(), ), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0)), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + FilterChains: v22.FilterChains(v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0)), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, ingress_https, staticListener(), @@ -768,24 +769,24 @@ func TestLDSCustomAddressAndPort(t *testing.T) { ingress_http := &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("127.0.0.100", 9100), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("127.0.0.100", 9100), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } ingress_https := &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("127.0.0.200", 9200), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("127.0.0.200", 9200), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ filterchaintls("kuard.example.com", s1, httpsFilterFor("kuard.example.com"), nil, "h2", "http/1.1"), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } c.Request(listenerType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, @@ -861,30 +862,30 @@ func TestLDSCustomAccessLogPaths(t *testing.T) { ingress_http := &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/tmp/http_access.log"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/tmp/http_access.log"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } ingress_https := &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ filterchaintls("kuard.example.com", s1, - envoy.HTTPConnectionManagerBuilder(). - AddFilter(envoy.FilterMisdirectedRequests("kuard.example.com")). + v22.HTTPConnectionManagerBuilder(). + AddFilter(v22.FilterMisdirectedRequests("kuard.example.com")). DefaultFilters(). RouteConfigName("https/kuard.example.com"). MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/tmp/https_access.log")). + AccessLoggers(v22.FileAccessLogEnvoy("/tmp/https_access.log")). Get(), nil, "h2", "http/1.1"), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } c.Request(listenerType).Equals(&v2.DiscoveryResponse{ VersionInfo: "1", @@ -961,25 +962,25 @@ func TestHTTPProxyHTTPS(t *testing.T) { ingressHTTP := &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } ingressHTTPS := &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ filterchaintls("example.com", s1, httpsFilterFor("example.com"), nil, "h2", "http/1.1"), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } c.Request(listenerType).Equals(&v2.DiscoveryResponse{ VersionInfo: "1", @@ -1043,22 +1044,22 @@ func TestHTTPProxyMinimumTLSVersion(t *testing.T) { l1 := &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ - envoy.FilterChainTLS( + v22.FilterChainTLS( "kuard.example.com", - envoy.DownstreamTLSContext( + v22.DownstreamTLSContext( &dag.Secret{Object: secret1}, envoy_api_v2_auth.TlsParameters_TLSv1_2, nil, "h2", "http/1.1"), - envoy.Filters(httpsFilterFor("kuard.example.com")), + v22.Filters(httpsFilterFor("kuard.example.com")), ), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } // verify that p1's TLS 1.1 minimum has been upgraded to 1.2 @@ -1066,11 +1067,11 @@ func TestHTTPProxyMinimumTLSVersion(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, l1, staticListener(), @@ -1108,22 +1109,22 @@ func TestHTTPProxyMinimumTLSVersion(t *testing.T) { l2 := &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ - envoy.FilterChainTLS( + v22.FilterChainTLS( "kuard.example.com", - envoy.DownstreamTLSContext( + v22.DownstreamTLSContext( &dag.Secret{Object: secret1}, envoy_api_v2_auth.TlsParameters_TLSv1_3, nil, "h2", "http/1.1"), - envoy.Filters(httpsFilterFor("kuard.example.com")), + v22.Filters(httpsFilterFor("kuard.example.com")), ), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } // verify that p2's TLS 1.3 minimum has NOT been downgraded to 1.2 @@ -1131,11 +1132,11 @@ func TestHTTPProxyMinimumTLSVersion(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, l2, staticListener(), @@ -1199,11 +1200,11 @@ func TestLDSHTTPProxyRootCannotDelegateToAnotherRoot(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), diff --git a/internal/featuretests/loadbalancerpolicy_test.go b/internal/featuretests/loadbalancerpolicy_test.go index 62662e0081c..13b221d943f 100644 --- a/internal/featuretests/loadbalancerpolicy_test.go +++ b/internal/featuretests/loadbalancerpolicy_test.go @@ -16,10 +16,11 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -54,8 +55,8 @@ func TestLoadBalancerPolicySessionAffinity(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/cart"), Action: withSessionAffinity(routeCluster("default/app/80/e4f81994fe")), @@ -90,8 +91,8 @@ func TestLoadBalancerPolicySessionAffinity(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/cart"), Action: withSessionAffinity( diff --git a/internal/featuretests/mirrorpolicy_test.go b/internal/featuretests/mirrorpolicy_test.go index 131d76098e2..d9f2d1dbc5a 100644 --- a/internal/featuretests/mirrorpolicy_test.go +++ b/internal/featuretests/mirrorpolicy_test.go @@ -16,11 +16,12 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/contour" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -62,8 +63,8 @@ func TestMirrorPolicy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost(p1.Spec.VirtualHost.Fqdn, + v22.RouteConfiguration("ingress_http", + v22.VirtualHost(p1.Spec.VirtualHost.Fqdn, &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withMirrorPolicy(routeCluster("default/kuard/8080/da39a3ee5e"), "default/mirror/8080/da39a3ee5e"), diff --git a/internal/featuretests/replaceprefix_test.go b/internal/featuretests/replaceprefix_test.go index a2b81f08982..d5b08d3e2f1 100644 --- a/internal/featuretests/replaceprefix_test.go +++ b/internal/featuretests/replaceprefix_test.go @@ -16,10 +16,11 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" "github.com/projectcontour/contour/internal/k8s" v1 "k8s.io/api/core/v1" @@ -69,8 +70,8 @@ func basic(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/api/"), Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/api/v1/"), @@ -99,7 +100,7 @@ func basic(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }).Status(vhost).Equals(projcontour.HTTPProxyStatus{ @@ -119,8 +120,8 @@ func basic(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/api/"), Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/api/v2/"), @@ -150,7 +151,7 @@ func basic(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }).Status(vhost).Equals(projcontour.HTTPProxyStatus{ @@ -170,8 +171,8 @@ func basic(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/api/"), Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/api/full/"), @@ -198,8 +199,8 @@ func basic(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/api/empty"), @@ -266,8 +267,8 @@ func multiInclude(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("host1.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("host1.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/v1/"), Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/api/v1/"), @@ -277,7 +278,7 @@ func multiInclude(t *testing.T) { Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/api/v1"), }, ), - envoy.VirtualHost("host2.projectcontour.io", + v22.VirtualHost("host2.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/v2/"), Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/api/v2/"), @@ -307,8 +308,8 @@ func multiInclude(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("host1.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("host1.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/v1/"), Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/api/v1/"), @@ -318,7 +319,7 @@ func multiInclude(t *testing.T) { Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/api/v1"), }, ), - envoy.VirtualHost("host2.projectcontour.io", + v22.VirtualHost("host2.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/v2"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -387,8 +388,8 @@ func replaceWithSlash(t *testing.T) { // too many '/'s. c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("host1.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("host1.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/foo/"), Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/"), @@ -398,7 +399,7 @@ func replaceWithSlash(t *testing.T) { Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/"), }, ), - envoy.VirtualHost("host2.projectcontour.io", + v22.VirtualHost("host2.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/bar/"), Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/"), @@ -432,8 +433,8 @@ func replaceWithSlash(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("host1.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("host1.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/foo/"), Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/"), @@ -443,7 +444,7 @@ func replaceWithSlash(t *testing.T) { Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/"), }, ), - envoy.VirtualHost("host2.projectcontour.io", + v22.VirtualHost("host2.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withPrefixRewrite(routeCluster("default/kuard/8080/da39a3ee5e"), "/bar"), @@ -507,8 +508,8 @@ func artifactoryDocker(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("artifactory.projectcontour.io", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("artifactory.projectcontour.io", &envoy_api_v2_route.Route{ Match: routePrefix("/v2/container-sandbox/"), diff --git a/internal/featuretests/retrypolicy_test.go b/internal/featuretests/retrypolicy_test.go index 5ed019dafe1..6828711ffb1 100644 --- a/internal/featuretests/retrypolicy_test.go +++ b/internal/featuretests/retrypolicy_test.go @@ -17,10 +17,11 @@ import ( "testing" "time" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" "k8s.io/api/networking/v1beta1" @@ -54,8 +55,8 @@ func TestRetryPolicy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withRetryPolicy(routeCluster("default/backend/80/da39a3ee5e"), "5xx,gateway-error", 7, 120*time.Millisecond), @@ -83,8 +84,8 @@ func TestRetryPolicy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withRetryPolicy(routeCluster("default/backend/80/da39a3ee5e"), "5xx,gateway-error", 7, 120*time.Millisecond), @@ -112,8 +113,8 @@ func TestRetryPolicy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withRetryPolicy(routeCluster("default/backend/80/da39a3ee5e"), "5xx,gateway-error", 7, 120*time.Millisecond), @@ -149,8 +150,8 @@ func TestRetryPolicy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost(hp1.Spec.VirtualHost.Fqdn, + v22.RouteConfiguration("ingress_http", + v22.VirtualHost(hp1.Spec.VirtualHost.Fqdn, &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withRetryPolicy(routeCluster("default/backend/80/da39a3ee5e"), "5xx", 5, 105*time.Second), diff --git a/internal/featuretests/rootnamespaces_test.go b/internal/featuretests/rootnamespaces_test.go index bf4c3ed5cc1..802eee977c4 100644 --- a/internal/featuretests/rootnamespaces_test.go +++ b/internal/featuretests/rootnamespaces_test.go @@ -16,11 +16,12 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/contour" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -89,7 +90,7 @@ func TestRootNamespaces(t *testing.T) { // assert that the route tables are present but empty. c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -120,11 +121,11 @@ func TestRootNamespaces(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -134,8 +135,8 @@ func TestRootNamespaces(t *testing.T) { // assert that hp2.example.com's routes are visible. c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hp2.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hp2.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("roots/kuard/8080/da39a3ee5e"), diff --git a/internal/featuretests/route_test.go b/internal/featuretests/route_test.go index 4f16c825468..0f92772550d 100644 --- a/internal/featuretests/route_test.go +++ b/internal/featuretests/route_test.go @@ -19,12 +19,13 @@ import ( "path" "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/contour" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" "github.com/projectcontour/contour/internal/protobuf" v1 "k8s.io/api/core/v1" @@ -86,8 +87,8 @@ func TestEditIngress(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "1", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", &envoy_api_v2_route.Route{ + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/80/da39a3ee5e"), }), @@ -121,8 +122,8 @@ func TestEditIngress(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "2", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", &envoy_api_v2_route.Route{ + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/testing"), Action: routecluster("default/kuard/80/da39a3ee5e"), }), @@ -180,8 +181,8 @@ func TestIngressPathRouteWithoutHost(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "2", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/hello"), Action: routecluster("default/hello/80/da39a3ee5e"), @@ -230,8 +231,8 @@ func TestEditIngressInPlace(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "2", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/wowie/80/da39a3ee5e"), @@ -273,8 +274,8 @@ func TestEditIngressInPlace(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "3", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/whoop"), Action: routecluster("default/kerpow/9000/da39a3ee5e"), @@ -325,15 +326,15 @@ func TestEditIngressInPlace(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "4", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/whoop"), - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, &envoy_api_v2_route.Route{ Match: routePrefix("/"), - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, ), ), @@ -391,20 +392,20 @@ func TestEditIngressInPlace(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "5", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("hello.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("hello.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/whoop"), - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, &envoy_api_v2_route.Route{ Match: routePrefix("/"), - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, ), ), - envoy.RouteConfiguration("https/hello.example.com", - envoy.VirtualHost("hello.example.com", + v22.RouteConfiguration("https/hello.example.com", + v22.VirtualHost("hello.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/whoop"), Action: routecluster("default/kerpow/9000/da39a3ee5e"), @@ -497,18 +498,18 @@ func TestSSLRedirectOverlay(t *testing.T) { WithPorts(v1.ServicePort{Name: "http", Port: 8009, TargetPort: intstr.FromInt(8080)})) assertRDS(t, c, "5", virtualhosts( - envoy.VirtualHost("example.com", + v22.VirtualHost("example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/.well-known/acme-challenge/gVJl5NWL2owUqZekjHkt_bo3OHYC2XNDURRRgLI5JTk"), Action: routecluster("nginx-ingress/challenge-service/8009/da39a3ee5e"), }, &envoy_api_v2_route.Route{ Match: routePrefix("/"), // match all - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, ), ), virtualhosts( - envoy.VirtualHost("example.com", + v22.VirtualHost("example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/.well-known/acme-challenge/gVJl5NWL2owUqZekjHkt_bo3OHYC2XNDURRRgLI5JTk"), Action: routecluster("nginx-ingress/challenge-service/8009/da39a3ee5e"), @@ -565,7 +566,7 @@ func TestInvalidCertInIngress(t *testing.T) { }) assertRDS(t, c, "1", virtualhosts( - envoy.VirtualHost("kuard.io", + v22.VirtualHost("kuard.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/80/da39a3ee5e"), @@ -584,14 +585,14 @@ func TestInvalidCertInIngress(t *testing.T) { }) assertRDS(t, c, "2", virtualhosts( - envoy.VirtualHost("kuard.io", + v22.VirtualHost("kuard.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/80/da39a3ee5e"), }, ), ), virtualhosts( - envoy.VirtualHost("kuard.io", + v22.VirtualHost("kuard.io", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/80/da39a3ee5e"), @@ -639,7 +640,7 @@ func TestIssue257(t *testing.T) { rh.OnAdd(s1) assertRDS(t, c, "2", virtualhosts( - envoy.VirtualHost("*", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/80/da39a3ee5e"), @@ -692,7 +693,7 @@ func TestIssue257(t *testing.T) { rh.OnUpdate(i1, i2) assertRDS(t, c, "3", virtualhosts( - envoy.VirtualHost("kuard.db.gd-ms.com", + v22.VirtualHost("kuard.db.gd-ms.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/80/da39a3ee5e"), @@ -779,20 +780,20 @@ func TestRDSFilter(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "5", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/.well-known/acme-challenge/gVJl5NWL2owUqZekjHkt_bo3OHYC2XNDURRRgLI5JTk"), Action: routecluster("nginx-ingress/challenge-service/8009/da39a3ee5e"), }, &envoy_api_v2_route.Route{ Match: routePrefix("/"), // match all - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, ), ), - envoy.RouteConfiguration("https/example.com", - envoy.VirtualHost("example.com", + v22.RouteConfiguration("https/example.com", + v22.VirtualHost("example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/.well-known/acme-challenge/gVJl5NWL2owUqZekjHkt_bo3OHYC2XNDURRRgLI5JTk"), Action: routecluster("nginx-ingress/challenge-service/8009/da39a3ee5e"), @@ -867,8 +868,8 @@ func TestDefaultBackendDoesNotOverwriteNamedHost(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "1", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/kuard"), Action: routecluster("default/kuard/8080/da39a3ee5e"), @@ -878,7 +879,7 @@ func TestDefaultBackendDoesNotOverwriteNamedHost(t *testing.T) { Action: routecluster("default/kuard/80/da39a3ee5e"), }, ), - envoy.VirtualHost("test-gui", + v22.VirtualHost("test-gui", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/test-gui/80/da39a3ee5e"), @@ -920,7 +921,7 @@ func TestRDSIngressClassAnnotation(t *testing.T) { } rh.OnAdd(i1) assertRDS(t, c, "1", virtualhosts( - envoy.VirtualHost("*", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/8080/da39a3ee5e"), @@ -981,7 +982,7 @@ func TestRDSIngressClassAnnotation(t *testing.T) { } rh.OnUpdate(i3, i4) assertRDS(t, c, "3", virtualhosts( - envoy.VirtualHost("*", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/8080/da39a3ee5e"), @@ -1006,7 +1007,7 @@ func TestRDSIngressClassAnnotation(t *testing.T) { } rh.OnUpdate(i4, i5) assertRDS(t, c, "4", virtualhosts( - envoy.VirtualHost("*", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/kuard/8080/da39a3ee5e"), @@ -1116,7 +1117,7 @@ func TestRDSIngressSpecMissingHTTPKey(t *testing.T) { WithPorts(v1.ServicePort{Name: "http", Port: 9001, TargetPort: intstr.FromInt(8080)})) assertRDS(t, c, "2", virtualhosts( - envoy.VirtualHost("test2.test.com", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("default/network-test/9001/da39a3ee5e"), @@ -1154,7 +1155,7 @@ func TestRouteWithAServiceWeight(t *testing.T) { rh.OnAdd(p1) assertRDS(t, c, "1", virtualhosts( - envoy.VirtualHost("test2.test.com", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/a"), Action: routecluster("default/kuard/80/da39a3ee5e"), @@ -1188,7 +1189,7 @@ func TestRouteWithAServiceWeight(t *testing.T) { rh.OnUpdate(p1, p2) assertRDS(t, c, "2", virtualhosts( - envoy.VirtualHost("test2.test.com", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/a"), Action: routeweightedcluster( @@ -1245,16 +1246,16 @@ func TestRouteWithTLS(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "1", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), Match: routePrefix("/a"), }, ), ), - envoy.RouteConfiguration("https/test2.test.com", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("https/test2.test.com", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/a"), Action: routecluster("default/kuard/80/da39a3ee5e"), @@ -1324,11 +1325,11 @@ func TestRouteWithTLS_InsecurePaths(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "1", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/secure"), - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, &envoy_api_v2_route.Route{ Match: routePrefix("/insecure"), @@ -1336,8 +1337,8 @@ func TestRouteWithTLS_InsecurePaths(t *testing.T) { }, ), ), - envoy.RouteConfiguration("https/test2.test.com", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("https/test2.test.com", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/secure"), Action: routecluster("default/svc2/80/da39a3ee5e"), @@ -1421,20 +1422,20 @@ func TestRouteWithTLS_InsecurePaths_DisablePermitInsecureTrue(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "1", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/secure"), - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, &envoy_api_v2_route.Route{ Match: routePrefix("/insecure"), - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, ), ), - envoy.RouteConfiguration("https/test2.test.com", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("https/test2.test.com", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/secure"), Action: routecluster("default/svc2/80/da39a3ee5e"), @@ -1491,8 +1492,8 @@ func TestRoutePrefixRouteRegex(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "1", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routeRegex("/[^/]+/invoices(/.*|/?)"), Action: routecluster("default/kuard/80/da39a3ee5e"), @@ -1513,12 +1514,12 @@ func assertRDS(t *testing.T, c *Contour, versioninfo string, ingressHTTP, ingres t.Helper() routes := []*v2.RouteConfiguration{ - envoy.RouteConfiguration("ingress_http", ingressHTTP...), + v22.RouteConfiguration("ingress_http", ingressHTTP...), } for _, vh := range ingressHTTPS { routes = append(routes, - envoy.RouteConfiguration(path.Join("https", vh.Name), vh)) + v22.RouteConfiguration(path.Join("https", vh.Name), vh)) } c.Request(routeType).Equals(&v2.DiscoveryResponse{ @@ -1535,7 +1536,7 @@ type weightedcluster struct { } func routeRegex(regex string, headers ...dag.HeaderMatchCondition) *envoy_api_v2_route.RouteMatch { - return envoy.RouteMatch(&dag.Route{ + return v22.RouteMatch(&dag.Route{ PathMatchCondition: &dag.RegexMatchCondition{ Regex: regex, }, @@ -1604,7 +1605,7 @@ func TestHTTPProxyRouteWithAServiceWeight(t *testing.T) { rh.OnAdd(proxy1) assertRDS(t, c, "1", virtualhosts( - envoy.VirtualHost("test2.test.com", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/a"), Action: routecluster("default/kuard/80/da39a3ee5e"), @@ -1636,7 +1637,7 @@ func TestHTTPProxyRouteWithAServiceWeight(t *testing.T) { rh.OnUpdate(proxy1, proxy2) assertRDS(t, c, "2", virtualhosts( - envoy.VirtualHost("test2.test.com", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/a"), Action: routeweightedcluster( @@ -1691,16 +1692,16 @@ func TestHTTPProxyRouteWithTLS(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "1", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/a"), - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, ), ), - envoy.RouteConfiguration("https/test2.test.com", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("https/test2.test.com", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/a"), Action: routecluster("default/kuard/80/da39a3ee5e"), @@ -1766,11 +1767,11 @@ func TestHTTPProxyRouteWithTLS_InsecurePaths(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "1", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/secure"), - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, &envoy_api_v2_route.Route{ Match: routePrefix("/insecure"), @@ -1778,8 +1779,8 @@ func TestHTTPProxyRouteWithTLS_InsecurePaths(t *testing.T) { }, ), ), - envoy.RouteConfiguration("https/test2.test.com", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("https/test2.test.com", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/secure"), Action: routecluster("default/svc2/80/da39a3ee5e"), @@ -1859,20 +1860,20 @@ func TestHTTPProxyRouteWithTLS_InsecurePaths_DisablePermitInsecureTrue(t *testin c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "1", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/secure"), - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, &envoy_api_v2_route.Route{ Match: routePrefix("/insecure"), - Action: envoy.UpgradeHTTPS(), + Action: v22.UpgradeHTTPS(), }, ), ), - envoy.RouteConfiguration("https/test2.test.com", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("https/test2.test.com", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/secure"), Action: routecluster("default/svc2/80/da39a3ee5e"), @@ -1938,8 +1939,8 @@ func TestRDSHTTPProxyRootCannotDelegateToAnotherRoot(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "2", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("www.containersteve.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("www.containersteve.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routecluster("marketing/green/80/da39a3ee5e"), @@ -2046,7 +2047,7 @@ func TestRDSHTTPProxyDuplicateIncludeConditions(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ VersionInfo: "2", Resources: routeResources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, Nonce: "2", diff --git a/internal/featuretests/secrets_test.go b/internal/featuretests/secrets_test.go index d4972aa0da7..c5e1b2eedea 100644 --- a/internal/featuretests/secrets_test.go +++ b/internal/featuretests/secrets_test.go @@ -16,10 +16,11 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" "k8s.io/api/networking/v1beta1" @@ -231,7 +232,7 @@ func TestSDSshouldNotPublishInvalidSecret(t *testing.T) { } func secret(sec *v1.Secret) *envoy_api_v2_auth.Secret { - return envoy.Secret(&dag.Secret{ + return v22.Secret(&dag.Secret{ Object: sec, }) } diff --git a/internal/featuretests/tcpproxy_test.go b/internal/featuretests/tcpproxy_test.go index 2ba1a537102..745c0d1f4aa 100644 --- a/internal/featuretests/tcpproxy_test.go +++ b/internal/featuretests/tcpproxy_test.go @@ -16,11 +16,12 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -79,14 +80,14 @@ func TestTCPProxy(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: appendFilterChains( filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "default/correct-backend/80/da39a3ee5e"), nil), ), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -96,7 +97,7 @@ func TestTCPProxy(t *testing.T) { // check that ingress_http is empty c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -163,14 +164,14 @@ func TestTCPProxyDelegation(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: appendFilterChains( filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "app/backend/80/da39a3ee5e"), nil), ), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -180,7 +181,7 @@ func TestTCPProxyDelegation(t *testing.T) { // check that ingress_http is empty c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -231,19 +232,19 @@ func TestTCPProxyTLSPassthrough(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ - Filters: envoy.Filters( + Filters: v22.Filters( tcpproxy("ingress_https", "default/correct-backend/80/da39a3ee5e"), ), FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"kuard-tcp.example.com"}, }, }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -253,7 +254,7 @@ func TestTCPProxyTLSPassthrough(t *testing.T) { // check that ingress_http is empty c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -308,15 +309,15 @@ func TestTCPProxyTLSBackend(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: appendFilterChains( filterchaintls("k8s.run.ubisoft.org", s1, tcpproxy("ingress_https", svc.Namespace+"/"+svc.Name+"/443/da39a3ee5e"), nil), ), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -336,7 +337,7 @@ func TestTCPProxyTLSBackend(t *testing.T) { // check that ingress_http is empty c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -397,24 +398,24 @@ func TestTCPProxyAndHTTPService(t *testing.T) { // ingress_http is present for // http://kuard-tcp.example.com/ -> default/backend:80 Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ // ingress_https is present for // kuard-tcp.example.com:443 terminated at envoy then forwarded to default/backend:80 Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: appendFilterChains( filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "default/backend/80/da39a3ee5e"), nil), ), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -427,8 +428,8 @@ func TestTCPProxyAndHTTPService(t *testing.T) { // is in tcpproxy mode. c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard-tcp.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard-tcp.example.com", upgradeHTTPS(routePrefix("/")), ), ), @@ -493,24 +494,24 @@ func TestTCPProxyAndHTTPServicePermitInsecure(t *testing.T) { // ingress_http is present for // http://kuard-tcp.example.com/ -> default/backend:80 Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ // ingress_https is present for // kuard-tcp.example.com:443 terminated at envoy then tcpproxied to default/backend:80 Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: appendFilterChains( filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "default/backend/80/da39a3ee5e"), nil), ), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -522,8 +523,8 @@ func TestTCPProxyAndHTTPServicePermitInsecure(t *testing.T) { // is in tcpproxy mode. c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard-tcp.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard-tcp.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), // this is a regular route cluster, not a 301 upgrade as @@ -582,29 +583,29 @@ func TestTCPProxyTLSPassthroughAndHTTPService(t *testing.T) { // ingress_http is present for // http://kuard-tcp.example.com/ -> default/backend:80 Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ // ingress_https is present for // kuard-tcp.example.com:443 direct to default/backend:80 Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ - Filters: envoy.Filters( + Filters: v22.Filters( tcpproxy("ingress_https", "default/backend/80/da39a3ee5e"), ), FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"kuard-tcp.example.com"}, }, }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -614,11 +615,11 @@ func TestTCPProxyTLSPassthroughAndHTTPService(t *testing.T) { // check port 80 is open and the route is a 301 upgrade. c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", + v22.RouteConfiguration("ingress_http", // 301 upgrade because permitInsecure is false, thus // the route is present on port 80, but unconditionally // upgrades to HTTPS. - envoy.VirtualHost("kuard-tcp.example.com", + v22.VirtualHost("kuard-tcp.example.com", upgradeHTTPS(routePrefix("/")), ), ), @@ -676,30 +677,30 @@ func TestTCPProxyTLSPassthroughAndHTTPServicePermitInsecure(t *testing.T) { // http://kuard-tcp.example.com/ -> default/backend:80, this is not 301 upgraded // because permitInsecure: true is in use. Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, &v2.Listener{ // ingress_https is present for // kuard-tcp.example.com:443 direct to default/backend:80, envoy does not handle // the TLS handshake beyond SNI demux because passthrough: true is in use. Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), + Address: v22.SocketAddress("0.0.0.0", 8443), FilterChains: []*envoy_api_v2_listener.FilterChain{{ - Filters: envoy.Filters( + Filters: v22.Filters( tcpproxy("ingress_https", "default/backend/80/da39a3ee5e"), ), FilterChainMatch: &envoy_api_v2_listener.FilterChainMatch{ ServerNames: []string{"kuard-tcp.example.com"}, }, }}, - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, staticListener(), ), @@ -711,8 +712,8 @@ func TestTCPProxyTLSPassthroughAndHTTPServicePermitInsecure(t *testing.T) { // is in tcpproxy mode. c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("kuard-tcp.example.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("kuard-tcp.example.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), // not a 301 upgrade because permitInsecure: true is in use. @@ -786,7 +787,7 @@ func TestTCPProxyMissingTLS(t *testing.T) { Resources: resources(t, // ingress_http and ingress_https should be empty // as hp1 is not valid. - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -832,7 +833,7 @@ func TestTCPProxyMissingTLS(t *testing.T) { Resources: resources(t, // ingress_http and ingress_https should be empty // as hp2 is not valid. - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) diff --git a/internal/featuretests/timeoutpolicy_test.go b/internal/featuretests/timeoutpolicy_test.go index cb2ff1a5b97..65947236988 100644 --- a/internal/featuretests/timeoutpolicy_test.go +++ b/internal/featuretests/timeoutpolicy_test.go @@ -17,11 +17,12 @@ import ( "testing" "time" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/contour" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" "k8s.io/api/networking/v1beta1" @@ -54,8 +55,8 @@ func TestTimeoutPolicyRequestTimeout(t *testing.T) { // check annotation with explicit timeout is propagated c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withResponseTimeout(routeCluster("default/kuard/8080/da39a3ee5e"), 80*time.Second), @@ -81,8 +82,8 @@ func TestTimeoutPolicyRequestTimeout(t *testing.T) { // check annotation with infinite timeout is propogated c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withResponseTimeout(routeCluster("default/kuard/8080/da39a3ee5e"), 0), // zero means infinity @@ -108,8 +109,8 @@ func TestTimeoutPolicyRequestTimeout(t *testing.T) { // check annotation with malformed timeout is not propagated c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: routeCluster("default/kuard/8080/da39a3ee5e"), @@ -136,8 +137,8 @@ func TestTimeoutPolicyRequestTimeout(t *testing.T) { // assert that projectcontour.io/response-timeout takes priority. c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("*", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("*", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withResponseTimeout(routeCluster("default/kuard/8080/da39a3ee5e"), 99*time.Second), @@ -173,7 +174,7 @@ func TestTimeoutPolicyRequestTimeout(t *testing.T) { // check timeout policy with malformed response timeout is not propogated c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -199,8 +200,8 @@ func TestTimeoutPolicyRequestTimeout(t *testing.T) { // check timeout policy with response timeout is propogated correctly c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withResponseTimeout(routeCluster("default/kuard/8080/da39a3ee5e"), 180*time.Second), @@ -232,8 +233,8 @@ func TestTimeoutPolicyRequestTimeout(t *testing.T) { // check timeout policy with explicit infine response timeout is propogated as infinity c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withResponseTimeout(routeCluster("default/kuard/8080/da39a3ee5e"), 0), // zero means infinity @@ -277,7 +278,7 @@ func TestTimeoutPolicyIdleTimeout(t *testing.T) { // check timeout policy with malformed response timeout is not propogated c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http"), + v22.RouteConfiguration("ingress_http"), ), TypeUrl: routeType, }) @@ -303,8 +304,8 @@ func TestTimeoutPolicyIdleTimeout(t *testing.T) { // check timeout policy with response timeout is propogated correctly c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withIdleTimeout(routeCluster("default/kuard/8080/da39a3ee5e"), 180*time.Second), @@ -336,8 +337,8 @@ func TestTimeoutPolicyIdleTimeout(t *testing.T) { // check timeout policy with explicit infine response timeout is propogated as infinity c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("test2.test.com", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("test2.test.com", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withIdleTimeout(routeCluster("default/kuard/8080/da39a3ee5e"), 0), // zero means infinity diff --git a/internal/featuretests/timeouts_test.go b/internal/featuretests/timeouts_test.go index 011c16974f4..2b3ee6c0fbd 100644 --- a/internal/featuretests/timeouts_test.go +++ b/internal/featuretests/timeouts_test.go @@ -17,10 +17,11 @@ import ( "testing" "time" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/contour" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" "github.com/projectcontour/contour/internal/timeout" v1 "k8s.io/api/core/v1" @@ -61,12 +62,12 @@ func TestTimeoutsNotSpecified(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: contour.ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManagerBuilder(). + Address: v22.SocketAddress("0.0.0.0", 8080), + SocketOptions: v22.TCPKeepaliveSocketOptions(), + FilterChains: v22.FilterChains(v22.HTTPConnectionManagerBuilder(). RouteConfigName(contour.ENVOY_HTTP_LISTENER). MetricsPrefix(contour.ENVOY_HTTP_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy(contour.DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(contour.DEFAULT_HTTP_ACCESS_LOG)). DefaultFilters(). Get(), ), @@ -114,12 +115,12 @@ func TestNonZeroTimeoutsSpecified(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: contour.ENVOY_HTTP_LISTENER, - Address: envoy.SocketAddress("0.0.0.0", 8080), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), - FilterChains: envoy.FilterChains(envoy.HTTPConnectionManagerBuilder(). + Address: v22.SocketAddress("0.0.0.0", 8080), + SocketOptions: v22.TCPKeepaliveSocketOptions(), + FilterChains: v22.FilterChains(v22.HTTPConnectionManagerBuilder(). RouteConfigName(contour.ENVOY_HTTP_LISTENER). MetricsPrefix(contour.ENVOY_HTTP_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy(contour.DEFAULT_HTTP_ACCESS_LOG)). + AccessLoggers(v22.FileAccessLogEnvoy(contour.DEFAULT_HTTP_ACCESS_LOG)). DefaultFilters(). ConnectionIdleTimeout(timeout.DurationSetting(7 * time.Second)). StreamIdleTimeout(timeout.DurationSetting(70 * time.Second)). diff --git a/internal/featuretests/tlscertificatedelegation_test.go b/internal/featuretests/tlscertificatedelegation_test.go index 876f58fe23b..503911e5bbb 100644 --- a/internal/featuretests/tlscertificatedelegation_test.go +++ b/internal/featuretests/tlscertificatedelegation_test.go @@ -16,9 +16,10 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -105,25 +106,25 @@ func TestTLSCertificateDelegation(t *testing.T) { ingress_http := &v2.Listener{ Name: "ingress_http", - Address: envoy.SocketAddress("0.0.0.0", 8080), - FilterChains: envoy.FilterChains( - envoy.HTTPConnectionManager("ingress_http", envoy.FileAccessLogEnvoy("/dev/stdout"), 0), + Address: v22.SocketAddress("0.0.0.0", 8080), + FilterChains: v22.FilterChains( + v22.HTTPConnectionManager("ingress_http", v22.FileAccessLogEnvoy("/dev/stdout"), 0), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } ingress_https := &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: appendFilterChains( filterchaintls("example.com", sec1, httpsFilterFor("example.com"), nil, "h2", "http/1.1"), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } c.Request(listenerType).Equals(&v2.DiscoveryResponse{ diff --git a/internal/featuretests/tlsprotocolversion_test.go b/internal/featuretests/tlsprotocolversion_test.go index 35cc2bb0d6e..bdcc9514942 100644 --- a/internal/featuretests/tlsprotocolversion_test.go +++ b/internal/featuretests/tlsprotocolversion_test.go @@ -16,12 +16,13 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" "k8s.io/api/networking/v1beta1" @@ -74,16 +75,16 @@ func TestTLSMinimumProtocolVersion(t *testing.T) { Resources: resources(t, &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: appendFilterChains( filterchaintls("kuard.example.com", sec1, httpsFilterFor("kuard.example.com"), nil, "h2", "http/1.1"), ), - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), }, ), TypeUrl: listenerType, @@ -118,22 +119,22 @@ func TestTLSMinimumProtocolVersion(t *testing.T) { l1 := &v2.Listener{ Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - ListenerFilters: envoy.ListenerFilters( - envoy.TLSInspector(), + Address: v22.SocketAddress("0.0.0.0", 8443), + ListenerFilters: v22.ListenerFilters( + v22.TLSInspector(), ), FilterChains: []*envoy_api_v2_listener.FilterChain{ - envoy.FilterChainTLS( + v22.FilterChainTLS( "kuard.example.com", - envoy.DownstreamTLSContext( + v22.DownstreamTLSContext( &dag.Secret{Object: sec1}, envoy_api_v2_auth.TlsParameters_TLSv1_3, nil, "h2", "http/1.1"), - envoy.Filters(httpsFilterFor("kuard.example.com")), + v22.Filters(httpsFilterFor("kuard.example.com")), ), }, - SocketOptions: envoy.TCPKeepaliveSocketOptions(), + SocketOptions: v22.TCPKeepaliveSocketOptions(), } c.Request(listenerType, "ingress_https").Equals(&v2.DiscoveryResponse{ diff --git a/internal/featuretests/websockets_test.go b/internal/featuretests/websockets_test.go index 030df0848c8..3128c7afb9b 100644 --- a/internal/featuretests/websockets_test.go +++ b/internal/featuretests/websockets_test.go @@ -16,10 +16,11 @@ package featuretests import ( "testing" + v22 "github.com/projectcontour/contour/internal/envoy/v2" + v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy_api_v2_route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" v1 "k8s.io/api/core/v1" "k8s.io/api/networking/v1beta1" @@ -65,8 +66,8 @@ func TestWebsocketsIngress(t *testing.T) { // check legacy websocket annotation c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("websocket.hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("websocket.hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/"), Action: withWebsocket(routeCluster("default/ws/80/da39a3ee5e")), @@ -107,8 +108,8 @@ func TestWebsocketsIngress(t *testing.T) { // check websocket annotation c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("websocket.hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("websocket.hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/ws2"), Action: withWebsocket(routeCluster("default/ws/80/da39a3ee5e")), @@ -166,8 +167,8 @@ func TestWebsocketHTTPProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("websocket.hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("websocket.hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/ws-2"), Action: withWebsocket(routeCluster("default/ws/80/da39a3ee5e")), @@ -223,8 +224,8 @@ func TestWebsocketHTTPProxy(t *testing.T) { c.Request(routeType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, - envoy.RouteConfiguration("ingress_http", - envoy.VirtualHost("websocket.hello.world", + v22.RouteConfiguration("ingress_http", + v22.VirtualHost("websocket.hello.world", &envoy_api_v2_route.Route{ Match: routePrefix("/ws-2"), Action: withWebsocket(routeCluster("default/ws/80/da39a3ee5e")),