Skip to content

Commit 66cf3d6

Browse files
Refactor Cluster controller
1 parent e5cbc4a commit 66cf3d6

File tree

4 files changed

+746
-557
lines changed

4 files changed

+746
-557
lines changed

internal/controllers/cluster/cluster_controller.go

+69-55
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package cluster
1919
import (
2020
"context"
2121
"fmt"
22-
"path"
2322
"strings"
2423
"time"
2524

@@ -28,6 +27,7 @@ import (
2827
apierrors "k8s.io/apimachinery/pkg/api/errors"
2928
"k8s.io/apimachinery/pkg/api/meta"
3029
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3131
"k8s.io/apimachinery/pkg/runtime"
3232
kerrors "k8s.io/apimachinery/pkg/util/errors"
3333
"k8s.io/client-go/tools/record"
@@ -141,6 +141,10 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re
141141
return ctrl.Result{}, err
142142
}
143143

144+
s := &scope{
145+
cluster: cluster,
146+
}
147+
144148
// Initialize the patch helper.
145149
patchHelper, err := patch.NewHelper(cluster, r.Client)
146150
if err != nil {
@@ -185,13 +189,28 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re
185189
})
186190
}
187191

192+
alwaysReconcile := []clusterReconcileFunc{
193+
r.reconcileInfrastructure,
194+
r.reconcileControlPlane,
195+
}
196+
188197
// Handle deletion reconciliation loop.
189198
if !cluster.ObjectMeta.DeletionTimestamp.IsZero() {
190-
return r.reconcileDelete(ctx, cluster)
199+
reconcileDelete := append(
200+
alwaysReconcile,
201+
r.reconcileDelete,
202+
)
203+
204+
return doReconcile(ctx, reconcileDelete, s)
191205
}
192206

193207
// Handle normal reconciliation loop.
194-
return r.reconcile(ctx, cluster)
208+
reconcileNormal := append(
209+
alwaysReconcile,
210+
r.reconcileKubeconfig,
211+
r.reconcileControlPlaneInitialized,
212+
)
213+
return doReconcile(ctx, reconcileNormal, s)
195214
}
196215

197216
func patchCluster(ctx context.Context, patchHelper *patch.Helper, cluster *clusterv1.Cluster, options ...patch.Option) error {
@@ -216,30 +235,14 @@ func patchCluster(ctx context.Context, patchHelper *patch.Helper, cluster *clust
216235
return patchHelper.Patch(ctx, cluster, options...)
217236
}
218237

219-
// reconcile handles cluster reconciliation.
220-
func (r *Reconciler) reconcile(ctx context.Context, cluster *clusterv1.Cluster) (ctrl.Result, error) {
221-
log := ctrl.LoggerFrom(ctx)
222-
223-
if cluster.Spec.Topology != nil {
224-
if cluster.Spec.ControlPlaneRef == nil || cluster.Spec.InfrastructureRef == nil {
225-
// TODO: add a condition to surface this scenario
226-
log.Info("Waiting for the topology to be generated")
227-
return ctrl.Result{}, nil
228-
}
229-
}
230-
231-
phases := []func(context.Context, *clusterv1.Cluster) (ctrl.Result, error){
232-
r.reconcileInfrastructure,
233-
r.reconcileControlPlane,
234-
r.reconcileKubeconfig,
235-
r.reconcileControlPlaneInitialized,
236-
}
238+
type clusterReconcileFunc func(context.Context, *scope) (ctrl.Result, error)
237239

240+
func doReconcile(ctx context.Context, phases []clusterReconcileFunc, s *scope) (ctrl.Result, error) {
238241
res := ctrl.Result{}
239242
errs := []error{}
240243
for _, phase := range phases {
241244
// Call the inner reconciliation methods.
242-
phaseResult, err := phase(ctx, cluster)
245+
phaseResult, err := phase(ctx, s)
243246
if err != nil {
244247
errs = append(errs, err)
245248
}
@@ -248,12 +251,42 @@ func (r *Reconciler) reconcile(ctx context.Context, cluster *clusterv1.Cluster)
248251
}
249252
res = util.LowestNonZeroResult(res, phaseResult)
250253
}
251-
return res, kerrors.NewAggregate(errs)
254+
255+
if len(errs) > 0 {
256+
return ctrl.Result{}, kerrors.NewAggregate(errs)
257+
}
258+
259+
return res, nil
260+
}
261+
262+
// scope holds the different objects that are read and used during the reconcile.
263+
type scope struct {
264+
// cluster is the Cluster object the Machine belongs to.
265+
// It is set at the beginning of the reconcile function.
266+
cluster *clusterv1.Cluster
267+
268+
// infraCluster is the Infrastructure Cluster object that is referenced by the
269+
// Cluster. It is set after reconcileInfrastructure is called.
270+
infraCluster *unstructured.Unstructured
271+
272+
// infraClusterNotFound is true if getting the infra cluster object failed with an NotFound err
273+
infraClusterIsNotFound bool
274+
275+
// controlPlane is the ControlPlane object that is referenced by the
276+
// Cluster. It is set after reconcileBootstrap is called.
277+
controlPlane *unstructured.Unstructured
278+
279+
// controlPlaneNotFound is true if getting the ControlPlane object failed with an NotFound err
280+
controlPlaneIsNotFound bool
281+
282+
// descendants is the list of objects related to this Cluster
283+
// descendants clusterDescendants
252284
}
253285

254286
// reconcileDelete handles cluster deletion.
255-
func (r *Reconciler) reconcileDelete(ctx context.Context, cluster *clusterv1.Cluster) (reconcile.Result, error) {
287+
func (r *Reconciler) reconcileDelete(ctx context.Context, s *scope) (reconcile.Result, error) {
256288
log := ctrl.LoggerFrom(ctx)
289+
cluster := s.cluster
257290

258291
// If the RuntimeSDK and ClusterTopology flags are enabled, for clusters with managed topologies
259292
// only proceed with delete if the cluster is marked as `ok-to-delete`
@@ -314,28 +347,18 @@ func (r *Reconciler) reconcileDelete(ctx context.Context, cluster *clusterv1.Clu
314347
}
315348

316349
if cluster.Spec.ControlPlaneRef != nil {
317-
obj, err := external.Get(ctx, r.Client, cluster.Spec.ControlPlaneRef, cluster.Namespace)
318-
switch {
319-
case apierrors.IsNotFound(errors.Cause(err)):
350+
if s.controlPlaneIsNotFound {
320351
// All good - the control plane resource has been deleted
321352
conditions.MarkFalse(cluster, clusterv1.ControlPlaneReadyCondition, clusterv1.DeletedReason, clusterv1.ConditionSeverityInfo, "")
322-
case err != nil:
323-
return reconcile.Result{}, errors.Wrapf(err, "failed to get %s %q for Cluster %s/%s",
324-
path.Join(cluster.Spec.ControlPlaneRef.APIVersion, cluster.Spec.ControlPlaneRef.Kind),
325-
cluster.Spec.ControlPlaneRef.Name, cluster.Namespace, cluster.Name)
326-
default:
327-
// Report a summary of current status of the control plane object defined for this cluster.
328-
conditions.SetMirror(cluster, clusterv1.ControlPlaneReadyCondition,
329-
conditions.UnstructuredGetter(obj),
330-
conditions.WithFallbackValue(false, clusterv1.DeletingReason, clusterv1.ConditionSeverityInfo, ""),
331-
)
353+
}
332354

355+
if s.controlPlane != nil {
333356
// Issue a deletion request for the control plane object.
334357
// Once it's been deleted, the cluster will get processed again.
335-
if err := r.Client.Delete(ctx, obj); err != nil {
358+
if err := r.Client.Delete(ctx, s.controlPlane); err != nil {
336359
return ctrl.Result{}, errors.Wrapf(err,
337360
"failed to delete %v %q for Cluster %q in namespace %q",
338-
obj.GroupVersionKind(), obj.GetName(), cluster.Name, cluster.Namespace)
361+
s.controlPlane.GroupVersionKind(), s.controlPlane.GetName(), cluster.Name, cluster.Namespace)
339362
}
340363

341364
// Return here so we don't remove the finalizer yet.
@@ -345,28 +368,18 @@ func (r *Reconciler) reconcileDelete(ctx context.Context, cluster *clusterv1.Clu
345368
}
346369

347370
if cluster.Spec.InfrastructureRef != nil {
348-
obj, err := external.Get(ctx, r.Client, cluster.Spec.InfrastructureRef, cluster.Namespace)
349-
switch {
350-
case apierrors.IsNotFound(errors.Cause(err)):
371+
if s.infraClusterIsNotFound {
351372
// All good - the infra resource has been deleted
352373
conditions.MarkFalse(cluster, clusterv1.InfrastructureReadyCondition, clusterv1.DeletedReason, clusterv1.ConditionSeverityInfo, "")
353-
case err != nil:
354-
return ctrl.Result{}, errors.Wrapf(err, "failed to get %s %q for Cluster %s/%s",
355-
path.Join(cluster.Spec.InfrastructureRef.APIVersion, cluster.Spec.InfrastructureRef.Kind),
356-
cluster.Spec.InfrastructureRef.Name, cluster.Namespace, cluster.Name)
357-
default:
358-
// Report a summary of current status of the infrastructure object defined for this cluster.
359-
conditions.SetMirror(cluster, clusterv1.InfrastructureReadyCondition,
360-
conditions.UnstructuredGetter(obj),
361-
conditions.WithFallbackValue(false, clusterv1.DeletingReason, clusterv1.ConditionSeverityInfo, ""),
362-
)
374+
}
363375

376+
if s.infraCluster != nil {
364377
// Issue a deletion request for the infrastructure object.
365378
// Once it's been deleted, the cluster will get processed again.
366-
if err := r.Client.Delete(ctx, obj); err != nil {
379+
if err := r.Client.Delete(ctx, s.infraCluster); err != nil {
367380
return ctrl.Result{}, errors.Wrapf(err,
368381
"failed to delete %v %q for Cluster %q in namespace %q",
369-
obj.GroupVersionKind(), obj.GetName(), cluster.Name, cluster.Namespace)
382+
s.infraCluster.GroupVersionKind(), s.infraCluster.GetName(), cluster.Name, cluster.Namespace)
370383
}
371384

372385
// Return here so we don't remove the finalizer yet.
@@ -516,8 +529,9 @@ func (c clusterDescendants) filterOwnedDescendants(cluster *clusterv1.Cluster) (
516529
return ownedDescendants, nil
517530
}
518531

519-
func (r *Reconciler) reconcileControlPlaneInitialized(ctx context.Context, cluster *clusterv1.Cluster) (ctrl.Result, error) {
532+
func (r *Reconciler) reconcileControlPlaneInitialized(ctx context.Context, s *scope) (ctrl.Result, error) {
520533
log := ctrl.LoggerFrom(ctx)
534+
cluster := s.cluster
521535

522536
// Skip checking if the control plane is initialized when using a Control Plane Provider (this is reconciled in
523537
// reconcileControlPlane instead).

0 commit comments

Comments
 (0)