@@ -35,7 +35,6 @@ import (
35
35
"sigs.k8s.io/controller-runtime/pkg/client"
36
36
37
37
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
38
- controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
39
38
runtimev1 "sigs.k8s.io/cluster-api/exp/runtime/api/v1alpha1"
40
39
"sigs.k8s.io/cluster-api/test/e2e/internal/log"
41
40
"sigs.k8s.io/cluster-api/test/framework"
@@ -44,8 +43,6 @@ import (
44
43
"sigs.k8s.io/cluster-api/util/conditions"
45
44
)
46
45
47
- var hookFailedMessage = "hook failed"
48
-
49
46
// clusterUpgradeWithRuntimeSDKSpecInput is the input for clusterUpgradeWithRuntimeSDKSpec.
50
47
type clusterUpgradeWithRuntimeSDKSpecInput struct {
51
48
E2EConfig * clusterctl.E2EConfig
@@ -83,14 +80,14 @@ func clusterUpgradeWithRuntimeSDKSpec(ctx context.Context, inputGetter func() cl
83
80
var (
84
81
input clusterUpgradeWithRuntimeSDKSpecInput
85
82
namespace * corev1.Namespace
86
- ext * runtimev1.ExtensionConfig
87
83
cancelWatches context.CancelFunc
88
84
89
85
controlPlaneMachineCount int64
90
86
workerMachineCount int64
91
87
92
88
clusterResources * clusterctl.ApplyClusterTemplateAndWaitResult
93
89
testExtensionPath string
90
+ clusterName string
94
91
)
95
92
96
93
BeforeEach (func () {
@@ -123,11 +120,12 @@ func clusterUpgradeWithRuntimeSDKSpec(ctx context.Context, inputGetter func() cl
123
120
124
121
// Set up a Namespace where to host objects for this spec and create a watcher for the Namespace events.
125
122
namespace , cancelWatches = setupSpecNamespace (ctx , specName , input .BootstrapClusterProxy , input .ArtifactFolder )
123
+ clusterName = fmt .Sprintf ("%s-%s" , specName , util .RandomString (6 ))
124
+
126
125
clusterResources = new (clusterctl.ApplyClusterTemplateAndWaitResult )
127
126
})
128
127
129
128
It ("Should create, upgrade and delete a workload cluster" , func () {
130
- clusterName := fmt .Sprintf ("%s-%s" , specName , util .RandomString (6 ))
131
129
By ("Deploy Test Extension" )
132
130
testExtensionDeploymentTemplate , err := os .ReadFile (testExtensionPath ) //nolint:gosec
133
131
Expect (err ).ToNot (HaveOccurred (), "Failed to read the extension deployment manifest file" )
@@ -141,12 +139,14 @@ func clusterUpgradeWithRuntimeSDKSpec(ctx context.Context, inputGetter func() cl
141
139
Expect (input .BootstrapClusterProxy .Apply (ctx , []byte (testExtensionDeployment ), "--namespace" , namespace .Name )).To (Succeed ())
142
140
143
141
By ("Deploy Test Extension ExtensionConfig and ConfigMap" )
144
- ext = extensionConfig (specName , namespace )
145
- err = input .BootstrapClusterProxy .GetClient ().Create (ctx , ext )
146
- Expect (err ).ToNot (HaveOccurred (), "Failed to create the extension config" )
147
- responses := responsesConfigMap (clusterName , namespace )
148
- err = input .BootstrapClusterProxy .GetClient ().Create (ctx , responses )
149
- Expect (err ).ToNot (HaveOccurred (), "Failed to create the responses configmap" )
142
+
143
+ Expect (input .BootstrapClusterProxy .GetClient ().Create (ctx ,
144
+ extensionConfig (specName , namespace ))).
145
+ To (Succeed (), "Failed to create the extension config" )
146
+
147
+ Expect (input .BootstrapClusterProxy .GetClient ().Create (ctx ,
148
+ responsesConfigMap (clusterName , namespace ))).
149
+ To (Succeed (), "Failed to create the responses configMap" )
150
150
151
151
By ("Creating a workload cluster" )
152
152
@@ -182,8 +182,6 @@ func clusterUpgradeWithRuntimeSDKSpec(ctx context.Context, inputGetter func() cl
182
182
ClusterProxy : input .BootstrapClusterProxy ,
183
183
Cluster : clusterResources .Cluster ,
184
184
ControlPlane : clusterResources .ControlPlane ,
185
- EtcdImageTag : input .E2EConfig .GetVariable (EtcdVersionUpgradeTo ),
186
- DNSImageTag : input .E2EConfig .GetVariable (CoreDNSVersionUpgradeTo ),
187
185
MachineDeployments : clusterResources .MachineDeployments ,
188
186
KubernetesUpgradeVersion : input .E2EConfig .GetVariable (KubernetesVersionUpgradeTo ),
189
187
WaitForMachinesToBeUpgraded : input .E2EConfig .GetIntervals (specName , "wait-machine-upgrade" ),
@@ -195,6 +193,7 @@ func clusterUpgradeWithRuntimeSDKSpec(ctx context.Context, inputGetter func() cl
195
193
input .BootstrapClusterProxy .GetClient (),
196
194
namespace .Name ,
197
195
clusterName ,
196
+ input .E2EConfig .GetVariable (KubernetesVersionUpgradeTo ),
198
197
input .E2EConfig .GetIntervals (specName , "wait-machine-upgrade" ))
199
198
},
200
199
PreWaitForMachineDeploymentToBeUpgraded : func () {
@@ -236,26 +235,26 @@ func clusterUpgradeWithRuntimeSDKSpec(ctx context.Context, inputGetter func() cl
236
235
237
236
By ("Checking all lifecycle hooks have been called" )
238
237
// Assert that each hook has been called and returned "Success" during the test.
239
- err = checkLifecycleHookResponses (ctx , input .BootstrapClusterProxy .GetClient (), namespace .Name , clusterName , map [string ]string {
240
- "BeforeClusterCreate" : "Success" ,
241
- "BeforeClusterUpgrade" : "Success" ,
242
- "BeforeClusterDelete" : "Success" ,
238
+ Expect (checkLifecycleHookResponses (ctx , input .BootstrapClusterProxy .GetClient (), namespace .Name , clusterName , map [string ]string {
239
+ "BeforeClusterCreate" : "Status: Success, RetryAfterSeconds: 0" ,
240
+ "BeforeClusterUpgrade" : "Status: Success, RetryAfterSeconds: 0" ,
241
+ "BeforeClusterDelete" : "Status: Success, RetryAfterSeconds: 0" ,
242
+ "AfterControlPlaneUpgrade" : "Status: Success, RetryAfterSeconds: 0" ,
243
243
"AfterControlPlaneInitialized" : "Success" ,
244
- "AfterControlPlaneUpgrade" : "Success" ,
245
244
"AfterClusterUpgrade" : "Success" ,
246
- })
247
- Expect (err ).ToNot (HaveOccurred (), "Lifecycle hook calls were not as expected" )
245
+ })).To (Succeed (), "Lifecycle hook calls were not as expected" )
248
246
249
247
By ("PASSED!" )
250
248
})
251
249
252
250
AfterEach (func () {
251
+ // Delete the extensionConfig first to ensure the BeforeDeleteCluster hook doesn't block deletion.
252
+ Eventually (func () error {
253
+ return input .BootstrapClusterProxy .GetClient ().Delete (ctx , extensionConfig (specName , namespace ))
254
+ }, 10 * time .Second , 1 * time .Second ).Should (Succeed (), "delete extensionConfig failed" )
255
+
253
256
// Dumps all the resources in the spec Namespace, then cleanups the cluster object and the spec Namespace itself.
254
257
dumpSpecResourcesAndCleanup (ctx , specName , input .BootstrapClusterProxy , input .ArtifactFolder , namespace , cancelWatches , clusterResources .Cluster , input .E2EConfig .GetIntervals , input .SkipCleanup )
255
-
256
- Eventually (func () error {
257
- return input .BootstrapClusterProxy .GetClient ().Delete (ctx , ext )
258
- }, 10 * time .Second , 1 * time .Second ).Should (Succeed ())
259
258
})
260
259
}
261
260
@@ -303,11 +302,11 @@ func responsesConfigMap(name string, namespace *corev1.Namespace) *corev1.Config
303
302
},
304
303
// Set the initial preloadedResponses for each of the tested hooks.
305
304
Data : map [string ]string {
306
- // Blocking hooks are set to Status:Failure initially. These will be changed during the test.
307
- "BeforeClusterCreate-preloadedResponse" : fmt . Sprintf ( `{"Status": "Failure ", "Message ": %q}` , hookFailedMessage ) ,
308
- "BeforeClusterUpgrade-preloadedResponse" : fmt . Sprintf ( `{"Status": "Failure ", "Message ": %q}` , hookFailedMessage ) ,
309
- "AfterControlPlaneUpgrade-preloadedResponse" : fmt . Sprintf ( `{"Status": "Failure ", "Message ": %q}` , hookFailedMessage ) ,
310
- "BeforeClusterDelete-preloadedResponse" : fmt . Sprintf ( `{"Status": "Failure ", "Message ": %q}` , hookFailedMessage ) ,
305
+ // Blocking hooks are set to return RetryAfterSeconds initially. These will be changed during the test.
306
+ "BeforeClusterCreate-preloadedResponse" : `{"Status": "Success ", "RetryAfterSeconds ": 5}` ,
307
+ "BeforeClusterUpgrade-preloadedResponse" : `{"Status": "Success ", "RetryAfterSeconds ": 5}` ,
308
+ "AfterControlPlaneUpgrade-preloadedResponse" : `{"Status": "Success ", "RetryAfterSeconds ": 5}` ,
309
+ "BeforeClusterDelete-preloadedResponse" : `{"Status": "Success ", "RetryAfterSeconds ": 5}` ,
311
310
312
311
// Non-blocking hooks are set to Status:Success.
313
312
"AfterControlPlaneInitialized-preloadedResponse" : `{"Status": "Success"}` ,
@@ -359,42 +358,29 @@ func beforeClusterCreateTestHandler(ctx context.Context, c client.Client, namesp
359
358
runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , true , func () bool {
360
359
blocked := true
361
360
// This hook should block the Cluster from entering the "Provisioned" state.
362
- cluster := & clusterv1.Cluster {}
363
- Eventually (func () error {
364
- return c .Get (ctx , client.ObjectKey {Namespace : namespace , Name : clusterName }, cluster )
365
- }).Should (Succeed ())
361
+ cluster := framework .GetClusterByName (ctx ,
362
+ framework.GetClusterByNameInput {Name : clusterName , Namespace : namespace , Getter : c })
366
363
367
- // Check if the TopologyReconciled condition message contains both the hook name and hookFailedMessage.
368
- if ! clusterConditionShowsHookFailed (cluster , hookName ) {
369
- blocked = false
370
- }
371
364
if cluster .Status .Phase == string (clusterv1 .ClusterPhaseProvisioned ) {
372
365
blocked = false
373
366
}
374
367
return blocked
375
368
}, intervals )
376
369
}
377
370
378
- // beforeClusterUpgradeTestHandler calls runtimeHookTestHandler with a blocking function which returns false if the
379
- // Cluster has controlplanev1.RollingUpdateInProgressReason in its ReadyCondition .
380
- func beforeClusterUpgradeTestHandler (ctx context.Context , c client.Client , namespace , clusterName string , intervals []interface {}) {
371
+ // beforeClusterUpgradeTestHandler calls runtimeHookTestHandler with a blocking function which returns false if
372
+ // any of the machines in the control plane has been updated to the target Kubernetes version .
373
+ func beforeClusterUpgradeTestHandler (ctx context.Context , c client.Client , namespace , clusterName , toVersion string , intervals []interface {}) {
381
374
hookName := "BeforeClusterUpgrade"
382
375
runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , true , func () bool {
383
376
var blocked = true
384
377
385
- cluster := & clusterv1.Cluster {}
386
- Eventually (func () error {
387
- return c .Get (ctx , client.ObjectKey {Namespace : namespace , Name : clusterName }, cluster )
388
- }).Should (Succeed ())
389
-
390
- // Check if the TopologyReconciled condition message contains both the hook name and hookFailedMessage.
391
- if ! clusterConditionShowsHookFailed (cluster , hookName ) {
392
- blocked = false
393
- }
394
- // Check if the Cluster is showing the RollingUpdateInProgress condition reason. If it has the update process is unblocked.
395
- if conditions .IsFalse (cluster , clusterv1 .ReadyCondition ) &&
396
- conditions .GetReason (cluster , clusterv1 .ReadyCondition ) == controlplanev1 .RollingUpdateInProgressReason {
397
- blocked = false
378
+ controlPlaneMachines := framework .GetControlPlaneMachinesByCluster (ctx ,
379
+ framework.GetControlPlaneMachinesByClusterInput {Lister : c , ClusterName : clusterName , Namespace : namespace })
380
+ for _ , machine := range controlPlaneMachines {
381
+ if * machine .Spec .Version == toVersion {
382
+ blocked = false
383
+ }
398
384
}
399
385
return blocked
400
386
}, intervals )
@@ -406,26 +392,11 @@ func afterControlPlaneUpgradeTestHandler(ctx context.Context, c client.Client, n
406
392
hookName := "AfterControlPlaneUpgrade"
407
393
runtimeHookTestHandler (ctx , c , namespace , clusterName , hookName , true , func () bool {
408
394
var blocked = true
409
- cluster := & clusterv1.Cluster {}
410
- Eventually (func () error {
411
- return c .Get (ctx , client.ObjectKey {Namespace : namespace , Name : clusterName }, cluster )
412
- }).Should (Succeed ())
413
-
414
- // Check if the TopologyReconciled condition message contains both the hook name and hookFailedMessage.
415
- if ! clusterConditionShowsHookFailed (cluster , hookName ) {
416
- blocked = false
417
- }
418
-
419
- mds := & clusterv1.MachineDeploymentList {}
420
- Eventually (func () error {
421
- return c .List (ctx , mds , client.MatchingLabels {
422
- clusterv1 .ClusterLabelName : clusterName ,
423
- clusterv1 .ClusterTopologyOwnedLabel : "" ,
424
- })
425
- }).Should (Succeed ())
426
395
396
+ mds := framework .GetMachineDeploymentsByCluster (ctx ,
397
+ framework.GetMachineDeploymentsByClusterInput {ClusterName : clusterName , Namespace : namespace , Lister : c })
427
398
// If any of the MachineDeployments have the target Kubernetes Version, the hook is unblocked.
428
- for _ , md := range mds . Items {
399
+ for _ , md := range mds {
429
400
if * md .Spec .Template .Spec .Version == version {
430
401
blocked = false
431
402
}
@@ -464,23 +435,23 @@ func runtimeHookTestHandler(ctx context.Context, c client.Client, namespace, clu
464
435
if err := checkLifecycleHooksCalledAtLeastOnce (ctx , c , namespace , clusterName , []string {hookName }); err != nil {
465
436
return err
466
437
}
467
- cluster := & clusterv1.Cluster {}
468
- if err := c .Get (ctx , client.ObjectKey {Namespace : namespace , Name : clusterName }, cluster ); err != nil {
469
- return err
470
- }
471
438
472
439
// Check for the existence of the condition if withTopologyReconciledCondition is true.
473
- if withTopologyReconciledCondition &&
474
- (conditions .GetReason (cluster , clusterv1 .TopologyReconciledCondition ) != clusterv1 .TopologyReconcileFailedReason ) {
475
- return errors .New ("Condition not found on Cluster object" )
440
+ if withTopologyReconciledCondition {
441
+ cluster := framework .GetClusterByName (ctx , framework.GetClusterByNameInput {
442
+ Name : clusterName , Namespace : namespace , Getter : c })
443
+
444
+ if ! clusterConditionShowsHookBlocking (cluster , hookName ) {
445
+ return errors .Errorf ("Blocking condition for %s not found on Cluster object" , hookName )
446
+ }
476
447
}
477
448
return nil
478
- }, 60 * time .Second ).Should (Succeed (), "%s has not been called" , hookName )
449
+ }, 30 * time .Second ).Should (Succeed (), "%s has not been called" , hookName )
479
450
480
451
// blockingCondition should consistently be true as the Runtime hook is returning "Failure".
481
452
Consistently (func () bool {
482
453
return blockingCondition ()
483
- }, 30 * time .Second ).Should (BeTrue (),
454
+ }, 60 * time .Second ).Should (BeTrue (),
484
455
fmt .Sprintf ("Cluster Topology reconciliation continued unexpectedly: hook %s not blocking" , hookName ))
485
456
486
457
// Patch the ConfigMap to set the hook response to "Success".
@@ -500,32 +471,32 @@ func runtimeHookTestHandler(ctx context.Context, c client.Client, namespace, clu
500
471
Eventually (func () bool {
501
472
return blockingCondition ()
502
473
}, intervals ... ).Should (BeFalse (),
503
- fmt .Sprintf ("ClusterTopology reconcile did not unblock after updating hook response: hook %s still blocking " , hookName ))
474
+ fmt .Sprintf ("ClusterTopology reconcile did proceed as expected when calling %s " , hookName ))
504
475
}
505
476
506
- // clusterConditionShowsHookFailed checks if the TopologyReconciled condition message contains both the hook name and hookFailedMessage.
507
- func clusterConditionShowsHookFailed (cluster * clusterv1.Cluster , hookName string ) bool {
508
- return conditions .GetReason (cluster , clusterv1 .TopologyReconciledCondition ) == clusterv1 .TopologyReconcileFailedReason &&
509
- strings .Contains (conditions .GetMessage (cluster , clusterv1 .TopologyReconciledCondition ), hookFailedMessage ) &&
477
+ // clusterConditionShowsHookBlocking checks if the TopologyReconciled condition message contains both the hook name and hookFailedMessage.
478
+ func clusterConditionShowsHookBlocking (cluster * clusterv1.Cluster , hookName string ) bool {
479
+ return conditions .GetReason (cluster , clusterv1 .TopologyReconciledCondition ) == clusterv1 .TopologyReconciledHookBlockingReason &&
510
480
strings .Contains (conditions .GetMessage (cluster , clusterv1 .TopologyReconciledCondition ), hookName )
511
481
}
512
482
513
483
func dumpAndDeleteCluster (ctx context.Context , proxy framework.ClusterProxy , namespace , clusterName , artifactFolder string ) {
514
484
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 ())
485
+
486
+ cluster := framework .GetClusterByName (ctx , framework.GetClusterByNameInput {
487
+ Name : clusterName , Namespace : namespace , Getter : proxy .GetClient ()})
519
488
520
489
// 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 ))
490
+ proxy .CollectWorkloadClusterLogs (ctx ,
491
+ cluster .Namespace ,
492
+ cluster .Name ,
493
+ filepath .Join (artifactFolder , "clusters-beforeClusterDelete" , cluster .Name ))
522
494
523
495
// Dump all Cluster API related resources to artifacts before deleting them.
524
496
framework .DumpAllResources (ctx , framework.DumpAllResourcesInput {
525
497
Lister : proxy .GetClient (),
526
498
Namespace : namespace ,
527
- LogPath : filepath .Join (artifactFolder , "clusters-beforeClusterDelete" , proxy .GetName (), "resources" ),
528
- })
499
+ LogPath : filepath .Join (artifactFolder , "clusters-beforeClusterDelete" , proxy .GetName (), "resources" )})
529
500
530
501
By ("Deleting the workload cluster" )
531
502
framework .DeleteCluster (ctx , framework.DeleteClusterInput {
0 commit comments