Skip to content

Commit

Permalink
Use enqueueRequestsFromMapFunc to reconcile multiple RolloutMangers
Browse files Browse the repository at this point in the history
Signed-off-by: Jonathan West <[email protected]>
  • Loading branch information
jgwest committed Jun 14, 2024
1 parent 37da9c4 commit 04fbb60
Showing 1 changed file with 135 additions and 32 deletions.
167 changes: 135 additions & 32 deletions controllers/argorollouts_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ import (
"k8s.io/client-go/discovery"
"k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
logr "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

Expand Down Expand Up @@ -111,52 +115,106 @@ func (r *RolloutManagerReconciler) Reconcile(ctx context.Context, req ctrl.Reque
}
}

// Fetch all RolloutManager instances in the namespace
rolloutsmanagerList := rolloutsmanagerv1alpha1.RolloutManagerList{}
if err := r.List(ctx, &rolloutsmanagerList, &client.ListOptions{Namespace: req.Namespace}); err != nil {
reqLogger.Error(err, "Failed to list RolloutManager instances")
return ctrl.Result{}, err
}

// Iterate through the list and reconcile each RolloutManager instance
for idx := range rolloutsmanagerList.Items {
rolloutManager := rolloutsmanagerList.Items[idx]
// Fetch the RolloutManager instance
if err := r.Client.Get(ctx, client.ObjectKeyFromObject(&rolloutManager), &rolloutManager); err != nil {
if apierrors.IsNotFound(err) {
// Request object not found, could have been deleted after reconcile request.
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
// Return and don't requeue
return reconcile.Result{}, nil
}
// Error reading the object - requeue the request.
return reconcile.Result{}, err
// Next, fetch and reconcile the RolloutManager instance
rolloutManager := &rolloutsmanagerv1alpha1.RolloutManager{}
if err := r.Client.Get(ctx, req.NamespacedName, rolloutManager); err != nil {
if apierrors.IsNotFound(err) {
// Request object not found, could have been deleted after reconcile request.
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
// Return and don't requeue
return reconcile.Result{}, nil
}
// Error reading the object - requeue the request.
return reconcile.Result{}, err
}

// Reconcile the RolloutManager instance
res, reconcileErr := r.reconcileRolloutsManager(ctx, rolloutManager)
res, reconcileErr := r.reconcileRolloutsManager(ctx, *rolloutManager)

// Set the condition/phase on the RolloutManager status
if err := updateStatusConditionOfRolloutManager(ctx, res, &rolloutManager, r.Client, log); err != nil {
log.Error(err, "Unable to update status of RolloutManager")
return reconcile.Result{}, err
}
// Set the condition/phase on the RolloutManager status (before we check the error from reconcileRolloutManager, below)
if err := updateStatusConditionOfRolloutManager(ctx, res, rolloutManager, r.Client, log); err != nil {
log.Error(err, "unable to update status of RolloutManager")
return reconcile.Result{}, err
}

// Check the reconcileErr and handle it
if reconcileErr != nil {
return reconcile.Result{}, reconcileErr
}
// Next return the reconcileErr if applicable
if reconcileErr != nil {
return reconcile.Result{}, reconcileErr
}

return reconcile.Result{}, nil
}

// func (r *RolloutManagerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// reqLogger := logr.FromContext(ctx, "Request.Namespace", req.Namespace, "Request.Name", req.Name)
// reqLogger.Info("Reconciling RolloutManager")

// // First retrieve the Namespace of the request: if it's being deleted, no more work for us.
// rolloutManagerNamespace := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: req.Namespace}}
// if err := r.Client.Get(ctx, client.ObjectKeyFromObject(&rolloutManagerNamespace), &rolloutManagerNamespace); err != nil {
// if apierrors.IsNotFound(err) { // If Namespace doesn't exist, our work is done
// reqLogger.Info("Skipping reconciliation of RolloutManager as request Namespace no longer exists")
// return ctrl.Result{}, nil
// }
// return ctrl.Result{}, err // Any other error, return it
// } else {
// // If the Namespace is in the process of being deleted, no more work required for us.
// if rolloutManagerNamespace.DeletionTimestamp != nil {
// return ctrl.Result{}, nil
// }
// }

// // Fetch all RolloutManager instances in the namespace
// rolloutsmanagerList := rolloutsmanagerv1alpha1.RolloutManagerList{}
// if err := r.List(ctx, &rolloutsmanagerList, &client.ListOptions{Namespace: req.Namespace}); err != nil {
// reqLogger.Error(err, "Failed to list RolloutManager instances")
// return ctrl.Result{}, err
// }

// // Iterate through the list and reconcile each RolloutManager instance
// for idx := range rolloutsmanagerList.Items {
// rolloutManager := rolloutsmanagerList.Items[idx]
// // Fetch the RolloutManager instance
// if err := r.Client.Get(ctx, client.ObjectKeyFromObject(&rolloutManager), &rolloutManager); err != nil {
// if apierrors.IsNotFound(err) {
// // Request object not found, could have been deleted after reconcile request.
// // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
// // Return and don't requeue
// return reconcile.Result{}, nil
// }
// // Error reading the object - requeue the request.
// return reconcile.Result{}, err
// }

// // Reconcile the RolloutManager instance
// res, reconcileErr := r.reconcileRolloutsManager(ctx, rolloutManager)

// // Set the condition/phase on the RolloutManager status
// if err := updateStatusConditionOfRolloutManager(ctx, res, &rolloutManager, r.Client, log); err != nil {
// log.Error(err, "Unable to update status of RolloutManager")
// return reconcile.Result{}, err
// }

// // Check the reconcileErr and handle it
// if reconcileErr != nil {
// return reconcile.Result{}, reconcileErr
// }
// }

// return reconcile.Result{}, nil
// }

// SetupWithManager sets up the controller with the Manager.
func (r *RolloutManagerReconciler) SetupWithManager(mgr ctrl.Manager) error {
bld := ctrl.NewControllerManagedBy(mgr)
// Watch for changes to primary resource RolloutManager.

bld.For(&rolloutsmanagerv1alpha1.RolloutManager{})

// If the .spec of any RolloutManager changes (or a RM is created/deleted), inform the other RolloutManagers on the cluster
bld.Watches(
&rolloutsmanagerv1alpha1.RolloutManager{},
handler.EnqueueRequestsFromMapFunc(r.queueOtherRolloutManagers),
builder.WithPredicates(predicate.Or(predicate.GenerationChangedPredicate{}, createdOrDeletedPredicate())))

// Watch for changes to ConfigMap sub-resources owned by RolloutManager.
bld.Owns(&corev1.ConfigMap{})

Expand Down Expand Up @@ -191,6 +249,51 @@ func (r *RolloutManagerReconciler) SetupWithManager(mgr ctrl.Manager) error {
return bld.Complete(r)
}

// createdOrDeletedPredicate returns a predicate which filters out
// only SpaceRequests whose Ready Status are set to true
func createdOrDeletedPredicate() predicate.Predicate {
return predicate.Funcs{
CreateFunc: func(createEvent event.CreateEvent) bool {
return true
},
DeleteFunc: func(deleteEvent event.DeleteEvent) bool {
return true
},
GenericFunc: func(genericEvent event.GenericEvent) bool {
return false
},
UpdateFunc: func(e event.UpdateEvent) bool {
return false
},
}
}

func (r *RolloutManagerReconciler) queueOtherRolloutManagers(context context.Context, obj client.Object) []reconcile.Request {

// List all other RolloutMangers on the cluster
rmList := rolloutsmanagerv1alpha1.RolloutManagerList{}
if err := r.List(context, &rmList); err != nil {
return []reconcile.Request{}
}

requests := []reconcile.Request{}

for idx := range rmList.Items {
rm := rmList.Items[idx]

if rm.Name == obj.GetName() && rm.Namespace == obj.GetNamespace() {
// Don't queue the object itself, we are already handling that elsewhere
continue
}

requests = append(requests, reconcile.Request{
NamespacedName: client.ObjectKeyFromObject(&rm),
})
}

return requests
}

// doesCRDExist checks if a CRD is present in the cluster, by using the discovery client.
//
// NOTE: this function should only be called from SetupWithManager. There are more efficient methods to determine this, elsewhere.
Expand Down

0 comments on commit 04fbb60

Please sign in to comment.