Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[backport: 1.7.x] xds: version sniff envoy and switch regular expressions from 'regex' to 'safe_regex' on newer envoy versions #8266

Merged
merged 12 commits into from
Jul 9, 2020
  •  
  •  
  •  
12 changes: 6 additions & 6 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -588,18 +588,18 @@ jobs:
ENVOY_VERSIONS: "1.11.2"
steps: *ENVOY_INTEGRATION_TEST_STEPS

envoy-integration-test-1.12.2:
envoy-integration-test-1.12.3:
docker:
- image: *GOLANG_IMAGE
environment:
ENVOY_VERSIONS: "1.12.2"
ENVOY_VERSIONS: "1.12.3"
steps: *ENVOY_INTEGRATION_TEST_STEPS

envoy-integration-test-1.13.0:
envoy-integration-test-1.13.1:
docker:
- image: *GOLANG_IMAGE
environment:
ENVOY_VERSIONS: "1.13.0"
ENVOY_VERSIONS: "1.13.1"
steps: *ENVOY_INTEGRATION_TEST_STEPS

# run tests on vault ca provider integration tests
Expand Down Expand Up @@ -705,10 +705,10 @@ workflows:
- envoy-integration-test-1.11.2:
requires:
- dev-build
- envoy-integration-test-1.12.2:
- envoy-integration-test-1.12.3:
requires:
- dev-build
- envoy-integration-test-1.13.0:
- envoy-integration-test-1.13.1:
requires:
- dev-build
- vault-ca-provider:
Expand Down
10 changes: 5 additions & 5 deletions agent/xds/clusters.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,24 @@ import (
)

// clustersFromSnapshot returns the xDS API representation of the "clusters" in the snapshot.
func (s *Server) clustersFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) {
func (s *Server) clustersFromSnapshot(_ connectionInfo, cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) {
if cfgSnap == nil {
return nil, errors.New("nil config given")
}

switch cfgSnap.Kind {
case structs.ServiceKindConnectProxy:
return s.clustersFromSnapshotConnectProxy(cfgSnap, token)
return s.clustersFromSnapshotConnectProxy(cfgSnap)
case structs.ServiceKindMeshGateway:
return s.clustersFromSnapshotMeshGateway(cfgSnap, token)
return s.clustersFromSnapshotMeshGateway(cfgSnap)
default:
return nil, fmt.Errorf("Invalid service kind: %v", cfgSnap.Kind)
}
}

// clustersFromSnapshot returns the xDS API representation of the "clusters"
// (upstreams) in the snapshot.
func (s *Server) clustersFromSnapshotConnectProxy(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) {
func (s *Server) clustersFromSnapshotConnectProxy(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) {
// TODO(rb): this sizing is a low bound.
clusters := make([]proto.Message, 0, len(cfgSnap.Proxy.Upstreams)+1)

Expand Down Expand Up @@ -112,7 +112,7 @@ func makeExposeClusterName(destinationPort int) string {
// clustersFromSnapshotMeshGateway returns the xDS API representation of the "clusters"
// for a mesh gateway. This will include 1 cluster per remote datacenter as well as
// 1 cluster for each service subset.
func (s *Server) clustersFromSnapshotMeshGateway(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) {
func (s *Server) clustersFromSnapshotMeshGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) {
// 1 cluster per remote dc + 1 cluster per local service (this is a lower bound - all subset specific clusters will be appended)
clusters := make([]proto.Message, 0, len(cfgSnap.MeshGateway.GatewayGroups)+len(cfgSnap.MeshGateway.ServiceGroups))

Expand Down
95 changes: 57 additions & 38 deletions agent/xds/clusters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package xds

import (
"bytes"
"path"
"path/filepath"
"sort"
"testing"
"text/template"
Expand Down Expand Up @@ -336,50 +336,59 @@ func TestClustersFromSnapshot(t *testing.T) {
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)

// Sanity check default with no overrides first
snap := tt.create(t)
for _, envoyVersion := range supportedEnvoyVersions {
sf := determineSupportedProxyFeaturesFromString(envoyVersion)
t.Run("envoy-"+envoyVersion, func(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)

// Sanity check default with no overrides first
snap := tt.create(t)

// We need to replace the TLS certs with deterministic ones to make golden
// files workable. Note we don't update these otherwise they'd change
// golder files for every test case and so not be any use!
if snap.ConnectProxy.Leaf != nil {
snap.ConnectProxy.Leaf.CertPEM = golden(t, "test-leaf-cert", "", "")
snap.ConnectProxy.Leaf.PrivateKeyPEM = golden(t, "test-leaf-key", "", "")
}
if snap.Roots != nil {
snap.Roots.Roots[0].RootCert = golden(t, "test-root-cert", "", "")
}

// We need to replace the TLS certs with deterministic ones to make golden
// files workable. Note we don't update these otherwise they'd change
// golder files for every test case and so not be any use!
if snap.ConnectProxy.Leaf != nil {
snap.ConnectProxy.Leaf.CertPEM = golden(t, "test-leaf-cert", "")
snap.ConnectProxy.Leaf.PrivateKeyPEM = golden(t, "test-leaf-key", "")
}
if snap.Roots != nil {
snap.Roots.Roots[0].RootCert = golden(t, "test-root-cert", "")
}
if tt.setup != nil {
tt.setup(snap)
}

if tt.setup != nil {
tt.setup(snap)
}
// Need server just for logger dependency
logger := testutil.Logger(t)
s := Server{
Logger: logger,
}

// Need server just for logger dependency
logger := testutil.Logger(t)
s := Server{
Logger: logger,
}
cInfo := connectionInfo{
Token: "my-token",
ProxyFeatures: sf,
}
clusters, err := s.clustersFromSnapshot(cInfo, snap)
require.NoError(err)
sort.Slice(clusters, func(i, j int) bool {
return clusters[i].(*envoy.Cluster).Name < clusters[j].(*envoy.Cluster).Name
})
r, err := createResponse(ClusterType, "00000001", "00000001", clusters)
require.NoError(err)

clusters, err := s.clustersFromSnapshot(snap, "my-token")
require.NoError(err)
sort.Slice(clusters, func(i, j int) bool {
return clusters[i].(*envoy.Cluster).Name < clusters[j].(*envoy.Cluster).Name
})
r, err := createResponse(ClusterType, "00000001", "00000001", clusters)
require.NoError(err)
gotJSON := responseToJSON(t, r)

gotJSON := responseToJSON(t, r)
gName := tt.name
if tt.overrideGoldenName != "" {
gName = tt.overrideGoldenName
}

gName := tt.name
if tt.overrideGoldenName != "" {
gName = tt.overrideGoldenName
require.JSONEq(goldenEnvoy(t, filepath.Join("clusters", gName), envoyVersion, gotJSON), gotJSON)
})
}

require.JSONEq(golden(t, path.Join("clusters", gName), gotJSON), gotJSON)
})
}
}
Expand Down Expand Up @@ -557,3 +566,13 @@ func customAppClusterJSON(t *testing.T, opts customClusterJSONOptions) string {
require.NoError(t, err)
return buf.String()
}

// 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.13.1",
"1.12.3",
"1.11.2",
"1.10.0",
}
10 changes: 5 additions & 5 deletions agent/xds/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,24 @@ const (
)

// endpointsFromSnapshot returns the xDS API representation of the "endpoints"
func (s *Server) endpointsFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) {
func (s *Server) endpointsFromSnapshot(cInfo connectionInfo, cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) {
if cfgSnap == nil {
return nil, errors.New("nil config given")
}

switch cfgSnap.Kind {
case structs.ServiceKindConnectProxy:
return s.endpointsFromSnapshotConnectProxy(cfgSnap, token)
return s.endpointsFromSnapshotConnectProxy(cfgSnap)
case structs.ServiceKindMeshGateway:
return s.endpointsFromSnapshotMeshGateway(cfgSnap, token)
return s.endpointsFromSnapshotMeshGateway(cfgSnap)
default:
return nil, fmt.Errorf("Invalid service kind: %v", cfgSnap.Kind)
}
}

// endpointsFromSnapshotConnectProxy returns the xDS API representation of the "endpoints"
// (upstream instances) in the snapshot.
func (s *Server) endpointsFromSnapshotConnectProxy(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) {
func (s *Server) endpointsFromSnapshotConnectProxy(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) {
resources := make([]proto.Message, 0,
len(cfgSnap.ConnectProxy.PreparedQueryEndpoints)+len(cfgSnap.ConnectProxy.WatchedUpstreamEndpoints))

Expand Down Expand Up @@ -168,7 +168,7 @@ func (s *Server) filterSubsetEndpoints(subset *structs.ServiceResolverSubset, en
return endpoints, nil
}

func (s *Server) endpointsFromSnapshotMeshGateway(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) {
func (s *Server) endpointsFromSnapshotMeshGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) {
resources := make([]proto.Message, 0, len(cfgSnap.MeshGateway.GatewayGroups)+len(cfgSnap.MeshGateway.ServiceGroups))

// generate the endpoints for the gateways in the remote datacenters
Expand Down
83 changes: 46 additions & 37 deletions agent/xds/endpoints_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package xds

import (
"path"
"path/filepath"
"sort"
"testing"

Expand Down Expand Up @@ -378,50 +378,59 @@ func Test_endpointsFromSnapshot(t *testing.T) {
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
for _, envoyVersion := range supportedEnvoyVersions {
sf := determineSupportedProxyFeaturesFromString(envoyVersion)
t.Run("envoy-"+envoyVersion, func(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)

// Sanity check default with no overrides first
snap := tt.create(t)
// Sanity check default with no overrides first
snap := tt.create(t)

// We need to replace the TLS certs with deterministic ones to make golden
// files workable. Note we don't update these otherwise they'd change
// golden files for every test case and so not be any use!
if snap.ConnectProxy.Leaf != nil {
snap.ConnectProxy.Leaf.CertPEM = golden(t, "test-leaf-cert", "")
snap.ConnectProxy.Leaf.PrivateKeyPEM = golden(t, "test-leaf-key", "")
}
if snap.Roots != nil {
snap.Roots.Roots[0].RootCert = golden(t, "test-root-cert", "")
}
// We need to replace the TLS certs with deterministic ones to make golden
// files workable. Note we don't update these otherwise they'd change
// golden files for every test case and so not be any use!
if snap.ConnectProxy.Leaf != nil {
snap.ConnectProxy.Leaf.CertPEM = golden(t, "test-leaf-cert", "", "")
snap.ConnectProxy.Leaf.PrivateKeyPEM = golden(t, "test-leaf-key", "", "")
}
if snap.Roots != nil {
snap.Roots.Roots[0].RootCert = golden(t, "test-root-cert", "", "")
}

if tt.setup != nil {
tt.setup(snap)
}
if tt.setup != nil {
tt.setup(snap)
}

// Need server just for logger dependency
logger := testutil.Logger(t)
s := Server{
Logger: logger,
}
// Need server just for logger dependency
logger := testutil.Logger(t)
s := Server{
Logger: logger,
}

endpoints, err := s.endpointsFromSnapshot(snap, "my-token")
sort.Slice(endpoints, func(i, j int) bool {
return endpoints[i].(*envoy.ClusterLoadAssignment).ClusterName < endpoints[j].(*envoy.ClusterLoadAssignment).ClusterName
})
require.NoError(err)
r, err := createResponse(EndpointType, "00000001", "00000001", endpoints)
require.NoError(err)
cInfo := connectionInfo{
Token: "my-token",
ProxyFeatures: sf,
}
endpoints, err := s.endpointsFromSnapshot(cInfo, snap)
sort.Slice(endpoints, func(i, j int) bool {
return endpoints[i].(*envoy.ClusterLoadAssignment).ClusterName < endpoints[j].(*envoy.ClusterLoadAssignment).ClusterName
})
require.NoError(err)
r, err := createResponse(EndpointType, "00000001", "00000001", endpoints)
require.NoError(err)

gotJSON := responseToJSON(t, r)
gotJSON := responseToJSON(t, r)

gName := tt.name
if tt.overrideGoldenName != "" {
gName = tt.overrideGoldenName
}
gName := tt.name
if tt.overrideGoldenName != "" {
gName = tt.overrideGoldenName
}

require.JSONEq(golden(t, path.Join("endpoints", gName), gotJSON), gotJSON)
require.JSONEq(goldenEnvoy(t, filepath.Join("endpoints", gName), envoyVersion, gotJSON), gotJSON)
})
}
})
}
}
Loading