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 of NET-5397 - wire up destination golden tests from sidecar-proxy controller for xds controller and xdsv2 into release/1.17.x #19350

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
20d1fb8
server: run the api checks against the path without params (#19205)
rboyer Oct 13, 2023
3d1a606
Clone proto into deepcopy correctly (#19204)
Oct 13, 2023
9b0f4b7
chore: update version and nightly CI for 1.17 (#19208)
zalimeni Oct 13, 2023
e94d6ce
mesh: add validation hook to proxy configuration (#19186)
ishustava Oct 13, 2023
2ea33e9
mesh: add more validations to Destinations resource (#19202)
ishustava Oct 13, 2023
105ebfd
catalog, mesh: implement missing ACL hooks (#19143)
ishustava Oct 13, 2023
a7fbd00
NET-5073 - ProxyConfiguration: implement various connection options (…
jmurret Oct 14, 2023
3716b69
Relplat 897 copywrite bot workarounds (#19200)
modrake Oct 16, 2023
6c7d075
mesh: add xRoute ACL hook tenancy tests (#19177)
rboyer Oct 16, 2023
ad17769
resource: enforce lowercase v2 resource names (#19218)
analogue Oct 16, 2023
df8ea43
mesh: add DestinationPolicy ACL hook tenancy tests (#19178)
rboyer Oct 16, 2023
6741392
catalog: add FailoverPolicy ACL hook tenancy test (#19179)
rboyer Oct 16, 2023
dcd5930
docs: Multi-port corrections (#19224)
boruszak Oct 16, 2023
b81c862
Add reason why port 53 is not used by default (#19222)
Oct 16, 2023
4c5a46e
v2tenancy: rename v1alpha1 -> v2beta1 (#19227)
analogue Oct 16, 2023
8eb074e
[NET-5944] security: Update Go version to 1.20.10 and `x/net` to 0.17…
zalimeni Oct 16, 2023
9f4f99c
NET-6097 - sidecar proxy controller - give name to first failover pol…
jmurret Oct 17, 2023
a6c990c
Cc 5545: Upgrade HDS packages and modifiers (#19226)
chris-hut Oct 17, 2023
b78465b
[NET-5810] CE changes for multiple virtual hosts (#19246)
jm96441n Oct 17, 2023
61bd08c
Net 4893- Ensure we're testing all the latest versions of Vault/Nomad…
sophie-gairo Oct 17, 2023
9976e08
docs: Fix example control-plane-request-limit HCL and JSON (#19105)
blake Oct 17, 2023
9b719e6
test: add 1.17 nightly integrations test (#19253)
DanStough Oct 17, 2023
51b58cd
fix expose paths (#19257)
ndhanushkodi Oct 17, 2023
c4d6d4d
docs: Multiport HCP constraint update (#19261)
boruszak Oct 17, 2023
16f0a24
docs: Fix multi-port install (#19262)
Oct 17, 2023
f45be22
Prevent circular dependencies between v2 resources and generate a mer…
erichaberkorn Oct 18, 2023
a94c013
build(docker): always publish full and minor version tags for dev ima…
DanStough Oct 18, 2023
d52ee6a
fix nightly integration test: envoy version and n-2 version (#19286)
huikang Oct 18, 2023
5e517c5
[NET-6221] Ensure LB policy set for locality-aware routing (CE) (#19283)
zalimeni Oct 19, 2023
2bd38d8
fix: allow snake case keys for ip based rate limit config entry (#19277)
JadhavPoonam Oct 19, 2023
e5a49bf
reformatted the JSON schema server conf ref (#19288)
trujillo-adam Oct 19, 2023
dfea3a0
acls,catalog,mesh: properly authorize workload selectors on writes (#…
ishustava Oct 19, 2023
ef27bc2
NET-6239: Temporarily disable verify envoy check (#19299)
NiniOak Oct 19, 2023
681aef3
Update supported Envoy versions (#19276)
cthain Oct 19, 2023
def66dd
mesh: provide missing domain to route configurations in ProxyStateTem…
ndhanushkodi Oct 19, 2023
6ffcf28
enable verify envoy script (#19303)
NiniOak Oct 19, 2023
9d00b13
Vault CA bugfixes (#19285)
Oct 20, 2023
b1871fd
Backout Envoy 1.28.0 (#19306)
cthain Oct 20, 2023
1280f45
added ent to ce downgrade changes (#19311)
aahel Oct 20, 2023
b962d91
skip envoy version check in ci (#19315)
NiniOak Oct 20, 2023
d5c9f11
Tenancy Bridge v2 (#19220)
dhiaayachi Oct 20, 2023
27f649c
remove branch name causing conflicts (#19319)
NiniOak Oct 20, 2023
809bf1d
mesh: ensure route configs are named uniquely per port (#19323)
ishustava Oct 20, 2023
46804c0
[NET-5327] Templated policies api/cli docs (#19270)
roncodingenthusiast Oct 23, 2023
fea35e6
More templated policies docs (#19312)
roncodingenthusiast Oct 23, 2023
62dec7e
Fixing docs to add more templated policies references (#19335)
roncodingenthusiast Oct 23, 2023
ee2f046
Upgrade Consul UI to Node 18 (#19252)
chris-hut Oct 23, 2023
96606d1
resource: default peername to local in list endpoints (#19340)
analogue Oct 23, 2023
f142c77
NET-5397 - wire up golden tests from sidecar-proxy controller for xds…
jmurret Oct 12, 2023
79eadd1
WIP
jmurret Oct 13, 2023
d269c63
WIP
jmurret Oct 13, 2023
532aad4
everything matching except leafCerts. need to mock those
jmurret Oct 16, 2023
2de83d4
single port destinations working except mixed destinations
jmurret Oct 16, 2023
c8af477
golden test input to xds controller tests for destinations
jmurret Oct 16, 2023
8822109
proposed fix for failover group naming errors
jmurret Oct 16, 2023
6a1e6c3
clean up test to use helper.
jmurret Oct 16, 2023
f8c81b6
clean up test to use helper.
jmurret Oct 16, 2023
ec5af3c
fix test file
jmurret Oct 16, 2023
854a6e1
add docstring for test function.
jmurret Oct 16, 2023
2b01f73
add docstring for test function.
jmurret Oct 16, 2023
b5fa4f2
fix linting error
jmurret Oct 17, 2023
bc9e8ec
backport of commit b5fa4f29c8f606ee91f0f6df35462564d1521070
jmurret Oct 17, 2023
71a3b1e
Merge b5fa4f29c8f606ee91f0f6df35462564d1521070 into backport/jm/NET-5…
hc-github-team-consul-core Oct 24, 2023
7a78096
backport of commit e7ff94b3a6cdc04a9d31f14781ef39d6ab309c48
jmurret Oct 24, 2023
4b50698
Merge branch 'release/1.17.x' into backport/jm/NET-5397/only-still-goose
jmurret Oct 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions internal/mesh/internal/controllers/xds/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import (
"context"
"crypto/x509"
"encoding/pem"
"fmt"
"strings"
"testing"

"github.com/hashicorp/consul/internal/testing/golden"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"google.golang.org/protobuf/encoding/protojson"

svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing"
"github.com/hashicorp/consul/agent/leafcert"
Expand Down Expand Up @@ -995,3 +999,158 @@ func (suite *xdsControllerTestSuite) TestReconcile_prevWatchesToCancel() {
func TestXdsController(t *testing.T) {
suite.Run(t, new(xdsControllerTestSuite))
}

// TestReconcile_SidecarProxyGoldenFileInputs tests the Reconcile() by using
// the golden test output/expected files from the sidecar proxy tests as inputs
// to the XDS controller reconciliation.
// XDS controller reconciles the full ProxyStateTemplate object. The fields
// that things that it focuses on are leaf certs, endpoints, and trust bundles,
// which is just a subset of the ProxyStateTemplate struct. Prior to XDS controller
// reconciliation, the sidecar proxy controller will have reconciled the other parts
// of the ProxyStateTemplate.
// Since the XDS controller does act on the ProxyStateTemplate, the tests
// utilize that entire object rather than just the parts that XDS controller
// internals reconciles. Namely, by using checking the full ProxyStateTemplate
// rather than just endpoints, leaf certs, and trust bundles, the test also ensures
// side effects or change in scope to XDS controller are not introduce mistakenly.
func (suite *xdsControllerTestSuite) TestReconcile_SidecarProxyGoldenFileInputs() {
path := "../sidecarproxy/builder/testdata"
cases := []string{
// destinations
"destination/l4-single-destination-ip-port-bind-address",
"destination/l4-single-destination-unix-socket-bind-address",
"destination/l4-single-implicit-destination-tproxy",
"destination/l4-multi-destination",
"destination/l4-multiple-implicit-destinations-tproxy",
"destination/l4-implicit-and-explicit-destinations-tproxy",
"destination/mixed-multi-destination",
"destination/multiport-l4-and-l7-multiple-implicit-destinations-tproxy",
"destination/multiport-l4-and-l7-single-implicit-destination-tproxy",
"destination/multiport-l4-and-l7-single-implicit-destination-with-multiple-workloads-tproxy",

//sources

}

for _, name := range cases {
suite.Run(name, func() {
// Create ProxyStateTemplate from the golden file.
pst := JSONToProxyTemplate(suite.T(),
golden.GetBytesAtFilePath(suite.T(), fmt.Sprintf("%s/%s.golden", path, name)))

// Destinations will need endpoint refs set up.
if strings.Split(name, "/")[0] == "destination" && len(pst.ProxyState.Endpoints) == 0 {
suite.addRequiredEndpointsAndRefs(pst)
}

// Store the initial ProxyStateTemplate.
proxyStateTemplate := resourcetest.Resource(pbmesh.ProxyStateTemplateType, "test").
WithData(suite.T(), pst).
Write(suite.T(), suite.client)

// Check with resource service that it exists.
retry.Run(suite.T(), func(r *retry.R) {
suite.client.RequireResourceExists(r, proxyStateTemplate.Id)
})

// Track it in the mapper.
suite.mapper.TrackItem(proxyStateTemplate.Id, []resource.ReferenceOrID{})

// Run the reconcile, and since no ProxyStateTemplate is stored, this simulates a deletion.
err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{
ID: proxyStateTemplate.Id,
})
require.NoError(suite.T(), err)
require.NotNil(suite.T(), proxyStateTemplate)

// Get the reconciled proxyStateTemplate to check the reconcile results.
reconciledPS := suite.updater.Get(proxyStateTemplate.Id.Name)

// Verify leaf cert contents then hard code them for comparison
// and downstream tests since they change from test run to test run.
require.NotEmpty(suite.T(), reconciledPS.LeafCertificates)
reconciledPS.LeafCertificates = map[string]*pbproxystate.LeafCertificate{
"test-identity": {
Cert: "-----BEGIN CERTIFICATE-----\nMIICDjCCAbWgAwIBAgIBAjAKBggqhkjOPQQDAjAUMRIwEAYDVQQDEwlUZXN0IENB\nIDEwHhcNMjMxMDE2MTYxMzI5WhcNMjMxMDE2MTYyMzI5WjAAMFkwEwYHKoZIzj0C\nAQYIKoZIzj0DAQcDQgAErErAIosDPheZQGbxFQ4hYC/e9Fi4MG9z/zjfCnCq/oK9\nta/bGT+5orZqTmdN/ICsKQDhykxZ2u/Xr6845zhcJaOCAQowggEGMA4GA1UdDwEB\n/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDAYDVR0TAQH/\nBAIwADApBgNVHQ4EIgQg3ogXVz9cqaK2B6xdiJYMa5NtT0KkYv7BA2dR7h9EcwUw\nKwYDVR0jBCQwIoAgq+C1mPlPoGa4lt7sSft1goN5qPGyBIB/3mUHJZKSFY8wbwYD\nVR0RAQH/BGUwY4Zhc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9hcC9kZWZhdWx0L25zL2RlZmF1bHQvaWRlbnRpdHkv\ndGVzdC1pZGVudGl0eTAKBggqhkjOPQQDAgNHADBEAiB6L+t5bzRrBPhiQYNeA7fF\nUCuLWrdjW4Xbv3SLg0IKMgIgfRC5hEx+DqzQxTCP4sexX3hVWMjKoWmHdwiUcg+K\n/IE=\n-----END CERTIFICATE-----\n",
Key: "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIFIFkTIL1iUV4O/RpveVHzHs7ZzhSkvYIzbdXDttz9EooAoGCCqGSM49\nAwEHoUQDQgAErErAIosDPheZQGbxFQ4hYC/e9Fi4MG9z/zjfCnCq/oK9ta/bGT+5\norZqTmdN/ICsKQDhykxZ2u/Xr6845zhcJQ==\n-----END EC PRIVATE KEY-----\n",
},
}

// Compare actual vs expected.
actual := prototest.ProtoToJSON(suite.T(), reconciledPS)
expected := golden.Get(suite.T(), actual, name+".golden")
require.JSONEq(suite.T(), expected, actual)
})
}
}

func (suite *xdsControllerTestSuite) addRequiredEndpointsAndRefs(pst *pbmesh.ProxyStateTemplate) {
//get service data
serviceData := &pbcatalog.Service{}
var vp uint32 = 7000
requiredEps := make(map[string]*pbproxystate.EndpointRef)

// iterate through clusters and set up endpoints for cluster/mesh port.
for clusterName := range pst.ProxyState.Clusters {
if clusterName == "null_route_cluster" || clusterName == "original-destination" {
continue
}

//increment the random port number.
vp++
clusterNameSplit := strings.Split(clusterName, ".")
port := clusterNameSplit[0]
svcName := clusterNameSplit[1]

// set up service data with port info.
serviceData.Ports = append(serviceData.Ports, &pbcatalog.ServicePort{
TargetPort: port,
VirtualPort: vp,
Protocol: pbcatalog.Protocol_PROTOCOL_TCP,
})

// create service.
svc := resourcetest.Resource(pbcatalog.ServiceType, svcName).
WithData(suite.T(), &pbcatalog.Service{}).
Write(suite.T(), suite.client)

// create endpoints with svc as owner.
eps := resourcetest.Resource(pbcatalog.ServiceEndpointsType, svcName).
WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{
{
Ports: map[string]*pbcatalog.WorkloadPort{
"mesh": {
Port: 20000,
Protocol: pbcatalog.Protocol_PROTOCOL_MESH,
},
},
Addresses: []*pbcatalog.WorkloadAddress{
{
Host: "10.1.1.1",
Ports: []string{"mesh"},
},
},
},
}}).
WithOwner(svc.Id).
Write(suite.T(), suite.client)

// add to working list of required endpoints.
requiredEps[clusterName] = &pbproxystate.EndpointRef{
Id: eps.Id,
Port: "mesh",
}
}

// set working list of required endpoints as proxy state's RequiredEndpoints.
pst.RequiredEndpoints = requiredEps
}

func JSONToProxyTemplate(t *testing.T, json []byte) *pbmesh.ProxyStateTemplate {
t.Helper()
proxyTemplate := &pbmesh.ProxyStateTemplate{}
m := protojson.UnmarshalOptions{}
err := m.Unmarshal(json, proxyTemplate)
require.NoError(t, err)
return proxyTemplate
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
{
"clusters": {
"original-destination": {
"endpointGroup": {
"passthrough": {
"config": {
"connectTimeout": "5s"
}
}
},
"name": "original-destination"
},
"tcp.api-1.default.dc1.internal.foo.consul": {
"altStatName": "tcp.api-1.default.dc1.internal.foo.consul",
"endpointGroup": {
"dynamic": {
"config": {
"connectTimeout": "5s",
"disablePanicThreshold": true
},
"outboundTls": {
"alpnProtocols": [
"consul~tcp"
],
"outboundMesh": {
"identityKey": "test-identity",
"sni": "api-1.default.dc1.internal.foo.consul",
"validationContext": {
"spiffeIds": [
"spiffe://foo.consul/ap/default/ns/default/identity/api1-identity"
],
"trustBundlePeerNameKey": "local"
}
}
}
}
},
"name": "tcp.api-1.default.dc1.internal.foo.consul"
},
"tcp.api-2.default.dc1.internal.foo.consul": {
"altStatName": "tcp.api-2.default.dc1.internal.foo.consul",
"endpointGroup": {
"dynamic": {
"config": {
"connectTimeout": "5s",
"disablePanicThreshold": true
},
"outboundTls": {
"alpnProtocols": [
"consul~tcp"
],
"outboundMesh": {
"identityKey": "test-identity",
"sni": "api-2.default.dc1.internal.foo.consul",
"validationContext": {
"spiffeIds": [
"spiffe://foo.consul/ap/default/ns/default/identity/api2-identity"
],
"trustBundlePeerNameKey": "local"
}
}
}
}
},
"name": "tcp.api-2.default.dc1.internal.foo.consul"
}
},
"identity": {
"name": "test-identity",
"tenancy": {
"namespace": "default",
"partition": "default",
"peerName": "local"
},
"type": {
"group": "auth",
"groupVersion": "v2beta1",
"kind": "WorkloadIdentity"
}
},
"listeners": [
{
"direction": "DIRECTION_OUTBOUND",
"hostPort": {
"host": "1.1.1.1",
"port": 1234
},
"name": "default/local/default/api-1:tcp:1.1.1.1:1234",
"routers": [
{
"l4": {
"cluster": {
"name": "tcp.api-1.default.dc1.internal.foo.consul"
},
"statPrefix": "upstream.tcp.api-1.default.default.dc1"
}
}
]
},
{
"capabilities": [
"CAPABILITY_TRANSPARENT"
],
"defaultRouter": {
"l4": {
"cluster": {
"name": "original-destination"
},
"statPrefix": "upstream.original-destination"
}
},
"direction": "DIRECTION_OUTBOUND",
"hostPort": {
"host": "127.0.0.1",
"port": 15001
},
"name": "outbound_listener",
"routers": [
{
"l4": {
"cluster": {
"name": "tcp.api-2.default.dc1.internal.foo.consul"
},
"statPrefix": "upstream.tcp.api-2.default.default.dc1"
},
"match": {
"destinationPort": 7070,
"prefixRanges": [
{
"addressPrefix": "2.2.2.2",
"prefixLen": 32
},
{
"addressPrefix": "3.3.3.3",
"prefixLen": 32
}
]
}
}
]
}
],
"endpoints": {
"tcp.api-1.default.dc1.internal.foo.consul": {
"endpoints": [
{
"healthStatus": "HEALTH_STATUS_HEALTHY",
"hostPort": {
"host": "10.1.1.1",
"port": 20000
}
}
]
},
"tcp.api-2.default.dc1.internal.foo.consul": {
"endpoints": [
{
"healthStatus": "HEALTH_STATUS_HEALTHY",
"hostPort": {
"host": "10.1.1.1",
"port": 20000
}
}
]
}
},
"trustBundles": {
"local": {
"roots": [
"some-root",
"some-other-root"
],
"trustDomain": "some-trust-domain"
}
},
"leafCertificates": {
"test-identity": {
"cert": "-----BEGIN CERTIFICATE-----\nMIICDjCCAbWgAwIBAgIBAjAKBggqhkjOPQQDAjAUMRIwEAYDVQQDEwlUZXN0IENB\nIDEwHhcNMjMxMDE2MTYxMzI5WhcNMjMxMDE2MTYyMzI5WjAAMFkwEwYHKoZIzj0C\nAQYIKoZIzj0DAQcDQgAErErAIosDPheZQGbxFQ4hYC/e9Fi4MG9z/zjfCnCq/oK9\nta/bGT+5orZqTmdN/ICsKQDhykxZ2u/Xr6845zhcJaOCAQowggEGMA4GA1UdDwEB\n/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDAYDVR0TAQH/\nBAIwADApBgNVHQ4EIgQg3ogXVz9cqaK2B6xdiJYMa5NtT0KkYv7BA2dR7h9EcwUw\nKwYDVR0jBCQwIoAgq+C1mPlPoGa4lt7sSft1goN5qPGyBIB/3mUHJZKSFY8wbwYD\nVR0RAQH/BGUwY4Zhc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9hcC9kZWZhdWx0L25zL2RlZmF1bHQvaWRlbnRpdHkv\ndGVzdC1pZGVudGl0eTAKBggqhkjOPQQDAgNHADBEAiB6L+t5bzRrBPhiQYNeA7fF\nUCuLWrdjW4Xbv3SLg0IKMgIgfRC5hEx+DqzQxTCP4sexX3hVWMjKoWmHdwiUcg+K\n/IE=\n-----END CERTIFICATE-----\n",
"key": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIFIFkTIL1iUV4O/RpveVHzHs7ZzhSkvYIzbdXDttz9EooAoGCCqGSM49\nAwEHoUQDQgAErErAIosDPheZQGbxFQ4hYC/e9Fi4MG9z/zjfCnCq/oK9ta/bGT+5\norZqTmdN/ICsKQDhykxZ2u/Xr6845zhcJQ==\n-----END EC PRIVATE KEY-----\n"
}
}
}
Loading