@@ -53,6 +53,10 @@ const (
53
53
scaleControlPlaneMachineCount = "CAPI_SCALE_CONTROL_PLANE_MACHINE_COUNT"
54
54
scaleWorkerMachineCount = "CAPI_SCALE_WORKER_MACHINE_COUNT"
55
55
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
+ scaleClusterNamespacePlaceholder = "scale-cluster-namespace-placeholder"
56
60
)
57
61
58
62
// scaleSpecInput is the input for scaleSpec.
@@ -79,6 +83,10 @@ type scaleSpecInput struct {
79
83
// Can be overridden by variable CAPI_SCALE_CLUSTER_COUNT.
80
84
ClusterCount * int64
81
85
86
+ // DeployClusterInSeparateNamespaces 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
+ DeployClusterInSeparateNamespaces bool
89
+
82
90
// Concurrency is the maximum concurrency of each of the scale operations.
83
91
// If unspecified it defaults to 5.
84
92
// Can be overridden by variable CAPI_SCALE_CONCURRENCY.
@@ -237,15 +245,14 @@ func scaleSpec(ctx context.Context, inputGetter func() scaleSpecInput) {
237
245
// Therefore, it is not advised to call this functions across all the concurrency workers.
238
246
// To avoid this problem we chose to run ConfigCluster once and reuse its output across all the workers.
239
247
log .Logf ("Generating YAML for base Cluster and ClusterClass" )
240
- baseClusterName := fmt .Sprintf ("%s-base" , specName )
241
248
baseWorkloadClusterTemplate := clusterctl .ConfigCluster (ctx , clusterctl.ConfigClusterInput {
242
249
LogFolder : filepath .Join (input .ArtifactFolder , "clusters" , input .BootstrapClusterProxy .GetName ()),
243
250
ClusterctlConfigPath : input .ClusterctlConfigPath ,
244
251
KubeconfigPath : input .BootstrapClusterProxy .GetKubeconfigPath (),
245
252
InfrastructureProvider : infrastructureProvider ,
246
253
Flavor : flavor ,
247
- Namespace : namespace . Name ,
248
- ClusterName : baseClusterName ,
254
+ Namespace : scaleClusterNamespacePlaceholder ,
255
+ ClusterName : scaleClusterNamePlaceholder ,
249
256
KubernetesVersion : input .E2EConfig .GetVariable (KubernetesVersion ),
250
257
ControlPlaneMachineCount : controlPlaneMachineCount ,
251
258
WorkerMachineCount : workerMachineCount ,
@@ -258,19 +265,23 @@ func scaleSpec(ctx context.Context, inputGetter func() scaleSpecInput) {
258
265
// if the resource has to be created or updated before actually executing the operation. If another worker changes
259
266
// the status of the cluster during this timeframe the operation will fail.
260
267
log .Logf ("Extract ClusterClass and Cluster from template YAML" )
261
- clusterClassYAML , baseClusterTemplateYAML := extractClusterClassAndClusterFromTemplate (baseWorkloadClusterTemplate )
268
+ baseClusterClassYAML , baseClusterTemplateYAML := extractClusterClassAndClusterFromTemplate (baseWorkloadClusterTemplate )
262
269
263
270
// 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 .DeployClusterInSeparateNamespaces {
276
+ if len (baseClusterClassYAML ) > 0 {
277
+ clusterClassYAML := bytes .Replace (baseClusterClassYAML , []byte (scaleClusterNamespacePlaceholder ), []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
+ }
274
285
}
275
286
276
287
By ("Create workload clusters concurrently" )
@@ -291,7 +302,6 @@ func scaleSpec(ctx context.Context, inputGetter func() scaleSpecInput) {
291
302
// use the "create only" creator function.
292
303
creator := getClusterCreateAndWaitFn (clusterctl.ApplyCustomClusterTemplateAndWaitInput {
293
304
ClusterProxy : input .BootstrapClusterProxy ,
294
- Namespace : namespace .Name ,
295
305
WaitForClusterIntervals : input .E2EConfig .GetIntervals (specName , "wait-cluster" ),
296
306
WaitForControlPlaneIntervals : input .E2EConfig .GetIntervals (specName , "wait-control-plane" ),
297
307
WaitForMachineDeployments : input .E2EConfig .GetIntervals (specName , "wait-worker-nodes" ),
@@ -300,15 +310,15 @@ func scaleSpec(ctx context.Context, inputGetter func() scaleSpecInput) {
300
310
if ! input .SkipCleanup {
301
311
log .Logf ("WARNING! Using SkipWaitForCreation=true while SkipCleanup=false can lead to workload clusters getting deleted before they are fully provisioned." )
302
312
}
303
- creator = getClusterCreateFn (input .BootstrapClusterProxy , namespace . Name )
313
+ creator = getClusterCreateFn (input .BootstrapClusterProxy )
304
314
}
305
315
306
316
clusterCreateResults , err := workConcurrentlyAndWait (ctx , workConcurrentlyAndWaitInput {
307
317
ClusterNames : clusterNames ,
308
318
Concurrency : concurrency ,
309
319
FailFast : input .FailFast ,
310
320
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 . DeployClusterInSeparateNamespaces , baseClusterClassYAML , baseClusterTemplateYAML , creator )
312
322
},
313
323
})
314
324
if err != nil {
@@ -341,7 +351,7 @@ func scaleSpec(ctx context.Context, inputGetter func() scaleSpecInput) {
341
351
Concurrency : concurrency ,
342
352
FailFast : input .FailFast ,
343
353
WorkerFunc : func (ctx context.Context , inputChan chan string , resultChan chan workResult , wg * sync.WaitGroup ) {
344
- deleteClusterAndWaitWorker (ctx , inputChan , resultChan , wg , input .BootstrapClusterProxy .GetClient (), namespace .Name )
354
+ deleteClusterAndWaitWorker (ctx , inputChan , resultChan , wg , input .BootstrapClusterProxy .GetClient (), namespace .Name , input . DeployClusterInSeparateNamespaces )
345
355
},
346
356
})
347
357
if err != nil {
@@ -471,10 +481,10 @@ outer:
471
481
return results , kerrors .NewAggregate (errs )
472
482
}
473
483
474
- type clusterCreator func (ctx context.Context , clusterName string , clusterTemplateYAML []byte )
484
+ type clusterCreator func (ctx context.Context , namespace , clusterName string , clusterTemplateYAML []byte )
475
485
476
486
func 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 ) {
478
488
clusterResources := & clusterctl.ApplyCustomClusterTemplateAndWaitResult {}
479
489
// Nb. We cannot directly modify and use `input` in this closure function because this function
480
490
// will be called multiple times and this closure will keep modifying the same `input` multiple
@@ -483,7 +493,7 @@ func getClusterCreateAndWaitFn(input clusterctl.ApplyCustomClusterTemplateAndWai
483
493
ClusterProxy : input .ClusterProxy ,
484
494
CustomTemplateYAML : clusterTemplateYAML ,
485
495
ClusterName : clusterName ,
486
- Namespace : input . Namespace ,
496
+ Namespace : namespace ,
487
497
CNIManifestPath : input .CNIManifestPath ,
488
498
WaitForClusterIntervals : input .WaitForClusterIntervals ,
489
499
WaitForControlPlaneIntervals : input .WaitForControlPlaneIntervals ,
@@ -497,16 +507,16 @@ func getClusterCreateAndWaitFn(input clusterctl.ApplyCustomClusterTemplateAndWai
497
507
}
498
508
}
499
509
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 ) {
502
512
log .Logf ("Applying the cluster template yaml of cluster %s" , klog .KRef (namespace , clusterName ))
503
513
Eventually (func () error {
504
514
return clusterProxy .Apply (ctx , clusterTemplateYAML )
505
515
}, 1 * time .Minute ).Should (Succeed (), "Failed to apply the cluster template of cluster %s" , klog .KRef (namespace , clusterName ))
506
516
}
507
517
}
508
518
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 , deployClusterInSeparateNamespaces bool , baseClusterClassYAML , baseClusterTemplateYAML [] byte , create clusterCreator ) {
510
520
defer wg .Done ()
511
521
512
522
for {
@@ -533,9 +543,37 @@ func createClusterWorker(ctx context.Context, inputChan <-chan string, resultCha
533
543
}
534
544
}()
535
545
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 deployClusterInSeparateNamespaces {
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 deployClusterInSeparateNamespaces {
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 (scaleClusterNamespacePlaceholder ), []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 (scaleClusterNamespacePlaceholder ), []byte (namespaceName ), - 1 )
573
+ clusterTemplateYAML = bytes .Replace (clusterTemplateYAML , []byte (scaleClusterNamePlaceholder ), []byte (clusterName ), - 1 )
574
+
575
+ // Deploy Cluster.
576
+ create (ctx , namespaceName , clusterName , clusterTemplateYAML )
539
577
return false
540
578
}
541
579
}()
@@ -545,7 +583,7 @@ func createClusterWorker(ctx context.Context, inputChan <-chan string, resultCha
545
583
}
546
584
}
547
585
548
- func deleteClusterAndWaitWorker (ctx context.Context , inputChan <- chan string , resultChan chan <- workResult , wg * sync.WaitGroup , c client.Client , namespace string ) {
586
+ func deleteClusterAndWaitWorker (ctx context.Context , inputChan <- chan string , resultChan chan <- workResult , wg * sync.WaitGroup , c client.Client , defaultNamespace string , deployClusterInSeparateNamespaces bool ) {
549
587
defer wg .Done ()
550
588
551
589
for {
@@ -572,10 +610,16 @@ func deleteClusterAndWaitWorker(ctx context.Context, inputChan <-chan string, re
572
610
}
573
611
}()
574
612
613
+ // Calculate namespace.
614
+ namespaceName := defaultNamespace
615
+ if deployClusterInSeparateNamespaces {
616
+ namespaceName = clusterName
617
+ }
618
+
575
619
cluster := & clusterv1.Cluster {
576
620
ObjectMeta : metav1.ObjectMeta {
577
621
Name : clusterName ,
578
- Namespace : namespace ,
622
+ Namespace : namespaceName ,
579
623
},
580
624
}
581
625
framework .DeleteCluster (ctx , framework.DeleteClusterInput {
@@ -586,6 +630,15 @@ func deleteClusterAndWaitWorker(ctx context.Context, inputChan <-chan string, re
586
630
Getter : c ,
587
631
Cluster : cluster ,
588
632
})
633
+
634
+ // Note: We only delete the namespace in this case because in the case where all clusters are deployed
635
+ // to the same namespace deleting the Namespace will lead to deleting all clusters.
636
+ if deployClusterInSeparateNamespaces {
637
+ framework .DeleteNamespace (ctx , framework.DeleteNamespaceInput {
638
+ Deleter : c ,
639
+ Name : namespaceName ,
640
+ })
641
+ }
589
642
return false
590
643
}
591
644
}()
0 commit comments