@@ -41,6 +41,7 @@ import (
41
41
clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
42
42
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
43
43
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
44
+ "sigs.k8s.io/cluster-api/util/annotations"
44
45
"sigs.k8s.io/cluster-api/util/conditions"
45
46
"sigs.k8s.io/cluster-api/util/patch"
46
47
"sigs.k8s.io/cluster-api/util/yaml"
@@ -232,8 +233,7 @@ func (o *objectMover) checkProvisioningCompleted(ctx context.Context, graph *obj
232
233
// Checking all the clusters have infrastructure is ready
233
234
readClusterBackoff := newReadBackoff ()
234
235
clusters := graph .getClusters ()
235
- for i := range clusters {
236
- cluster := clusters [i ]
236
+ for _ , cluster := range clusters {
237
237
clusterObj := & clusterv1.Cluster {}
238
238
if err := retryWithExponentialBackoff (ctx , readClusterBackoff , func (ctx context.Context ) error {
239
239
return getClusterObj (ctx , o .fromProxy , cluster , clusterObj )
@@ -297,6 +297,25 @@ func getClusterObj(ctx context.Context, proxy Proxy, cluster *node, clusterObj *
297
297
return nil
298
298
}
299
299
300
+ // getClusterClassObj retrieves the clusterClassObj corresponding to a node with type ClusterClass.
301
+ func getClusterClassObj (ctx context.Context , proxy Proxy , clusterClass * node , clusterClassObj * clusterv1.ClusterClass ) error {
302
+ c , err := proxy .NewClient (ctx )
303
+ if err != nil {
304
+ return err
305
+ }
306
+
307
+ clusterClassObjKey := client.ObjectKey {
308
+ Namespace : clusterClass .identity .Namespace ,
309
+ Name : clusterClass .identity .Name ,
310
+ }
311
+
312
+ if err := c .Get (ctx , clusterClassObjKey , clusterClassObj ); err != nil {
313
+ return errors .Wrapf (err , "error reading ClusterClass %s/%s" ,
314
+ clusterClass .identity .Namespace , clusterClass .identity .Name )
315
+ }
316
+ return nil
317
+ }
318
+
300
319
// getMachineObj retrieves the machineObj corresponding to a node with type Machine.
301
320
func getMachineObj (ctx context.Context , proxy Proxy , machine * node , machineObj * clusterv1.Machine ) error {
302
321
c , err := proxy .NewClient (ctx )
@@ -320,9 +339,17 @@ func (o *objectMover) move(ctx context.Context, graph *objectGraph, toProxy Prox
320
339
log := logf .Log
321
340
322
341
clusters := graph .getClusters ()
342
+ if err := checkClustersNotPaused (ctx , o .fromProxy , clusters ); err != nil {
343
+ return err
344
+ }
345
+
323
346
log .Info ("Moving Cluster API objects" , "Clusters" , len (clusters ))
324
347
325
348
clusterClasses := graph .getClusterClasses ()
349
+ if err := checkClusterClassesNotPaused (ctx , o .fromProxy , clusterClasses ); err != nil {
350
+ return err
351
+ }
352
+
326
353
log .Info ("Moving Cluster API objects" , "ClusterClasses" , len (clusterClasses ))
327
354
328
355
// Sets the pause field on the Cluster object in the source management cluster, so the controllers stop reconciling it.
@@ -395,9 +422,17 @@ func (o *objectMover) toDirectory(ctx context.Context, graph *objectGraph, direc
395
422
log := logf .Log
396
423
397
424
clusters := graph .getClusters ()
425
+ if err := checkClustersNotPaused (ctx , o .fromProxy , clusters ); err != nil {
426
+ return err
427
+ }
428
+
398
429
log .Info ("Starting move of Cluster API objects" , "Clusters" , len (clusters ))
399
430
400
431
clusterClasses := graph .getClusterClasses ()
432
+ if err := checkClusterClassesNotPaused (ctx , o .fromProxy , clusterClasses ); err != nil {
433
+ return err
434
+ }
435
+
401
436
log .Info ("Moving Cluster API objects" , "ClusterClasses" , len (clusterClasses ))
402
437
403
438
// Sets the pause field on the Cluster object in the source management cluster, so the controllers stop reconciling it.
@@ -570,8 +605,7 @@ func setClusterPause(ctx context.Context, proxy Proxy, clusters []*node, value b
570
605
patch := client .RawPatch (types .MergePatchType , []byte (fmt .Sprintf ("{\" spec\" :{\" paused\" :%s}}" , patchValue )))
571
606
572
607
setClusterPauseBackoff := newWriteBackoff ()
573
- for i := range clusters {
574
- cluster := clusters [i ]
608
+ for _ , cluster := range clusters {
575
609
log .V (5 ).Info ("Set Cluster.Spec.Paused" , "paused" , value , "Cluster" , klog .KRef (cluster .identity .Namespace , cluster .identity .Name ))
576
610
577
611
// Nb. The operation is wrapped in a retry loop to make setClusterPause more resilient to unexpected conditions.
@@ -593,8 +627,7 @@ func setClusterClassPause(ctx context.Context, proxy Proxy, clusterclasses []*no
593
627
log := logf .Log
594
628
595
629
setClusterClassPauseBackoff := newWriteBackoff ()
596
- for i := range clusterclasses {
597
- clusterclass := clusterclasses [i ]
630
+ for _ , clusterclass := range clusterclasses {
598
631
if pause {
599
632
log .V (5 ).Info ("Set Paused annotation" , "ClusterClass" , clusterclass .identity .Name , "Namespace" , clusterclass .identity .Namespace )
600
633
} else {
@@ -611,6 +644,38 @@ func setClusterClassPause(ctx context.Context, proxy Proxy, clusterclasses []*no
611
644
return nil
612
645
}
613
646
647
+ // checkClustersNotPaused checks that no cluster in the graph is paused before proceeding.
648
+ func checkClustersNotPaused (ctx context.Context , proxy Proxy , clusters []* node ) error {
649
+ for _ , cluster := range clusters {
650
+ clusterObj := & clusterv1.Cluster {}
651
+ if err := getClusterObj (ctx , proxy , cluster , clusterObj ); err != nil {
652
+ return err
653
+ }
654
+
655
+ if ptr .Deref (clusterObj .Spec .Paused , false ) || annotations .HasPaused (clusterObj ) {
656
+ return errors .Errorf ("cannot start operation while Cluster %s/%s is paused" , clusterObj .Namespace , clusterObj .Name )
657
+ }
658
+ }
659
+
660
+ return nil
661
+ }
662
+
663
+ // checkClusterClassesNotPaused checks that no clusterClass in the graph is paused before proceeding.
664
+ func checkClusterClassesNotPaused (ctx context.Context , proxy Proxy , clusterClasses []* node ) error {
665
+ for _ , clusterClass := range clusterClasses {
666
+ clusterClassObj := & clusterv1.ClusterClass {}
667
+ if err := getClusterClassObj (ctx , proxy , clusterClass , clusterClassObj ); err != nil {
668
+ return err
669
+ }
670
+
671
+ if annotations .HasPaused (clusterClassObj ) {
672
+ return errors .Errorf ("cannot start operation while ClusterClass %s/%s is paused" , clusterClassObj .Namespace , clusterClassObj .Name )
673
+ }
674
+ }
675
+
676
+ return nil
677
+ }
678
+
614
679
func waitReadyForMove (ctx context.Context , proxy Proxy , nodes []* node , dryRun bool , backoff wait.Backoff ) error {
615
680
if dryRun {
616
681
return nil
@@ -723,7 +788,8 @@ func pauseClusterClass(ctx context.Context, proxy Proxy, n *node, pause bool, mu
723
788
ObjectMeta : metav1.ObjectMeta {
724
789
Name : n .identity .Name ,
725
790
Namespace : n .identity .Namespace ,
726
- }}, mutators ... )
791
+ },
792
+ }, mutators ... )
727
793
if err != nil {
728
794
return err
729
795
}
@@ -1173,7 +1239,6 @@ func (o *objectMover) deleteGroup(ctx context.Context, group moveGroup) error {
1173
1239
err := retryWithExponentialBackoff (ctx , deleteSourceObjectBackoff , func (ctx context.Context ) error {
1174
1240
return o .deleteSourceObject (ctx , nodeToDelete )
1175
1241
})
1176
-
1177
1242
if err != nil {
1178
1243
errList = append (errList , err )
1179
1244
}
0 commit comments