xds: add support for envoy 1.15.0 and drop support for 1.11.x (#8424)

Related changes:

- hard-fail the xDS connection attempt if the envoy version is known to be too old to be supported
- remove the RouterMatchSafeRegex proxy feature since all supported envoy versions have it
- stop using --max-obj-name-len (due to: envoyproxy/envoy#11740)
This commit is contained in:
R.B. Boyer 2020-07-31 15:52:49 -05:00 committed by GitHub
parent 6960afdfe3
commit c599a2f5f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
184 changed files with 113 additions and 149 deletions

View File

@ -640,13 +640,13 @@ jobs:
command: bash <(curl -s https://codecov.io/bash) -v -c -C $CIRCLE_SHA1 -F ui command: bash <(curl -s https://codecov.io/bash) -v -c -C $CIRCLE_SHA1 -F ui
- run: *notify-slack-failure - run: *notify-slack-failure
envoy-integration-test-1.11.2: envoy-integration-test-1.12.6:
docker: docker:
# We only really need bash and docker-compose which is installed on all # We only really need bash and docker-compose which is installed on all
# Circle images but pick Go since we have to pick one of them. # Circle images but pick Go since we have to pick one of them.
- image: *GOLANG_IMAGE - image: *GOLANG_IMAGE
environment: environment:
ENVOY_VERSION: "1.11.2" ENVOY_VERSION: "1.12.6"
steps: &ENVOY_INTEGRATION_TEST_STEPS steps: &ENVOY_INTEGRATION_TEST_STEPS
- checkout - checkout
# Get go binary from workspace # Get go binary from workspace
@ -675,13 +675,6 @@ jobs:
path: *TEST_RESULTS_DIR path: *TEST_RESULTS_DIR
- run: *notify-slack-failure - run: *notify-slack-failure
envoy-integration-test-1.12.6:
docker:
- image: *GOLANG_IMAGE
environment:
ENVOY_VERSION: "1.12.6"
steps: *ENVOY_INTEGRATION_TEST_STEPS
envoy-integration-test-1.13.4: envoy-integration-test-1.13.4:
docker: docker:
- image: *GOLANG_IMAGE - image: *GOLANG_IMAGE
@ -696,6 +689,13 @@ jobs:
ENVOY_VERSION: "1.14.4" ENVOY_VERSION: "1.14.4"
steps: *ENVOY_INTEGRATION_TEST_STEPS steps: *ENVOY_INTEGRATION_TEST_STEPS
envoy-integration-test-1.15.0:
docker:
- image: *GOLANG_IMAGE
environment:
ENVOY_VERSION: "1.15.0"
steps: *ENVOY_INTEGRATION_TEST_STEPS
# run integration tests for the connect ca providers # run integration tests for the connect ca providers
test-connect-ca-providers: test-connect-ca-providers:
docker: docker:
@ -807,9 +807,6 @@ workflows:
- nomad-integration-0_8: - nomad-integration-0_8:
requires: requires:
- dev-build - dev-build
- envoy-integration-test-1.11.2:
requires:
- dev-build
- envoy-integration-test-1.12.6: - envoy-integration-test-1.12.6:
requires: requires:
- dev-build - dev-build
@ -819,6 +816,9 @@ workflows:
- envoy-integration-test-1.14.4: - envoy-integration-test-1.14.4:
requires: requires:
- dev-build - dev-build
- envoy-integration-test-1.15.0:
requires:
- dev-build
website: website:
jobs: jobs:

View File

@ -11,6 +11,7 @@ import (
envoy "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy "github.com/envoyproxy/go-control-plane/envoy/api/v2"
"github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/agent/xds/proxysupport"
"github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil"
testinf "github.com/mitchellh/go-testing-interface" testinf "github.com/mitchellh/go-testing-interface"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -527,8 +528,9 @@ func TestClustersFromSnapshot(t *testing.T) {
}, },
} }
for _, envoyVersion := range supportedEnvoyVersions { for _, envoyVersion := range proxysupport.EnvoyVersions {
sf := determineSupportedProxyFeaturesFromString(envoyVersion) sf, err := determineSupportedProxyFeaturesFromString(envoyVersion)
require.NoError(t, err)
t.Run("envoy-"+envoyVersion, func(t *testing.T) { t.Run("envoy-"+envoyVersion, func(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -737,13 +739,3 @@ func setupTLSRootsAndLeaf(t *testing.T, snap *proxycfg.ConfigSnapshot) {
snap.Roots.Roots[0].RootCert = golden(t, "test-root-cert", "", "") snap.Roots.Roots[0].RootCert = golden(t, "test-root-cert", "", "")
} }
} }
// supportedEnvoyVersions lists the versions that we generated golden tests for
//
// see: https://www.consul.io/docs/connect/proxies/envoy#supported-versions
var supportedEnvoyVersions = []string{
"1.14.4",
"1.13.4",
"1.12.6",
"1.11.2",
}

View File

@ -14,6 +14,7 @@ import (
envoyendpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint" envoyendpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
"github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/agent/xds/proxysupport"
"github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil"
testinf "github.com/mitchellh/go-testing-interface" testinf "github.com/mitchellh/go-testing-interface"
) )
@ -554,8 +555,9 @@ func Test_endpointsFromSnapshot(t *testing.T) {
}, },
} }
for _, envoyVersion := range supportedEnvoyVersions { for _, envoyVersion := range proxysupport.EnvoyVersions {
sf := determineSupportedProxyFeaturesFromString(envoyVersion) sf, err := determineSupportedProxyFeaturesFromString(envoyVersion)
require.NoError(t, err)
t.Run("envoy-"+envoyVersion, func(t *testing.T) { t.Run("envoy-"+envoyVersion, func(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View File

@ -9,25 +9,37 @@ import (
) )
var ( var (
// minSafeRegexVersion reflects the minimum version where we could use safe_regex instead of regex // minSupportedVersion is the oldest mainline version we support. This should always be
// // the zero'th point release of the last element of proxysupport.EnvoyVersions.
// NOTE: the first version that no longer supported the old style was 1.13.0 minSupportedVersion = version.Must(version.NewVersion("1.12.0"))
minSafeRegexVersion = version.Must(version.NewVersion("1.11.2"))
) )
type supportedProxyFeatures struct { type supportedProxyFeatures struct {
RouterMatchSafeRegex bool // use safe_regex instead of regex in http.router rules // add version dependent feature flags here
} }
func determineSupportedProxyFeatures(node *envoycore.Node) supportedProxyFeatures { func determineSupportedProxyFeatures(node *envoycore.Node) (supportedProxyFeatures, error) {
version := determineEnvoyVersionFromNode(node) version := determineEnvoyVersionFromNode(node)
return determineSupportedProxyFeaturesFromVersion(version)
}
func determineSupportedProxyFeaturesFromString(vs string) (supportedProxyFeatures, error) {
version := version.Must(version.NewVersion(vs))
return determineSupportedProxyFeaturesFromVersion(version)
}
func determineSupportedProxyFeaturesFromVersion(version *version.Version) (supportedProxyFeatures, error) {
if version == nil { if version == nil {
return supportedProxyFeatures{} // This would happen on either extremely old builds OR perhaps on
// custom builds. Should we error?
return supportedProxyFeatures{}, nil
} }
return supportedProxyFeatures{ if version.LessThan(minSupportedVersion) {
RouterMatchSafeRegex: !version.LessThan(minSafeRegexVersion), return supportedProxyFeatures{}, fmt.Errorf("Envoy %s is too old and is not supported by Consul", version)
} }
return supportedProxyFeatures{}, nil
} }
// example: 1580db37e9a97c37e410bad0e1507ae1a0fd9e77/1.12.4/Clean/RELEASE/BoringSSL // example: 1580db37e9a97c37e410bad0e1507ae1a0fd9e77/1.12.4/Clean/RELEASE/BoringSSL
@ -74,10 +86,3 @@ func determineEnvoyVersionFromNode(node *envoycore.Node) *version.Version {
), ),
)) ))
} }
func determineSupportedProxyFeaturesFromString(vs string) supportedProxyFeatures {
version := version.Must(version.NewVersion(vs))
return supportedProxyFeatures{
RouterMatchSafeRegex: !version.LessThan(minSafeRegexVersion),
}
}

View File

@ -11,6 +11,7 @@ import (
envoy "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy "github.com/envoyproxy/go-control-plane/envoy/api/v2"
"github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/agent/xds/proxysupport"
"github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil"
testinf "github.com/mitchellh/go-testing-interface" testinf "github.com/mitchellh/go-testing-interface"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -433,8 +434,9 @@ func TestListenersFromSnapshot(t *testing.T) {
}, },
} }
for _, envoyVersion := range supportedEnvoyVersions { for _, envoyVersion := range proxysupport.EnvoyVersions {
sf := determineSupportedProxyFeaturesFromString(envoyVersion) sf, err := determineSupportedProxyFeaturesFromString(envoyVersion)
require.NoError(t, err)
t.Run("envoy-"+envoyVersion, func(t *testing.T) { t.Run("envoy-"+envoyVersion, func(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View File

@ -0,0 +1,11 @@
package proxysupport
// EnvoyVersions lists the latest officially supported versions of envoy.
//
// see: https://www.consul.io/docs/connect/proxies/envoy#supported-versions
var EnvoyVersions = []string{
"1.15.0",
"1.14.4",
"1.13.4",
"1.12.6",
}

View File

@ -277,7 +277,7 @@ func makeUpstreamRouteForDiscoveryChain(
return host, nil return host, nil
} }
func makeRouteMatchForDiscoveryRoute(cInfo connectionInfo, discoveryRoute *structs.DiscoveryRoute) *envoyroute.RouteMatch { func makeRouteMatchForDiscoveryRoute(_ connectionInfo, discoveryRoute *structs.DiscoveryRoute) *envoyroute.RouteMatch {
match := discoveryRoute.Definition.Match match := discoveryRoute.Definition.Match
if match == nil || match.IsEmpty() { if match == nil || match.IsEmpty() {
return makeDefaultRouteMatch() return makeDefaultRouteMatch()
@ -295,14 +295,8 @@ func makeRouteMatchForDiscoveryRoute(cInfo connectionInfo, discoveryRoute *struc
Prefix: match.HTTP.PathPrefix, Prefix: match.HTTP.PathPrefix,
} }
case match.HTTP.PathRegex != "": case match.HTTP.PathRegex != "":
if cInfo.ProxyFeatures.RouterMatchSafeRegex { em.PathSpecifier = &envoyroute.RouteMatch_SafeRegex{
em.PathSpecifier = &envoyroute.RouteMatch_SafeRegex{ SafeRegex: makeEnvoyRegexMatch(match.HTTP.PathRegex),
SafeRegex: makeEnvoyRegexMatch(match.HTTP.PathRegex),
}
} else {
em.PathSpecifier = &envoyroute.RouteMatch_Regex{
Regex: match.HTTP.PathRegex,
}
} }
default: default:
em.PathSpecifier = &envoyroute.RouteMatch_Prefix{ em.PathSpecifier = &envoyroute.RouteMatch_Prefix{
@ -323,14 +317,8 @@ func makeRouteMatchForDiscoveryRoute(cInfo connectionInfo, discoveryRoute *struc
ExactMatch: hdr.Exact, ExactMatch: hdr.Exact,
} }
case hdr.Regex != "": case hdr.Regex != "":
if cInfo.ProxyFeatures.RouterMatchSafeRegex { eh.HeaderMatchSpecifier = &envoyroute.HeaderMatcher_SafeRegexMatch{
eh.HeaderMatchSpecifier = &envoyroute.HeaderMatcher_SafeRegexMatch{ SafeRegexMatch: makeEnvoyRegexMatch(hdr.Regex),
SafeRegexMatch: makeEnvoyRegexMatch(hdr.Regex),
}
} else {
eh.HeaderMatchSpecifier = &envoyroute.HeaderMatcher_RegexMatch{
RegexMatch: hdr.Regex,
}
} }
case hdr.Prefix != "": case hdr.Prefix != "":
eh.HeaderMatchSpecifier = &envoyroute.HeaderMatcher_PrefixMatch{ eh.HeaderMatchSpecifier = &envoyroute.HeaderMatcher_PrefixMatch{
@ -361,15 +349,9 @@ func makeRouteMatchForDiscoveryRoute(cInfo connectionInfo, discoveryRoute *struc
eh := &envoyroute.HeaderMatcher{ eh := &envoyroute.HeaderMatcher{
Name: ":method", Name: ":method",
} HeaderMatchSpecifier: &envoyroute.HeaderMatcher_SafeRegexMatch{
if cInfo.ProxyFeatures.RouterMatchSafeRegex {
eh.HeaderMatchSpecifier = &envoyroute.HeaderMatcher_SafeRegexMatch{
SafeRegexMatch: makeEnvoyRegexMatch(methodHeaderRegex), SafeRegexMatch: makeEnvoyRegexMatch(methodHeaderRegex),
} },
} else {
eh.HeaderMatchSpecifier = &envoyroute.HeaderMatcher_RegexMatch{
RegexMatch: methodHeaderRegex,
}
} }
em.Headers = append(em.Headers, eh) em.Headers = append(em.Headers, eh)
@ -384,37 +366,24 @@ func makeRouteMatchForDiscoveryRoute(cInfo connectionInfo, discoveryRoute *struc
switch { switch {
case qm.Exact != "": case qm.Exact != "":
if cInfo.ProxyFeatures.RouterMatchSafeRegex { eq.QueryParameterMatchSpecifier = &envoyroute.QueryParameterMatcher_StringMatch{
eq.QueryParameterMatchSpecifier = &envoyroute.QueryParameterMatcher_StringMatch{ StringMatch: &envoymatcher.StringMatcher{
StringMatch: &envoymatcher.StringMatcher{ MatchPattern: &envoymatcher.StringMatcher_Exact{
MatchPattern: &envoymatcher.StringMatcher_Exact{ Exact: qm.Exact,
Exact: qm.Exact,
},
}, },
} },
} else {
eq.Value = qm.Exact
} }
case qm.Regex != "": case qm.Regex != "":
if cInfo.ProxyFeatures.RouterMatchSafeRegex { eq.QueryParameterMatchSpecifier = &envoyroute.QueryParameterMatcher_StringMatch{
eq.QueryParameterMatchSpecifier = &envoyroute.QueryParameterMatcher_StringMatch{ StringMatch: &envoymatcher.StringMatcher{
StringMatch: &envoymatcher.StringMatcher{ MatchPattern: &envoymatcher.StringMatcher_SafeRegex{
MatchPattern: &envoymatcher.StringMatcher_SafeRegex{ SafeRegex: makeEnvoyRegexMatch(qm.Regex),
SafeRegex: makeEnvoyRegexMatch(qm.Regex),
},
}, },
} },
} else {
eq.Value = qm.Regex
eq.Regex = makeBoolValue(true)
} }
case qm.Present: case qm.Present:
if cInfo.ProxyFeatures.RouterMatchSafeRegex { eq.QueryParameterMatchSpecifier = &envoyroute.QueryParameterMatcher_PresentMatch{
eq.QueryParameterMatchSpecifier = &envoyroute.QueryParameterMatcher_PresentMatch{ PresentMatch: true,
PresentMatch: true,
}
} else {
eq.Value = ""
} }
default: default:
continue // skip this impossible situation continue // skip this impossible situation

View File

@ -11,6 +11,7 @@ import (
"github.com/hashicorp/consul/agent/consul/discoverychain" "github.com/hashicorp/consul/agent/consul/discoverychain"
"github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/agent/xds/proxysupport"
testinf "github.com/mitchellh/go-testing-interface" testinf "github.com/mitchellh/go-testing-interface"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -175,8 +176,9 @@ func TestRoutesFromSnapshot(t *testing.T) {
}, },
} }
for _, envoyVersion := range supportedEnvoyVersions { for _, envoyVersion := range proxysupport.EnvoyVersions {
sf := determineSupportedProxyFeaturesFromString(envoyVersion) sf, err := determineSupportedProxyFeaturesFromString(envoyVersion)
require.NoError(t, err)
t.Run("envoy-"+envoyVersion, func(t *testing.T) { t.Run("envoy-"+envoyVersion, func(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View File

@ -311,7 +311,11 @@ func (s *Server) process(stream ADSStream, reqCh <-chan *envoy.DiscoveryRequest)
if node == nil && req.Node != nil { if node == nil && req.Node != nil {
node = req.Node node = req.Node
proxyFeatures = determineSupportedProxyFeatures(req.Node) var err error
proxyFeatures, err = determineSupportedProxyFeatures(req.Node)
if err != nil {
return status.Errorf(codes.InvalidArgument, err.Error())
}
} }
if handler, ok := handlers[req.TypeUrl]; ok { if handler, ok := handlers[req.TypeUrl]; ok {

Some files were not shown because too many files have changed in this diff Show More