diff --git a/controllers/vrg_volsync.go b/controllers/vrg_volsync.go index c63b170c7..f8068da9d 100644 --- a/controllers/vrg_volsync.go +++ b/controllers/vrg_volsync.go @@ -6,6 +6,7 @@ package controllers import ( "fmt" "reflect" + "strings" ramendrv1alpha1 "github.com/ramendr/ramen/api/v1alpha1" corev1 "k8s.io/api/core/v1" @@ -112,6 +113,7 @@ func (v *VRGInstance) reconcilePVCAsVolSyncPrimary(pvc corev1.PersistentVolumeCl Name: pvc.Name, ProtectedByVolSync: true, StorageClassName: pvc.Spec.StorageClassName, + Annotations: protectedPVCAnnotations(pvc), Labels: pvc.Labels, AccessModes: pvc.Spec.AccessModes, Resources: pvc.Spec.Resources, @@ -367,3 +369,19 @@ func (v VRGInstance) isVolSyncProtectedPVCConditionReady(conType string) bool { return ready } + +// protectedPVCAnnotations return the annotations that we must propagate to the +// destination cluster: +// - apps.open-cluster-management.io/* - required to make the protected PVC +// owned by OCM when DR is disabled. +func protectedPVCAnnotations(pvc corev1.PersistentVolumeClaim) map[string]string { + res := map[string]string{} + + for key, value := range pvc.Annotations { + if strings.HasPrefix(key, "apps.open-cluster-management.io/") { + res[key] = value + } + } + + return res +} diff --git a/controllers/vrg_volsync_test.go b/controllers/vrg_volsync_test.go index 8abb7f254..29c0072ad 100644 --- a/controllers/vrg_volsync_test.go +++ b/controllers/vrg_volsync_test.go @@ -108,12 +108,22 @@ var _ = Describe("VolumeReplicationGroupVolSyncController", func() { Context("When matching PVCs are bound", func() { var boundPvcs []corev1.PersistentVolumeClaim + + pvcAnnotations := map[string]string{ + "apps.open-cluster-management.io/hosting-subscription": "sub-name", + "apps.open-cluster-management.io/reconcile-option": "merge", + "pv.kubernetes.io/bind-completed": "yes", + "volume.kubernetes.io/storage-provisioner": "provisioner", + } + JustBeforeEach(func() { - boundPvcs = []corev1.PersistentVolumeClaim{} // Reset for each test + // Reset for each test + boundPvcs = []corev1.PersistentVolumeClaim{} // Create some PVCs that are bound for i := 0; i < 3; i++ { - newPvc := createPVCBoundToRunningPod(testCtx, testNamespace.GetName(), testMatchLabels) + newPvc := createPVCBoundToRunningPod(testCtx, testNamespace.GetName(), + testMatchLabels, pvcAnnotations) boundPvcs = append(boundPvcs, *newPvc) } @@ -147,6 +157,20 @@ var _ = Describe("VolumeReplicationGroupVolSyncController", func() { Expect(foundBoundPVC2).To(BeTrue()) }) + It("Should report only OCM annotaions in Status", func() { + for _, vsPvc := range testVsrg.Status.ProtectedPVCs { + // OCM annontations are propagated. + Expect(vsPvc.Annotations).To(HaveKeyWithValue( + "apps.open-cluster-management.io/hosting-subscription", "sub-name")) + Expect(vsPvc.Annotations).To(HaveKeyWithValue( + "apps.open-cluster-management.io/reconcile-option", "merge")) + + // Other annotations are droopped. + Expect(vsPvc.Annotations).NotTo(HaveKey("pv.kubernetes.io/bind-completed")) + Expect(vsPvc.Annotations).NotTo(HaveKey("volume.kubernetes.io/storage-provisioner")) + } + }) + Context("When RSSpec entries are added to vrg spec", func() { It("Should create ReplicationSources for each", func() { allRSs := &volsyncv1alpha1.ReplicationSourceList{} @@ -343,7 +367,7 @@ var _ = Describe("VolumeReplicationGroupVolSyncController", func() { //nolint:funlen func createPVCBoundToRunningPod(ctx context.Context, namespace string, - labels map[string]string, + labels map[string]string, annotations map[string]string, ) *corev1.PersistentVolumeClaim { capacity := corev1.ResourceList{ corev1.ResourceStorage: resource.MustParse("1Gi"), @@ -358,6 +382,7 @@ func createPVCBoundToRunningPod(ctx context.Context, namespace string, TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{ GenerateName: "testpvc-", + Annotations: annotations, Labels: labels, Namespace: namespace, },