[NET-6438] Add tenancy to xDS Tests (#19551)

* [NET-6438] Add tenancy to xDS Tests

* [NET-6438] Add tenancy to xDS Tests
- Fixing imports

* [NET-6438] Add tenancy to xDS Tests
- Added cleanup post test run

* [NET-6356] Add tenancy to xDS Tests
- Added cleanup post test run

* [NET-6438] Add tenancy to xDS Tests
- using t.Cleanup instead of defer delete

* [NET-6438] Add tenancy to xDS Tests
- rebased

* [NET-6438] Add tenancy to xDS Tests
- rebased
This commit is contained in:
Kumar Kavish 2023-11-10 15:32:36 +05:30 committed by GitHub
parent 005e1b9926
commit 68e7f27fd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 696 additions and 566 deletions

View File

@ -5,7 +5,6 @@ package testing
import ( import (
"context" "context"
rtest "github.com/hashicorp/consul/internal/resource/resourcetest"
"testing" "testing"
"github.com/hashicorp/go-uuid" "github.com/hashicorp/go-uuid"
@ -21,6 +20,7 @@ import (
internal "github.com/hashicorp/consul/agent/grpc-internal" internal "github.com/hashicorp/consul/agent/grpc-internal"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/resource"
rtest "github.com/hashicorp/consul/internal/resource/resourcetest"
"github.com/hashicorp/consul/internal/storage/inmem" "github.com/hashicorp/consul/internal/storage/inmem"
"github.com/hashicorp/consul/internal/tenancy" "github.com/hashicorp/consul/internal/tenancy"
"github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/consul/proto-public/pbresource"

View File

@ -11,7 +11,6 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/hashicorp/consul/internal/testing/golden"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
@ -26,6 +25,7 @@ import (
"github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/resource/mappers/bimapper" "github.com/hashicorp/consul/internal/resource/mappers/bimapper"
"github.com/hashicorp/consul/internal/resource/resourcetest" "github.com/hashicorp/consul/internal/resource/resourcetest"
"github.com/hashicorp/consul/internal/testing/golden"
pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1"
pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1"
"github.com/hashicorp/consul/proto-public/pbmesh/v2beta1/pbproxystate" "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1/pbproxystate"
@ -51,6 +51,7 @@ type xdsControllerTestSuite struct {
leafCancels *LeafCancels leafCancels *LeafCancels
leafCertEvents chan controller.Event leafCertEvents chan controller.Event
signer *leafcert.TestSigner signer *leafcert.TestSigner
tenancies []*pbresource.Tenancy
fooProxyStateTemplate *pbresource.Resource fooProxyStateTemplate *pbresource.Resource
barProxyStateTemplate *pbresource.Resource barProxyStateTemplate *pbresource.Resource
@ -69,7 +70,7 @@ type xdsControllerTestSuite struct {
func (suite *xdsControllerTestSuite) SetupTest() { func (suite *xdsControllerTestSuite) SetupTest() {
suite.ctx = testutil.TestContext(suite.T()) suite.ctx = testutil.TestContext(suite.T())
resourceClient := svctest.RunResourceService(suite.T(), types.Register, catalog.RegisterTypes) resourceClient := svctest.RunResourceServiceWithTenancies(suite.T(), types.Register, catalog.RegisterTypes)
suite.runtime = controller.Runtime{Client: resourceClient, Logger: testutil.Logger(suite.T())} suite.runtime = controller.Runtime{Client: resourceClient, Logger: testutil.Logger(suite.T())}
suite.client = resourcetest.NewClient(resourceClient) suite.client = resourcetest.NewClient(resourceClient)
suite.fetcher = mockFetcher suite.fetcher = mockFetcher
@ -99,6 +100,8 @@ func (suite *xdsControllerTestSuite) SetupTest() {
leafCertEvents: suite.leafCertEvents, leafCertEvents: suite.leafCertEvents,
datacenter: "dc1", datacenter: "dc1",
} }
suite.tenancies = resourcetest.TestTenancies()
} }
func mockFetcher() (*pbproxystate.TrustBundle, error) { func mockFetcher() (*pbproxystate.TrustBundle, error) {
@ -112,8 +115,12 @@ func mockFetcher() (*pbproxystate.TrustBundle, error) {
// This test ensures when a ProxyState is deleted, it is no longer tracked in the mappers. // This test ensures when a ProxyState is deleted, it is no longer tracked in the mappers.
func (suite *xdsControllerTestSuite) TestReconcile_NoProxyStateTemplate() { func (suite *xdsControllerTestSuite) TestReconcile_NoProxyStateTemplate() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Track the id of a non-existent ProxyStateTemplate. // Track the id of a non-existent ProxyStateTemplate.
proxyStateTemplateId := resourcetest.Resource(pbmesh.ProxyStateTemplateType, "not-found").ID() proxyStateTemplateId := resourcetest.Resource(pbmesh.ProxyStateTemplateType, "not-found").WithTenancy(tenancy).ID()
suite.T().Cleanup(suite.deleteResourceFunc(proxyStateTemplateId))
suite.mapper.TrackItem(proxyStateTemplateId, []resource.ReferenceOrID{}) suite.mapper.TrackItem(proxyStateTemplateId, []resource.ReferenceOrID{})
suite.leafMapper.TrackItem(proxyStateTemplateId, []resource.ReferenceOrID{}) suite.leafMapper.TrackItem(proxyStateTemplateId, []resource.ReferenceOrID{})
require.False(suite.T(), suite.mapper.IsEmpty()) require.False(suite.T(), suite.mapper.IsEmpty())
@ -128,16 +135,21 @@ func (suite *xdsControllerTestSuite) TestReconcile_NoProxyStateTemplate() {
// Assert that nothing is tracked in the endpoints mapper. // Assert that nothing is tracked in the endpoints mapper.
require.True(suite.T(), suite.mapper.IsEmpty()) require.True(suite.T(), suite.mapper.IsEmpty())
require.True(suite.T(), suite.leafMapper.IsEmpty()) require.True(suite.T(), suite.leafMapper.IsEmpty())
})
} }
// This test ensures if the controller was previously tracking a ProxyStateTemplate, and now that proxy has // This test ensures if the controller was previously tracking a ProxyStateTemplate, and now that proxy has
// disconnected from this server, it's ignored and removed from the mapper. // disconnected from this server, it's ignored and removed from the mapper.
func (suite *xdsControllerTestSuite) TestReconcile_RemoveTrackingProxiesNotConnectedToServer() { func (suite *xdsControllerTestSuite) TestReconcile_RemoveTrackingProxiesNotConnectedToServer() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Store the initial ProxyStateTemplate and track it in the mapper. // Store the initial ProxyStateTemplate and track it in the mapper.
proxyStateTemplate := resourcetest.Resource(pbmesh.ProxyStateTemplateType, "test"). proxyStateTemplate := resourcetest.Resource(pbmesh.ProxyStateTemplateType, "test").
WithData(suite.T(), &pbmesh.ProxyStateTemplate{}). WithData(suite.T(), &pbmesh.ProxyStateTemplate{}).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(proxyStateTemplate.Id))
suite.mapper.TrackItem(proxyStateTemplate.Id, []resource.ReferenceOrID{}) suite.mapper.TrackItem(proxyStateTemplate.Id, []resource.ReferenceOrID{})
// Simulate the proxy disconnecting from this server. The resource still exists, but this proxy might be connected // Simulate the proxy disconnecting from this server. The resource still exists, but this proxy might be connected
@ -152,16 +164,18 @@ func (suite *xdsControllerTestSuite) TestReconcile_RemoveTrackingProxiesNotConne
// Assert that nothing is tracked in the mapper. // Assert that nothing is tracked in the mapper.
require.True(suite.T(), suite.mapper.IsEmpty()) require.True(suite.T(), suite.mapper.IsEmpty())
})
} }
// This test sets up the updater to return an error when calling PushChange, and ensures the status is set // This test sets up the updater to return an error when calling PushChange, and ensures the status is set
// correctly. // correctly.
func (suite *xdsControllerTestSuite) TestReconcile_PushChangeError() { func (suite *xdsControllerTestSuite) TestReconcile_PushChangeError() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Have the mock simulate an error from the PushChange call. // Have the mock simulate an error from the PushChange call.
suite.updater.pushChangeError = true suite.updater.pushChangeError = true
// Setup a happy path scenario. // Setup a happy path scenario.
suite.setupFooProxyStateTemplateWithReferences() suite.setupFooProxyStateTemplateWithReferences(tenancy)
// Run the reconcile. // Run the reconcile.
err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{ err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{
@ -171,14 +185,16 @@ func (suite *xdsControllerTestSuite) TestReconcile_PushChangeError() {
// Assert on the status reflecting endpoint not found. // Assert on the status reflecting endpoint not found.
suite.client.RequireStatusCondition(suite.T(), suite.fooProxyStateTemplate.Id, ControllerName, status.ConditionRejectedPushChangeFailed(status.KeyFromID(suite.fooProxyStateTemplate.Id))) suite.client.RequireStatusCondition(suite.T(), suite.fooProxyStateTemplate.Id, ControllerName, status.ConditionRejectedPushChangeFailed(status.KeyFromID(suite.fooProxyStateTemplate.Id)))
})
} }
// This test sets up a ProxyStateTemplate that references a ServiceEndpoints that doesn't exist, and ensures the // This test sets up a ProxyStateTemplate that references a ServiceEndpoints that doesn't exist, and ensures the
// status is correct. // status is correct.
func (suite *xdsControllerTestSuite) TestReconcile_MissingEndpoint() { func (suite *xdsControllerTestSuite) TestReconcile_MissingEndpoint() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Set fooProxyStateTemplate with a reference to fooEndpoints, without storing fooEndpoints so the controller should // Set fooProxyStateTemplate with a reference to fooEndpoints, without storing fooEndpoints so the controller should
// notice it's missing. // notice it's missing.
fooEndpointsId := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "foo-service").WithTenancy(resource.DefaultNamespacedTenancy()).ID() fooEndpointsId := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "foo-service").WithTenancy(tenancy).ID()
fooRequiredEndpoints := make(map[string]*pbproxystate.EndpointRef) fooRequiredEndpoints := make(map[string]*pbproxystate.EndpointRef)
fooRequiredEndpoints["test-cluster-1"] = &pbproxystate.EndpointRef{ fooRequiredEndpoints["test-cluster-1"] = &pbproxystate.EndpointRef{
Id: fooEndpointsId, Id: fooEndpointsId,
@ -190,8 +206,11 @@ func (suite *xdsControllerTestSuite) TestReconcile_MissingEndpoint() {
RequiredEndpoints: fooRequiredEndpoints, RequiredEndpoints: fooRequiredEndpoints,
ProxyState: &pbmesh.ProxyState{}, ProxyState: &pbmesh.ProxyState{},
}). }).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooProxyStateTemplate.Id))
retry.Run(suite.T(), func(r *retry.R) { retry.Run(suite.T(), func(r *retry.R) {
suite.client.RequireResourceExists(r, fooProxyStateTemplate.Id) suite.client.RequireResourceExists(r, fooProxyStateTemplate.Id)
}) })
@ -204,18 +223,20 @@ func (suite *xdsControllerTestSuite) TestReconcile_MissingEndpoint() {
// Assert on the status reflecting endpoint not found. // Assert on the status reflecting endpoint not found.
suite.client.RequireStatusCondition(suite.T(), fooProxyStateTemplate.Id, ControllerName, status.ConditionRejectedErrorReadingEndpoints(status.KeyFromID(fooEndpointsId), "rpc error: code = NotFound desc = resource not found")) suite.client.RequireStatusCondition(suite.T(), fooProxyStateTemplate.Id, ControllerName, status.ConditionRejectedErrorReadingEndpoints(status.KeyFromID(fooEndpointsId), "rpc error: code = NotFound desc = resource not found"))
})
} }
// This test sets up a ProxyStateTemplate that references a ServiceEndpoints that can't be read correctly, and // This test sets up a ProxyStateTemplate that references a ServiceEndpoints that can't be read correctly, and
// checks the status is correct. // checks the status is correct.
func (suite *xdsControllerTestSuite) TestReconcile_ReadEndpointError() { func (suite *xdsControllerTestSuite) TestReconcile_ReadEndpointError() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
badID := &pbresource.ID{ badID := &pbresource.ID{
Type: &pbresource.Type{ Type: &pbresource.Type{
Group: "not", Group: "not",
Kind: "found", Kind: "found",
GroupVersion: "vfake", GroupVersion: "vfake",
}, },
Tenancy: &pbresource.Tenancy{Namespace: "default", Partition: "default", PeerName: "local"}, Tenancy: tenancy,
} }
fooRequiredEndpoints := make(map[string]*pbproxystate.EndpointRef) fooRequiredEndpoints := make(map[string]*pbproxystate.EndpointRef)
fooRequiredEndpoints["test-cluster-1"] = &pbproxystate.EndpointRef{ fooRequiredEndpoints["test-cluster-1"] = &pbproxystate.EndpointRef{
@ -228,8 +249,11 @@ func (suite *xdsControllerTestSuite) TestReconcile_ReadEndpointError() {
RequiredEndpoints: fooRequiredEndpoints, RequiredEndpoints: fooRequiredEndpoints,
ProxyState: &pbmesh.ProxyState{}, ProxyState: &pbmesh.ProxyState{},
}). }).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooProxyStateTemplate.Id))
retry.Run(suite.T(), func(r *retry.R) { retry.Run(suite.T(), func(r *retry.R) {
suite.client.RequireResourceExists(r, fooProxyStateTemplate.Id) suite.client.RequireResourceExists(r, fooProxyStateTemplate.Id)
}) })
@ -245,15 +269,17 @@ func (suite *xdsControllerTestSuite) TestReconcile_ReadEndpointError() {
status.KeyFromID(badID), status.KeyFromID(badID),
"rpc error: code = InvalidArgument desc = id.name invalid: a resource name must consist of lower case alphanumeric characters or '-', must start and end with an alphanumeric character and be less than 64 characters, got: \"\"", "rpc error: code = InvalidArgument desc = id.name invalid: a resource name must consist of lower case alphanumeric characters or '-', must start and end with an alphanumeric character and be less than 64 characters, got: \"\"",
)) ))
})
} }
// This test is a happy path creation test to make sure pbproxystate.Endpoints are created in the computed // This test is a happy path creation test to make sure pbproxystate.Endpoints are created in the computed
// pbmesh.ProxyState from the RequiredEndpoints references. More specific translations between endpoint references // pbmesh.ProxyState from the RequiredEndpoints references. More specific translations between endpoint references
// and pbproxystate.Endpoints are unit tested in endpoint_builder.go. // and pbproxystate.Endpoints are unit tested in endpoint_builder.go.
func (suite *xdsControllerTestSuite) TestReconcile_ProxyStateTemplateComputesEndpoints() { func (suite *xdsControllerTestSuite) TestReconcile_ProxyStateTemplateComputesEndpoints() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Set up fooEndpoints and fooProxyStateTemplate with a reference to fooEndpoints and store them in the state store. // Set up fooEndpoints and fooProxyStateTemplate with a reference to fooEndpoints and store them in the state store.
// This setup saves expected values in the suite so it can be asserted against later. // This setup saves expected values in the suite so it can be asserted against later.
suite.setupFooProxyStateTemplateWithReferences() suite.setupFooProxyStateTemplateWithReferences(tenancy)
// Run the reconcile. // Run the reconcile.
err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{ err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{
@ -267,12 +293,14 @@ func (suite *xdsControllerTestSuite) TestReconcile_ProxyStateTemplateComputesEnd
// Assert that the endpoints computed in the controller matches the expected endpoints. // Assert that the endpoints computed in the controller matches the expected endpoints.
actualEndpoints := suite.updater.GetEndpoints(suite.fooProxyStateTemplate.Id.Name) actualEndpoints := suite.updater.GetEndpoints(suite.fooProxyStateTemplate.Id.Name)
prototest.AssertDeepEqual(suite.T(), suite.expectedFooProxyStateEndpoints, actualEndpoints) prototest.AssertDeepEqual(suite.T(), suite.expectedFooProxyStateEndpoints, actualEndpoints)
})
} }
func (suite *xdsControllerTestSuite) TestReconcile_ProxyStateTemplateComputesLeafCerts() { func (suite *xdsControllerTestSuite) TestReconcile_ProxyStateTemplateComputesLeafCerts() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Set up fooEndpoints and fooProxyStateTemplate with a reference to fooEndpoints and store them in the state store. // Set up fooEndpoints and fooProxyStateTemplate with a reference to fooEndpoints and store them in the state store.
// This setup saves expected values in the suite so it can be asserted against later. // This setup saves expected values in the suite so it can be asserted against later.
suite.setupFooProxyStateTemplateWithReferences() suite.setupFooProxyStateTemplateWithReferences(tenancy)
// Run the reconcile. // Run the reconcile.
err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{ err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{
@ -287,17 +315,19 @@ func (suite *xdsControllerTestSuite) TestReconcile_ProxyStateTemplateComputesLea
actualLeafs := suite.updater.GetLeafs(suite.fooProxyStateTemplate.Id.Name) actualLeafs := suite.updater.GetLeafs(suite.fooProxyStateTemplate.Id.Name)
for k, l := range actualLeafs { for k, l := range actualLeafs {
pem, _ := pem.Decode([]byte(l.Cert)) pemDecode, _ := pem.Decode([]byte(l.Cert))
cert, err := x509.ParseCertificate(pem.Bytes) cert, err := x509.ParseCertificate(pemDecode.Bytes)
require.NoError(suite.T(), err) require.NoError(suite.T(), err)
require.Equal(suite.T(), cert.URIs[0].String(), suite.expectedFooProxyStateSpiffes[k]) require.Equal(suite.T(), cert.URIs[0].String(), suite.expectedFooProxyStateSpiffes[k])
} }
})
} }
// This test is a happy path creation test to make sure pbproxystate.Template.TrustBundles are created in the computed // This test is a happy path creation test to make sure pbproxystate.Template.TrustBundles are created in the computed
// pbmesh.ProxyState from the TrustBundleFetcher. // pbmesh.ProxyState from the TrustBundleFetcher.
func (suite *xdsControllerTestSuite) TestReconcile_ProxyStateTemplateSetsTrustBundles() { func (suite *xdsControllerTestSuite) TestReconcile_ProxyStateTemplateSetsTrustBundles() {
suite.setupFooProxyStateTemplateWithReferences() suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
suite.setupFooProxyStateTemplateWithReferences(tenancy)
// Run the reconcile. // Run the reconcile.
err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{ err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{
@ -311,6 +341,7 @@ func (suite *xdsControllerTestSuite) TestReconcile_ProxyStateTemplateSetsTrustBu
// Assert that the endpoints computed in the controller matches the expected endpoints. // Assert that the endpoints computed in the controller matches the expected endpoints.
actualTrustBundle := suite.updater.GetTrustBundle(suite.fooProxyStateTemplate.Id.Name) actualTrustBundle := suite.updater.GetTrustBundle(suite.fooProxyStateTemplate.Id.Name)
prototest.AssertDeepEqual(suite.T(), suite.expectedTrustBundle, actualTrustBundle) prototest.AssertDeepEqual(suite.T(), suite.expectedTrustBundle, actualTrustBundle)
})
} }
// This test is a happy path creation test that calls reconcile multiple times with a more complex setup. This // This test is a happy path creation test that calls reconcile multiple times with a more complex setup. This
@ -318,9 +349,10 @@ func (suite *xdsControllerTestSuite) TestReconcile_ProxyStateTemplateSetsTrustBu
// stored in the state store. So this test ensures that between multiple reconciles the correct ProxyStates are // stored in the state store. So this test ensures that between multiple reconciles the correct ProxyStates are
// computed for each ProxyStateTemplate. // computed for each ProxyStateTemplate.
func (suite *xdsControllerTestSuite) TestReconcile_MultipleProxyStateTemplatesComputesMultipleEndpoints() { func (suite *xdsControllerTestSuite) TestReconcile_MultipleProxyStateTemplatesComputesMultipleEndpoints() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Set up fooProxyStateTemplate and barProxyStateTemplate and their associated resources and store them. Resources // Set up fooProxyStateTemplate and barProxyStateTemplate and their associated resources and store them. Resources
// and expected results are stored in the suite to assert against. // and expected results are stored in the suite to assert against.
suite.setupFooBarProxyStateTemplateAndEndpoints() suite.setupFooBarProxyStateTemplateAndEndpoints(tenancy)
// Reconcile the fooProxyStateTemplate. // Reconcile the fooProxyStateTemplate.
err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{ err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{
@ -347,17 +379,19 @@ func (suite *xdsControllerTestSuite) TestReconcile_MultipleProxyStateTemplatesCo
// Assert that the endpoints computed in the controller matches the expected endpoints. // Assert that the endpoints computed in the controller matches the expected endpoints.
actualBarEndpoints := suite.updater.GetEndpoints(suite.barProxyStateTemplate.Id.Name) actualBarEndpoints := suite.updater.GetEndpoints(suite.barProxyStateTemplate.Id.Name)
prototest.AssertDeepEqual(suite.T(), suite.expectedBarProxyStateEndpoints, actualBarEndpoints) prototest.AssertDeepEqual(suite.T(), suite.expectedBarProxyStateEndpoints, actualBarEndpoints)
})
} }
// Sets up a full controller, and tests that reconciles are getting triggered for the events it should. // Sets up a full controller, and tests that reconciles are getting triggered for the events it should.
func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateEndpointReferences() { func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateEndpointReferences() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Run the controller manager. // Run the controller manager.
mgr := controller.NewManager(suite.client, suite.runtime.Logger) mgr := controller.NewManager(suite.client, suite.runtime.Logger)
mgr.Register(Controller(suite.mapper, suite.updater, suite.fetcher, suite.leafCertManager, suite.leafMapper, suite.leafCancels, "dc1")) mgr.Register(Controller(suite.mapper, suite.updater, suite.fetcher, suite.leafCertManager, suite.leafMapper, suite.leafCancels, "dc1"))
mgr.SetRaftLeader(true) mgr.SetRaftLeader(true)
go mgr.Run(suite.ctx) go mgr.Run(suite.ctx)
suite.setupFooProxyStateTemplateWithReferences() suite.setupFooProxyStateTemplateWithReferences(tenancy)
// Assert that the expected ProxyState matches the actual ProxyState that PushChange was called with. This needs to // Assert that the expected ProxyState matches the actual ProxyState that PushChange was called with. This needs to
// be in a retry block unlike the Reconcile tests because the controller triggers asynchronously. // be in a retry block unlike the Reconcile tests because the controller triggers asynchronously.
@ -371,7 +405,7 @@ func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateEndpointRefe
// Now, update the endpoint to be unhealthy. This will ensure the controller is getting triggered on changes to this // Now, update the endpoint to be unhealthy. This will ensure the controller is getting triggered on changes to this
// endpoint that it should be tracking, even when the ProxyStateTemplate does not change. // endpoint that it should be tracking, even when the ProxyStateTemplate does not change.
resourcetest.Resource(pbcatalog.ServiceEndpointsType, "foo-service"). svc := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "foo-service").
WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{ WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{
{ {
Ports: map[string]*pbcatalog.WorkloadPort{ Ports: map[string]*pbcatalog.WorkloadPort{
@ -394,8 +428,11 @@ func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateEndpointRefe
}, },
}}). }}).
WithOwner(suite.fooService.Id). WithOwner(suite.fooService.Id).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
// Wait for the endpoint to be written. // Wait for the endpoint to be written.
retry.Run(suite.T(), func(r *retry.R) { retry.Run(suite.T(), func(r *retry.R) {
suite.client.RequireVersionChanged(suite.T(), suite.fooEndpoints.Id, suite.fooEndpoints.Version) suite.client.RequireVersionChanged(suite.T(), suite.fooEndpoints.Id, suite.fooEndpoints.Version)
@ -417,8 +454,11 @@ func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateEndpointRefe
// now tracks the newly added endpoint. // now tracks the newly added endpoint.
secondService := resourcetest.Resource(pbcatalog.ServiceType, "second-service"). secondService := resourcetest.Resource(pbcatalog.ServiceType, "second-service").
WithData(suite.T(), &pbcatalog.Service{}). WithData(suite.T(), &pbcatalog.Service{}).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(secondService.Id))
secondEndpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "second-service"). secondEndpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "second-service").
WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{ WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{
{ {
@ -441,8 +481,11 @@ func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateEndpointRefe
}, },
}}). }}).
WithOwner(secondService.Id). WithOwner(secondService.Id).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(secondEndpoints.Id))
// Update the endpoint references on the fooProxyStateTemplate. // Update the endpoint references on the fooProxyStateTemplate.
suite.fooEndpointRefs["test-cluster-2"] = &pbproxystate.EndpointRef{ suite.fooEndpointRefs["test-cluster-2"] = &pbproxystate.EndpointRef{
Id: secondEndpoints.Id, Id: secondEndpoints.Id,
@ -456,8 +499,11 @@ func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateEndpointRefe
ProxyState: &pbmesh.ProxyState{}, ProxyState: &pbmesh.ProxyState{},
RequiredLeafCertificates: suite.fooLeafRefs, RequiredLeafCertificates: suite.fooLeafRefs,
}). }).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooProxyStateTemplate.Id))
retry.Run(suite.T(), func(r *retry.R) { retry.Run(suite.T(), func(r *retry.R) {
suite.client.RequireVersionChanged(r, fooProxyStateTemplate.Id, oldVersion) suite.client.RequireVersionChanged(r, fooProxyStateTemplate.Id, oldVersion)
}) })
@ -494,18 +540,20 @@ func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateEndpointRefe
prototest.AssertDeepEqual(r, suite.expectedFooProxyStateEndpoints, actualEndpoints) prototest.AssertDeepEqual(r, suite.expectedFooProxyStateEndpoints, actualEndpoints)
}) })
})
} }
// Sets up a full controller, and tests that reconciles are getting triggered for the leaf cert events it should. // Sets up a full controller, and tests that reconciles are getting triggered for the leaf cert events it should.
// This test ensures when a CA is updated, the controller is triggered to update the leaf cert when it changes. // This test ensures when a CA is updated, the controller is triggered to update the leaf cert when it changes.
func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateDeleteLeafReferences() { func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateDeleteLeafReferences() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Run the controller manager. // Run the controller manager.
mgr := controller.NewManager(suite.client, suite.runtime.Logger) mgr := controller.NewManager(suite.client, suite.runtime.Logger)
mgr.Register(Controller(suite.mapper, suite.updater, suite.fetcher, suite.leafCertManager, suite.leafMapper, suite.leafCancels, "dc1")) mgr.Register(Controller(suite.mapper, suite.updater, suite.fetcher, suite.leafCertManager, suite.leafMapper, suite.leafCancels, "dc1"))
mgr.SetRaftLeader(true) mgr.SetRaftLeader(true)
go mgr.Run(suite.ctx) go mgr.Run(suite.ctx)
suite.setupFooProxyStateTemplateWithReferences() suite.setupFooProxyStateTemplateWithReferences(tenancy)
leafCertRef := suite.fooLeafRefs["foo-workload-identity"] leafCertRef := suite.fooLeafRefs["foo-workload-identity"]
fooLeafResRef := leafResourceRef(leafCertRef.Name, leafCertRef.Namespace, leafCertRef.Partition) fooLeafResRef := leafResourceRef(leafCertRef.Name, leafCertRef.Namespace, leafCertRef.Partition)
@ -524,8 +572,8 @@ func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateDeleteLeafRe
// Assert that the leafs computed in the controller matches the expected leafs. // Assert that the leafs computed in the controller matches the expected leafs.
require.Len(r, actualLeafs, 1) require.Len(r, actualLeafs, 1)
for k, l := range actualLeafs { for k, l := range actualLeafs {
pem, _ := pem.Decode([]byte(l.Cert)) pemDecode, _ := pem.Decode([]byte(l.Cert))
cert, err := x509.ParseCertificate(pem.Bytes) cert, err := x509.ParseCertificate(pemDecode.Bytes)
oldLeaf = cert oldLeaf = cert
require.NoError(r, err) require.NoError(r, err)
require.Equal(r, cert.URIs[0].String(), suite.expectedFooProxyStateSpiffes[k]) require.Equal(r, cert.URIs[0].String(), suite.expectedFooProxyStateSpiffes[k])
@ -541,8 +589,8 @@ func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateDeleteLeafRe
actualLeafs := suite.updater.GetLeafs(suite.fooProxyStateTemplate.Id.Name) actualLeafs := suite.updater.GetLeafs(suite.fooProxyStateTemplate.Id.Name)
require.Len(r, actualLeafs, 1) require.Len(r, actualLeafs, 1)
for k, l := range actualLeafs { for k, l := range actualLeafs {
pem, _ := pem.Decode([]byte(l.Cert)) pemDecode, _ := pem.Decode([]byte(l.Cert))
cert, err := x509.ParseCertificate(pem.Bytes) cert, err := x509.ParseCertificate(pemDecode.Bytes)
// Ensure the leaf was actually updated by checking that the leaf we just got is different from the old leaf. // Ensure the leaf was actually updated by checking that the leaf we just got is different from the old leaf.
require.NotEqual(r, oldLeaf.Raw, cert.Raw) require.NotEqual(r, oldLeaf.Raw, cert.Raw)
require.NoError(r, err) require.NoError(r, err)
@ -563,8 +611,11 @@ func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateDeleteLeafRe
ProxyState: &pbmesh.ProxyState{}, ProxyState: &pbmesh.ProxyState{},
RequiredLeafCertificates: suite.fooLeafRefs, RequiredLeafCertificates: suite.fooLeafRefs,
}). }).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooProxyStateTemplate.Id))
retry.Run(suite.T(), func(r *retry.R) { retry.Run(suite.T(), func(r *retry.R) {
suite.client.RequireVersionChanged(r, fooProxyStateTemplate.Id, oldVersion) suite.client.RequireVersionChanged(r, fooProxyStateTemplate.Id, oldVersion)
}) })
@ -574,18 +625,20 @@ func (suite *xdsControllerTestSuite) TestController_ComputeAddUpdateDeleteLeafRe
_, ok := suite.leafCancels.Get(keyFromReference(fooLeafResRef)) _, ok := suite.leafCancels.Get(keyFromReference(fooLeafResRef))
require.False(r, ok) require.False(r, ok)
}) })
})
} }
// Sets up a full controller, and tests that reconciles are getting triggered for the leaf cert events it should. // Sets up a full controller, and tests that reconciles are getting triggered for the leaf cert events it should.
// This test ensures that when a ProxyStateTemplate is deleted, the leaf watches are cancelled. // This test ensures that when a ProxyStateTemplate is deleted, the leaf watches are cancelled.
func (suite *xdsControllerTestSuite) TestController_ComputeLeafReferencesDeletePST() { func (suite *xdsControllerTestSuite) TestController_ComputeLeafReferencesDeletePST() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Run the controller manager. // Run the controller manager.
mgr := controller.NewManager(suite.client, suite.runtime.Logger) mgr := controller.NewManager(suite.client, suite.runtime.Logger)
mgr.Register(Controller(suite.mapper, suite.updater, suite.fetcher, suite.leafCertManager, suite.leafMapper, suite.leafCancels, "dc1")) mgr.Register(Controller(suite.mapper, suite.updater, suite.fetcher, suite.leafCertManager, suite.leafMapper, suite.leafCancels, "dc1"))
mgr.SetRaftLeader(true) mgr.SetRaftLeader(true)
go mgr.Run(suite.ctx) go mgr.Run(suite.ctx)
suite.setupFooProxyStateTemplateWithReferences() suite.setupFooProxyStateTemplateWithReferences(tenancy)
leafCertRef := suite.fooLeafRefs["foo-workload-identity"] leafCertRef := suite.fooLeafRefs["foo-workload-identity"]
fooLeafResRef := leafResourceRef(leafCertRef.Name, leafCertRef.Namespace, leafCertRef.Partition) fooLeafResRef := leafResourceRef(leafCertRef.Name, leafCertRef.Namespace, leafCertRef.Partition)
@ -601,8 +654,8 @@ func (suite *xdsControllerTestSuite) TestController_ComputeLeafReferencesDeleteP
// Assert that the leafs computed in the controller matches the expected leafs. // Assert that the leafs computed in the controller matches the expected leafs.
require.Len(r, actualLeafs, 1) require.Len(r, actualLeafs, 1)
for k, l := range actualLeafs { for k, l := range actualLeafs {
pem, _ := pem.Decode([]byte(l.Cert)) pemDecode, _ := pem.Decode([]byte(l.Cert))
cert, err := x509.ParseCertificate(pem.Bytes) cert, err := x509.ParseCertificate(pemDecode.Bytes)
require.NoError(r, err) require.NoError(r, err)
require.Equal(r, cert.URIs[0].String(), suite.expectedFooProxyStateSpiffes[k]) require.Equal(r, cert.URIs[0].String(), suite.expectedFooProxyStateSpiffes[k])
// Check the state of the cancel functions map. // Check the state of the cancel functions map.
@ -616,17 +669,20 @@ func (suite *xdsControllerTestSuite) TestController_ComputeLeafReferencesDeleteP
req := &pbresource.DeleteRequest{ req := &pbresource.DeleteRequest{
Id: suite.fooProxyStateTemplate.Id, Id: suite.fooProxyStateTemplate.Id,
} }
suite.client.Delete(suite.ctx, req) _, err := suite.client.Delete(suite.ctx, req)
require.NoError(suite.T(), err)
// Ensure the leaf certificate watches were cancelled since we deleted the leaf reference. // Ensure the leaf certificate watches were cancelled since we deleted the leaf reference.
retry.Run(suite.T(), func(r *retry.R) { retry.Run(suite.T(), func(r *retry.R) {
_, ok := suite.leafCancels.Get(keyFromReference(fooLeafResRef)) _, ok := suite.leafCancels.Get(keyFromReference(fooLeafResRef))
require.False(r, ok) require.False(r, ok)
}) })
})
} }
// Sets up a full controller, and tests that reconciles are getting triggered for the events it should. // Sets up a full controller, and tests that reconciles are getting triggered for the events it should.
func (suite *xdsControllerTestSuite) TestController_ComputeEndpointForProxyConnections() { func (suite *xdsControllerTestSuite) TestController_ComputeEndpointForProxyConnections() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Run the controller manager. // Run the controller manager.
mgr := controller.NewManager(suite.client, suite.runtime.Logger) mgr := controller.NewManager(suite.client, suite.runtime.Logger)
@ -636,7 +692,7 @@ func (suite *xdsControllerTestSuite) TestController_ComputeEndpointForProxyConne
// Set up fooEndpoints and fooProxyStateTemplate with a reference to fooEndpoints. These need to be stored // Set up fooEndpoints and fooProxyStateTemplate with a reference to fooEndpoints. These need to be stored
// because the controller reconcile looks them up. // because the controller reconcile looks them up.
suite.setupFooProxyStateTemplateWithReferences() suite.setupFooProxyStateTemplateWithReferences(tenancy)
// Assert that the expected ProxyState matches the actual ProxyState that PushChange was called with. This needs to // Assert that the expected ProxyState matches the actual ProxyState that PushChange was called with. This needs to
// be in a retry block unlike the Reconcile tests because the controller triggers asynchronously. // be in a retry block unlike the Reconcile tests because the controller triggers asynchronously.
@ -654,6 +710,7 @@ func (suite *xdsControllerTestSuite) TestController_ComputeEndpointForProxyConne
// Wait for the proxy state template to be re-evaluated. // Wait for the proxy state template to be re-evaluated.
proxyStateTemp := suite.client.WaitForNewVersion(suite.T(), suite.fooProxyStateTemplate.Id, suite.fooProxyStateTemplate.Version) proxyStateTemp := suite.client.WaitForNewVersion(suite.T(), suite.fooProxyStateTemplate.Id, suite.fooProxyStateTemplate.Version)
require.NotNil(suite.T(), proxyStateTemp) require.NotNil(suite.T(), proxyStateTemp)
})
} }
// Setup: fooProxyStateTemplate with: // Setup: fooProxyStateTemplate with:
@ -661,11 +718,14 @@ func (suite *xdsControllerTestSuite) TestController_ComputeEndpointForProxyConne
// - a LeafCertificateRef to "foo-workload-identity" // - a LeafCertificateRef to "foo-workload-identity"
// //
// Saves all related resources to the suite so they can be looked up by the controller or modified if needed. // Saves all related resources to the suite so they can be looked up by the controller or modified if needed.
func (suite *xdsControllerTestSuite) setupFooProxyStateTemplateWithReferences() { func (suite *xdsControllerTestSuite) setupFooProxyStateTemplateWithReferences(tenancy *pbresource.Tenancy) {
fooService := resourcetest.Resource(pbcatalog.ServiceType, "foo-service"). fooService := resourcetest.Resource(pbcatalog.ServiceType, "foo-service").
WithData(suite.T(), &pbcatalog.Service{}). WithData(suite.T(), &pbcatalog.Service{}).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooService.Id))
fooEndpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "foo-service"). fooEndpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "foo-service").
WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{ WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{
{ {
@ -687,9 +747,12 @@ func (suite *xdsControllerTestSuite) setupFooProxyStateTemplateWithReferences()
}, },
}, },
}}). }}).
WithTenancy(tenancy).
WithOwner(fooService.Id). WithOwner(fooService.Id).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooEndpoints.Id))
fooRequiredEndpoints := make(map[string]*pbproxystate.EndpointRef) fooRequiredEndpoints := make(map[string]*pbproxystate.EndpointRef)
fooRequiredEndpoints["test-cluster-1"] = &pbproxystate.EndpointRef{ fooRequiredEndpoints["test-cluster-1"] = &pbproxystate.EndpointRef{
Id: fooEndpoints.Id, Id: fooEndpoints.Id,
@ -707,8 +770,11 @@ func (suite *xdsControllerTestSuite) setupFooProxyStateTemplateWithReferences()
RequiredLeafCertificates: fooRequiredLeafs, RequiredLeafCertificates: fooRequiredLeafs,
ProxyState: &pbmesh.ProxyState{}, ProxyState: &pbmesh.ProxyState{},
}). }).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooProxyStateTemplate.Id))
retry.Run(suite.T(), func(r *retry.R) { retry.Run(suite.T(), func(r *retry.R) {
suite.client.RequireResourceExists(r, fooProxyStateTemplate.Id) suite.client.RequireResourceExists(r, fooProxyStateTemplate.Id)
}) })
@ -754,6 +820,14 @@ func (suite *xdsControllerTestSuite) setupFooProxyStateTemplateWithReferences()
suite.expectedFooProxyStateEndpoints = expectedFooProxyStateEndpoints suite.expectedFooProxyStateEndpoints = expectedFooProxyStateEndpoints
suite.expectedTrustBundle = expectedTrustBundle suite.expectedTrustBundle = expectedTrustBundle
suite.expectedFooProxyStateSpiffes = expectedFooLeafSpiffes suite.expectedFooProxyStateSpiffes = expectedFooLeafSpiffes
suite.T().Cleanup(func() {
suite.fooEndpointRefs = make(map[string]*pbproxystate.EndpointRef)
suite.fooLeafRefs = make(map[string]*pbproxystate.LeafCertificateRef)
suite.expectedFooProxyStateEndpoints = make(map[string]*pbproxystate.Endpoints)
suite.expectedTrustBundle = make(map[string]*pbproxystate.TrustBundle)
suite.expectedFooProxyStateSpiffes = make(map[string]string)
})
} }
// Setup: // Setup:
@ -761,11 +835,14 @@ func (suite *xdsControllerTestSuite) setupFooProxyStateTemplateWithReferences()
// - barProxyStateTemplate with an EndpointsRef to fooBarEndpoints. // - barProxyStateTemplate with an EndpointsRef to fooBarEndpoints.
// //
// Saves all related resources to the suite so they can be modified if needed. // Saves all related resources to the suite so they can be modified if needed.
func (suite *xdsControllerTestSuite) setupFooBarProxyStateTemplateAndEndpoints() { func (suite *xdsControllerTestSuite) setupFooBarProxyStateTemplateAndEndpoints(tenancy *pbresource.Tenancy) {
fooService := resourcetest.Resource(pbcatalog.ServiceType, "foo-service"). fooService := resourcetest.Resource(pbcatalog.ServiceType, "foo-service").
WithData(suite.T(), &pbcatalog.Service{}). WithData(suite.T(), &pbcatalog.Service{}).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooService.Id))
fooEndpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "foo-service"). fooEndpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "foo-service").
WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{ WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{
{ {
@ -788,12 +865,18 @@ func (suite *xdsControllerTestSuite) setupFooBarProxyStateTemplateAndEndpoints()
}, },
}}). }}).
WithOwner(fooService.Id). WithOwner(fooService.Id).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooEndpoints.Id))
fooBarService := resourcetest.Resource(pbcatalog.ServiceType, "foo-bar-service"). fooBarService := resourcetest.Resource(pbcatalog.ServiceType, "foo-bar-service").
WithData(suite.T(), &pbcatalog.Service{}). WithData(suite.T(), &pbcatalog.Service{}).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooBarService.Id))
fooBarEndpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "foo-bar-service"). fooBarEndpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "foo-bar-service").
WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{ WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{
{ {
@ -816,8 +899,11 @@ func (suite *xdsControllerTestSuite) setupFooBarProxyStateTemplateAndEndpoints()
}, },
}}). }}).
WithOwner(fooBarService.Id). WithOwner(fooBarService.Id).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooBarEndpoints.Id))
fooRequiredEndpoints := make(map[string]*pbproxystate.EndpointRef) fooRequiredEndpoints := make(map[string]*pbproxystate.EndpointRef)
fooRequiredEndpoints["test-cluster-1"] = &pbproxystate.EndpointRef{ fooRequiredEndpoints["test-cluster-1"] = &pbproxystate.EndpointRef{
Id: fooEndpoints.Id, Id: fooEndpoints.Id,
@ -841,8 +927,11 @@ func (suite *xdsControllerTestSuite) setupFooBarProxyStateTemplateAndEndpoints()
RequiredEndpoints: fooRequiredEndpoints, RequiredEndpoints: fooRequiredEndpoints,
ProxyState: &pbmesh.ProxyState{}, ProxyState: &pbmesh.ProxyState{},
}). }).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(fooProxyStateTemplate.Id))
retry.Run(suite.T(), func(r *retry.R) { retry.Run(suite.T(), func(r *retry.R) {
suite.client.RequireResourceExists(r, fooProxyStateTemplate.Id) suite.client.RequireResourceExists(r, fooProxyStateTemplate.Id)
}) })
@ -853,8 +942,11 @@ func (suite *xdsControllerTestSuite) setupFooBarProxyStateTemplateAndEndpoints()
RequiredEndpoints: barRequiredEndpoints, RequiredEndpoints: barRequiredEndpoints,
ProxyState: &pbmesh.ProxyState{}, ProxyState: &pbmesh.ProxyState{},
}). }).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(barProxyStateTemplate.Id))
retry.Run(suite.T(), func(r *retry.R) { retry.Run(suite.T(), func(r *retry.R) {
suite.client.RequireResourceExists(r, barProxyStateTemplate.Id) suite.client.RequireResourceExists(r, barProxyStateTemplate.Id)
}) })
@ -935,9 +1027,17 @@ func (suite *xdsControllerTestSuite) setupFooBarProxyStateTemplateAndEndpoints()
suite.fooBarService = fooBarService suite.fooBarService = fooBarService
suite.expectedFooProxyStateEndpoints = expectedFooProxyStateEndpoints suite.expectedFooProxyStateEndpoints = expectedFooProxyStateEndpoints
suite.expectedBarProxyStateEndpoints = expectedBarProxyStateEndpoints suite.expectedBarProxyStateEndpoints = expectedBarProxyStateEndpoints
suite.T().Cleanup(func() {
suite.barEndpointRefs = make(map[string]*pbproxystate.EndpointRef)
suite.fooEndpointRefs = make(map[string]*pbproxystate.EndpointRef)
suite.expectedFooProxyStateEndpoints = make(map[string]*pbproxystate.Endpoints)
suite.expectedBarProxyStateEndpoints = make(map[string]*pbproxystate.Endpoints)
})
} }
func (suite *xdsControllerTestSuite) TestReconcile_prevWatchesToCancel() { func (suite *xdsControllerTestSuite) TestReconcile_prevWatchesToCancel() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
makeRef := func(names ...string) []*pbresource.Reference { makeRef := func(names ...string) []*pbresource.Reference {
out := make([]*pbresource.Reference, len(names)) out := make([]*pbresource.Reference, len(names))
for i, name := range names { for i, name := range names {
@ -948,7 +1048,7 @@ func (suite *xdsControllerTestSuite) TestReconcile_prevWatchesToCancel() {
GroupVersion: "v", GroupVersion: "v",
Kind: "k", Kind: "k",
}, },
Tenancy: &pbresource.Tenancy{}, Tenancy: tenancy,
} }
} }
return out return out
@ -997,6 +1097,7 @@ func (suite *xdsControllerTestSuite) TestReconcile_prevWatchesToCancel() {
toCancel := prevWatchesToCancel(tc.old, convert(tc.new)) toCancel := prevWatchesToCancel(tc.old, convert(tc.new))
require.ElementsMatch(suite.T(), toCancel, tc.expect) require.ElementsMatch(suite.T(), toCancel, tc.expect)
} }
})
} }
func TestXdsController(t *testing.T) { func TestXdsController(t *testing.T) {
@ -1017,6 +1118,7 @@ func TestXdsController(t *testing.T) {
// rather than just endpoints, leaf certs, and trust bundles, the test also ensures // 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. // side effects or change in scope to XDS controller are not introduce mistakenly.
func (suite *xdsControllerTestSuite) TestReconcile_SidecarProxyGoldenFileInputs() { func (suite *xdsControllerTestSuite) TestReconcile_SidecarProxyGoldenFileInputs() {
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
path := "../sidecarproxy/builder/testdata" path := "../sidecarproxy/builder/testdata"
cases := []string{ cases := []string{
// destinations - please add in alphabetical order // destinations - please add in alphabetical order
@ -1053,14 +1155,17 @@ func (suite *xdsControllerTestSuite) TestReconcile_SidecarProxyGoldenFileInputs(
// Destinations will need endpoint refs set up. // Destinations will need endpoint refs set up.
if strings.Split(name, "/")[0] == "destination" && len(pst.ProxyState.Endpoints) == 0 { if strings.Split(name, "/")[0] == "destination" && len(pst.ProxyState.Endpoints) == 0 {
suite.addRequiredEndpointsAndRefs(pst) suite.addRequiredEndpointsAndRefs(pst, tenancy)
} }
// Store the initial ProxyStateTemplate. // Store the initial ProxyStateTemplate.
proxyStateTemplate := resourcetest.Resource(pbmesh.ProxyStateTemplateType, "test"). proxyStateTemplate := resourcetest.Resource(pbmesh.ProxyStateTemplateType, "test").
WithData(suite.T(), pst). WithData(suite.T(), pst).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(proxyStateTemplate.Id))
// Check with resource service that it exists. // Check with resource service that it exists.
retry.Run(suite.T(), func(r *retry.R) { retry.Run(suite.T(), func(r *retry.R) {
suite.client.RequireResourceExists(r, proxyStateTemplate.Id) suite.client.RequireResourceExists(r, proxyStateTemplate.Id)
@ -1095,9 +1200,10 @@ func (suite *xdsControllerTestSuite) TestReconcile_SidecarProxyGoldenFileInputs(
require.JSONEq(suite.T(), expected, actual) require.JSONEq(suite.T(), expected, actual)
}) })
} }
})
} }
func (suite *xdsControllerTestSuite) addRequiredEndpointsAndRefs(pst *pbmesh.ProxyStateTemplate) { func (suite *xdsControllerTestSuite) addRequiredEndpointsAndRefs(pst *pbmesh.ProxyStateTemplate, tenancy *pbresource.Tenancy) {
//get service data //get service data
serviceData := &pbcatalog.Service{} serviceData := &pbcatalog.Service{}
var vp uint32 = 7000 var vp uint32 = 7000
@ -1125,8 +1231,11 @@ func (suite *xdsControllerTestSuite) addRequiredEndpointsAndRefs(pst *pbmesh.Pro
// create service. // create service.
svc := resourcetest.Resource(pbcatalog.ServiceType, svcName). svc := resourcetest.Resource(pbcatalog.ServiceType, svcName).
WithData(suite.T(), &pbcatalog.Service{}). WithData(suite.T(), &pbcatalog.Service{}).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
// create endpoints with svc as owner. // create endpoints with svc as owner.
eps := resourcetest.Resource(pbcatalog.ServiceEndpointsType, svcName). eps := resourcetest.Resource(pbcatalog.ServiceEndpointsType, svcName).
WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{ WithData(suite.T(), &pbcatalog.ServiceEndpoints{Endpoints: []*pbcatalog.Endpoint{
@ -1146,8 +1255,11 @@ func (suite *xdsControllerTestSuite) addRequiredEndpointsAndRefs(pst *pbmesh.Pro
}, },
}}). }}).
WithOwner(svc.Id). WithOwner(svc.Id).
WithTenancy(tenancy).
Write(suite.T(), suite.client) Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(eps.Id))
// add to working list of required endpoints. // add to working list of required endpoints.
requiredEps[clusterName] = &pbproxystate.EndpointRef{ requiredEps[clusterName] = &pbproxystate.EndpointRef{
Id: eps.Id, Id: eps.Id,
@ -1167,3 +1279,21 @@ func JSONToProxyTemplate(t *testing.T, json []byte) *pbmesh.ProxyStateTemplate {
require.NoError(t, err) require.NoError(t, err)
return proxyTemplate return proxyTemplate
} }
func (suite *xdsControllerTestSuite) runTestCaseWithTenancies(testCase func(tenancy *pbresource.Tenancy)) {
for _, tenancy := range suite.tenancies {
suite.Run(suite.appendTenancyInfo(tenancy), func() {
testCase(tenancy)
})
}
}
func (suite *xdsControllerTestSuite) appendTenancyInfo(tenancy *pbresource.Tenancy) string {
return fmt.Sprintf("%s_Namespace_%s_Partition", tenancy.Namespace, tenancy.Partition)
}
func (suite *xdsControllerTestSuite) deleteResourceFunc(id *pbresource.ID) func() {
return func() {
suite.client.MustDelete(suite.T(), id)
}
}

View File

@ -4,10 +4,10 @@
package resourcetest package resourcetest
import ( import (
"github.com/hashicorp/consul/agent/structs"
"strings" "strings"
"testing" "testing"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/consul/proto-public/pbresource"
) )