@@ -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,18 +229,36 @@ func clusterUpgradeWithRuntimeSDKSpec(ctx context.Context, inputGetter func() cl
228
229
WaitForNodesReady : input .E2EConfig .GetIntervals (specName , "wait-nodes-ready" ),
229
230
})
230
231
232
+ Expect (err ).ToNot (HaveOccurred (), "Lifecycle hook calls were not as expected" )
233
+
234
+ By ("Deleting the workload cluster" )
235
+ cluster := & clusterv1.Cluster {}
236
+ Eventually (func () error {
237
+ return input .BootstrapClusterProxy .GetClient ().Get (ctx , client.ObjectKey {Namespace : namespace .Name , Name : clusterName }, cluster )
238
+ }).Should (Succeed ())
239
+
240
+ // Dump all the logs from the workload cluster before deleting them.
241
+ input .BootstrapClusterProxy .CollectWorkloadClusterLogs (ctx , cluster .Namespace , cluster .Name , filepath .Join (input .ArtifactFolder , "clusters" , cluster .Name ))
242
+
243
+ framework .DeleteCluster (ctx , framework.DeleteClusterInput {
244
+ Deleter : input .BootstrapClusterProxy .GetClient (),
245
+ Cluster : cluster ,
246
+ })
247
+
248
+ beforeClusterDeleteHandler (ctx , input .BootstrapClusterProxy .GetClient (), namespace .Name , clusterName , input .E2EConfig .GetIntervals (specName , "wait-machine-upgrade" ))
249
+
231
250
By ("Checking all lifecycle hooks have been called" )
232
251
// Assert that each hook has been called and returned "Success" during the test.
233
252
err = checkLifecycleHookResponses (ctx , input .BootstrapClusterProxy .GetClient (), namespace .Name , clusterName , map [string ]string {
234
253
"BeforeClusterCreate" : "Success" ,
235
254
"BeforeClusterUpgrade" : "Success" ,
255
+ "BeforeClusterDelete" : "Success" ,
236
256
"AfterControlPlaneInitialized" : "Success" ,
237
257
"AfterControlPlaneUpgrade" : "Success" ,
238
258
"AfterClusterUpgrade" : "Success" ,
239
259
})
240
- Expect (err ).ToNot (HaveOccurred (), "Lifecycle hook calls were not as expected" )
241
-
242
260
By ("PASSED!" )
261
+
243
262
})
244
263
245
264
AfterEach (func () {
@@ -300,6 +319,7 @@ func responsesConfigMap(name string, namespace *corev1.Namespace) *corev1.Config
300
319
"BeforeClusterCreate-preloadedResponse" : fmt .Sprintf (`{"Status": "Failure", "Message": %q}` , hookFailedMessage ),
301
320
"BeforeClusterUpgrade-preloadedResponse" : fmt .Sprintf (`{"Status": "Failure", "Message": %q}` , hookFailedMessage ),
302
321
"AfterControlPlaneUpgrade-preloadedResponse" : fmt .Sprintf (`{"Status": "Failure", "Message": %q}` , hookFailedMessage ),
322
+ "BeforeClusterDelete-preloadedResponse" : fmt .Sprintf (`{"Status": "Failure", "Message": %q}` , hookFailedMessage ),
303
323
304
324
// Non-blocking hooks are set to Status:Success.
305
325
"AfterControlPlaneInitialized-preloadedResponse" : `{"Status": "Success"}` ,
@@ -347,9 +367,8 @@ func getLifecycleHookResponsesFromConfigMap(ctx context.Context, c client.Client
347
367
// beforeClusterCreateTestHandler calls runtimeHookTestHandler with a blockedCondition function which returns false if
348
368
// the Cluster has entered ClusterPhaseProvisioned.
349
369
func beforeClusterCreateTestHandler (ctx context.Context , c client.Client , namespace , clusterName string , intervals []interface {}) {
350
- log .Logf ("Blocking with BeforeClusterCreate hook" )
351
370
hookName := "BeforeClusterCreate"
352
- runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , func () bool {
371
+ runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , true , func () bool {
353
372
blocked := true
354
373
// This hook should block the Cluster from entering the "Provisioned" state.
355
374
cluster := & clusterv1.Cluster {}
@@ -371,9 +390,8 @@ func beforeClusterCreateTestHandler(ctx context.Context, c client.Client, namesp
371
390
// beforeClusterUpgradeTestHandler calls runtimeHookTestHandler with a blocking function which returns false if the
372
391
// Cluster has controlplanev1.RollingUpdateInProgressReason in its ReadyCondition.
373
392
func beforeClusterUpgradeTestHandler (ctx context.Context , c client.Client , namespace , clusterName string , intervals []interface {}) {
374
- log .Logf ("Blocking with BeforeClusterUpgrade hook" )
375
393
hookName := "BeforeClusterUpgrade"
376
- runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , func () bool {
394
+ runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , true , func () bool {
377
395
var blocked = true
378
396
379
397
cluster := & clusterv1.Cluster {}
@@ -397,9 +415,8 @@ func beforeClusterUpgradeTestHandler(ctx context.Context, c client.Client, names
397
415
// afterControlPlaneUpgradeTestHandler calls runtimeHookTestHandler with a blocking function which returns false if any
398
416
// MachineDeployment in the Cluster has upgraded to the target Kubernetes version.
399
417
func afterControlPlaneUpgradeTestHandler (ctx context.Context , c client.Client , namespace , clusterName , version string , intervals []interface {}) {
400
- log .Logf ("Blocking with AfterControlPlaneUpgrade hook" )
401
418
hookName := "AfterControlPlaneUpgrade"
402
- runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , func () bool {
419
+ runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , true , func () bool {
403
420
var blocked = true
404
421
cluster := & clusterv1.Cluster {}
405
422
Eventually (func () error {
@@ -429,15 +446,47 @@ func afterControlPlaneUpgradeTestHandler(ctx context.Context, c client.Client, n
429
446
}, intervals )
430
447
}
431
448
449
+ // beforeClusterDeleteHandler calls runtimeHookTestHandler with a blocking function which returns false if any of the
450
+ // MachineDeployments associated with the Cluster are in a deleting state.
451
+ func beforeClusterDeleteHandler (ctx context.Context , c client.Client , namespace , clusterName string , intervals []interface {}) {
452
+ hookName := "BeforeClusterDelete"
453
+ runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , false , func () bool {
454
+ var blocked = true
455
+ mds := & clusterv1.MachineDeploymentList {}
456
+ Eventually (func () error {
457
+ return c .List (ctx , mds , client.MatchingLabels {
458
+ clusterv1 .ClusterLabelName : clusterName ,
459
+ clusterv1 .ClusterTopologyOwnedLabel : "" ,
460
+ })
461
+ }).Should (Succeed ())
462
+
463
+ // If any of the MachineDeployments has a deletion timestamp the delete process is unblocked.
464
+ for _ , md := range mds .Items {
465
+ if md .ObjectMeta .DeletionTimestamp != nil {
466
+ blocked = false
467
+ }
468
+ }
469
+
470
+ // If the Cluster is not found it has been deleted and the hook is unblocked.
471
+ if apierrors .IsNotFound (c .Get (ctx , client.ObjectKey {Namespace : namespace , Name : clusterName }, & clusterv1.Cluster {})) {
472
+ blocked = false
473
+ }
474
+
475
+ return blocked
476
+ }, intervals )
477
+ }
478
+
432
479
// 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.
480
+ // 1) Checks that the hook has been called at least once, and if set by withTopologyReconciledCondition, that the TopologyReconciled condition is a Failure.
434
481
// 2) Check that the hook's blockingCondition is consistently true.
435
482
// - At this point the function sets the hook's response to be non-blocking.
436
483
// 3) Check that the hook's blocking condition becomes false.
437
484
// Note: runtimeHookTestHandler assumes that the hook passed to it is currently returning a blocking response.
438
485
// 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.
486
+ func runtimeHookTestHandler (ctx context.Context , c client.Client , namespace , clusterName , hookName string , withTopologyReconciledCondition bool , blockingCondition func () bool , intervals []interface {}) {
487
+ log .Logf ("Blocking with %s hook" , hookName )
488
+
489
+ // Check that the LifecycleHook has been called at least once and - when required - that the TopologyReconciled condition is a Failure.
441
490
Eventually (func () error {
442
491
if err := checkLifecycleHooksCalledAtLeastOnce (ctx , c , namespace , clusterName , []string {hookName }); err != nil {
443
492
return err
@@ -446,11 +495,14 @@ func runtimeHookTestHandler(ctx context.Context, c client.Client, namespace, clu
446
495
if err := c .Get (ctx , client.ObjectKey {Namespace : namespace , Name : clusterName }, cluster ); err != nil {
447
496
return err
448
497
}
449
- if ! (conditions .GetReason (cluster , clusterv1 .TopologyReconciledCondition ) == clusterv1 .TopologyReconcileFailedReason ) {
498
+
499
+ // Check for the existence of the condition if withTopologyReconciledCondition is true.
500
+ if withTopologyReconciledCondition &&
501
+ ! (conditions .GetReason (cluster , clusterv1 .TopologyReconciledCondition ) == clusterv1 .TopologyReconcileFailedReason ) {
450
502
return errors .New ("Condition not found on Cluster object" )
451
503
}
452
504
return nil
453
- }, 60 * time . Second ).Should (Succeed (), "%s has not been called" , hookName )
505
+ }, intervals ... ).Should (Succeed (), "%s has not been called" , hookName )
454
506
455
507
// blockingCondition should consistently be true as the Runtime hook is returning "Failure".
456
508
Consistently (func () bool {
0 commit comments