@@ -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,163 @@ 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 , machine )
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
+ key := client.ObjectKey {Name : machine .Name , Namespace : machine .Namespace }
2517
+
2518
+ // Wait for reconciliation to happen when infra and bootstrap objects are not ready.
2519
+ g .Eventually (func () bool {
2520
+ if err := env .Get (ctx , key , machine ); err != nil {
2521
+ return false
2522
+ }
2523
+ return len (machine .Finalizers ) > 0
2524
+ }, timeout ).Should (BeTrue ())
2525
+
2526
+ // Set bootstrap ready.
2527
+ bootstrapPatch := client .MergeFrom (defaultBootstrap .DeepCopy ())
2528
+ g .Expect (unstructured .SetNestedField (defaultBootstrap .Object , true , "status" , "ready" )).ToNot (HaveOccurred ())
2529
+ g .Expect (env .Status ().Patch (ctx , defaultBootstrap , bootstrapPatch )).To (Succeed ())
2530
+
2531
+ // Set infrastructure ready.
2532
+ infraMachinePatch := client .MergeFrom (infraMachine .DeepCopy ())
2533
+ g .Expect (unstructured .SetNestedField (infraMachine .Object , true , "status" , "ready" )).To (Succeed ())
2534
+ g .Expect (env .Status ().Patch (ctx , infraMachine , infraMachinePatch )).To (Succeed ())
2535
+
2536
+ // Wait for Machine Ready Condition to become True.
2537
+ g .Eventually (func () bool {
2538
+ if err := env .Get (ctx , key , machine ); err != nil {
2539
+ return false
2540
+ }
2541
+ if ! conditions .Has (machine , clusterv1 .InfrastructureReadyCondition ) {
2542
+ return false
2543
+ }
2544
+ readyCondition := conditions .Get (machine , clusterv1 .ReadyCondition )
2545
+ return readyCondition .Status == corev1 .ConditionTrue
2546
+ }, timeout ).Should (BeTrue ())
2547
+
2548
+ // The cluster starts unpaused, so the machine machine has a Paused: false
2549
+ // condition
2550
+ g .Eventually (func () bool {
2551
+ if err := env .Get (ctx , key , machine ); err != nil {
2552
+ return false
2553
+ }
2554
+ if ! conditions .Has (machine , clusterv1 .PausedCondition ) {
2555
+ return false
2556
+ }
2557
+ pausedCondition := conditions .Get (machine , clusterv1 .PausedCondition )
2558
+ return pausedCondition .Status == corev1 .ConditionFalse
2559
+ }, timeout ).Should (BeTrue ())
2560
+
2561
+ // Case: We pause the machine indirectly by pausing the cluster, eventually
2562
+ // the machine has a Paused: true condition
2563
+
2564
+ testCluster .Spec .Paused = true
2565
+ g .Expect (env .Update (ctx , testCluster )).To (Succeed ())
2566
+
2567
+ // Eventually, machine has condition paused: true
2568
+ g .Eventually (func () bool {
2569
+ if err := env .Get (ctx , key , machine ); err != nil {
2570
+ return false
2571
+ }
2572
+ if ! conditions .Has (machine , clusterv1 .PausedCondition ) {
2573
+ return false
2574
+ }
2575
+ pausedCondition := conditions .Get (machine , clusterv1 .PausedCondition )
2576
+ return pausedCondition .Status == corev1 .ConditionTrue
2577
+ }, timeout ).Should (BeTrue ())
2578
+
2579
+ // Case: Then we unpause, eventually machine has paused:false
2580
+ testCluster .Spec .Paused = false
2581
+ g .Expect (env .Update (ctx , testCluster )).To (Succeed ())
2582
+
2583
+ // Eventually, machine has condition paused: true
2584
+ g .Eventually (func () bool {
2585
+ if err := env .Get (ctx , key , machine ); err != nil {
2586
+ return false
2587
+ }
2588
+ if ! conditions .Has (machine , clusterv1 .PausedCondition ) {
2589
+ return false
2590
+ }
2591
+ pausedCondition := conditions .Get (machine , clusterv1 .PausedCondition )
2592
+ return pausedCondition .Status == corev1 .ConditionFalse
2593
+ }, timeout ).Should (BeTrue ())
2594
+ }
2595
+
2426
2596
// adds a condition list to an external object.
2427
2597
func addConditionsToExternal (u * unstructured.Unstructured , newConditions clusterv1.Conditions ) {
2428
2598
existingConditions := clusterv1.Conditions {}
0 commit comments