Skip to content

Commit a3bbd47

Browse files
authored
Merge pull request #4734 from nojnhuh/v2-reconcile
implement top-level Reconcile methods for AzureASO... resources
2 parents 98971f6 + 9e0b220 commit a3bbd47

6 files changed

+782
-2
lines changed

exp/controllers/azureasomanagedcluster_controller.go

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,20 @@ package controllers
1818

1919
import (
2020
"context"
21+
"fmt"
2122

23+
infracontroller "sigs.k8s.io/cluster-api-provider-azure/controllers"
2224
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha1"
2325
"sigs.k8s.io/cluster-api-provider-azure/util/tele"
26+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
27+
"sigs.k8s.io/cluster-api/util"
28+
"sigs.k8s.io/cluster-api/util/annotations"
29+
"sigs.k8s.io/cluster-api/util/patch"
2430
"sigs.k8s.io/cluster-api/util/predicates"
2531
ctrl "sigs.k8s.io/controller-runtime"
32+
"sigs.k8s.io/controller-runtime/pkg/builder"
2633
"sigs.k8s.io/controller-runtime/pkg/client"
34+
"sigs.k8s.io/controller-runtime/pkg/handler"
2735
)
2836

2937
// AzureASOManagedClusterReconciler reconciles a AzureASOManagedCluster object.
@@ -34,7 +42,7 @@ type AzureASOManagedClusterReconciler struct {
3442

3543
// SetupWithManager sets up the controller with the Manager.
3644
func (r *AzureASOManagedClusterReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error {
37-
_, log, done := tele.StartSpanWithLogger(ctx,
45+
ctx, log, done := tele.StartSpanWithLogger(ctx,
3846
"controllers.AzureASOManagedClusterReconciler.SetupWithManager",
3947
tele.KVP("controller", infrav1exp.AzureASOManagedClusterKind),
4048
)
@@ -43,6 +51,18 @@ func (r *AzureASOManagedClusterReconciler) SetupWithManager(ctx context.Context,
4351
_, err := ctrl.NewControllerManagedBy(mgr).
4452
For(&infrav1exp.AzureASOManagedCluster{}).
4553
WithEventFilter(predicates.ResourceHasFilterLabel(log, r.WatchFilterValue)).
54+
WithEventFilter(predicates.ResourceIsNotExternallyManaged(log)).
55+
// Watch clusters for pause/unpause notifications
56+
Watches(
57+
&clusterv1.Cluster{},
58+
handler.EnqueueRequestsFromMapFunc(
59+
util.ClusterToInfrastructureMapFunc(ctx, infrav1exp.GroupVersion.WithKind(infrav1exp.AzureASOManagedClusterKind), mgr.GetClient(), &infrav1exp.AzureASOManagedCluster{}),
60+
),
61+
builder.WithPredicates(
62+
predicates.ResourceHasFilterLabel(log, r.WatchFilterValue),
63+
infracontroller.ClusterUpdatePauseChange(log),
64+
),
65+
).
4666
Build(r)
4767
if err != nil {
4868
return err
@@ -57,5 +77,81 @@ func (r *AzureASOManagedClusterReconciler) SetupWithManager(ctx context.Context,
5777

5878
// Reconcile reconciles an AzureASOManagedCluster.
5979
func (r *AzureASOManagedClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, resultErr error) {
80+
ctx, _, done := tele.StartSpanWithLogger(ctx,
81+
"controllers.AzureASOManagedClusterReconciler.Reconcile",
82+
tele.KVP("namespace", req.Namespace),
83+
tele.KVP("name", req.Name),
84+
tele.KVP("kind", infrav1exp.AzureASOManagedClusterKind),
85+
)
86+
defer done()
87+
88+
asoManagedCluster := &infrav1exp.AzureASOManagedCluster{}
89+
err := r.Get(ctx, req.NamespacedName, asoManagedCluster)
90+
if err != nil {
91+
return ctrl.Result{}, client.IgnoreNotFound(err)
92+
}
93+
94+
patchHelper, err := patch.NewHelper(asoManagedCluster, r.Client)
95+
if err != nil {
96+
return ctrl.Result{}, fmt.Errorf("failed to create patch helper: %w", err)
97+
}
98+
defer func() {
99+
err := patchHelper.Patch(ctx, asoManagedCluster)
100+
if err != nil && resultErr == nil {
101+
resultErr = err
102+
result = ctrl.Result{}
103+
}
104+
}()
105+
106+
cluster, err := util.GetOwnerCluster(ctx, r.Client, asoManagedCluster.ObjectMeta)
107+
if err != nil {
108+
return ctrl.Result{}, err
109+
}
110+
111+
if cluster != nil && cluster.Spec.Paused ||
112+
annotations.HasPaused(asoManagedCluster) {
113+
return r.reconcilePaused(ctx, asoManagedCluster, cluster)
114+
}
115+
116+
if !asoManagedCluster.GetDeletionTimestamp().IsZero() {
117+
return r.reconcileDelete(ctx, asoManagedCluster)
118+
}
119+
120+
return r.reconcileNormal(ctx, asoManagedCluster, cluster)
121+
}
122+
123+
//nolint:unparam // these parameters will be used soon enough
124+
func (r *AzureASOManagedClusterReconciler) reconcileNormal(ctx context.Context, asoManagedCluster *infrav1exp.AzureASOManagedCluster, cluster *clusterv1.Cluster) (ctrl.Result, error) {
125+
//nolint:all // ctx will be used soon
126+
ctx, log, done := tele.StartSpanWithLogger(ctx,
127+
"controllers.AzureASOManagedClusterReconciler.reconcileNormal",
128+
)
129+
defer done()
130+
log.V(4).Info("reconciling normally")
131+
132+
return ctrl.Result{}, nil
133+
}
134+
135+
//nolint:unparam // these parameters will be used soon enough
136+
func (r *AzureASOManagedClusterReconciler) reconcilePaused(ctx context.Context, asoManagedCluster *infrav1exp.AzureASOManagedCluster, cluster *clusterv1.Cluster) (ctrl.Result, error) {
137+
//nolint:all // ctx will be used soon
138+
ctx, log, done := tele.StartSpanWithLogger(ctx,
139+
"controllers.AzureASOManagedClusterReconciler.reconcilePaused",
140+
)
141+
defer done()
142+
log.V(4).Info("reconciling pause")
143+
144+
return ctrl.Result{}, nil
145+
}
146+
147+
//nolint:unparam // these parameters will be used soon enough
148+
func (r *AzureASOManagedClusterReconciler) reconcileDelete(ctx context.Context, asoManagedCluster *infrav1exp.AzureASOManagedCluster) (ctrl.Result, error) {
149+
//nolint:all // ctx will be used soon
150+
ctx, log, done := tele.StartSpanWithLogger(ctx,
151+
"controllers.AzureASOManagedClusterReconciler.reconcileDelete",
152+
)
153+
defer done()
154+
log.V(4).Info("reconciling delete")
155+
60156
return ctrl.Result{}, nil
61157
}

exp/controllers/azureasomanagedcluster_controller_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ package controllers
1919
import (
2020
"context"
2121
"testing"
22+
"time"
2223

2324
. "github.com/onsi/gomega"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2426
"k8s.io/apimachinery/pkg/runtime"
2527
"k8s.io/apimachinery/pkg/types"
2628
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha1"
29+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2730
ctrl "sigs.k8s.io/controller-runtime"
31+
"sigs.k8s.io/controller-runtime/pkg/client"
2832
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
2933
)
3034

@@ -34,6 +38,7 @@ func TestAzureASOManagedClusterReconcile(t *testing.T) {
3438
s := runtime.NewScheme()
3539
sb := runtime.NewSchemeBuilder(
3640
infrav1exp.AddToScheme,
41+
clusterv1.AddToScheme,
3742
)
3843
NewGomegaWithT(t).Expect(sb.AddToScheme(s)).To(Succeed())
3944

@@ -55,4 +60,110 @@ func TestAzureASOManagedClusterReconcile(t *testing.T) {
5560
g.Expect(err).NotTo(HaveOccurred())
5661
g.Expect(result).To(Equal(ctrl.Result{}))
5762
})
63+
64+
t.Run("Cluster does not exist", func(t *testing.T) {
65+
g := NewGomegaWithT(t)
66+
67+
asoManagedCluster := &infrav1exp.AzureASOManagedCluster{
68+
ObjectMeta: metav1.ObjectMeta{
69+
Name: "amc",
70+
Namespace: "ns",
71+
OwnerReferences: []metav1.OwnerReference{
72+
{
73+
APIVersion: clusterv1.GroupVersion.Identifier(),
74+
Kind: "Cluster",
75+
Name: "cluster",
76+
},
77+
},
78+
},
79+
}
80+
c := fakeClientBuilder().
81+
WithObjects(asoManagedCluster).
82+
Build()
83+
r := &AzureASOManagedClusterReconciler{
84+
Client: c,
85+
}
86+
_, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedCluster)})
87+
g.Expect(err).To(HaveOccurred())
88+
})
89+
90+
t.Run("successfully reconciles normally", func(t *testing.T) {
91+
g := NewGomegaWithT(t)
92+
93+
asoManagedCluster := &infrav1exp.AzureASOManagedCluster{
94+
ObjectMeta: metav1.ObjectMeta{
95+
Name: "amc",
96+
Namespace: "ns",
97+
},
98+
}
99+
c := fakeClientBuilder().
100+
WithObjects(asoManagedCluster).
101+
Build()
102+
r := &AzureASOManagedClusterReconciler{
103+
Client: c,
104+
}
105+
result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedCluster)})
106+
g.Expect(err).NotTo(HaveOccurred())
107+
g.Expect(result).To(Equal(ctrl.Result{}))
108+
})
109+
110+
t.Run("successfully reconciles pause", func(t *testing.T) {
111+
g := NewGomegaWithT(t)
112+
113+
cluster := &clusterv1.Cluster{
114+
ObjectMeta: metav1.ObjectMeta{
115+
Name: "cluster",
116+
Namespace: "ns",
117+
},
118+
Spec: clusterv1.ClusterSpec{
119+
Paused: true,
120+
},
121+
}
122+
asoManagedCluster := &infrav1exp.AzureASOManagedCluster{
123+
ObjectMeta: metav1.ObjectMeta{
124+
Name: "amc",
125+
Namespace: cluster.Namespace,
126+
OwnerReferences: []metav1.OwnerReference{
127+
{
128+
APIVersion: clusterv1.GroupVersion.Identifier(),
129+
Kind: "Cluster",
130+
Name: cluster.Name,
131+
},
132+
},
133+
},
134+
}
135+
c := fakeClientBuilder().
136+
WithObjects(cluster, asoManagedCluster).
137+
Build()
138+
r := &AzureASOManagedClusterReconciler{
139+
Client: c,
140+
}
141+
result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedCluster)})
142+
g.Expect(err).NotTo(HaveOccurred())
143+
g.Expect(result).To(Equal(ctrl.Result{}))
144+
})
145+
146+
t.Run("successfully reconciles delete", func(t *testing.T) {
147+
g := NewGomegaWithT(t)
148+
149+
asoManagedCluster := &infrav1exp.AzureASOManagedCluster{
150+
ObjectMeta: metav1.ObjectMeta{
151+
Name: "amc",
152+
Namespace: "ns",
153+
Finalizers: []string{
154+
clusterv1.ClusterFinalizer,
155+
},
156+
DeletionTimestamp: &metav1.Time{Time: time.Date(1, 0, 0, 0, 0, 0, 0, time.UTC)},
157+
},
158+
}
159+
c := fakeClientBuilder().
160+
WithObjects(asoManagedCluster).
161+
Build()
162+
r := &AzureASOManagedClusterReconciler{
163+
Client: c,
164+
}
165+
result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedCluster)})
166+
g.Expect(err).NotTo(HaveOccurred())
167+
g.Expect(result).To(Equal(ctrl.Result{}))
168+
})
58169
}

exp/controllers/azureasomanagedcontrolplane_controller.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,20 @@ package controllers
1818

1919
import (
2020
"context"
21+
"fmt"
2122

23+
infracontroller "sigs.k8s.io/cluster-api-provider-azure/controllers"
2224
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha1"
2325
"sigs.k8s.io/cluster-api-provider-azure/util/tele"
26+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
27+
"sigs.k8s.io/cluster-api/util"
28+
"sigs.k8s.io/cluster-api/util/annotations"
29+
"sigs.k8s.io/cluster-api/util/patch"
2430
"sigs.k8s.io/cluster-api/util/predicates"
2531
ctrl "sigs.k8s.io/controller-runtime"
32+
"sigs.k8s.io/controller-runtime/pkg/builder"
2633
"sigs.k8s.io/controller-runtime/pkg/client"
34+
"sigs.k8s.io/controller-runtime/pkg/handler"
2735
)
2836

2937
// AzureASOManagedControlPlaneReconciler reconciles a AzureASOManagedControlPlane object.
@@ -43,6 +51,13 @@ func (r *AzureASOManagedControlPlaneReconciler) SetupWithManager(ctx context.Con
4351
_, err := ctrl.NewControllerManagedBy(mgr).
4452
For(&infrav1exp.AzureASOManagedControlPlane{}).
4553
WithEventFilter(predicates.ResourceHasFilterLabel(log, r.WatchFilterValue)).
54+
Watches(&clusterv1.Cluster{},
55+
handler.EnqueueRequestsFromMapFunc(clusterToAzureASOManagedControlPlane),
56+
builder.WithPredicates(
57+
predicates.ResourceHasFilterLabel(log, r.WatchFilterValue),
58+
infracontroller.ClusterPauseChangeAndInfrastructureReady(log),
59+
),
60+
).
4661
Build(r)
4762
if err != nil {
4863
return err
@@ -51,11 +66,97 @@ func (r *AzureASOManagedControlPlaneReconciler) SetupWithManager(ctx context.Con
5166
return nil
5267
}
5368

69+
func clusterToAzureASOManagedControlPlane(_ context.Context, o client.Object) []ctrl.Request {
70+
controlPlaneRef := o.(*clusterv1.Cluster).Spec.ControlPlaneRef
71+
if controlPlaneRef != nil &&
72+
controlPlaneRef.APIVersion == infrav1exp.GroupVersion.Identifier() &&
73+
controlPlaneRef.Kind == infrav1exp.AzureASOManagedControlPlaneKind {
74+
return []ctrl.Request{{NamespacedName: client.ObjectKey{Namespace: controlPlaneRef.Namespace, Name: controlPlaneRef.Name}}}
75+
}
76+
return nil
77+
}
78+
5479
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azureasomanagedcontrolplanes,verbs=get;list;watch;create;update;patch;delete
5580
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azureasomanagedcontrolplanes/status,verbs=get;update;patch
5681
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azureasomanagedcontrolplanes/finalizers,verbs=update
5782

5883
// Reconcile reconciles an AzureASOManagedControlPlane.
5984
func (r *AzureASOManagedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, resultErr error) {
85+
ctx, _, done := tele.StartSpanWithLogger(ctx,
86+
"controllers.AzureASOManagedControlPlaneReconciler.Reconcile",
87+
tele.KVP("namespace", req.Namespace),
88+
tele.KVP("name", req.Name),
89+
tele.KVP("kind", infrav1exp.AzureASOManagedControlPlaneKind),
90+
)
91+
defer done()
92+
93+
asoManagedControlPlane := &infrav1exp.AzureASOManagedControlPlane{}
94+
err := r.Get(ctx, req.NamespacedName, asoManagedControlPlane)
95+
if err != nil {
96+
return ctrl.Result{}, client.IgnoreNotFound(err)
97+
}
98+
99+
patchHelper, err := patch.NewHelper(asoManagedControlPlane, r.Client)
100+
if err != nil {
101+
return ctrl.Result{}, fmt.Errorf("failed to create patch helper: %w", err)
102+
}
103+
defer func() {
104+
err := patchHelper.Patch(ctx, asoManagedControlPlane)
105+
if err != nil && resultErr == nil {
106+
resultErr = err
107+
result = ctrl.Result{}
108+
}
109+
}()
110+
111+
cluster, err := util.GetOwnerCluster(ctx, r.Client, asoManagedControlPlane.ObjectMeta)
112+
if err != nil {
113+
return ctrl.Result{}, err
114+
}
115+
116+
if cluster != nil && cluster.Spec.Paused ||
117+
annotations.HasPaused(asoManagedControlPlane) {
118+
return r.reconcilePaused(ctx, asoManagedControlPlane, cluster)
119+
}
120+
121+
if !asoManagedControlPlane.GetDeletionTimestamp().IsZero() {
122+
return r.reconcileDelete(ctx, asoManagedControlPlane)
123+
}
124+
125+
return r.reconcileNormal(ctx, asoManagedControlPlane, cluster)
126+
}
127+
128+
//nolint:unparam // these parameters will be used soon enough
129+
func (r *AzureASOManagedControlPlaneReconciler) reconcileNormal(ctx context.Context, asoManagedControlPlane *infrav1exp.AzureASOManagedControlPlane, cluster *clusterv1.Cluster) (ctrl.Result, error) {
130+
//nolint:all // ctx will be used soon
131+
ctx, log, done := tele.StartSpanWithLogger(ctx,
132+
"controllers.AzureASOManagedControlPlaneReconciler.reconcileNormal",
133+
)
134+
defer done()
135+
log.V(4).Info("reconciling normally")
136+
137+
return ctrl.Result{}, nil
138+
}
139+
140+
//nolint:unparam // these parameters will be used soon enough
141+
func (r *AzureASOManagedControlPlaneReconciler) reconcilePaused(ctx context.Context, asoManagedControlPlane *infrav1exp.AzureASOManagedControlPlane, cluster *clusterv1.Cluster) (ctrl.Result, error) {
142+
//nolint:all // ctx will be used soon
143+
ctx, log, done := tele.StartSpanWithLogger(ctx,
144+
"controllers.AzureASOManagedControlPlaneReconciler.reconcilePaused",
145+
)
146+
defer done()
147+
log.V(4).Info("reconciling pause")
148+
149+
return ctrl.Result{}, nil
150+
}
151+
152+
//nolint:unparam // these parameters will be used soon enough
153+
func (r *AzureASOManagedControlPlaneReconciler) reconcileDelete(ctx context.Context, asoManagedControlPlane *infrav1exp.AzureASOManagedControlPlane) (ctrl.Result, error) {
154+
//nolint:all // ctx will be used soon
155+
ctx, log, done := tele.StartSpanWithLogger(ctx,
156+
"controllers.AzureASOManagedControlPlaneReconciler.reconcileDelete",
157+
)
158+
defer done()
159+
log.V(4).Info("reconciling delete")
160+
60161
return ctrl.Result{}, nil
61162
}

0 commit comments

Comments
 (0)