Repository: red-hat-storage/odf-multicluster-orchestrator
Pull request #289: Create a template for VRC creation on provider cluster
Author: login: umangachapagain
Labels: name: approved
name: lgtm
Created: 2025-03-19T11:31:09Z | Merged: 2025-03-21T04:19:29Z

This PR implements a feature to create an OpenShift Template object which contains a VRC object.
We do not directly create the VRC object. There will be a follow-up PR which will enable the distribution of VRC from provider to clients.


Diff:
diff --git a/controllers/drpolicy_controller.go b/controllers/drpolicy_controller.go
index 0d7fd66d..cc7a23c2 100644
--- a/controllers/drpolicy_controller.go
+++ b/controllers/drpolicy_controller.go
@@ -2,38 +2,42 @@ package controllers
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 	"log/slog"
 	"time"
 
+	replicationv1alpha1 "github.com/csi-addons/kubernetes-csi-addons/apis/replication.storage/v1alpha1"
+	templatev1 "github.com/openshift/api/template/v1"
 	ramenv1alpha1 "github.com/ramendr/ramen/api/v1alpha1"
 	multiclusterv1alpha1 "github.com/red-hat-storage/odf-multicluster-orchestrator/api/v1alpha1"
 	"github.com/red-hat-storage/odf-multicluster-orchestrator/controllers/utils"
+	corev1 "k8s.io/api/core/v1"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/types"
+	workv1 "open-cluster-management.io/api/work/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/controller/controllerutil"
+	"sigs.k8s.io/controller-runtime/pkg/handler"
 	"sigs.k8s.io/controller-runtime/pkg/predicate"
+	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 )
 
 const (
 	DefaultMirroringMode                         = "snapshot"
 	MirroringModeKey                             = "mirroringMode"
 	SchedulingIntervalKey                        = "schedulingInterval"
-	ReplicationSecretNameKey                     = "replication.storage.openshift.io/replication-secret-name"
-	ReplicationSecretNamespaceKey                = "replication.storage.openshift.io/replication-secret-namespace"
-	ReplicationIDKey                             = "replicationid"
 	RBDVolumeReplicationClassNameTemplate        = "rbd-volumereplicationclass-%v"
-	RBDReplicationSecretName                     = "rook-csi-rbd-provisioner"
-	RamenLabelTemplate                           = "ramendr.openshift.io/%s"
-	RBDProvisionerTemplate                       = "%s.rbd.csi.ceph.com"
+	RBDProvisionerName                           = "openshift-storage.rbd.csi.ceph.com"
 	RBDFlattenVolumeReplicationClassNameTemplate = "rbd-flatten-volumereplicationclass-%v"
 	RBDFlattenVolumeReplicationClassLabelKey     = "replication.storage.openshift.io/flatten-mode"
 	RBDFlattenVolumeReplicationClassLabelValue   = "force"
 	RBDVolumeReplicationClassDefaultAnnotation   = "replication.storage.openshift.io/is-default-class"
-	StorageIDKey                                 = "storageid"
 )
 
 type DRPolicyReconciler struct {
@@ -49,8 +53,37 @@ type DRPolicyReconciler struct {
 func (r *DRPolicyReconciler) SetupWithManager(mgr ctrl.Manager) error {
 	r.Logger.Info("Setting up DRPolicyReconciler with manager")
 
+	cmToDRPolicyMapFunc := func(ctx context.Context, object client.Object) []ctrl.Request {
+		r.Logger.Debug("Mapping ConfigMap to DRPolicy", "ConfigMap", client.ObjectKeyFromObject(object))
+		var reqs []ctrl.Request
+		_, ok := object.(*corev1.ConfigMap)
+		if !ok {
+			r.Logger.Debug("Unable to cast object into a ConfigMap. Not requeing any requests.")
+			return reqs
+		}
+		var drpolicyList ramenv1alpha1.DRPolicyList
+		err := r.HubClient.List(ctx, &drpolicyList)
+		if err != nil {
+			r.Logger.Debug("Unable to fetch list of all DRPolicies. Not requeing any requests.")
+			return reqs
+		}
+		for _, mp := range drpolicyList.Items {
+			reqs = append(reqs, reconcile.Request{NamespacedName: types.NamespacedName{Name: mp.Name}})
+		}
+		r.Logger.Info("DRPolicy reconcile requests generated based on ConfigMap change.", "RequestCount", len(reqs), "Requests", reqs)
+		return reqs
+	}
+
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&ramenv1alpha1.DRPolicy{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
+		Watches(&corev1.ConfigMap{}, handler.EnqueueRequestsFromMapFunc(cmToDRPolicyMapFunc),
+			builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
+				cm, ok := object.(*corev1.ConfigMap)
+				if !ok || cm.Name != utils.ClientInfoConfigMapName || cm.Namespace != r.CurrentNamespace {
+					return false
+				}
+				return true
+			}))).
 		Complete(r)
 }
 
@@ -108,18 +141,142 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, err
 	}
 
-	// Check if the MirrorPeer contains StorageClient reference
-	hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.HubClient, *mirrorPeer, false)
-	if err != nil {
-		logger.Error("Failed to determine if MirrorPeer contains StorageClient reference", "error", err)
-		return ctrl.Result{}, err
+	if mirrorPeer.Spec.Type != multiclusterv1alpha1.Async {
+		return ctrl.Result{}, nil
 	}
 
-	if hasStorageClientRef {
-		logger.Info("MirrorPeer contains StorageClient reference. Skipping creation of VolumeReplicationClasses", "MirrorPeer", mirrorPeer.Name)
-		return ctrl.Result{}, nil
+	err = r.createOrUpdateManifestWorkForVRC(ctx, mirrorPeer, &drpolicy)
+	if err != nil {
+		return ctrl.Result{}, fmt.Errorf("failed to create VolumeReplicationClass via ManifestWork: %v", err)
 	}
 
 	logger.Info("Successfully reconciled DRPolicy")
 	return ctrl.Result{}, nil
 }
+
+func (r *DRPolicyReconciler) createOrUpdateManifestWorkForVRC(ctx context.Context, mp *multiclusterv1alpha1.MirrorPeer, dp *ramenv1alpha1.DRPolicy) error {
+	logger := r.Logger.With("DRPolicy", dp.Name, "MirrorPeer", mp.Name)
+
+	var vrcList []replicationv1alpha1.VolumeReplicationClass
+
+	vrc := replicationv1alpha1.VolumeReplicationClass{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "VolumeReplicationClass",
+			APIVersion: "replication.storage.openshift.io/v1alpha1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name: fmt.Sprintf(RBDVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval)),
+			Annotations: map[string]string{
+				RBDVolumeReplicationClassDefaultAnnotation: "true",
+			},
+		},
+		Spec: replicationv1alpha1.VolumeReplicationClassSpec{
+			Parameters: map[string]string{
+				MirroringModeKey:      DefaultMirroringMode,
+				SchedulingIntervalKey: dp.Spec.SchedulingInterval,
+			},
+			Provisioner: RBDProvisionerName,
+		},
+	}
+	vrcList = append(vrcList, vrc)
+
+	if dp.Spec.ReplicationClassSelector.MatchLabels[RBDFlattenVolumeReplicationClassLabelKey] == RBDFlattenVolumeReplicationClassLabelValue {
+		vrcFlatten := *vrc.DeepCopy()
+		vrcFlatten.Name = fmt.Sprintf(RBDFlattenVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval))
+		vrcFlatten.Labels = map[string]string{
+			RBDFlattenVolumeReplicationClassLabelKey: RBDFlattenVolumeReplicationClassLabelValue,
+		}
+		vrcFlatten.Annotations = map[string]string{}
+		vrcFlatten.Spec.Parameters["flattenMode"] = "force"
+		vrcList = append(vrcList, vrcFlatten)
+	}
+
+	cm, err := utils.FetchClientInfoConfigMap(ctx, r.HubClient, r.CurrentNamespace)
+	if err != nil {
+		return err
+	}
+
+	manifestWorkName := fmt.Sprintf("vrc-%v", utils.FnvHash(dp.Name))
+	for _, pr := range mp.Spec.Items {
+		cInfo, err := utils.GetClientInfoFromConfigMap(cm.Data, utils.GetKey(pr.ClusterName, pr.StorageClusterRef.Name))
+		if err != nil {
+			return err
+		}
+
+		var manifestList []workv1.Manifest
+		for _, vrc := range vrcList {
+			vrcTemplateJson, err := getTemplateForVRC(vrc, cInfo.ProviderInfo.NamespacedName.Namespace)
+			if err != nil {
+				return fmt.Errorf("failed to get template for VRC %q, error %w", vrc.Name, err)
+			}
+			manifestList = append(manifestList, workv1.Manifest{
+				RawExtension: runtime.RawExtension{
+					Raw: vrcTemplateJson,
+				},
+			})
+		}
+
+		mw := workv1.ManifestWork{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      manifestWorkName,
+				Namespace: cInfo.ProviderInfo.ProviderManagedClusterName,
+				OwnerReferences: []metav1.OwnerReference{
+					{
+						Kind:       dp.Kind,
+						Name:       dp.Name,
+						UID:        dp.UID,
+						APIVersion: dp.APIVersion,
+					},
+				},
+			},
+		}
+
+		_, err = controllerutil.CreateOrUpdate(ctx, r.HubClient, &mw, func() error {
+			mw.Spec = workv1.ManifestWorkSpec{
+				Workload: workv1.ManifestsTemplate{
+					Manifests: manifestList,
+				},
+			}
+			return nil
+		})
+
+		if err != nil {
+			logger.Error("Failed to create/update ManifestWork", "ManifestWorkName", manifestWorkName, "error", err)
+			return err
+		}
+
+		logger.Info("ManifestWork created/updated successfully", "ManifestWorkName", manifestWorkName, "VolumeReplicationClassName", vrc.Name)
+	}
+
+	return nil
+}
+
+func getTemplateForVRC(vrc replicationv1alpha1.VolumeReplicationClass, templateNamespace string) ([]byte, error) {
+	vrcJson, err := json.Marshal(vrc)
+	if err != nil {
+		return []byte{}, fmt.Errorf("failed to marshal %v to JSON, error %w", vrc, err)
+	}
+
+	vrcTemplate := templatev1.Template{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "Template",
+			APIVersion: "template.openshift.io/v1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      vrc.Name,
+			Namespace: templateNamespace,
+		},
+		Objects: []runtime.RawExtension{
+			{
+				Raw: vrcJson,
+			},
+		},
+	}
+
+	vrcTemplateJson, err := json.Marshal(vrcTemplate)
+	if err != nil {
+		return []byte{}, fmt.Errorf("failed to marshal %v to JSON, error %w", vrcTemplate, err)
+	}
+
+	return vrcTemplateJson, nil
+}
diff --git a/controllers/drpolicy_controller_test.go b/controllers/drpolicy_controller_test.go
index 760ba4e5..6b461f88 100644
--- a/controllers/drpolicy_controller_test.go
+++ b/controllers/drpolicy_controller_test.go
@@ -149,9 +149,10 @@ func getFakeDRPolicyReconciler(drpolicy *ramenv1alpha1.DRPolicy, mp *multicluste
 	fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(drpolicy, mp, ns1, ns2, &hubSecret1, &hubSecret2, odfClientInfoConfigMap).Build()
 
 	r := DRPolicyReconciler{
-		HubClient: fakeClient,
-		Scheme:    scheme,
-		Logger:    utils.GetLogger(utils.GetZapLogger(true)),
+		HubClient:        fakeClient,
+		Scheme:           scheme,
+		Logger:           utils.GetLogger(utils.GetZapLogger(true)),
+		CurrentNamespace: utils.GetEnv("POD_NAMESPACE"),
 	}
 
 	return r


Reviews:
user: login: vbnrh
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-20T11:51:35Z
user: login: umangachapagain
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T14:20:06Z
user: login: umangachapagain
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T14:20:54Z
user: login: umangachapagain
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T14:21:54Z
user: login: vbnrh
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-21T04:16:57Z

Review comments:
diff_hunk: @@ -108,18 +141,142 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, err
 	}
 
-	// Check if the MirrorPeer contains StorageClient reference
-	hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.HubClient, *mirrorPeer, false)
-	if err != nil {
-		logger.Error("Failed to determine if MirrorPeer contains StorageClient reference", "error", err)
-		return ctrl.Result{}, err
+	if mirrorPeer.Spec.Type != multiclusterv1alpha1.Async {
+		return ctrl.Result{}, nil
 	}
 
-	if hasStorageClientRef {
-		logger.Info("MirrorPeer contains StorageClient reference. Skipping creation of VolumeReplicationClasses", "MirrorPeer", mirrorPeer.Name)
-		return ctrl.Result{}, nil
+	err = r.createOrUpdateManifestWorkForVRC(ctx, mirrorPeer, &drpolicy)
+	if err != nil {
+		return ctrl.Result{}, fmt.Errorf("failed to create VolumeReplicationClass via ManifestWork: %v", err)
 	}
 
 	logger.Info("Successfully reconciled DRPolicy")
 	return ctrl.Result{}, nil
 }
+
+func (r *DRPolicyReconciler) createOrUpdateManifestWorkForVRC(ctx context.Context, mp *multiclusterv1alpha1.MirrorPeer, dp *ramenv1alpha1.DRPolicy) error {
+	logger := r.Logger.With("DRPolicy", dp.Name, "MirrorPeer", mp.Name)
+
+	var vrcList []replicationv1alpha1.VolumeReplicationClass
+
+	vrc := replicationv1alpha1.VolumeReplicationClass{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "VolumeReplicationClass",
+			APIVersion: "replication.storage.openshift.io/v1alpha1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name: fmt.Sprintf(RBDVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval)),
+			Annotations: map[string]string{
+				RBDVolumeReplicationClassDefaultAnnotation: "true",
+			},
+		},
+		Spec: replicationv1alpha1.VolumeReplicationClassSpec{
+			Parameters: map[string]string{
+				MirroringModeKey:      DefaultMirroringMode,
+				SchedulingIntervalKey: dp.Spec.SchedulingInterval,
+			},
+			Provisioner: RBDProvisionerName,
+		},
+	}
+	vrcList = append(vrcList, vrc)
+
+	if dp.Spec.ReplicationClassSelector.MatchLabels[RBDFlattenVolumeReplicationClassLabelKey] == RBDFlattenVolumeReplicationClassLabelValue {
+		vrcFlatten := *vrc.DeepCopy()
+		vrcFlatten.Name = fmt.Sprintf(RBDFlattenVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval))
+		vrcFlatten.Labels = map[string]string{
+			RBDFlattenVolumeReplicationClassLabelKey: RBDFlattenVolumeReplicationClassLabelValue,
+		}
path: controllers/drpolicy_controller.go
user: login: vbnrh
body: If no labels are required then shouldn't this be labelled by provider as well ?
created_at: 2025-03-20T11:35:24Z
author_association: MEMBER
diff_hunk: @@ -108,18 +141,142 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, err
 	}
 
-	// Check if the MirrorPeer contains StorageClient reference
-	hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.HubClient, *mirrorPeer, false)
-	if err != nil {
-		logger.Error("Failed to determine if MirrorPeer contains StorageClient reference", "error", err)
-		return ctrl.Result{}, err
+	if mirrorPeer.Spec.Type != multiclusterv1alpha1.Async {
+		return ctrl.Result{}, nil
 	}
 
-	if hasStorageClientRef {
-		logger.Info("MirrorPeer contains StorageClient reference. Skipping creation of VolumeReplicationClasses", "MirrorPeer", mirrorPeer.Name)
-		return ctrl.Result{}, nil
+	err = r.createOrUpdateManifestWorkForVRC(ctx, mirrorPeer, &drpolicy)
+	if err != nil {
+		return ctrl.Result{}, fmt.Errorf("failed to create VolumeReplicationClass via ManifestWork: %v", err)
 	}
 
 	logger.Info("Successfully reconciled DRPolicy")
 	return ctrl.Result{}, nil
 }
+
+func (r *DRPolicyReconciler) createOrUpdateManifestWorkForVRC(ctx context.Context, mp *multiclusterv1alpha1.MirrorPeer, dp *ramenv1alpha1.DRPolicy) error {
+	logger := r.Logger.With("DRPolicy", dp.Name, "MirrorPeer", mp.Name)
+
+	var vrcList []replicationv1alpha1.VolumeReplicationClass
+
+	vrc := replicationv1alpha1.VolumeReplicationClass{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "VolumeReplicationClass",
+			APIVersion: "replication.storage.openshift.io/v1alpha1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name: fmt.Sprintf(RBDVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval)),
+			Annotations: map[string]string{
+				RBDVolumeReplicationClassDefaultAnnotation: "true",
+			},
+		},
+		Spec: replicationv1alpha1.VolumeReplicationClassSpec{
+			Parameters: map[string]string{
+				MirroringModeKey:      DefaultMirroringMode,
+				SchedulingIntervalKey: dp.Spec.SchedulingInterval,
+			},
+			Provisioner: RBDProvisionerName,
+		},
+	}
+	vrcList = append(vrcList, vrc)
+
+	if dp.Spec.ReplicationClassSelector.MatchLabels[RBDFlattenVolumeReplicationClassLabelKey] == RBDFlattenVolumeReplicationClassLabelValue {
+		vrcFlatten := *vrc.DeepCopy()
+		vrcFlatten.Name = fmt.Sprintf(RBDFlattenVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval))
+		vrcFlatten.Labels = map[string]string{
+			RBDFlattenVolumeReplicationClassLabelKey: RBDFlattenVolumeReplicationClassLabelValue,
+		}
+		vrcFlatten.Annotations = map[string]string{}
+		vrcFlatten.Spec.Parameters["flattenMode"] = "force"
+		vrcList = append(vrcList, vrcFlatten)
+	}
+
+	cm, err := utils.FetchClientInfoConfigMap(ctx, r.HubClient, r.CurrentNamespace)
+	if err != nil {
+		return err
+	}
+
+	manifestWorkName := fmt.Sprintf("vrc-%v", utils.FnvHash(dp.Name))
+	for _, pr := range mp.Spec.Items {
+		cInfo, err := utils.GetClientInfoFromConfigMap(cm.Data, utils.GetKey(pr.ClusterName, pr.StorageClusterRef.Name))
+		if err != nil {
+			return err
+		}
+
+		var manifestList []workv1.Manifest
+		for _, vrc := range vrcList {
+			vrcTemplateJson, err := getTemplateForVRC(vrc, cInfo.ProviderInfo.NamespacedName.Namespace)
+			if err != nil {
+				return fmt.Errorf("failed to get template for VRC %q, error %w", vrc.Name, err)
+			}
+			manifestList = append(manifestList, workv1.Manifest{
+				RawExtension: runtime.RawExtension{
+					Raw: vrcTemplateJson,
+				},
+			})
+		}
+
+		mw := workv1.ManifestWork{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      manifestWorkName,
+				Namespace: cInfo.ProviderInfo.ProviderManagedClusterName,
+				OwnerReferences: []metav1.OwnerReference{
+					{
+						Kind:       dp.Kind,
+						Name:       dp.Name,
+						UID:        dp.UID,
+						APIVersion: dp.APIVersion,
+					},
+				},
+			},
+		}
+
+		_, err = controllerutil.CreateOrUpdate(ctx, r.HubClient, &mw, func() error {
+			mw.Spec = workv1.ManifestWorkSpec{
+				Workload: workv1.ManifestsTemplate{
+					Manifests: manifestList,
+				},
+			}
+			return nil
+		})
+
+		if err != nil {
+			logger.Error("Failed to create/update ManifestWork", "ManifestWorkName", manifestWorkName, "error", err)
+			return err
+		}
+
+		logger.Info("ManifestWork created/updated successfully", "ManifestWorkName", manifestWorkName, "VolumeReplicationClassName", vrc.Name)
+	}
+
+	return nil
+}
+
+func getTemplateForVRC(vrc replicationv1alpha1.VolumeReplicationClass, templateNamespace string) ([]byte, error) {
+	vrcJson, err := json.Marshal(vrc)
+	if err != nil {
+		return []byte{}, fmt.Errorf("failed to marshal %v to JSON, error %w", vrc, err)
+	}
+
+	vrcTemplate := templatev1.Template{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "Template",
+			APIVersion: "template.openshift.io/v1",
+		},
path: controllers/drpolicy_controller.go
user: login: vbnrh
body: Why is type meta for the template required here ? 
created_at: 2025-03-20T11:49:37Z
author_association: MEMBER
diff_hunk: @@ -108,18 +141,142 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, err
 	}
 
-	// Check if the MirrorPeer contains StorageClient reference
-	hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.HubClient, *mirrorPeer, false)
-	if err != nil {
-		logger.Error("Failed to determine if MirrorPeer contains StorageClient reference", "error", err)
-		return ctrl.Result{}, err
+	if mirrorPeer.Spec.Type != multiclusterv1alpha1.Async {
+		return ctrl.Result{}, nil
 	}
 
-	if hasStorageClientRef {
-		logger.Info("MirrorPeer contains StorageClient reference. Skipping creation of VolumeReplicationClasses", "MirrorPeer", mirrorPeer.Name)
-		return ctrl.Result{}, nil
+	err = r.createOrUpdateManifestWorkForVRC(ctx, mirrorPeer, &drpolicy)
+	if err != nil {
+		return ctrl.Result{}, fmt.Errorf("failed to create VolumeReplicationClass via ManifestWork: %v", err)
path: controllers/drpolicy_controller.go
user: login: vbnrh
body: ```suggestion
		return ctrl.Result{}, fmt.Errorf("failed to create VolumeReplicationClass template via ManifestWork: %v", err)
```

nit 
created_at: 2025-03-20T11:50:54Z
author_association: MEMBER
diff_hunk: @@ -108,18 +141,142 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, err
 	}
 
-	// Check if the MirrorPeer contains StorageClient reference
-	hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.HubClient, *mirrorPeer, false)
-	if err != nil {
-		logger.Error("Failed to determine if MirrorPeer contains StorageClient reference", "error", err)
-		return ctrl.Result{}, err
+	if mirrorPeer.Spec.Type != multiclusterv1alpha1.Async {
+		return ctrl.Result{}, nil
 	}
 
-	if hasStorageClientRef {
-		logger.Info("MirrorPeer contains StorageClient reference. Skipping creation of VolumeReplicationClasses", "MirrorPeer", mirrorPeer.Name)
-		return ctrl.Result{}, nil
+	err = r.createOrUpdateManifestWorkForVRC(ctx, mirrorPeer, &drpolicy)
+	if err != nil {
+		return ctrl.Result{}, fmt.Errorf("failed to create VolumeReplicationClass via ManifestWork: %v", err)
 	}
 
 	logger.Info("Successfully reconciled DRPolicy")
 	return ctrl.Result{}, nil
 }
+
+func (r *DRPolicyReconciler) createOrUpdateManifestWorkForVRC(ctx context.Context, mp *multiclusterv1alpha1.MirrorPeer, dp *ramenv1alpha1.DRPolicy) error {
+	logger := r.Logger.With("DRPolicy", dp.Name, "MirrorPeer", mp.Name)
+
+	var vrcList []replicationv1alpha1.VolumeReplicationClass
+
+	vrc := replicationv1alpha1.VolumeReplicationClass{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "VolumeReplicationClass",
+			APIVersion: "replication.storage.openshift.io/v1alpha1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name: fmt.Sprintf(RBDVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval)),
+			Annotations: map[string]string{
+				RBDVolumeReplicationClassDefaultAnnotation: "true",
+			},
+		},
+		Spec: replicationv1alpha1.VolumeReplicationClassSpec{
+			Parameters: map[string]string{
+				MirroringModeKey:      DefaultMirroringMode,
+				SchedulingIntervalKey: dp.Spec.SchedulingInterval,
+			},
+			Provisioner: RBDProvisionerName,
+		},
+	}
+	vrcList = append(vrcList, vrc)
+
+	if dp.Spec.ReplicationClassSelector.MatchLabels[RBDFlattenVolumeReplicationClassLabelKey] == RBDFlattenVolumeReplicationClassLabelValue {
+		vrcFlatten := *vrc.DeepCopy()
+		vrcFlatten.Name = fmt.Sprintf(RBDFlattenVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval))
+		vrcFlatten.Labels = map[string]string{
+			RBDFlattenVolumeReplicationClassLabelKey: RBDFlattenVolumeReplicationClassLabelValue,
+		}
path: controllers/drpolicy_controller.go
user: login: umangachapagain
body: No this will be MCO driven.
created_at: 2025-03-20T14:20:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -108,18 +141,142 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, err
 	}
 
-	// Check if the MirrorPeer contains StorageClient reference
-	hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.HubClient, *mirrorPeer, false)
-	if err != nil {
-		logger.Error("Failed to determine if MirrorPeer contains StorageClient reference", "error", err)
-		return ctrl.Result{}, err
+	if mirrorPeer.Spec.Type != multiclusterv1alpha1.Async {
+		return ctrl.Result{}, nil
 	}
 
-	if hasStorageClientRef {
-		logger.Info("MirrorPeer contains StorageClient reference. Skipping creation of VolumeReplicationClasses", "MirrorPeer", mirrorPeer.Name)
-		return ctrl.Result{}, nil
+	err = r.createOrUpdateManifestWorkForVRC(ctx, mirrorPeer, &drpolicy)
+	if err != nil {
+		return ctrl.Result{}, fmt.Errorf("failed to create VolumeReplicationClass via ManifestWork: %v", err)
 	}
 
 	logger.Info("Successfully reconciled DRPolicy")
 	return ctrl.Result{}, nil
 }
+
+func (r *DRPolicyReconciler) createOrUpdateManifestWorkForVRC(ctx context.Context, mp *multiclusterv1alpha1.MirrorPeer, dp *ramenv1alpha1.DRPolicy) error {
+	logger := r.Logger.With("DRPolicy", dp.Name, "MirrorPeer", mp.Name)
+
+	var vrcList []replicationv1alpha1.VolumeReplicationClass
+
+	vrc := replicationv1alpha1.VolumeReplicationClass{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "VolumeReplicationClass",
+			APIVersion: "replication.storage.openshift.io/v1alpha1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name: fmt.Sprintf(RBDVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval)),
+			Annotations: map[string]string{
+				RBDVolumeReplicationClassDefaultAnnotation: "true",
+			},
+		},
+		Spec: replicationv1alpha1.VolumeReplicationClassSpec{
+			Parameters: map[string]string{
+				MirroringModeKey:      DefaultMirroringMode,
+				SchedulingIntervalKey: dp.Spec.SchedulingInterval,
+			},
+			Provisioner: RBDProvisionerName,
+		},
+	}
+	vrcList = append(vrcList, vrc)
+
+	if dp.Spec.ReplicationClassSelector.MatchLabels[RBDFlattenVolumeReplicationClassLabelKey] == RBDFlattenVolumeReplicationClassLabelValue {
+		vrcFlatten := *vrc.DeepCopy()
+		vrcFlatten.Name = fmt.Sprintf(RBDFlattenVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval))
+		vrcFlatten.Labels = map[string]string{
+			RBDFlattenVolumeReplicationClassLabelKey: RBDFlattenVolumeReplicationClassLabelValue,
+		}
+		vrcFlatten.Annotations = map[string]string{}
+		vrcFlatten.Spec.Parameters["flattenMode"] = "force"
+		vrcList = append(vrcList, vrcFlatten)
+	}
+
+	cm, err := utils.FetchClientInfoConfigMap(ctx, r.HubClient, r.CurrentNamespace)
+	if err != nil {
+		return err
+	}
+
+	manifestWorkName := fmt.Sprintf("vrc-%v", utils.FnvHash(dp.Name))
+	for _, pr := range mp.Spec.Items {
+		cInfo, err := utils.GetClientInfoFromConfigMap(cm.Data, utils.GetKey(pr.ClusterName, pr.StorageClusterRef.Name))
+		if err != nil {
+			return err
+		}
+
+		var manifestList []workv1.Manifest
+		for _, vrc := range vrcList {
+			vrcTemplateJson, err := getTemplateForVRC(vrc, cInfo.ProviderInfo.NamespacedName.Namespace)
+			if err != nil {
+				return fmt.Errorf("failed to get template for VRC %q, error %w", vrc.Name, err)
+			}
+			manifestList = append(manifestList, workv1.Manifest{
+				RawExtension: runtime.RawExtension{
+					Raw: vrcTemplateJson,
+				},
+			})
+		}
+
+		mw := workv1.ManifestWork{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      manifestWorkName,
+				Namespace: cInfo.ProviderInfo.ProviderManagedClusterName,
+				OwnerReferences: []metav1.OwnerReference{
+					{
+						Kind:       dp.Kind,
+						Name:       dp.Name,
+						UID:        dp.UID,
+						APIVersion: dp.APIVersion,
+					},
+				},
+			},
+		}
+
+		_, err = controllerutil.CreateOrUpdate(ctx, r.HubClient, &mw, func() error {
+			mw.Spec = workv1.ManifestWorkSpec{
+				Workload: workv1.ManifestsTemplate{
+					Manifests: manifestList,
+				},
+			}
+			return nil
+		})
+
+		if err != nil {
+			logger.Error("Failed to create/update ManifestWork", "ManifestWorkName", manifestWorkName, "error", err)
+			return err
+		}
+
+		logger.Info("ManifestWork created/updated successfully", "ManifestWorkName", manifestWorkName, "VolumeReplicationClassName", vrc.Name)
+	}
+
+	return nil
+}
+
+func getTemplateForVRC(vrc replicationv1alpha1.VolumeReplicationClass, templateNamespace string) ([]byte, error) {
+	vrcJson, err := json.Marshal(vrc)
+	if err != nil {
+		return []byte{}, fmt.Errorf("failed to marshal %v to JSON, error %w", vrc, err)
+	}
+
+	vrcTemplate := templatev1.Template{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "Template",
+			APIVersion: "template.openshift.io/v1",
+		},
path: controllers/drpolicy_controller.go
user: login: umangachapagain
body: To stop ManifestWork from complaining. It probably needs TypeMeta to resolve json to runtime object.
created_at: 2025-03-20T14:20:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -108,18 +141,142 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, err
 	}
 
-	// Check if the MirrorPeer contains StorageClient reference
-	hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.HubClient, *mirrorPeer, false)
-	if err != nil {
-		logger.Error("Failed to determine if MirrorPeer contains StorageClient reference", "error", err)
-		return ctrl.Result{}, err
+	if mirrorPeer.Spec.Type != multiclusterv1alpha1.Async {
+		return ctrl.Result{}, nil
 	}
 
-	if hasStorageClientRef {
-		logger.Info("MirrorPeer contains StorageClient reference. Skipping creation of VolumeReplicationClasses", "MirrorPeer", mirrorPeer.Name)
-		return ctrl.Result{}, nil
+	err = r.createOrUpdateManifestWorkForVRC(ctx, mirrorPeer, &drpolicy)
+	if err != nil {
+		return ctrl.Result{}, fmt.Errorf("failed to create VolumeReplicationClass via ManifestWork: %v", err)
path: controllers/drpolicy_controller.go
user: login: umangachapagain
body: It's a small detail. Can I fix it when I work on that file next time?
created_at: 2025-03-20T14:21:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -108,18 +141,142 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, err
 	}
 
-	// Check if the MirrorPeer contains StorageClient reference
-	hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.HubClient, *mirrorPeer, false)
-	if err != nil {
-		logger.Error("Failed to determine if MirrorPeer contains StorageClient reference", "error", err)
-		return ctrl.Result{}, err
+	if mirrorPeer.Spec.Type != multiclusterv1alpha1.Async {
+		return ctrl.Result{}, nil
 	}
 
-	if hasStorageClientRef {
-		logger.Info("MirrorPeer contains StorageClient reference. Skipping creation of VolumeReplicationClasses", "MirrorPeer", mirrorPeer.Name)
-		return ctrl.Result{}, nil
+	err = r.createOrUpdateManifestWorkForVRC(ctx, mirrorPeer, &drpolicy)
+	if err != nil {
+		return ctrl.Result{}, fmt.Errorf("failed to create VolumeReplicationClass via ManifestWork: %v", err)
path: controllers/drpolicy_controller.go
user: login: vbnrh
body: Sure !
created_at: 2025-03-21T04:15:47Z
author_association: MEMBER
diff_hunk: @@ -108,18 +141,142 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, err
 	}
 
-	// Check if the MirrorPeer contains StorageClient reference
-	hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.HubClient, *mirrorPeer, false)
-	if err != nil {
-		logger.Error("Failed to determine if MirrorPeer contains StorageClient reference", "error", err)
-		return ctrl.Result{}, err
+	if mirrorPeer.Spec.Type != multiclusterv1alpha1.Async {
+		return ctrl.Result{}, nil
 	}
 
-	if hasStorageClientRef {
-		logger.Info("MirrorPeer contains StorageClient reference. Skipping creation of VolumeReplicationClasses", "MirrorPeer", mirrorPeer.Name)
-		return ctrl.Result{}, nil
+	err = r.createOrUpdateManifestWorkForVRC(ctx, mirrorPeer, &drpolicy)
+	if err != nil {
+		return ctrl.Result{}, fmt.Errorf("failed to create VolumeReplicationClass via ManifestWork: %v", err)
 	}
 
 	logger.Info("Successfully reconciled DRPolicy")
 	return ctrl.Result{}, nil
 }
+
+func (r *DRPolicyReconciler) createOrUpdateManifestWorkForVRC(ctx context.Context, mp *multiclusterv1alpha1.MirrorPeer, dp *ramenv1alpha1.DRPolicy) error {
+	logger := r.Logger.With("DRPolicy", dp.Name, "MirrorPeer", mp.Name)
+
+	var vrcList []replicationv1alpha1.VolumeReplicationClass
+
+	vrc := replicationv1alpha1.VolumeReplicationClass{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "VolumeReplicationClass",
+			APIVersion: "replication.storage.openshift.io/v1alpha1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name: fmt.Sprintf(RBDVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval)),
+			Annotations: map[string]string{
+				RBDVolumeReplicationClassDefaultAnnotation: "true",
+			},
+		},
+		Spec: replicationv1alpha1.VolumeReplicationClassSpec{
+			Parameters: map[string]string{
+				MirroringModeKey:      DefaultMirroringMode,
+				SchedulingIntervalKey: dp.Spec.SchedulingInterval,
+			},
+			Provisioner: RBDProvisionerName,
+		},
+	}
+	vrcList = append(vrcList, vrc)
+
+	if dp.Spec.ReplicationClassSelector.MatchLabels[RBDFlattenVolumeReplicationClassLabelKey] == RBDFlattenVolumeReplicationClassLabelValue {
+		vrcFlatten := *vrc.DeepCopy()
+		vrcFlatten.Name = fmt.Sprintf(RBDFlattenVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval))
+		vrcFlatten.Labels = map[string]string{
+			RBDFlattenVolumeReplicationClassLabelKey: RBDFlattenVolumeReplicationClassLabelValue,
+		}
path: controllers/drpolicy_controller.go
user: login: vbnrh
body: ok but sounds like an odd segregation of responsibilities 
created_at: 2025-03-21T04:16:22Z
author_association: MEMBER
diff_hunk: @@ -108,18 +141,142 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, err
 	}
 
-	// Check if the MirrorPeer contains StorageClient reference
-	hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.HubClient, *mirrorPeer, false)
-	if err != nil {
-		logger.Error("Failed to determine if MirrorPeer contains StorageClient reference", "error", err)
-		return ctrl.Result{}, err
+	if mirrorPeer.Spec.Type != multiclusterv1alpha1.Async {
+		return ctrl.Result{}, nil
 	}
 
-	if hasStorageClientRef {
-		logger.Info("MirrorPeer contains StorageClient reference. Skipping creation of VolumeReplicationClasses", "MirrorPeer", mirrorPeer.Name)
-		return ctrl.Result{}, nil
+	err = r.createOrUpdateManifestWorkForVRC(ctx, mirrorPeer, &drpolicy)
+	if err != nil {
+		return ctrl.Result{}, fmt.Errorf("failed to create VolumeReplicationClass via ManifestWork: %v", err)
 	}
 
 	logger.Info("Successfully reconciled DRPolicy")
 	return ctrl.Result{}, nil
 }
+
+func (r *DRPolicyReconciler) createOrUpdateManifestWorkForVRC(ctx context.Context, mp *multiclusterv1alpha1.MirrorPeer, dp *ramenv1alpha1.DRPolicy) error {
+	logger := r.Logger.With("DRPolicy", dp.Name, "MirrorPeer", mp.Name)
+
+	var vrcList []replicationv1alpha1.VolumeReplicationClass
+
+	vrc := replicationv1alpha1.VolumeReplicationClass{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "VolumeReplicationClass",
+			APIVersion: "replication.storage.openshift.io/v1alpha1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name: fmt.Sprintf(RBDVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval)),
+			Annotations: map[string]string{
+				RBDVolumeReplicationClassDefaultAnnotation: "true",
+			},
+		},
+		Spec: replicationv1alpha1.VolumeReplicationClassSpec{
+			Parameters: map[string]string{
+				MirroringModeKey:      DefaultMirroringMode,
+				SchedulingIntervalKey: dp.Spec.SchedulingInterval,
+			},
+			Provisioner: RBDProvisionerName,
+		},
+	}
+	vrcList = append(vrcList, vrc)
+
+	if dp.Spec.ReplicationClassSelector.MatchLabels[RBDFlattenVolumeReplicationClassLabelKey] == RBDFlattenVolumeReplicationClassLabelValue {
+		vrcFlatten := *vrc.DeepCopy()
+		vrcFlatten.Name = fmt.Sprintf(RBDFlattenVolumeReplicationClassNameTemplate, utils.FnvHash(dp.Spec.SchedulingInterval))
+		vrcFlatten.Labels = map[string]string{
+			RBDFlattenVolumeReplicationClassLabelKey: RBDFlattenVolumeReplicationClassLabelValue,
+		}
+		vrcFlatten.Annotations = map[string]string{}
+		vrcFlatten.Spec.Parameters["flattenMode"] = "force"
+		vrcList = append(vrcList, vrcFlatten)
+	}
+
+	cm, err := utils.FetchClientInfoConfigMap(ctx, r.HubClient, r.CurrentNamespace)
+	if err != nil {
+		return err
+	}
+
+	manifestWorkName := fmt.Sprintf("vrc-%v", utils.FnvHash(dp.Name))
+	for _, pr := range mp.Spec.Items {
+		cInfo, err := utils.GetClientInfoFromConfigMap(cm.Data, utils.GetKey(pr.ClusterName, pr.StorageClusterRef.Name))
+		if err != nil {
+			return err
+		}
+
+		var manifestList []workv1.Manifest
+		for _, vrc := range vrcList {
+			vrcTemplateJson, err := getTemplateForVRC(vrc, cInfo.ProviderInfo.NamespacedName.Namespace)
+			if err != nil {
+				return fmt.Errorf("failed to get template for VRC %q, error %w", vrc.Name, err)
+			}
+			manifestList = append(manifestList, workv1.Manifest{
+				RawExtension: runtime.RawExtension{
+					Raw: vrcTemplateJson,
+				},
+			})
+		}
+
+		mw := workv1.ManifestWork{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      manifestWorkName,
+				Namespace: cInfo.ProviderInfo.ProviderManagedClusterName,
+				OwnerReferences: []metav1.OwnerReference{
+					{
+						Kind:       dp.Kind,
+						Name:       dp.Name,
+						UID:        dp.UID,
+						APIVersion: dp.APIVersion,
+					},
+				},
+			},
+		}
+
+		_, err = controllerutil.CreateOrUpdate(ctx, r.HubClient, &mw, func() error {
+			mw.Spec = workv1.ManifestWorkSpec{
+				Workload: workv1.ManifestsTemplate{
+					Manifests: manifestList,
+				},
+			}
+			return nil
+		})
+
+		if err != nil {
+			logger.Error("Failed to create/update ManifestWork", "ManifestWorkName", manifestWorkName, "error", err)
+			return err
+		}
+
+		logger.Info("ManifestWork created/updated successfully", "ManifestWorkName", manifestWorkName, "VolumeReplicationClassName", vrc.Name)
+	}
+
+	return nil
+}
+
+func getTemplateForVRC(vrc replicationv1alpha1.VolumeReplicationClass, templateNamespace string) ([]byte, error) {
+	vrcJson, err := json.Marshal(vrc)
+	if err != nil {
+		return []byte{}, fmt.Errorf("failed to marshal %v to JSON, error %w", vrc, err)
+	}
+
+	vrcTemplate := templatev1.Template{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "Template",
+			APIVersion: "template.openshift.io/v1",
+		},
path: controllers/drpolicy_controller.go
user: login: vbnrh
body: ok
created_at: 2025-03-21T04:16:51Z
author_association: MEMBER

PR comments:
user: login: umangachapagain
created_at: 2025-03-20T03:46:41Z
body: /hold
author_association: CONTRIBUTOR
user: login: umangachapagain
created_at: 2025-03-20T09:24:37Z
body: /unhold
author_association: CONTRIBUTOR
user: login: openshift-ci[bot]
created_at: 2025-03-21T04:17:02Z
body: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/red-hat-storage/odf-multicluster-orchestrator/pull/289#" title="Author self-approved">umangachapagain</a>*, *<a href="https://github.com/red-hat-storage/odf-multicluster-orchestrator/pull/289#pullrequestreview-2704687262" title="Approved">vbnrh</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=red-hat-storage%2Fodf-multicluster-orchestrator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/red-hat-storage/odf-multicluster-orchestrator/blob/main/OWNERS)~~ [umangachapagain,vbnrh]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
author_association: CONTRIBUTOR