@@ -28,6 +28,7 @@ import (
28
28
. "github.com/onsi/gomega"
29
29
"github.com/pkg/errors"
30
30
corev1 "k8s.io/api/core/v1"
31
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
31
32
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
33
"k8s.io/apimachinery/pkg/types"
33
34
"k8s.io/utils/pointer"
@@ -125,7 +126,7 @@ func clusterUpgradeWithRuntimeSDKSpec(ctx context.Context, inputGetter func() cl
125
126
clusterResources = new (clusterctl.ApplyClusterTemplateAndWaitResult )
126
127
})
127
128
128
- It ("Should create and upgrade a workload cluster" , func () {
129
+ It ("Should create, upgrade and delete a workload cluster" , func () {
129
130
clusterName := fmt .Sprintf ("%s-%s" , specName , util .RandomString (6 ))
130
131
By ("Deploy Test Extension" )
131
132
testExtensionDeploymentTemplate , err := os .ReadFile (testExtensionPath ) //nolint:gosec
@@ -228,11 +229,17 @@ func clusterUpgradeWithRuntimeSDKSpec(ctx context.Context, inputGetter func() cl
228
229
WaitForNodesReady : input .E2EConfig .GetIntervals (specName , "wait-nodes-ready" ),
229
230
})
230
231
232
+ By ("Backing up and deleting the workload cluster" )
233
+ backupAndDeleteCluster (ctx , input .BootstrapClusterProxy , namespace .Name , clusterName , input .ArtifactFolder )
234
+
235
+ beforeClusterDeleteHandler (ctx , input .BootstrapClusterProxy .GetClient (), namespace .Name , clusterName , input .E2EConfig .GetIntervals (specName , "wait-delete-cluster" ))
236
+
231
237
By ("Checking all lifecycle hooks have been called" )
232
238
// Assert that each hook has been called and returned "Success" during the test.
233
239
err = checkLifecycleHookResponses (ctx , input .BootstrapClusterProxy .GetClient (), namespace .Name , clusterName , map [string ]string {
234
240
"BeforeClusterCreate" : "Success" ,
235
241
"BeforeClusterUpgrade" : "Success" ,
242
+ "BeforeClusterDelete" : "Success" ,
236
243
"AfterControlPlaneInitialized" : "Success" ,
237
244
"AfterControlPlaneUpgrade" : "Success" ,
238
245
"AfterClusterUpgrade" : "Success" ,
@@ -300,6 +307,7 @@ func responsesConfigMap(name string, namespace *corev1.Namespace) *corev1.Config
300
307
"BeforeClusterCreate-preloadedResponse" : fmt .Sprintf (`{"Status": "Failure", "Message": %q}` , hookFailedMessage ),
301
308
"BeforeClusterUpgrade-preloadedResponse" : fmt .Sprintf (`{"Status": "Failure", "Message": %q}` , hookFailedMessage ),
302
309
"AfterControlPlaneUpgrade-preloadedResponse" : fmt .Sprintf (`{"Status": "Failure", "Message": %q}` , hookFailedMessage ),
310
+ "BeforeClusterDelete-preloadedResponse" : fmt .Sprintf (`{"Status": "Failure", "Message": %q}` , hookFailedMessage ),
303
311
304
312
// Non-blocking hooks are set to Status:Success.
305
313
"AfterControlPlaneInitialized-preloadedResponse" : `{"Status": "Success"}` ,
@@ -347,9 +355,8 @@ func getLifecycleHookResponsesFromConfigMap(ctx context.Context, c client.Client
347
355
// beforeClusterCreateTestHandler calls runtimeHookTestHandler with a blockedCondition function which returns false if
348
356
// the Cluster has entered ClusterPhaseProvisioned.
349
357
func beforeClusterCreateTestHandler (ctx context.Context , c client.Client , namespace , clusterName string , intervals []interface {}) {
350
- log .Logf ("Blocking with BeforeClusterCreate hook" )
351
358
hookName := "BeforeClusterCreate"
352
- runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , func () bool {
359
+ runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , true , func () bool {
353
360
blocked := true
354
361
// This hook should block the Cluster from entering the "Provisioned" state.
355
362
cluster := & clusterv1.Cluster {}
@@ -371,9 +378,8 @@ func beforeClusterCreateTestHandler(ctx context.Context, c client.Client, namesp
371
378
// beforeClusterUpgradeTestHandler calls runtimeHookTestHandler with a blocking function which returns false if the
372
379
// Cluster has controlplanev1.RollingUpdateInProgressReason in its ReadyCondition.
373
380
func beforeClusterUpgradeTestHandler (ctx context.Context , c client.Client , namespace , clusterName string , intervals []interface {}) {
374
- log .Logf ("Blocking with BeforeClusterUpgrade hook" )
375
381
hookName := "BeforeClusterUpgrade"
376
- runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , func () bool {
382
+ runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , true , func () bool {
377
383
var blocked = true
378
384
379
385
cluster := & clusterv1.Cluster {}
@@ -397,9 +403,8 @@ func beforeClusterUpgradeTestHandler(ctx context.Context, c client.Client, names
397
403
// afterControlPlaneUpgradeTestHandler calls runtimeHookTestHandler with a blocking function which returns false if any
398
404
// MachineDeployment in the Cluster has upgraded to the target Kubernetes version.
399
405
func afterControlPlaneUpgradeTestHandler (ctx context.Context , c client.Client , namespace , clusterName , version string , intervals []interface {}) {
400
- log .Logf ("Blocking with AfterControlPlaneUpgrade hook" )
401
406
hookName := "AfterControlPlaneUpgrade"
402
- runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , func () bool {
407
+ runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , true , func () bool {
403
408
var blocked = true
404
409
cluster := & clusterv1.Cluster {}
405
410
Eventually (func () error {
@@ -429,15 +434,32 @@ func afterControlPlaneUpgradeTestHandler(ctx context.Context, c client.Client, n
429
434
}, intervals )
430
435
}
431
436
437
+ // beforeClusterDeleteHandler calls runtimeHookTestHandler with a blocking function which returns false if any of the
438
+ // MachineDeployments associated with the Cluster are in a deleting state.
439
+ func beforeClusterDeleteHandler (ctx context.Context , c client.Client , namespace , clusterName string , intervals []interface {}) {
440
+ hookName := "BeforeClusterDelete"
441
+ runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , false , func () bool {
442
+ var blocked = true
443
+
444
+ // If the Cluster is not found it has been deleted and the hook is unblocked.
445
+ if apierrors .IsNotFound (c .Get (ctx , client.ObjectKey {Namespace : namespace , Name : clusterName }, & clusterv1.Cluster {})) {
446
+ blocked = false
447
+ }
448
+ return blocked
449
+ }, intervals )
450
+ }
451
+
432
452
// runtimeHookTestHandler runs a series of tests in sequence to check if the runtimeHook passed to it succeeds.
433
- // 1) Checks that the hook has been called at least once the TopologyReconciled condition is a Failure.
453
+ // 1) Checks that the hook has been called at least once, and if set by withTopologyReconciledCondition, that the TopologyReconciled condition is a Failure.
434
454
// 2) Check that the hook's blockingCondition is consistently true.
435
455
// - At this point the function sets the hook's response to be non-blocking.
436
456
// 3) Check that the hook's blocking condition becomes false.
437
457
// Note: runtimeHookTestHandler assumes that the hook passed to it is currently returning a blocking response.
438
458
// Updating the response to be non-blocking happens inline in the function.
439
- func runtimeHookTestHandler (ctx context.Context , c client.Client , namespace , clusterName , hookName string , blockingCondition func () bool , intervals []interface {}) {
440
- // Check that the LifecycleHook has been called at least once and the TopologyReconciled condition is a Failure.
459
+ func runtimeHookTestHandler (ctx context.Context , c client.Client , namespace , clusterName , hookName string , withTopologyReconciledCondition bool , blockingCondition func () bool , intervals []interface {}) {
460
+ log .Logf ("Blocking with %s hook" , hookName )
461
+
462
+ // Check that the LifecycleHook has been called at least once and - when required - that the TopologyReconciled condition is a Failure.
441
463
Eventually (func () error {
442
464
if err := checkLifecycleHooksCalledAtLeastOnce (ctx , c , namespace , clusterName , []string {hookName }); err != nil {
443
465
return err
@@ -446,7 +468,10 @@ func runtimeHookTestHandler(ctx context.Context, c client.Client, namespace, clu
446
468
if err := c .Get (ctx , client.ObjectKey {Namespace : namespace , Name : clusterName }, cluster ); err != nil {
447
469
return err
448
470
}
449
- if ! (conditions .GetReason (cluster , clusterv1 .TopologyReconciledCondition ) == clusterv1 .TopologyReconcileFailedReason ) {
471
+
472
+ // Check for the existence of the condition if withTopologyReconciledCondition is true.
473
+ if withTopologyReconciledCondition &&
474
+ (conditions .GetReason (cluster , clusterv1 .TopologyReconciledCondition ) != clusterv1 .TopologyReconcileFailedReason ) {
450
475
return errors .New ("Condition not found on Cluster object" )
451
476
}
452
477
return nil
@@ -484,3 +509,28 @@ func clusterConditionShowsHookFailed(cluster *clusterv1.Cluster, hookName string
484
509
strings .Contains (conditions .GetMessage (cluster , clusterv1 .TopologyReconciledCondition ), hookFailedMessage ) &&
485
510
strings .Contains (conditions .GetMessage (cluster , clusterv1 .TopologyReconciledCondition ), hookName )
486
511
}
512
+
513
+ func backupAndDeleteCluster (ctx context.Context , proxy framework.ClusterProxy , namespace , clusterName , artifactFolder string ) {
514
+ By ("Deleting the workload cluster" )
515
+ cluster := & clusterv1.Cluster {}
516
+ Eventually (func () error {
517
+ return proxy .GetClient ().Get (ctx , client.ObjectKey {Namespace : namespace , Name : clusterName }, cluster )
518
+ }).Should (Succeed ())
519
+
520
+ // Dump all the logs from the workload cluster before deleting them.
521
+ proxy .CollectWorkloadClusterLogs (ctx , cluster .Namespace , cluster .Name , filepath .Join (artifactFolder , "clusters-beforeClusterDelete" , cluster .Name ))
522
+
523
+ // Dump all Cluster API related resources to artifacts before deleting them.
524
+ framework .DumpAllResources (ctx , framework.DumpAllResourcesInput {
525
+ Lister : proxy .GetClient (),
526
+ Namespace : namespace ,
527
+ LogPath : filepath .Join (artifactFolder , "clusters-beforeClusterDelete" , proxy .GetName (), "resources" ),
528
+ })
529
+
530
+ By ("Deleting the workload cluster" )
531
+ // Delete the workload cluster and call the before ClusterDeleteTestHandler.
532
+ framework .DeleteCluster (ctx , framework.DeleteClusterInput {
533
+ Deleter : proxy .GetClient (),
534
+ Cluster : cluster ,
535
+ })
536
+ }
0 commit comments