-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add VolSync Support for PVCs with Block VolumeMode #1582
Conversation
internal/controller/util/misc.go
Outdated
@@ -22,6 +22,8 @@ const ( | |||
OCMBackupLabelValue string = "ramen" | |||
|
|||
IsCGEnabledAnnotation = "drplacementcontrol.ramendr.openshift.io/is-cg-enabled" | |||
|
|||
UseVolSyncForRBDAnnotation = "drplacementcontrol.ramendr.openshift.io/is-rbd-enabled-for-volsync-replication" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name of the annotation is little bit too specific, ramen should not care about the storage (rbd). The value of the annotation does not match the annotation name and also too specific - about storage. There is no concept of RBD enabled or not for volsync replication.
How about:
PreferVolSyncAnnontation = "drplacementcontrol.ramendr.openshift.io/is-volsync-preferred"
Which means, when we have a VRC, prefer volsync. Current code will use the volrep in this case, with this flag will use volsync.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I expected some feedback on the annotation name, which is a good thing. However, the change in this PR is focused on individual workloads, even when we have VRCs. Essentially, we want to use VolSync for a specific RBD workload. Your suggestion implies that for this workload, VolSync should be preferred, and if it’s not enabled, it should fall back to VolRep. Is that what your comment was getting at?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ye, isn't this the behavior we want to add?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For CG, when a user chooses to use VolSync, there’s no fallback. This is because if CG is supported for RBD with both VolSync and VolRep, we’ll always default to VolRep. If not, the user can opt for VolSync, but Ramen won’t make that choice automatically.
As for individual PVC protection, why would we need a fallback? I’m not sure I see the need for one.
That said, I’m still exploring better options for naming the annotation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will more clear if we start with design page or documentation showing the various options and when ramen use which replication mode. Starting with documentation helps to get good APIs and names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So for now I use the same annotation name as the variable.
UseVolSyncForPVCProtection = "drplacementcontrol.ramendr.openshift.io/use-volsync-for-pvc-protection"
internal/controller/util/misc.go
Outdated
@@ -251,3 +253,11 @@ func TrimToK8sResourceNameLength(name string) string { | |||
|
|||
return name | |||
} | |||
|
|||
func IsRBDEnabledForVolSyncReplication(annotations map[string]string) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue with the name as the annotation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll address this when the previous comment is addressed.
internal/controller/util/misc.go
Outdated
func IsRBDEnabledForVolSyncReplication(annotations map[string]string) bool { | ||
if annotations == nil { | ||
return false | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to check for nil, accessing nil map works (returns nil for everything).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Point taken. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Expect(pvc.GetName()).To(Equal(rdSpec.ProtectedPVC.Name)) | ||
Expect(pvc.GetOwnerReferences()[0].Kind).To(Equal("ConfigMap")) | ||
Expect(*pvc.Spec.VolumeMode).To(Equal(corev1.PersistentVolumeFilesystem)) | ||
Expect(k8sClient.Delete(ctx, pvc)).ToNot(HaveOccurred()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the tests fail before this line, do we run the delete line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need. If the test fails, the unit test fails and that's what we want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the created pvc has the wrong mode - we still need to delete it when the test ends. Othewise the leftover pvc can cause another test to fail or worse, succeed when the code is broken
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure I understand what you are asking. I don't want to clean up. If the test fails in line 697, I want that line to fail for vshandler_test
and no more. When I am debugging the unit test failure, I won't start from the last failure. I start from the first failure and I ignore everything else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like cleanup after test, not part of the test. Cleanup code should always run regardless of the outcome of the test. We probably have some hook to run cleanup after a test like JustBeforeEach
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I am not sure about the best practice here. AfterEach
should be what you want, but not when the test fails.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cleanup must run in all cases. If AfterEach does this we should use it. If not we can do cleanup using defer.
Expect(pvc.GetName()).To(Equal(rdSpecForBlockPVC.ProtectedPVC.Name)) | ||
Expect(pvc.GetOwnerReferences()[0].Kind).To(Equal("ConfigMap")) | ||
Expect(*pvc.Spec.VolumeMode).To(Equal(corev1.PersistentVolumeBlock)) | ||
Expect(k8sClient.Delete(ctx, pvc)).ToNot(HaveOccurred()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a duplicate of the previous test - we have different setup and one different assertion. Can extract the repeated test code to a helper?
Different setup:
util.AddAnnotation(owner, util.UseVolSyncForRBDAnnotation, "true")
Expect(k8sClient.Update(ctx, owner)).To(Succeed())
rdSpecForBlockPVC := rdSpec.DeepCopy()
block := corev1.PersistentVolumeBlock
rdSpecForBlockPVC.ProtectedPVC.VolumeMode = &block
Different check:
Expect(*pvc.Spec.VolumeMode).To(Equal(corev1.PersistentVolumeBlock))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you miss this comment?
ab695f1
to
018f295
Compare
internal/controller/util/misc.go
Outdated
@@ -22,6 +22,9 @@ const ( | |||
OCMBackupLabelValue string = "ramen" | |||
|
|||
IsCGEnabledAnnotation = "drplacementcontrol.ramendr.openshift.io/is-cg-enabled" | |||
|
|||
// Annotation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is not useful - maybe describe here how this annotation change the system behavior?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed.
internal/controller/util/misc.go
Outdated
return annotations[IsCGEnabledAnnotation] == "true" | ||
} | ||
|
||
func IsRBDEnabledForVolSyncReplication(annotations map[string]string) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe rename to UseVolsyncForPVCProtection()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to IsPVCMarkedForVolSync
DoNotDeletePVCAnnotation: d.instance.GetAnnotations()[DoNotDeletePVCAnnotation], | ||
DRPCUIDAnnotation: string(d.instance.UID), | ||
rmnutil.IsCGEnabledAnnotation: d.instance.GetAnnotations()[rmnutil.IsCGEnabledAnnotation], | ||
rmnutil.UseVolSyncForPVCProtection: d.instance.GetAnnotations()[rmnutil.UseVolSyncForPVCProtection], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other annotation have "Annotation" suffix. Maybe rename to "UseVolSyncAnnotation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ack.
@@ -2036,8 +2034,8 @@ func (v *VSHandler) createReadOnlyPVCFromSnapshot(rd *volsyncv1alpha1.Replicatio | |||
pvc.Spec.AccessModes = accessModes | |||
pvc.Spec.StorageClassName = rd.Spec.RsyncTLS.StorageClassName | |||
|
|||
// Only set when initially creating | |||
pvc.Spec.DataSource = &snapshotRef | |||
pvc.Spec.DataSource = snapshotRef |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why snapshotRef changed? I don't see any other change that explain this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It changed to a pointer
if util.IsRBDEnabledForVolSyncReplication(v.owner.GetAnnotations()) && | ||
protectedPVC.VolumeMode != nil && | ||
*protectedPVC.VolumeMode == corev1.PersistentVolumeBlock { | ||
volumeMode = corev1.PersistentVolumeBlock |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation here is confusing - maybe indent the conditions more to make the block more clear?
if util.IsRBDEnabledForVolSyncReplication(v.owner.GetAnnotations()) &&
protectedPVC.VolumeMode != nil &&
*protectedPVC.VolumeMode == corev1.PersistentVolumeBlock {
volumeMode = corev1.PersistentVolumeBlock
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you miss this comment?
Expect(pvc.GetName()).To(Equal(rdSpec.ProtectedPVC.Name)) | ||
Expect(pvc.GetOwnerReferences()[0].Kind).To(Equal("ConfigMap")) | ||
Expect(*pvc.Spec.VolumeMode).To(Equal(corev1.PersistentVolumeFilesystem)) | ||
Expect(k8sClient.Delete(ctx, pvc)).ToNot(HaveOccurred()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cleanup must run in all cases. If AfterEach does this we should use it. If not we can do cleanup using defer.
e0a3fd0
to
74f8093
Compare
74f8093
to
87df5ea
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BenamarMk we need a better way forward to support all PVCs as VolSync than using annotations. I am thinking we can create a DRPolicy that would only advertise Async PeerClasses that are VS only. This policy can hence be used, as VRG would be asked to protect PVCs for SCs with the VS and not VR method.
There are possibly other alternatives, but asking PVCs to be labelled would be a bit of a stretch for app devs at present. This is not the final solution I understand, but just throwing it out there for consideration in the future.
…resource Signed-off-by: Benamar Mekhissi <[email protected]>
…cross relevant components Signed-off-by: Benamar Mekhissi <[email protected]>
Signed-off-by: Benamar Mekhissi <[email protected]>
87df5ea
to
a542889
Compare
Agreed - the intent was to explore a better solution for 4.19. Using an annotation to differentiate workloads isn’t necessarily a bad approach; it provides a lightweight, simple option where the user can just check a box when creating the workload. For now, this serves as a quick way to enable RBD workloads with VolSync, and we can think of a better solution for 4.19. |
Signed-off-by: Benamar Mekhissi <[email protected]>
a542889
to
6f83287
Compare
|
||
break | ||
if !pvcEnabledForVolSync { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need the temporary variable? we can use:
if !util.IsPVCMarkedForVolSync(v.instance.GetAnnotations()) {
...
}
@@ -22,6 +22,9 @@ const ( | |||
OCMBackupLabelValue string = "ramen" | |||
|
|||
IsCGEnabledAnnotation = "drplacementcontrol.ramendr.openshift.io/is-cg-enabled" | |||
|
|||
// When this annotation is set to true, VolSync will protect RBD PVCs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be any storage, RBD is a good example but we don't care which storage is this.
if util.IsRBDEnabledForVolSyncReplication(v.owner.GetAnnotations()) && | ||
protectedPVC.VolumeMode != nil && | ||
*protectedPVC.VolumeMode == corev1.PersistentVolumeBlock { | ||
volumeMode = corev1.PersistentVolumeBlock |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you miss this comment?
Expect(pvc.GetName()).To(Equal(rdSpecForBlockPVC.ProtectedPVC.Name)) | ||
Expect(pvc.GetOwnerReferences()[0].Kind).To(Equal("ConfigMap")) | ||
Expect(*pvc.Spec.VolumeMode).To(Equal(corev1.PersistentVolumeBlock)) | ||
Expect(k8sClient.Delete(ctx, pvc)).ToNot(HaveOccurred()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you miss this comment?
|
||
return nil | ||
} | ||
if !pvcEnabledForVolSync { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, we could eliminate the temporary variable.
Merging changes, open comments do not impact functionality at present. |
This PR adds support for snapshotting and replicating RBD PVCs with Block VolumeMode using VolSync. Key changes include:
UseVolSyncForRBDAnnotation
to the DRPC resource to enable VolSync snapshotting and replication of RBD PVCs with Block VolumeMode on a per-instance basis.