Skip to content

Commit

Permalink
Fixes to functions, tests and adding new predicate
Browse files Browse the repository at this point in the history
- Added a predicate function `managedClusterViewStatusChangePredicate` to filter updates based on status changes of ManagedClusterView.
- Refactored utility functions in `utils/acm.go` for consistency and added `GetManagedClusterViewName` function to generate ManagedClusterView names.
- Updated unit tests for `ManagedClusterReconciler` and utility functions to reflect the new logic and structure.
- Updated RBAC permissions to include specific verbs (create, get, list, update, watch) for ManagedClusterView resources in both `config/rbac/role.yaml` and `bundle/manifests/odf-multicluster-orchestrator.clusterserviceversion.yaml`.

Signed-off-by: vbadrina <[email protected]>
  • Loading branch information
vbnrh committed Jul 12, 2024
1 parent c4b27a4 commit 0a9f688
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ metadata:
]
capabilities: Basic Install
console.openshift.io/plugins: '["odf-multicluster-console"]'
createdAt: "2024-07-04T11:28:14Z"
createdAt: "2024-07-09T07:46:31Z"
olm.skipRange: ""
operators.openshift.io/infrastructure-features: '["disconnected"]'
operators.operatorframework.io/builder: operator-sdk-v1.34.1
Expand Down Expand Up @@ -229,7 +229,11 @@ spec:
resources:
- managedclusterviews
verbs:
- '*'
- create
- get
- list
- update
- watch
- apiGroups:
- work.open-cluster-management.io
resources:
Expand Down
6 changes: 5 additions & 1 deletion config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ rules:
resources:
- managedclusterviews
verbs:
- '*'
- create
- get
- list
- update
- watch
- apiGroups:
- work.open-cluster-management.io
resources:
Expand Down
97 changes: 60 additions & 37 deletions controllers/managedcluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,35 @@ package controllers

import (
"context"
"errors"
"fmt"
"log/slog"
"reflect"
"strings"

"github.com/red-hat-storage/odf-multicluster-orchestrator/controllers/utils"
viewv1beta1 "github.com/stolostron/multicloud-operators-foundation/pkg/apis/view/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
clusterv1 "open-cluster-management.io/api/cluster/v1"
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"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

type ManagedClusterReconciler struct {
Client client.Client
Scheme *runtime.Scheme
Logger *slog.Logger
}

const odfConfigMapName = "odf-info"
const (
ClusterClaimGroup = "odf"
)

var OdfInfoNamespacedNameClaimName = fmt.Sprintf("odfinfo.%s.openshift.io", ClusterClaimGroup)

func (r *ManagedClusterReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
logger := r.Logger.With("ManagedCluster", req.NamespacedName)
Expand All @@ -37,7 +44,7 @@ func (r *ManagedClusterReconciler) Reconcile(ctx context.Context, req reconcile.
return ctrl.Result{}, client.IgnoreNotFound(err)
}

if err := r.ensureManagedClusterViews(ctx, managedCluster.Name); err != nil {
if err := r.processManagedClusterViews(ctx, managedCluster); err != nil {
logger.Error("Failed to ensure ManagedClusterView", "error", err)
return ctrl.Result{}, err
}
Expand All @@ -55,7 +62,7 @@ func (r *ManagedClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
Watches(
&viewv1beta1.ManagedClusterView{},
handler.EnqueueRequestsFromMapFunc(r.managedClusterViewRequestMapper),
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}, predicate.GenerationChangedPredicate{}),
builder.WithPredicates(managedClusterViewStatusChangePredicate, predicate.GenerationChangedPredicate{}),
).
Complete(r)
}
Expand All @@ -64,17 +71,17 @@ func (r *ManagedClusterReconciler) managedClusterViewRequestMapper(ctx context.C
mcv, ok := obj.(*viewv1beta1.ManagedClusterView)

if !ok {
r.Logger.Error("Something unexpected occurred when casting obj into ManagedClusterView")
r.Logger.Error("Received object is not a ManagedClusterView object")
return []reconcile.Request{}
}
logger := r.Logger.With("ManagedClusterView", mcv)
logger := r.Logger.With("ManagedClusterView", mcv.Name)
mcName, ok := mcv.Labels[utils.MCVLabelKey]

if !ok {
return []reconcile.Request{}
}

logger.Info("ManagedClusterView of interest just got updated. Raising a reconcile request for ManagedCluster", "ManagedCluster", mcName)
logger.Debug("ManagedClusterView of interest just got updated. Raising a reconcile request for ManagedCluster", "ManagedCluster", mcName)

return []reconcile.Request{
{
Expand All @@ -85,39 +92,55 @@ func (r *ManagedClusterReconciler) managedClusterViewRequestMapper(ctx context.C
}

}
func (r *ManagedClusterReconciler) ensureManagedClusterViews(ctx context.Context, clusterName string) error {
namespace := "openshift-storage"
func (r *ManagedClusterReconciler) processManagedClusterViews(ctx context.Context, managedCluster clusterv1.ManagedCluster) error {
resourceType := "ConfigMap"
r.Logger.Info("Processing PeerRef", "ClusterName", clusterName)
mcv, err := utils.GetManagedClusterViewByLabel(r.Client, utils.MCVLabelKey, clusterName, clusterName)
odfInfoConfigMapNamespacedName, err := getNamespacedNameForClusterInfo(managedCluster)
if err != nil {
r.Logger.Info("ManagedClusterView does not exist, creating a new one")
mcv, err = utils.CreateOrUpdateManagedClusterView(ctx, r.Client, odfConfigMapName, namespace, resourceType, clusterName)
if err != nil {
r.Logger.Error("Failed to create or update ManagedClusterView", "error", err)
return err
}
r.Logger.Info("ManagedClusterView created or updated successfully", "ManagedClusterView", mcv.Name)
} else {
desiredSpec := viewv1beta1.ViewSpec{
Scope: viewv1beta1.ViewScope{
Name: odfConfigMapName,
Namespace: namespace,
Resource: resourceType,
},
}
if mcv.Spec != desiredSpec {
r.Logger.Info("ManagedClusterView spec does not match, updating", "ClusterName", clusterName)
mcv, err = utils.CreateOrUpdateManagedClusterView(ctx, r.Client, odfConfigMapName, namespace, resourceType, clusterName)
if err != nil {
r.Logger.Error("Failed to update ManagedClusterView", "error", err)
return err
r.Logger.Error("Error while getting the namespaced name of the configmap")
return err
}
mcv, or, err := utils.CreateOrUpdateManagedClusterView(ctx, r.Client, odfInfoConfigMapNamespacedName.Name, odfInfoConfigMapNamespacedName.Namespace, resourceType, managedCluster.Name)
if err != nil {
r.Logger.Error("Failed to create or update ManagedClusterView", "error", err)
return err
}
r.Logger.Info(fmt.Sprintf("ManagedClusterView was %s", or), "ManagedClusterView", mcv.Name)

return nil
}

func getNamespacedNameForClusterInfo(managedCluster clusterv1.ManagedCluster) (types.NamespacedName, error) {
clusterClaims := managedCluster.Status.ClusterClaims
for _, claim := range clusterClaims {
if claim.Name == OdfInfoNamespacedNameClaimName {
namespacedName := strings.Split(claim.Value, "/")
if len(namespacedName) != 2 {
return types.NamespacedName{}, fmt.Errorf("invalid format for namespaced name claim: expected 'namespace/name', got '%s'", claim.Value)
}
r.Logger.Info("ManagedClusterView updated successfully", "ManagedClusterView", mcv.Name)
} else {
r.Logger.Info("ManagedClusterView spec matches, no update needed", "ManagedClusterView", mcv.Name)
return types.NamespacedName{Namespace: namespacedName[0], Name: namespacedName[1]}, nil
}
}

return nil
return types.NamespacedName{}, errors.New("cannot find namespaced name claim in cluster status")
}

var managedClusterViewStatusChangePredicate = predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
oldObj, okOld := e.ObjectOld.(*viewv1beta1.ManagedClusterView)
newObj, okNew := e.ObjectNew.(*viewv1beta1.ManagedClusterView)
if !okOld || !okNew {
return false
}

return !reflect.DeepEqual(oldObj.Status, newObj.Status)
},
CreateFunc: func(e event.CreateEvent) bool {
return true
},
DeleteFunc: func(e event.DeleteEvent) bool {
return true
},
GenericFunc: func(e event.GenericEvent) bool {
return true
},
}
Loading

0 comments on commit 0a9f688

Please sign in to comment.