Skip to content

Commit

Permalink
Add support for pausing cluster reconcilation (#1769)
Browse files Browse the repository at this point in the history
  • Loading branch information
Karthik-K-N authored Nov 4, 2024
1 parent 9b07704 commit 2a3745e
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 10 deletions.
19 changes: 17 additions & 2 deletions controllers/ibmpowervscluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"

capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/util"
Expand Down Expand Up @@ -562,8 +564,21 @@ func (c clusterDescendants) filterOwnedDescendants(cluster *infrav1beta2.IBMPowe

// SetupWithManager creates a new IBMPowerVSCluster controller for a manager.
func (r *IBMPowerVSClusterReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
controller, err := ctrl.NewControllerManagedBy(mgr).
For(&infrav1beta2.IBMPowerVSCluster{}).
WithEventFilter(predicates.ResourceIsNotExternallyManaged(ctrl.LoggerFrom(ctx))).
Complete(r)
WithEventFilter(predicates.ResourceNotPaused(ctrl.LoggerFrom(ctx))).
Build(r)
if err != nil {
return errors.Wrap(err, "error creating controller")
}
// Add a watch on capiv1beta1.Cluster object for unpause notifications.
if err = controller.Watch(
source.Kind[client.Object](mgr.GetCache(), &capiv1beta1.Cluster{},
handler.EnqueueRequestsFromMapFunc(util.ClusterToInfrastructureMapFunc(ctx, infrav1beta2.GroupVersion.WithKind("IBMPowerVSCluster"), mgr.GetClient(), &infrav1beta2.IBMPowerVSCluster{})),
predicates.ClusterUnpaused(ctrl.LoggerFrom(ctx)),
)); err != nil {
return errors.Wrap(err, "failed adding a watch for ready clusters")
}
return nil
}
84 changes: 77 additions & 7 deletions controllers/ibmpowervsmachine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"time"

"github.com/go-logr/logr"
"github.com/pkg/errors"

"github.com/IBM-Cloud/power-go-client/power/models"

Expand All @@ -34,11 +35,14 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/source"

capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1"
capierrors "sigs.k8s.io/cluster-api/errors"
"sigs.k8s.io/cluster-api/util"
"sigs.k8s.io/cluster-api/util/conditions"
"sigs.k8s.io/cluster-api/util/predicates"

infrav1beta2 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2"
"sigs.k8s.io/cluster-api-provider-ibmcloud/cloud/scope"
Expand Down Expand Up @@ -156,13 +160,6 @@ func (r *IBMPowerVSMachineReconciler) Reconcile(ctx context.Context, req ctrl.Re
return r.reconcileNormal(machineScope)
}

// SetupWithManager creates a new IBMPowerVSMachine controller for a manager.
func (r *IBMPowerVSMachineReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&infrav1beta2.IBMPowerVSMachine{}).
Complete(r)
}

func (r *IBMPowerVSMachineReconciler) reconcileDelete(scope *scope.PowerVSMachineScope) (_ ctrl.Result, reterr error) {
scope.Info("Handling deleted IBMPowerVSMachine")

Expand Down Expand Up @@ -311,3 +308,76 @@ func (r *IBMPowerVSMachineReconciler) reconcileNormal(machineScope *scope.PowerV

return ctrl.Result{}, nil
}

// IBMPowerVSClusterToIBMPowerVSMachines is a handler.ToRequestsFunc to be used to enqeue requests for reconciliation
// of IBMPowerVSMachines.
func (r *IBMPowerVSMachineReconciler) IBMPowerVSClusterToIBMPowerVSMachines(ctx context.Context) handler.MapFunc {
log := ctrl.LoggerFrom(ctx)
return func(mapCtx context.Context, o client.Object) []ctrl.Request {
result := []ctrl.Request{}

c, ok := o.(*infrav1beta2.IBMPowerVSCluster)
if !ok {
log.Error(errors.Errorf("expected a IBMPowerVSCluster but got a %T", o), "failed to get IBMPowerVSMachines for IBMPowerVSCluster")
return nil
}

cluster, err := util.GetOwnerCluster(mapCtx, r.Client, c.ObjectMeta)
switch {
case apierrors.IsNotFound(err) || cluster == nil:
return result
case err != nil:
log.Error(err, "failed to get owning cluster")
return result
}

labels := map[string]string{capiv1beta1.ClusterNameLabel: cluster.Name}
machineList := &capiv1beta1.MachineList{}
if err := r.List(mapCtx, machineList, client.InNamespace(c.Namespace), client.MatchingLabels(labels)); err != nil {
log.Error(err, "failed to list Machines")
return nil
}
for _, m := range machineList.Items {
if m.Spec.InfrastructureRef.Name == "" {
continue
}
name := client.ObjectKey{Namespace: m.Namespace, Name: m.Spec.InfrastructureRef.Name}
result = append(result, ctrl.Request{NamespacedName: name})
}

return result
}
}

// SetupWithManager creates a new IBMVPCMachine controller for a manager.
func (r *IBMPowerVSMachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error {
controller, err := ctrl.NewControllerManagedBy(mgr).
For(&infrav1beta2.IBMPowerVSMachine{}).
WithEventFilter(predicates.ResourceNotPaused(ctrl.LoggerFrom(ctx))).
Watches(
&capiv1beta1.Machine{},
handler.EnqueueRequestsFromMapFunc(util.MachineToInfrastructureMapFunc(infrav1beta2.GroupVersion.WithKind("IBMPowerVSMachine"))),
).
Watches(
&infrav1beta2.IBMPowerVSCluster{},
handler.EnqueueRequestsFromMapFunc(r.IBMPowerVSClusterToIBMPowerVSMachines(ctx)),
).
Build(r)
if err != nil {
return errors.Wrap(err, "error creating controller")
}

clusterToObjectFunc, err := util.ClusterToTypedObjectsMapper(r.Client, &infrav1beta2.IBMPowerVSMachineList{}, mgr.GetScheme())
if err != nil {
return errors.Wrap(err, "failed to create mapper for Cluster to IBMPowerVSMachines")
}
// Add a watch on capiv1beta1.Cluster object for unpause & ready notifications.
if err := controller.Watch(
source.Kind[client.Object](mgr.GetCache(), &capiv1beta1.Cluster{},
handler.EnqueueRequestsFromMapFunc(clusterToObjectFunc),
predicates.ClusterUnpausedAndInfrastructureReady(ctrl.LoggerFrom(ctx)),
)); err != nil {
return errors.Wrap(err, "failed adding a watch for ready clusters")
}
return nil
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager, serviceEndpoint []e
Recorder: mgr.GetEventRecorderFor("ibmpowervsmachine-controller"),
ServiceEndpoint: serviceEndpoint,
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "IBMPowerVSMachine")
os.Exit(1)
}
Expand Down

0 comments on commit 2a3745e

Please sign in to comment.