@@ -53,6 +53,10 @@ const (
5353 scaleControlPlaneMachineCount = "CAPI_SCALE_CONTROL_PLANE_MACHINE_COUNT"
5454 scaleWorkerMachineCount = "CAPI_SCALE_WORKER_MACHINE_COUNT"
5555 scaleMachineDeploymentCount = "CAPI_SCALE_MACHINE_DEPLOYMENT_COUNT"
56+
57+ // Note: Names must consist of lower case alphanumeric characters or '-'.
58+ scaleClusterNamePlaceholder = "scale-cluster-name-placeholder"
59+ scaleNamespacePlaceholder = "scale-namespace-placeholder"
5660)
5761
5862// scaleSpecInput is the input for scaleSpec.
@@ -79,6 +83,10 @@ type scaleSpecInput struct {
7983 // Can be overridden by variable CAPI_SCALE_CLUSTER_COUNT.
8084 ClusterCount * int64
8185
86+ // SeparateNamespacePerCluster defines if each cluster should be deployed into its separate namespace.
87+ // In this case The namespace name will be the name of the cluster.
88+ SeparateNamespacePerCluster bool
89+
8290 // Concurrency is the maximum concurrency of each of the scale operations.
8391 // If unspecified it defaults to 5.
8492 // Can be overridden by variable CAPI_SCALE_CONCURRENCY.
@@ -237,15 +245,14 @@ func scaleSpec(ctx context.Context, inputGetter func() scaleSpecInput) {
237245 // Therefore, it is not advised to call this functions across all the concurrency workers.
238246 // To avoid this problem we chose to run ConfigCluster once and reuse its output across all the workers.
239247 log .Logf ("Generating YAML for base Cluster and ClusterClass" )
240- baseClusterName := fmt .Sprintf ("%s-base" , specName )
241248 baseWorkloadClusterTemplate := clusterctl .ConfigCluster (ctx , clusterctl.ConfigClusterInput {
242249 LogFolder : filepath .Join (input .ArtifactFolder , "clusters" , input .BootstrapClusterProxy .GetName ()),
243250 ClusterctlConfigPath : input .ClusterctlConfigPath ,
244251 KubeconfigPath : input .BootstrapClusterProxy .GetKubeconfigPath (),
245252 InfrastructureProvider : infrastructureProvider ,
246253 Flavor : flavor ,
247- Namespace : namespace . Name ,
248- ClusterName : baseClusterName ,
254+ Namespace : scaleNamespacePlaceholder ,
255+ ClusterName : scaleClusterNamePlaceholder ,
249256 KubernetesVersion : input .E2EConfig .GetVariable (KubernetesVersion ),
250257 ControlPlaneMachineCount : controlPlaneMachineCount ,
251258 WorkerMachineCount : workerMachineCount ,
@@ -258,19 +265,23 @@ func scaleSpec(ctx context.Context, inputGetter func() scaleSpecInput) {
258265 // if the resource has to be created or updated before actually executing the operation. If another worker changes
259266 // the status of the cluster during this timeframe the operation will fail.
260267 log .Logf ("Extract ClusterClass and Cluster from template YAML" )
261- clusterClassYAML , baseClusterTemplateYAML := extractClusterClassAndClusterFromTemplate (baseWorkloadClusterTemplate )
268+ baseClusterClassYAML , baseClusterTemplateYAML := extractClusterClassAndClusterFromTemplate (baseWorkloadClusterTemplate )
262269
263270 // Modify the baseClusterTemplateYAML so that it has the desired number of machine deployments.
264- modifiedBaseTemplateYAML := modifyMachineDeployments (baseClusterTemplateYAML , int (* machineDeploymentCount ))
265-
266- if len (clusterClassYAML ) > 0 {
267- // Apply the ClusterClass.
268- log .Logf ("Create ClusterClass" )
269- Eventually (func () error {
270- return input .BootstrapClusterProxy .Apply (ctx , clusterClassYAML )
271- }).Should (Succeed ())
272- } else {
273- log .Logf ("ClusterClass already exists. Skipping creation." )
271+ baseClusterTemplateYAML = modifyMachineDeployments (baseClusterTemplateYAML , int (* machineDeploymentCount ))
272+
273+ // If all clusters should be deployed in the same namespace (namespace.Name),
274+ // then deploy the ClusterClass in this namespace.
275+ if ! input .SeparateNamespacePerCluster {
276+ if len (baseClusterClassYAML ) > 0 {
277+ clusterClassYAML := bytes .Replace (baseClusterClassYAML , []byte (scaleNamespacePlaceholder ), []byte (namespace .Name ), - 1 )
278+ log .Logf ("Apply ClusterClass" )
279+ Eventually (func () error {
280+ return input .BootstrapClusterProxy .Apply (ctx , clusterClassYAML )
281+ }, 1 * time .Minute ).Should (Succeed ())
282+ } else {
283+ log .Logf ("ClusterClass already exists. Skipping creation." )
284+ }
274285 }
275286
276287 By ("Create workload clusters concurrently" )
@@ -291,7 +302,6 @@ func scaleSpec(ctx context.Context, inputGetter func() scaleSpecInput) {
291302 // use the "create only" creator function.
292303 creator := getClusterCreateAndWaitFn (clusterctl.ApplyCustomClusterTemplateAndWaitInput {
293304 ClusterProxy : input .BootstrapClusterProxy ,
294- Namespace : namespace .Name ,
295305 WaitForClusterIntervals : input .E2EConfig .GetIntervals (specName , "wait-cluster" ),
296306 WaitForControlPlaneIntervals : input .E2EConfig .GetIntervals (specName , "wait-control-plane" ),
297307 WaitForMachineDeployments : input .E2EConfig .GetIntervals (specName , "wait-worker-nodes" ),
@@ -300,15 +310,15 @@ func scaleSpec(ctx context.Context, inputGetter func() scaleSpecInput) {
300310 if ! input .SkipCleanup {
301311 log .Logf ("WARNING! Using SkipWaitForCreation=true while SkipCleanup=false can lead to workload clusters getting deleted before they are fully provisioned." )
302312 }
303- creator = getClusterCreateFn (input .BootstrapClusterProxy , namespace . Name )
313+ creator = getClusterCreateFn (input .BootstrapClusterProxy )
304314 }
305315
306316 clusterCreateResults , err := workConcurrentlyAndWait (ctx , workConcurrentlyAndWaitInput {
307317 ClusterNames : clusterNames ,
308318 Concurrency : concurrency ,
309319 FailFast : input .FailFast ,
310320 WorkerFunc : func (ctx context.Context , inputChan chan string , resultChan chan workResult , wg * sync.WaitGroup ) {
311- createClusterWorker (ctx , inputChan , resultChan , wg , modifiedBaseTemplateYAML , baseClusterName , creator )
321+ createClusterWorker (ctx , input . BootstrapClusterProxy , inputChan , resultChan , wg , namespace . Name , input . SeparateNamespacePerCluster , baseClusterClassYAML , baseClusterTemplateYAML , creator )
312322 },
313323 })
314324 if err != nil {
@@ -471,10 +481,10 @@ outer:
471481 return results , kerrors .NewAggregate (errs )
472482}
473483
474- type clusterCreator func (ctx context.Context , clusterName string , clusterTemplateYAML []byte )
484+ type clusterCreator func (ctx context.Context , namespace , clusterName string , clusterTemplateYAML []byte )
475485
476486func getClusterCreateAndWaitFn (input clusterctl.ApplyCustomClusterTemplateAndWaitInput ) clusterCreator {
477- return func (ctx context.Context , clusterName string , clusterTemplateYAML []byte ) {
487+ return func (ctx context.Context , namespace , clusterName string , clusterTemplateYAML []byte ) {
478488 clusterResources := & clusterctl.ApplyCustomClusterTemplateAndWaitResult {}
479489 // Nb. We cannot directly modify and use `input` in this closure function because this function
480490 // will be called multiple times and this closure will keep modifying the same `input` multiple
@@ -483,7 +493,7 @@ func getClusterCreateAndWaitFn(input clusterctl.ApplyCustomClusterTemplateAndWai
483493 ClusterProxy : input .ClusterProxy ,
484494 CustomTemplateYAML : clusterTemplateYAML ,
485495 ClusterName : clusterName ,
486- Namespace : input . Namespace ,
496+ Namespace : namespace ,
487497 CNIManifestPath : input .CNIManifestPath ,
488498 WaitForClusterIntervals : input .WaitForClusterIntervals ,
489499 WaitForControlPlaneIntervals : input .WaitForControlPlaneIntervals ,
@@ -497,16 +507,16 @@ func getClusterCreateAndWaitFn(input clusterctl.ApplyCustomClusterTemplateAndWai
497507 }
498508}
499509
500- func getClusterCreateFn (clusterProxy framework.ClusterProxy , namespace string ) clusterCreator {
501- return func (ctx context.Context , clusterName string , clusterTemplateYAML []byte ) {
510+ func getClusterCreateFn (clusterProxy framework.ClusterProxy ) clusterCreator {
511+ return func (ctx context.Context , namespace , clusterName string , clusterTemplateYAML []byte ) {
502512 log .Logf ("Applying the cluster template yaml of cluster %s" , klog .KRef (namespace , clusterName ))
503513 Eventually (func () error {
504514 return clusterProxy .Apply (ctx , clusterTemplateYAML )
505515 }, 1 * time .Minute ).Should (Succeed (), "Failed to apply the cluster template of cluster %s" , klog .KRef (namespace , clusterName ))
506516 }
507517}
508518
509- func createClusterWorker (ctx context.Context , inputChan <- chan string , resultChan chan <- workResult , wg * sync.WaitGroup , baseTemplate [] byte , baseClusterName string , create clusterCreator ) {
519+ func createClusterWorker (ctx context.Context , clusterProxy framework. ClusterProxy , inputChan <- chan string , resultChan chan <- workResult , wg * sync.WaitGroup , defaultNamespace string , separateNamespacePerCluster bool , baseClusterClassYAML , baseClusterTemplateYAML [] byte , create clusterCreator ) {
510520 defer wg .Done ()
511521
512522 for {
@@ -533,9 +543,37 @@ func createClusterWorker(ctx context.Context, inputChan <-chan string, resultCha
533543 }
534544 }()
535545
536- // Create the cluster template YAML with the target cluster name.
537- clusterTemplateYAML := bytes .Replace (baseTemplate , []byte (baseClusterName ), []byte (clusterName ), - 1 )
538- create (ctx , clusterName , clusterTemplateYAML )
546+ // Calculate namespace.
547+ namespaceName := defaultNamespace
548+ if separateNamespacePerCluster {
549+ namespaceName = clusterName
550+ }
551+
552+ // If every cluster should be deployed in a separate namespace:
553+ // * Adjust namespace in ClusterClass YAML.
554+ // * Create new namespace.
555+ // * Deploy ClusterClass in new namespace.
556+ if separateNamespacePerCluster {
557+ log .Logf ("Create namespace %" , namespaceName )
558+ _ = framework .CreateNamespace (ctx , framework.CreateNamespaceInput {
559+ Creator : clusterProxy .GetClient (),
560+ Name : namespaceName ,
561+ IgnoreAlreadyExists : true ,
562+ }, "40s" , "10s" )
563+
564+ log .Logf ("Apply ClusterClass in namespace %" , namespaceName )
565+ clusterClassYAML := bytes .Replace (baseClusterClassYAML , []byte (scaleNamespacePlaceholder ), []byte (namespaceName ), - 1 )
566+ Eventually (func () error {
567+ return clusterProxy .Apply (ctx , clusterClassYAML )
568+ }, 1 * time .Minute ).Should (Succeed ())
569+ }
570+
571+ // Adjust namespace and name in Cluster YAML
572+ clusterTemplateYAML := bytes .Replace (baseClusterTemplateYAML , []byte (scaleNamespacePlaceholder ), []byte (namespaceName ), - 1 )
573+ clusterTemplateYAML = bytes .Replace (clusterTemplateYAML , []byte (scaleClusterNamePlaceholder ), []byte (clusterName ), - 1 )
574+
575+ // Deploy Cluster.
576+ create (ctx , namespaceName , clusterName , clusterTemplateYAML )
539577 return false
540578 }
541579 }()
0 commit comments