From 51d7ea1b8c76c10acc2bbcec19dc0abd29b4c953 Mon Sep 17 00:00:00 2001 From: Karthik K N Date: Thu, 9 May 2024 16:47:46 +0530 Subject: [PATCH] Add support for pausing cluster reconcilation --- controllers/ibmpowervscluster_controller.go | 19 ++++- controllers/ibmvpcmachine_controller.go | 84 +++++++++++++++++++-- main.go | 2 +- 3 files changed, 95 insertions(+), 10 deletions(-) diff --git a/controllers/ibmpowervscluster_controller.go b/controllers/ibmpowervscluster_controller.go index a3e785f48..6bba56b99 100644 --- a/controllers/ibmpowervscluster_controller.go +++ b/controllers/ibmpowervscluster_controller.go @@ -34,7 +34,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" @@ -455,8 +457,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(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 } diff --git a/controllers/ibmvpcmachine_controller.go b/controllers/ibmvpcmachine_controller.go index 1a4535426..130faa6e2 100644 --- a/controllers/ibmvpcmachine_controller.go +++ b/controllers/ibmvpcmachine_controller.go @@ -22,6 +22,7 @@ import ( "time" "github.com/go-logr/logr" + "github.com/pkg/errors" "github.com/IBM/vpc-go-sdk/vpcv1" @@ -33,9 +34,12 @@ 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" "sigs.k8s.io/cluster-api/util" + "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" @@ -132,13 +136,6 @@ func (r *IBMVPCMachineReconciler) Reconcile(ctx context.Context, req ctrl.Reques return r.reconcileNormal(machineScope) } -// SetupWithManager creates a new IBMVPCMachine controller for a manager. -func (r *IBMVPCMachineReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&infrav1beta2.IBMVPCMachine{}). - Complete(r) -} - func (r *IBMVPCMachineReconciler) reconcileNormal(machineScope *scope.MachineScope) (ctrl.Result, error) { if controllerutil.AddFinalizer(machineScope.IBMVPCMachine, infrav1beta2.MachineFinalizer) { return ctrl.Result{}, nil @@ -221,3 +218,76 @@ func (r *IBMVPCMachineReconciler) reconcileDelete(scope *scope.MachineScope) (_ return ctrl.Result{}, nil } + +// IBMPowerVSClusterToIBMPowerVSMachines is a handler.ToRequestsFunc to be used to enqeue requests for reconciliation +// of IBMPowerVSMachines. +func (r *IBMVPCMachineReconciler) 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 *IBMVPCMachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error { + controller, err := ctrl.NewControllerManagedBy(mgr). + For(&infrav1beta2.IBMVPCMachine{}). + 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 GCPMachines") + } + // Add a watch on capiv1beta1.Cluster object for unpause & ready notifications. + if err := controller.Watch( + source.Kind(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 +} diff --git a/main.go b/main.go index 945cfc93d..c0d618bf1 100644 --- a/main.go +++ b/main.go @@ -251,7 +251,7 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager, serviceEndpoint []e Recorder: mgr.GetEventRecorderFor("ibmvpcmachine-controller"), ServiceEndpoint: serviceEndpoint, Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { + }).SetupWithManager(ctx, mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "IBMVPCMachine") os.Exit(1) }