@@ -1050,6 +1050,19 @@ func TestMachineConditions(t *testing.T) {
1050
1050
conditions .TrueCondition (clusterv1 .ReadyCondition ),
1051
1051
},
1052
1052
},
1053
+ {
1054
+ name : "paused initialises false" ,
1055
+ infraReady : true ,
1056
+ bootstrapReady : true ,
1057
+ beforeFunc : func (_ , _ * unstructured.Unstructured , m * clusterv1.Machine ) {
1058
+ // since these conditions are set by an external controller
1059
+ conditions .MarkTrue (m , clusterv1 .MachineHealthCheckSucceededCondition )
1060
+ conditions .MarkTrue (m , clusterv1 .MachineOwnerRemediatedCondition )
1061
+ },
1062
+ conditionsToAssert : []* clusterv1.Condition {
1063
+ conditions .FalseCondition (clusterv1 .PausedCondition , "ResourceNotPaused" , clusterv1 .ConditionSeverityInfo , "Resource is operating as expected" ),
1064
+ },
1065
+ },
1053
1066
{
1054
1067
name : "infra condition consumes reason from the infra config" ,
1055
1068
infraReady : false ,
@@ -2423,6 +2436,167 @@ func TestNodeDeletion(t *testing.T) {
2423
2436
}
2424
2437
}
2425
2438
2439
+ func TestPauseConditionReconcile (t * testing.T ) {
2440
+ g := NewWithT (t )
2441
+
2442
+ ns , err := env .CreateNamespace (ctx , "test-paused-condition-reconcile" )
2443
+ g .Expect (err ).ToNot (HaveOccurred ())
2444
+
2445
+ infraMachine := & unstructured.Unstructured {
2446
+ Object : map [string ]interface {}{
2447
+ "kind" : "GenericInfrastructureMachine" ,
2448
+ "apiVersion" : "infrastructure.cluster.x-k8s.io/v1beta1" ,
2449
+ "metadata" : map [string ]interface {}{
2450
+ "name" : "infra-config1" ,
2451
+ "namespace" : ns .Name ,
2452
+ },
2453
+ "spec" : map [string ]interface {}{
2454
+ "providerID" : "test://id-1" ,
2455
+ },
2456
+ },
2457
+ }
2458
+
2459
+ defaultBootstrap := & unstructured.Unstructured {
2460
+ Object : map [string ]interface {}{
2461
+ "kind" : "GenericBootstrapConfig" ,
2462
+ "apiVersion" : "bootstrap.cluster.x-k8s.io/v1beta1" ,
2463
+ "metadata" : map [string ]interface {}{
2464
+ "name" : "bootstrap-config-pausereconcile" ,
2465
+ "namespace" : ns .Name ,
2466
+ },
2467
+ "spec" : map [string ]interface {}{},
2468
+ "status" : map [string ]interface {}{},
2469
+ },
2470
+ }
2471
+
2472
+ testCluster := & clusterv1.Cluster {
2473
+ ObjectMeta : metav1.ObjectMeta {
2474
+ GenerateName : "pause-condition-reconcile-" ,
2475
+ Namespace : ns .Name ,
2476
+ },
2477
+ }
2478
+
2479
+ g .Expect (env .Create (ctx , testCluster )).To (Succeed ())
2480
+ g .Expect (env .Create (ctx , infraMachine )).To (Succeed ())
2481
+ g .Expect (env .Create (ctx , defaultBootstrap )).To (Succeed ())
2482
+
2483
+ defer func (do ... client.Object ) {
2484
+ g .Expect (env .Cleanup (ctx , do ... )).To (Succeed ())
2485
+ }(ns , testCluster , defaultBootstrap , infraMachine )
2486
+
2487
+ machine := & clusterv1.Machine {
2488
+ ObjectMeta : metav1.ObjectMeta {
2489
+ GenerateName : "machine-created-" ,
2490
+ Namespace : ns .Name ,
2491
+ Finalizers : []string {clusterv1 .MachineFinalizer },
2492
+ },
2493
+ Spec : clusterv1.MachineSpec {
2494
+ ClusterName : testCluster .Name ,
2495
+ InfrastructureRef : corev1.ObjectReference {
2496
+ APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" ,
2497
+ Kind : "GenericInfrastructureMachine" ,
2498
+ Name : "infra-config1" ,
2499
+ },
2500
+ Bootstrap : clusterv1.Bootstrap {
2501
+ ConfigRef : & corev1.ObjectReference {
2502
+ APIVersion : "bootstrap.cluster.x-k8s.io/v1beta1" ,
2503
+ Kind : "GenericBootstrapConfig" ,
2504
+ Name : "bootstrap-config-machinereconcile" ,
2505
+ },
2506
+ },
2507
+ },
2508
+ Status : clusterv1.MachineStatus {
2509
+ NodeRef : & corev1.ObjectReference {
2510
+ Name : "test" ,
2511
+ },
2512
+ },
2513
+ }
2514
+ g .Expect (env .Create (ctx , machine )).To (Succeed ())
2515
+
2516
+ defer func (do ... client.Object ) {
2517
+ g .Expect (env .Cleanup (ctx , do ... )).To (Succeed ())
2518
+ }(machine )
2519
+
2520
+ key := client.ObjectKey {Name : machine .Name , Namespace : machine .Namespace }
2521
+
2522
+ // Wait for reconciliation to happen when infra and bootstrap objects are not ready.
2523
+ g .Eventually (func () bool {
2524
+ if err := env .Get (ctx , key , machine ); err != nil {
2525
+ return false
2526
+ }
2527
+ return len (machine .Finalizers ) > 0
2528
+ }, timeout ).Should (BeTrue ())
2529
+
2530
+ // Set bootstrap ready.
2531
+ bootstrapPatch := client .MergeFrom (defaultBootstrap .DeepCopy ())
2532
+ g .Expect (unstructured .SetNestedField (defaultBootstrap .Object , true , "status" , "ready" )).ToNot (HaveOccurred ())
2533
+ g .Expect (env .Status ().Patch (ctx , defaultBootstrap , bootstrapPatch )).To (Succeed ())
2534
+
2535
+ // Set infrastructure ready.
2536
+ infraMachinePatch := client .MergeFrom (infraMachine .DeepCopy ())
2537
+ g .Expect (unstructured .SetNestedField (infraMachine .Object , true , "status" , "ready" )).To (Succeed ())
2538
+ g .Expect (env .Status ().Patch (ctx , infraMachine , infraMachinePatch )).To (Succeed ())
2539
+
2540
+ // Wait for Machine Ready Condition to become True.
2541
+ g .Eventually (func () bool {
2542
+ if err := env .Get (ctx , key , machine ); err != nil {
2543
+ return false
2544
+ }
2545
+ if ! conditions .Has (machine , clusterv1 .InfrastructureReadyCondition ) {
2546
+ return false
2547
+ }
2548
+ readyCondition := conditions .Get (machine , clusterv1 .ReadyCondition )
2549
+ return readyCondition .Status == corev1 .ConditionTrue
2550
+ }, timeout ).Should (BeTrue ())
2551
+
2552
+ // The cluster starts unpaused, so the machine machine has a Paused: false
2553
+ // condition
2554
+ g .Eventually (func () bool {
2555
+ if err := env .Get (ctx , key , machine ); err != nil {
2556
+ return false
2557
+ }
2558
+ if ! conditions .Has (machine , clusterv1 .PausedCondition ) {
2559
+ return false
2560
+ }
2561
+ pausedCondition := conditions .Get (machine , clusterv1 .PausedCondition )
2562
+ return pausedCondition .Status == corev1 .ConditionFalse
2563
+ }, timeout ).Should (BeTrue ())
2564
+
2565
+ // Case: We pause the machine indirectly by pausing the cluster, eventually
2566
+ // the machine has a Paused: true condition
2567
+
2568
+ testCluster .Spec .Paused = true
2569
+ g .Expect (env .Update (ctx , testCluster )).To (Succeed ())
2570
+
2571
+ // Eventually, machine has condition paused: true
2572
+ g .Eventually (func () bool {
2573
+ if err := env .Get (ctx , key , machine ); err != nil {
2574
+ return false
2575
+ }
2576
+ if ! conditions .Has (machine , clusterv1 .PausedCondition ) {
2577
+ return false
2578
+ }
2579
+ pausedCondition := conditions .Get (machine , clusterv1 .PausedCondition )
2580
+ return pausedCondition .Status == corev1 .ConditionTrue
2581
+ }, timeout ).Should (BeTrue ())
2582
+
2583
+ // Case: Then we unpause, eventually machine has paused:false
2584
+ testCluster .Spec .Paused = false
2585
+ g .Expect (env .Update (ctx , testCluster )).To (Succeed ())
2586
+
2587
+ // Eventually, machine has condition paused: true
2588
+ g .Eventually (func () bool {
2589
+ if err := env .Get (ctx , key , machine ); err != nil {
2590
+ return false
2591
+ }
2592
+ if ! conditions .Has (machine , clusterv1 .PausedCondition ) {
2593
+ return false
2594
+ }
2595
+ pausedCondition := conditions .Get (machine , clusterv1 .PausedCondition )
2596
+ return pausedCondition .Status == corev1 .ConditionFalse
2597
+ }, timeout ).Should (BeTrue ())
2598
+ }
2599
+
2426
2600
// adds a condition list to an external object.
2427
2601
func addConditionsToExternal (u * unstructured.Unstructured , newConditions clusterv1.Conditions ) {
2428
2602
existingConditions := clusterv1.Conditions {}
0 commit comments