Skip to content

Commit bcb0f16

Browse files
authored
Merge pull request #4803 from nojnhuh/v2-pause
ASOAPI: add pause handling
2 parents 1008d31 + e96e37b commit bcb0f16

10 files changed

+318
-24
lines changed

exp/controllers/azureasomanagedcluster_controller.go

+20-7
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ type resourceReconciler interface {
5858
// state of the specified resources.
5959
Reconcile(context.Context) error
6060

61+
// Pause stops ASO from continuously reconciling the specified resources.
62+
Pause(context.Context) error
63+
6164
// Delete begins deleting the specified resources and updates the object's status to reflect the state of
6265
// the specified resources.
6366
Delete(context.Context) error
@@ -195,7 +198,7 @@ func (r *AzureASOManagedClusterReconciler) Reconcile(ctx context.Context, req ct
195198

196199
if cluster != nil && cluster.Spec.Paused ||
197200
annotations.HasPaused(asoManagedCluster) {
198-
return r.reconcilePaused(ctx, asoManagedCluster, cluster)
201+
return r.reconcilePaused(ctx, asoManagedCluster)
199202
}
200203

201204
if !asoManagedCluster.GetDeletionTimestamp().IsZero() {
@@ -223,6 +226,7 @@ func (r *AzureASOManagedClusterReconciler) reconcileNormal(ctx context.Context,
223226
}
224227

225228
needsPatch := controllerutil.AddFinalizer(asoManagedCluster, clusterv1.ClusterFinalizer)
229+
needsPatch = infracontroller.AddBlockMoveAnnotation(asoManagedCluster) || needsPatch
226230
if needsPatch {
227231
return ctrl.Result{Requeue: true}, nil
228232
}
@@ -259,15 +263,24 @@ func (r *AzureASOManagedClusterReconciler) reconcileNormal(ctx context.Context,
259263
return ctrl.Result{}, nil
260264
}
261265

262-
//nolint:unparam // these parameters will be used soon enough
263-
func (r *AzureASOManagedClusterReconciler) reconcilePaused(ctx context.Context, asoManagedCluster *infrav1exp.AzureASOManagedCluster, cluster *clusterv1.Cluster) (ctrl.Result, error) {
264-
//nolint:all // ctx will be used soon
265-
ctx, log, done := tele.StartSpanWithLogger(ctx,
266-
"controllers.AzureASOManagedClusterReconciler.reconcilePaused",
267-
)
266+
//nolint:unparam // an empty ctrl.Result is always returned here, leaving it as-is to avoid churn in refactoring later if that changes.
267+
func (r *AzureASOManagedClusterReconciler) reconcilePaused(ctx context.Context, asoManagedCluster *infrav1exp.AzureASOManagedCluster) (ctrl.Result, error) {
268+
ctx, log, done := tele.StartSpanWithLogger(ctx, "controllers.AzureASOManagedClusterReconciler.reconcilePaused")
268269
defer done()
269270
log.V(4).Info("reconciling pause")
270271

272+
resources, err := mutators.ToUnstructured(ctx, asoManagedCluster.Spec.Resources)
273+
if err != nil {
274+
return ctrl.Result{}, err
275+
}
276+
resourceReconciler := r.newResourceReconciler(asoManagedCluster, resources)
277+
err = resourceReconciler.Pause(ctx)
278+
if err != nil {
279+
return ctrl.Result{}, fmt.Errorf("failed to pause resources: %w", err)
280+
}
281+
282+
infracontroller.RemoveBlockMoveAnnotation(asoManagedCluster)
283+
271284
return ctrl.Result{}, nil
272285
}
273286

exp/controllers/azureasomanagedcluster_controller_test.go

+30-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"k8s.io/apimachinery/pkg/types"
3131
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha1"
3232
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
33+
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
3334
ctrl "sigs.k8s.io/controller-runtime"
3435
"sigs.k8s.io/controller-runtime/pkg/client"
3536
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
@@ -38,6 +39,7 @@ import (
3839
type fakeResourceReconciler struct {
3940
owner client.Object
4041
reconcileFunc func(context.Context, client.Object) error
42+
pauseFunc func(context.Context, client.Object) error
4143
deleteFunc func(context.Context, client.Object) error
4244
}
4345

@@ -48,6 +50,13 @@ func (r *fakeResourceReconciler) Reconcile(ctx context.Context) error {
4850
return r.reconcileFunc(ctx, r.owner)
4951
}
5052

53+
func (r *fakeResourceReconciler) Pause(ctx context.Context) error {
54+
if r.pauseFunc == nil {
55+
return nil
56+
}
57+
return r.pauseFunc(ctx, r.owner)
58+
}
59+
5160
func (r *fakeResourceReconciler) Delete(ctx context.Context) error {
5261
if r.deleteFunc == nil {
5362
return nil
@@ -110,7 +119,7 @@ func TestAzureASOManagedClusterReconcile(t *testing.T) {
110119
g.Expect(err).To(HaveOccurred())
111120
})
112121

113-
t.Run("adds a finalizer", func(t *testing.T) {
122+
t.Run("adds a finalizer and block-move annotation", func(t *testing.T) {
114123
g := NewGomegaWithT(t)
115124

116125
cluster := &clusterv1.Cluster{
@@ -150,6 +159,7 @@ func TestAzureASOManagedClusterReconcile(t *testing.T) {
150159

151160
g.Expect(c.Get(ctx, client.ObjectKeyFromObject(asoManagedCluster), asoManagedCluster)).To(Succeed())
152161
g.Expect(asoManagedCluster.GetFinalizers()).To(ContainElement(clusterv1.ClusterFinalizer))
162+
g.Expect(asoManagedCluster.GetAnnotations()).To(HaveKey(clusterctlv1.BlockMoveAnnotation))
153163
})
154164

155165
t.Run("reconciles resources that are not ready", func(t *testing.T) {
@@ -181,6 +191,9 @@ func TestAzureASOManagedClusterReconcile(t *testing.T) {
181191
Finalizers: []string{
182192
clusterv1.ClusterFinalizer,
183193
},
194+
Annotations: map[string]string{
195+
clusterctlv1.BlockMoveAnnotation: "true",
196+
},
184197
},
185198
Status: infrav1exp.AzureASOManagedClusterStatus{
186199
Ready: true,
@@ -244,6 +257,9 @@ func TestAzureASOManagedClusterReconcile(t *testing.T) {
244257
Finalizers: []string{
245258
clusterv1.ClusterFinalizer,
246259
},
260+
Annotations: map[string]string{
261+
clusterctlv1.BlockMoveAnnotation: "true",
262+
},
247263
},
248264
Status: infrav1exp.AzureASOManagedClusterStatus{
249265
Ready: false,
@@ -303,17 +319,30 @@ func TestAzureASOManagedClusterReconcile(t *testing.T) {
303319
Name: cluster.Name,
304320
},
305321
},
322+
Annotations: map[string]string{
323+
clusterctlv1.BlockMoveAnnotation: "true",
324+
},
306325
},
307326
}
308327
c := fakeClientBuilder().
309328
WithObjects(cluster, asoManagedCluster).
310329
Build()
311330
r := &AzureASOManagedClusterReconciler{
312331
Client: c,
332+
newResourceReconciler: func(_ *infrav1exp.AzureASOManagedCluster, _ []*unstructured.Unstructured) resourceReconciler {
333+
return &fakeResourceReconciler{
334+
pauseFunc: func(_ context.Context, _ client.Object) error {
335+
return nil
336+
},
337+
}
338+
},
313339
}
314340
result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedCluster)})
315341
g.Expect(err).NotTo(HaveOccurred())
316342
g.Expect(result).To(Equal(ctrl.Result{}))
343+
344+
g.Expect(c.Get(ctx, client.ObjectKeyFromObject(asoManagedCluster), asoManagedCluster)).To(Succeed())
345+
g.Expect(asoManagedCluster.GetAnnotations()).NotTo(HaveKey(clusterctlv1.BlockMoveAnnotation))
317346
})
318347

319348
t.Run("successfully reconciles in-progress delete", func(t *testing.T) {

exp/controllers/azureasomanagedcontrolplane_controller.go

+17-7
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ func (r *AzureASOManagedControlPlaneReconciler) Reconcile(ctx context.Context, r
167167

168168
if cluster != nil && cluster.Spec.Paused ||
169169
annotations.HasPaused(asoManagedControlPlane) {
170-
return r.reconcilePaused(ctx, asoManagedControlPlane, cluster)
170+
return r.reconcilePaused(ctx, asoManagedControlPlane)
171171
}
172172

173173
if !asoManagedControlPlane.GetDeletionTimestamp().IsZero() {
@@ -195,6 +195,7 @@ func (r *AzureASOManagedControlPlaneReconciler) reconcileNormal(ctx context.Cont
195195
}
196196

197197
needsPatch := controllerutil.AddFinalizer(asoManagedControlPlane, infrav1exp.AzureASOManagedControlPlaneFinalizer)
198+
needsPatch = infracontroller.AddBlockMoveAnnotation(asoManagedControlPlane) || needsPatch
198199
if needsPatch {
199200
return ctrl.Result{Requeue: true}, nil
200201
}
@@ -295,15 +296,24 @@ func (r *AzureASOManagedControlPlaneReconciler) reconcileKubeconfig(ctx context.
295296
return r.Patch(ctx, expectedSecret, client.Apply, client.FieldOwner("capz-manager"), client.ForceOwnership)
296297
}
297298

298-
//nolint:unparam // these parameters will be used soon enough
299-
func (r *AzureASOManagedControlPlaneReconciler) reconcilePaused(ctx context.Context, asoManagedControlPlane *infrav1exp.AzureASOManagedControlPlane, cluster *clusterv1.Cluster) (ctrl.Result, error) {
300-
//nolint:all // ctx will be used soon
301-
ctx, log, done := tele.StartSpanWithLogger(ctx,
302-
"controllers.AzureASOManagedControlPlaneReconciler.reconcilePaused",
303-
)
299+
//nolint:unparam // an empty ctrl.Result is always returned here, leaving it as-is to avoid churn in refactoring later if that changes.
300+
func (r *AzureASOManagedControlPlaneReconciler) reconcilePaused(ctx context.Context, asoManagedControlPlane *infrav1exp.AzureASOManagedControlPlane) (ctrl.Result, error) {
301+
ctx, log, done := tele.StartSpanWithLogger(ctx, "controllers.AzureASOManagedControlPlaneReconciler.reconcilePaused")
304302
defer done()
305303
log.V(4).Info("reconciling pause")
306304

305+
resources, err := mutators.ToUnstructured(ctx, asoManagedControlPlane.Spec.Resources)
306+
if err != nil {
307+
return ctrl.Result{}, err
308+
}
309+
resourceReconciler := r.newResourceReconciler(asoManagedControlPlane, resources)
310+
err = resourceReconciler.Pause(ctx)
311+
if err != nil {
312+
return ctrl.Result{}, fmt.Errorf("failed to pause resources: %w", err)
313+
}
314+
315+
infracontroller.RemoveBlockMoveAnnotation(asoManagedControlPlane)
316+
307317
return ctrl.Result{}, nil
308318
}
309319

exp/controllers/azureasomanagedcontrolplane_controller_test.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"k8s.io/utils/ptr"
3535
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha1"
3636
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
37+
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
3738
"sigs.k8s.io/cluster-api/util/secret"
3839
ctrl "sigs.k8s.io/controller-runtime"
3940
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -96,7 +97,7 @@ func TestAzureASOManagedControlPlaneReconcile(t *testing.T) {
9697
g.Expect(err).To(HaveOccurred())
9798
})
9899

99-
t.Run("adds a finalizer", func(t *testing.T) {
100+
t.Run("adds a finalizer and block-move annotation", func(t *testing.T) {
100101
g := NewGomegaWithT(t)
101102

102103
cluster := &clusterv1.Cluster{
@@ -136,6 +137,7 @@ func TestAzureASOManagedControlPlaneReconcile(t *testing.T) {
136137

137138
g.Expect(c.Get(ctx, client.ObjectKeyFromObject(asoManagedControlPlane), asoManagedControlPlane)).To(Succeed())
138139
g.Expect(asoManagedControlPlane.GetFinalizers()).To(ContainElement(infrav1exp.AzureASOManagedControlPlaneFinalizer))
140+
g.Expect(asoManagedControlPlane.GetAnnotations()).To(HaveKey(clusterctlv1.BlockMoveAnnotation))
139141
})
140142

141143
t.Run("reconciles resources that are not ready", func(t *testing.T) {
@@ -167,6 +169,9 @@ func TestAzureASOManagedControlPlaneReconcile(t *testing.T) {
167169
Finalizers: []string{
168170
infrav1exp.AzureASOManagedControlPlaneFinalizer,
169171
},
172+
Annotations: map[string]string{
173+
clusterctlv1.BlockMoveAnnotation: "true",
174+
},
170175
},
171176
Spec: infrav1exp.AzureASOManagedControlPlaneSpec{
172177
AzureASOManagedControlPlaneTemplateResourceSpec: infrav1exp.AzureASOManagedControlPlaneTemplateResourceSpec{
@@ -270,6 +275,9 @@ func TestAzureASOManagedControlPlaneReconcile(t *testing.T) {
270275
Finalizers: []string{
271276
infrav1exp.AzureASOManagedControlPlaneFinalizer,
272277
},
278+
Annotations: map[string]string{
279+
clusterctlv1.BlockMoveAnnotation: "true",
280+
},
273281
},
274282
Spec: infrav1exp.AzureASOManagedControlPlaneSpec{
275283
AzureASOManagedControlPlaneTemplateResourceSpec: infrav1exp.AzureASOManagedControlPlaneTemplateResourceSpec{
@@ -344,17 +352,30 @@ func TestAzureASOManagedControlPlaneReconcile(t *testing.T) {
344352
Name: cluster.Name,
345353
},
346354
},
355+
Annotations: map[string]string{
356+
clusterctlv1.BlockMoveAnnotation: "true",
357+
},
347358
},
348359
}
349360
c := fakeClientBuilder().
350361
WithObjects(cluster, asoManagedControlPlane).
351362
Build()
352363
r := &AzureASOManagedControlPlaneReconciler{
353364
Client: c,
365+
newResourceReconciler: func(_ *infrav1exp.AzureASOManagedControlPlane, _ []*unstructured.Unstructured) resourceReconciler {
366+
return &fakeResourceReconciler{
367+
pauseFunc: func(_ context.Context, _ client.Object) error {
368+
return nil
369+
},
370+
}
371+
},
354372
}
355373
result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedControlPlane)})
356374
g.Expect(err).NotTo(HaveOccurred())
357375
g.Expect(result).To(Equal(ctrl.Result{}))
376+
377+
g.Expect(c.Get(ctx, client.ObjectKeyFromObject(asoManagedControlPlane), asoManagedControlPlane)).To(Succeed())
378+
g.Expect(asoManagedControlPlane.GetAnnotations()).NotTo(HaveKey(clusterctlv1.BlockMoveAnnotation))
358379
})
359380

360381
t.Run("successfully reconciles delete", func(t *testing.T) {

exp/controllers/azureasomanagedmachinepool_controller.go

+17-7
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func (r *AzureASOManagedMachinePoolReconciler) Reconcile(ctx context.Context, re
186186
}
187187

188188
if annotations.IsPaused(cluster, asoManagedMachinePool) {
189-
return r.reconcilePause(ctx, asoManagedMachinePool, cluster)
189+
return r.reconcilePaused(ctx, asoManagedMachinePool)
190190
}
191191

192192
if !asoManagedMachinePool.DeletionTimestamp.IsZero() {
@@ -204,6 +204,7 @@ func (r *AzureASOManagedMachinePoolReconciler) reconcileNormal(ctx context.Conte
204204
log.V(4).Info("reconciling normally")
205205

206206
needsPatch := controllerutil.AddFinalizer(asoManagedMachinePool, clusterv1.ClusterFinalizer)
207+
needsPatch = infracontroller.AddBlockMoveAnnotation(asoManagedMachinePool) || needsPatch
207208
if needsPatch {
208209
return ctrl.Result{Requeue: true}, nil
209210
}
@@ -291,15 +292,24 @@ func expectedNodeLabels(poolName, nodeRG string) map[string]string {
291292
}
292293
}
293294

294-
//nolint:unparam // these parameters will be used soon enough
295-
func (r *AzureASOManagedMachinePoolReconciler) reconcilePause(ctx context.Context, asoManagedMachinePool *infrav1exp.AzureASOManagedMachinePool, cluster *clusterv1.Cluster) (ctrl.Result, error) {
296-
//nolint:all // ctx will be used soon
297-
ctx, log, done := tele.StartSpanWithLogger(ctx,
298-
"controllers.AzureASOManagedMachinePoolReconciler.reconcilePaused",
299-
)
295+
//nolint:unparam // an empty ctrl.Result is always returned here, leaving it as-is to avoid churn in refactoring later if that changes.
296+
func (r *AzureASOManagedMachinePoolReconciler) reconcilePaused(ctx context.Context, asoManagedMachinePool *infrav1exp.AzureASOManagedMachinePool) (ctrl.Result, error) {
297+
ctx, log, done := tele.StartSpanWithLogger(ctx, "controllers.AzureASOManagedMachinePoolReconciler.reconcilePaused")
300298
defer done()
301299
log.V(4).Info("reconciling pause")
302300

301+
resources, err := mutators.ToUnstructured(ctx, asoManagedMachinePool.Spec.Resources)
302+
if err != nil {
303+
return ctrl.Result{}, err
304+
}
305+
resourceReconciler := r.newResourceReconciler(asoManagedMachinePool, resources)
306+
err = resourceReconciler.Pause(ctx)
307+
if err != nil {
308+
return ctrl.Result{}, fmt.Errorf("failed to pause resources: %w", err)
309+
}
310+
311+
infracontroller.RemoveBlockMoveAnnotation(asoManagedMachinePool)
312+
303313
return ctrl.Result{}, nil
304314
}
305315

0 commit comments

Comments
 (0)