Skip to content

Commit

Permalink
Fixes to functions, tests and adding new predicate
Browse files Browse the repository at this point in the history
Signed-off-by: vbadrina <[email protected]>
  • Loading branch information
vbnrh committed Jul 12, 2024
1 parent c4b27a4 commit 1d772d8
Show file tree
Hide file tree
Showing 10 changed files with 371 additions and 210 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-12T13:14:27Z"
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
132 changes: 73 additions & 59 deletions controllers/managedcluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,33 @@ package controllers

import (
"context"
"fmt"
"log/slog"
"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"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"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/handler"
"sigs.k8s.io/controller-runtime/pkg/event"
"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 (
OdfInfoClusterClaimNamespacedName = "odfinfo.odf.openshift.io"
)

// +kubebuilder:rbac:groups=view.open-cluster-management.io,resources=managedclusterviews,verbs=get;list;watch;create;update
func (r *ManagedClusterReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
logger := r.Logger.With("ManagedCluster", req.NamespacedName)
logger.Info("Reconciling ManagedCluster")
Expand All @@ -37,7 +41,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 @@ -47,77 +51,87 @@ func (r *ManagedClusterReconciler) Reconcile(ctx context.Context, req reconcile.
return ctrl.Result{}, nil
}

func hasRequiredODFKey(mc *clusterv1.ManagedCluster) bool {
claims := mc.Status.ClusterClaims
for _, claim := range claims {
if claim.Name == OdfInfoClusterClaimNamespacedName {
return true
}
}
return false

}
func (r *ManagedClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
r.Logger.Info("Setting up ManagedClusterReconciler with manager")
managedClusterPredicate := predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
obj, ok := e.ObjectNew.(*clusterv1.ManagedCluster)
if !ok {
return false
}
return hasRequiredODFKey(obj)
},
CreateFunc: func(e event.CreateEvent) bool {
obj, ok := e.Object.(*clusterv1.ManagedCluster)
if !ok {
return false
}
return hasRequiredODFKey(obj)
},

DeleteFunc: func(e event.DeleteEvent) bool {
return false
},
GenericFunc: func(e event.GenericEvent) bool {
return false
},
}

return ctrl.NewControllerManagedBy(mgr).
For(&clusterv1.ManagedCluster{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Watches(
&viewv1beta1.ManagedClusterView{},
handler.EnqueueRequestsFromMapFunc(r.managedClusterViewRequestMapper),
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}, predicate.GenerationChangedPredicate{}),
).
For(&clusterv1.ManagedCluster{}, builder.WithPredicates(managedClusterPredicate, predicate.GenerationChangedPredicate{})).
Owns(&viewv1beta1.ManagedClusterView{}).
Complete(r)
}

func (r *ManagedClusterReconciler) managedClusterViewRequestMapper(ctx context.Context, obj client.Object) []reconcile.Request {
mcv, ok := obj.(*viewv1beta1.ManagedClusterView)

if !ok {
r.Logger.Error("Something unexpected occurred when casting obj into ManagedClusterView")
return []reconcile.Request{}
func (r *ManagedClusterReconciler) processManagedClusterViews(ctx context.Context, managedCluster clusterv1.ManagedCluster) error {
resourceType := "ConfigMap"
odfInfoConfigMapNamespacedName, err := getNamespacedNameForClusterInfo(managedCluster)
if err != nil {
return fmt.Errorf("error while getting NamespacedName of the %s. %w", resourceType, err)
}
logger := r.Logger.With("ManagedClusterView", mcv)
mcName, ok := mcv.Labels[utils.MCVLabelKey]

if !ok {
return []reconcile.Request{}
enabled := true
disabled := false
mcvOwnerRef := &metav1.OwnerReference{
APIVersion: managedCluster.APIVersion,
Kind: managedCluster.Kind,
UID: managedCluster.UID,
Name: managedCluster.Name,
Controller: &enabled,
BlockOwnerDeletion: &disabled,
}

logger.Info("ManagedClusterView of interest just got updated. Raising a reconcile request for ManagedCluster", "ManagedCluster", mcName)
mcv, operationResult, err := utils.CreateOrUpdateManagedClusterView(ctx, r.Client, odfInfoConfigMapNamespacedName.Name, odfInfoConfigMapNamespacedName.Namespace, resourceType, managedCluster.Name, mcvOwnerRef)
if err != nil {
return fmt.Errorf("failed to create or update ManagedClusterView. %w", err)

return []reconcile.Request{
{
NamespacedName: types.NamespacedName{
Name: mcName,
},
},
}
r.Logger.Info(fmt.Sprintf("ManagedClusterView was %s", operationResult), "ManagedClusterView", mcv.Name)

return nil
}
func (r *ManagedClusterReconciler) ensureManagedClusterViews(ctx context.Context, clusterName string) error {
namespace := "openshift-storage"
resourceType := "ConfigMap"
r.Logger.Info("Processing PeerRef", "ClusterName", clusterName)
mcv, err := utils.GetManagedClusterViewByLabel(r.Client, utils.MCVLabelKey, clusterName, clusterName)
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

func getNamespacedNameForClusterInfo(managedCluster clusterv1.ManagedCluster) (types.NamespacedName, error) {
clusterClaims := managedCluster.Status.ClusterClaims
for _, claim := range clusterClaims {
if claim.Name == OdfInfoClusterClaimNamespacedName {
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{}, fmt.Errorf("cannot find %q in ManagedCluster status", OdfInfoClusterClaimNamespacedName)
}
Loading

0 comments on commit 1d772d8

Please sign in to comment.