Skip to content

Commit

Permalink
Make scale e2e test reusable for CAPM3 and other providers
Browse files Browse the repository at this point in the history
- Export ScaleSpec and ScaleSpecInput to allow reuse in other providers.
- Add PostScaleClusterNamespaceCreated hook to be called after generating cluster name and namespace but before applying the template.

Signed-off-by: Mohammed Boukhalfa <mohammed.boukhalfa@est.tech>
  • Loading branch information
mboukhalfa committed Oct 31, 2024
1 parent 0000f09 commit 241b8e4
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 12 deletions.
44 changes: 34 additions & 10 deletions test/e2e/scale.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ const (
scaleClusterNamespacePlaceholder = "scale-cluster-namespace-placeholder"
)

// scaleSpecInput is the input for scaleSpec.
type scaleSpecInput struct {
// ScaleSpecInput is the input for ScaleSpec.
type ScaleSpecInput struct {
E2EConfig *clusterctl.E2EConfig
ClusterctlConfigPath string
BootstrapClusterProxy framework.ClusterProxy
Expand Down Expand Up @@ -119,6 +119,16 @@ type scaleSpecInput struct {
// If not specified, this is a no-op.
PostNamespaceCreated func(managementClusterProxy framework.ClusterProxy, workloadClusterNamespace string)

// Allows to inject a function to be run after test workload cluster name and namespace are generated and
// before applying the clusterclass and the cluster template.
// If not specified, this is a no-op.
PostScaleClusterNamespaceCreated func(
clusterProxy framework.ClusterProxy,
clusterNamespace string,
clusterName string,
clusterClassYAML []byte,
clusterTemplateYAML []byte) ([]byte, []byte)

// FailFast if set to true will return immediately after the first cluster operation fails.
// If set to false, the test suite will not exit immediately after the first cluster operation fails.
// Example: When creating clusters from c1 to c20 consider c6 fails creation. If FailFast is set to true
Expand All @@ -141,11 +151,11 @@ type scaleSpecInput struct {
SkipWaitForCreation bool
}

// scaleSpec implements a scale test for clusters with MachineDeployments.
func scaleSpec(ctx context.Context, inputGetter func() scaleSpecInput) {
// ScaleSpec implements a scale test for clusters with MachineDeployments.
func ScaleSpec(ctx context.Context, inputGetter func() ScaleSpecInput) {
var (
specName = "scale"
input scaleSpecInput
input ScaleSpecInput
namespace *corev1.Namespace
cancelWatches context.CancelFunc
)
Expand Down Expand Up @@ -331,7 +341,7 @@ func scaleSpec(ctx context.Context, inputGetter func() scaleSpecInput) {
Concurrency: concurrency,
FailFast: input.FailFast,
WorkerFunc: func(ctx context.Context, inputChan chan string, resultChan chan workResult, wg *sync.WaitGroup) {
createClusterWorker(ctx, input.BootstrapClusterProxy, inputChan, resultChan, wg, namespace.Name, input.DeployClusterInSeparateNamespaces, baseClusterClassYAML, baseClusterTemplateYAML, creator)
createClusterWorker(ctx, input.BootstrapClusterProxy, inputChan, resultChan, wg, namespace.Name, input.DeployClusterInSeparateNamespaces, baseClusterClassYAML, baseClusterTemplateYAML, creator, input.PostScaleClusterNamespaceCreated)
},
})
if err != nil {
Expand Down Expand Up @@ -568,7 +578,9 @@ func getClusterCreateFn(clusterProxy framework.ClusterProxy) clusterCreator {
}
}

func createClusterWorker(ctx context.Context, clusterProxy framework.ClusterProxy, inputChan <-chan string, resultChan chan<- workResult, wg *sync.WaitGroup, defaultNamespace string, deployClusterInSeparateNamespaces bool, baseClusterClassYAML, baseClusterTemplateYAML []byte, create clusterCreator) {
type PostScaleClusterNamespaceCreated func(clusterProxy framework.ClusterProxy, clusterNamespace string, clusterName string, clusterClassYAML []byte, clusterTemplateYAML []byte) ([]byte, []byte)

func createClusterWorker(ctx context.Context, clusterProxy framework.ClusterProxy, inputChan <-chan string, resultChan chan<- workResult, wg *sync.WaitGroup, defaultNamespace string, deployClusterInSeparateNamespaces bool, baseClusterClassYAML, baseClusterTemplateYAML []byte, create clusterCreator, postScaleClusterNamespaceCreated PostScaleClusterNamespaceCreated) {
defer wg.Done()

for {
Expand Down Expand Up @@ -604,24 +616,36 @@ func createClusterWorker(ctx context.Context, clusterProxy framework.ClusterProx
// If every cluster should be deployed in a separate namespace:
// * Adjust namespace in ClusterClass YAML.
// * Create new namespace.
// * Deploy ClusterClass in new namespace.
if deployClusterInSeparateNamespaces {
log.Logf("Create namespace %", namespaceName)
_ = framework.CreateNamespace(ctx, framework.CreateNamespaceInput{
Creator: clusterProxy.GetClient(),
Name: namespaceName,
IgnoreAlreadyExists: true,
}, "40s", "10s")
}

// Call postScaleClusterNamespaceCreated hook to apply custom requirements based on the cluster name and namespace
// User might need to apply additional custom resource in the cluster namespace or customize the templates
customizedClusterTemplateYAML := baseClusterTemplateYAML
customizedClusterClassYAML := baseClusterClassYAML
if postScaleClusterNamespaceCreated != nil {
log.Logf("Calling postScaleClusterNamespaceCreated for cluster %s in namespace %s", clusterName, namespaceName)
customizedClusterClassYAML, customizedClusterTemplateYAML = postScaleClusterNamespaceCreated(clusterProxy, namespaceName, clusterName, baseClusterClassYAML, baseClusterTemplateYAML)
}

// If every cluster should be deployed in a separate namespace:
// * Deploy ClusterClass in new namespace.
if deployClusterInSeparateNamespaces {
log.Logf("Apply ClusterClass in namespace %", namespaceName)
clusterClassYAML := bytes.Replace(baseClusterClassYAML, []byte(scaleClusterNamespacePlaceholder), []byte(namespaceName), -1)
clusterClassYAML := bytes.Replace(customizedClusterClassYAML, []byte(scaleClusterNamespacePlaceholder), []byte(namespaceName), -1)
Eventually(func() error {
return clusterProxy.CreateOrUpdate(ctx, clusterClassYAML)
}, 1*time.Minute).Should(Succeed())
}

// Adjust namespace and name in Cluster YAML
clusterTemplateYAML := bytes.Replace(baseClusterTemplateYAML, []byte(scaleClusterNamespacePlaceholder), []byte(namespaceName), -1)
clusterTemplateYAML := bytes.Replace(customizedClusterTemplateYAML, []byte(scaleClusterNamespacePlaceholder), []byte(namespaceName), -1)
clusterTemplateYAML = bytes.Replace(clusterTemplateYAML, []byte(scaleClusterNamePlaceholder), []byte(clusterName), -1)

// Deploy Cluster.
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/scale_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (

var _ = Describe("When testing the machinery for scale testing using in-memory provider", func() {
// Note: This test does not support MachinePools.
scaleSpec(ctx, func() scaleSpecInput {
return scaleSpecInput{
ScaleSpec(ctx, func() ScaleSpecInput {
return ScaleSpecInput{
E2EConfig: e2eConfig,
ClusterctlConfigPath: clusterctlConfigPath,
InfrastructureProvider: ptr.To("in-memory"),
Expand Down

0 comments on commit 241b8e4

Please sign in to comment.