-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement reconciliation for ManagedCluster and create ManagedC…
…lusterView - Added reconciliation logic for `ManagedCluster` - Added tests for `ManagedClusterReconciler` reconciliation logic and ensure ManagedClusterViews function. - Reconciliation for ManagedCluster creates ManagedClusterView which pulls the ‘odf-info’ configmap onto the hub. - Updated RBAC rules in `config/rbac/role.yaml` to include permissions for ManagedClusterView resources. (ManagedCluster RBAC already there) - Plumbing to make the controllers work like the items above - Updated go.mod and go.sum to include `github.com/stolostron/multicloud-operators-foundation`. - Fixes to functions, tests and adding new predicate Signed-off-by: vbadrina <[email protected]>
- Loading branch information
Showing
10 changed files
with
575 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
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" | ||
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/event" | ||
"sigs.k8s.io/controller-runtime/pkg/predicate" | ||
"sigs.k8s.io/controller-runtime/pkg/reconcile" | ||
) | ||
|
||
type ManagedClusterReconciler struct { | ||
Client client.Client | ||
Logger *slog.Logger | ||
} | ||
|
||
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") | ||
|
||
var managedCluster clusterv1.ManagedCluster | ||
if err := r.Client.Get(ctx, req.NamespacedName, &managedCluster); err != nil { | ||
if client.IgnoreNotFound(err) != nil { | ||
logger.Error("Failed to get ManagedCluster", "error", err) | ||
} | ||
return ctrl.Result{}, client.IgnoreNotFound(err) | ||
} | ||
|
||
if err := r.processManagedClusterViews(ctx, managedCluster); err != nil { | ||
logger.Error("Failed to ensure ManagedClusterView", "error", err) | ||
return ctrl.Result{}, err | ||
} | ||
|
||
logger.Info("Successfully reconciled ManagedCluster", "name", managedCluster.Name) | ||
|
||
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(managedClusterPredicate, predicate.ResourceVersionChangedPredicate{})). | ||
Owns(&viewv1beta1.ManagedClusterView{}). | ||
Complete(r) | ||
} | ||
|
||
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) | ||
} | ||
|
||
enabled := true | ||
disabled := false | ||
mcvOwnerRef := &metav1.OwnerReference{ | ||
APIVersion: managedCluster.APIVersion, | ||
Kind: managedCluster.Kind, | ||
UID: managedCluster.UID, | ||
Name: managedCluster.Name, | ||
Controller: &enabled, | ||
BlockOwnerDeletion: &disabled, | ||
} | ||
|
||
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) | ||
|
||
} | ||
r.Logger.Info(fmt.Sprintf("ManagedClusterView was %s", operationResult), "ManagedClusterView", mcv.Name) | ||
|
||
return nil | ||
} | ||
|
||
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) | ||
} | ||
return types.NamespacedName{Namespace: namespacedName[0], Name: namespacedName[1]}, nil | ||
} | ||
} | ||
|
||
return types.NamespacedName{}, fmt.Errorf("cannot find ClusterClaim %q in ManagedCluster status", OdfInfoClusterClaimNamespacedName) | ||
} |
Oops, something went wrong.