Skip to content

Commit 36b1eae

Browse files
GowthamShanmugampruthvitd
authored andcommitted
Check for PVC label selector conflicts and merge conflict conditions
Handles the PVC conflict across primary and secondary clusters. And priotize the conflict on primary cluster over the secondary. Signed-off-by: pruthvitd <[email protected]>
1 parent 1864982 commit 36b1eae

File tree

3 files changed

+167
-8
lines changed

3 files changed

+167
-8
lines changed

internal/controller/status.go

+12-5
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,16 @@ const (
4040
// protected from a disaster by uploading it to the required S3 store(s).
4141
VRGConditionTypeClusterDataProtected = "ClusterDataProtected"
4242

43-
VRGConditionTypeNoClusterDataConflict = "NoClusterDataConflict"
44-
4543
// VolSync related conditions. These conditions are only applicable
4644
// at individual PVCs and not generic VRG conditions.
4745
VRGConditionTypeVolSyncRepSourceSetup = "ReplicationSourceSetup"
4846
VRGConditionTypeVolSyncFinalSyncInProgress = "FinalSyncInProgress"
4947
VRGConditionTypeVolSyncRepDestinationSetup = "ReplicationDestinationSetup"
5048
VRGConditionTypeVolSyncPVsRestored = "PVsRestored"
49+
50+
// Indicates no conflict in PVC and Kubernetes resource data
51+
// between primary and secondary clusters.
52+
VRGConditionTypeNoClusterDataConflict = "NoClusterDataConflict"
5153
)
5254

5355
// VRG condition reasons
@@ -76,9 +78,14 @@ const (
7678
VRGConditionReasonClusterDataAnnotationFailed = "AnnotationFailed"
7779
VRGConditionReasonPeerClassNotFound = "PeerClassNotFound"
7880
VRGConditionReasonStorageIDNotFound = "StorageIDNotFound"
79-
VRGConditionReasonDataConflictPrimary = "ClusterDataConflictPrimary"
80-
VRGConditionReasonDataConflictSecondary = "ClusterDataConflictSecondary"
81-
VRGConditionReasonConflictResolved = "ConflictResolved"
81+
// Indicates a conflict in cluster data detected on the primary cluster.
82+
VRGConditionReasonClusterDataConflictPrimary = "ClusterDataConflictPrimary"
83+
84+
// Indicates a conflict in cluster data detected on the secondary cluster.
85+
VRGConditionReasonClusterDataConflictSecondary = "ClusterDataConflictSecondary"
86+
87+
// Indicates no conflict in cluster data detected on both the primary and secondary cluster.
88+
VRGConditionReasonConflictResolved = "ConflictResolved"
8289
)
8390

8491
const (

internal/controller/volumereplicationgroup_controller.go

+107-3
Original file line numberDiff line numberDiff line change
@@ -1847,10 +1847,11 @@ func (v *VRGInstance) updateVRGConditions() {
18471847
v.log.Info(msg, "finalCondition", finalCondition)
18481848
}
18491849

1850-
var volSyncDataReady, volSyncDataProtected, volSyncClusterDataProtected *metav1.Condition
1850+
var volSyncDataReady, volSyncDataProtected, volSyncClusterDataProtected, volSyncClusterDataConflict *metav1.Condition
18511851
if v.instance.Spec.Sync == nil {
18521852
volSyncDataReady = v.aggregateVolSyncDataReadyCondition()
18531853
volSyncDataProtected, volSyncClusterDataProtected = v.aggregateVolSyncDataProtectedConditions()
1854+
volSyncClusterDataConflict = v.aggregateVolSyncClusterDataConflictCondition()
18541855
}
18551856

18561857
logAndSet(VRGConditionTypeDataReady,
@@ -1869,6 +1870,7 @@ func (v *VRGInstance) updateVRGConditions() {
18691870
v.kubeObjectsProtected,
18701871
)
18711872
logAndSet(VRGConditionTypeNoClusterDataConflict,
1873+
volSyncClusterDataConflict,
18721874
v.aggregateVRGNoClusterDataConflictCondition(),
18731875
)
18741876
v.updateVRGLastGroupSyncTime()
@@ -2263,6 +2265,60 @@ func (v *VRGInstance) CheckForVMNameConflictOnSecondary(vmNamespaceList, vmList
22632265
}
22642266

22652267
func (v *VRGInstance) aggregateVRGNoClusterDataConflictCondition() *metav1.Condition {
2268+
var vmResourceConflict, pvcResourceConflict bool
2269+
vmResourceConflict = false
2270+
pvcResourceConflict = false
2271+
2272+
vmConflictCondition := v.aggregateVMNoClusterDataConflictCondition()
2273+
2274+
if vmConflictCondition != nil {
2275+
if vmConflictCondition.Status == metav1.ConditionFalse {
2276+
vmResourceConflict = true
2277+
}
2278+
}
2279+
2280+
pvcConflictCondition := v.aggregateVolRepClusterDataConflictCondition()
2281+
2282+
if pvcConflictCondition != nil {
2283+
if vmConflictCondition.Status == metav1.ConditionFalse {
2284+
pvcResourceConflict = true
2285+
}
2286+
}
2287+
2288+
if !vmResourceConflict && !pvcResourceConflict {
2289+
return vmConflictCondition
2290+
}
2291+
2292+
// Priortize the resource conflict condition on Primary cluster
2293+
if vmResourceConflict && pvcResourceConflict {
2294+
return v.PriortizePrimaryClusterDataConflictCondition(vmConflictCondition, pvcConflictCondition)
2295+
}
2296+
2297+
if vmResourceConflict {
2298+
return vmConflictCondition
2299+
}
2300+
2301+
return pvcConflictCondition
2302+
}
2303+
2304+
func (v *VRGInstance) PriortizePrimaryClusterDataConflictCondition(
2305+
vmConflictCondition, pvcConflictCondition *metav1.Condition,
2306+
) *metav1.Condition {
2307+
if vmConflictCondition.Reason == pvcConflictCondition.Reason {
2308+
vmConflictCondition.Message = fmt.Sprintf("Both VM and PVC resource conflicting on %s cluster",
2309+
v.instance.Spec.ReplicationState)
2310+
2311+
return vmConflictCondition
2312+
}
2313+
2314+
if vmConflictCondition.Reason == VRGConditionReasonClusterDataConflictPrimary {
2315+
return vmConflictCondition
2316+
}
2317+
2318+
return pvcConflictCondition
2319+
}
2320+
2321+
func (v *VRGInstance) aggregateVMNoClusterDataConflictCondition() *metav1.Condition {
22662322
var msg string
22672323

22682324
if v.isVMRecipeProtection() {
@@ -2282,11 +2338,11 @@ func (v *VRGInstance) aggregateVRGNoClusterDataConflictCondition() *metav1.Condi
22822338
func (v *VRGInstance) clusterDataConflict(msg string, status metav1.ConditionStatus) *metav1.Condition {
22832339
if v.instance.Spec.ReplicationState == ramendrv1alpha1.Primary {
22842340
return updateVRGNoClusterDataConflictCondition(
2285-
v.instance.Status.ObservedGeneration, status, VRGConditionReasonDataConflictPrimary,
2341+
v.instance.Status.ObservedGeneration, status, VRGConditionReasonClusterDataConflictPrimary,
22862342
msg)
22872343
} else if v.instance.Spec.ReplicationState == ramendrv1alpha1.Secondary {
22882344
return updateVRGNoClusterDataConflictCondition(
2289-
v.instance.Status.ObservedGeneration, status, VRGConditionReasonDataConflictSecondary,
2345+
v.instance.Status.ObservedGeneration, status, VRGConditionReasonClusterDataConflictSecondary,
22902346
msg)
22912347
}
22922348

@@ -2302,3 +2358,51 @@ func (v *VRGInstance) isVMRecipeProtection() bool {
23022358

23032359
return false
23042360
}
2361+
2362+
func (v *VRGInstance) aggregateVolRepClusterDataConflictCondition() *metav1.Condition {
2363+
noClusterDataConflictCondition := &metav1.Condition{
2364+
Status: metav1.ConditionTrue,
2365+
Type: VRGConditionTypeNoClusterDataConflict,
2366+
Reason: VRGConditionReasonConflictResolved,
2367+
ObservedGeneration: v.instance.Generation,
2368+
Message: "No PVC conflict detected for VolumeReplication scheme",
2369+
}
2370+
2371+
if conflictCondition := v.validateSecondaryPVCConflictForVolRep(); conflictCondition != nil {
2372+
return conflictCondition
2373+
}
2374+
2375+
return noClusterDataConflictCondition
2376+
}
2377+
2378+
func (v *VRGInstance) IsSecondaryVRG() bool {
2379+
spec := v.instance.Spec
2380+
status := v.instance.Status
2381+
2382+
isSecondary := spec.ReplicationState == ramendrv1alpha1.Secondary
2383+
isStateSecondary := status.State == ramendrv1alpha1.SecondaryState
2384+
isRelocateOrNone := spec.Action == ramendrv1alpha1.VRGActionRelocate || spec.Action == ""
2385+
isPrepareForFinalSyncFalse := !spec.PrepareForFinalSync
2386+
isRunFinalSyncFalse := !spec.RunFinalSync
2387+
2388+
return isSecondary &&
2389+
isStateSecondary &&
2390+
isRelocateOrNone &&
2391+
isPrepareForFinalSyncFalse &&
2392+
isRunFinalSyncFalse
2393+
}
2394+
2395+
func (v *VRGInstance) isSecondaryWithVolRepProtectedPVCs() bool {
2396+
return v.IsSecondaryVRG() && len(v.volRepPVCs) > 0
2397+
}
2398+
2399+
func (v *VRGInstance) validateSecondaryPVCConflictForVolRep() *metav1.Condition {
2400+
if v.isSecondaryWithVolRepProtectedPVCs() {
2401+
return updateVRGNoClusterDataConflictCondition(
2402+
v.instance.Generation, metav1.ConditionFalse, VRGConditionReasonClusterDataConflictSecondary,
2403+
"No PVC on the secondary should match the label selector",
2404+
)
2405+
}
2406+
2407+
return nil
2408+
}

internal/controller/vrg_volsync.go

+48
Original file line numberDiff line numberDiff line change
@@ -639,3 +639,51 @@ func (v *VRGInstance) doCleanupResources(name, namespace string) error {
639639

640640
return nil
641641
}
642+
643+
func (v *VRGInstance) isSecondaryWithVolSyncProtectedPVCs() bool {
644+
return v.IsSecondaryVRG() && len(v.volSyncPVCs) > 0
645+
}
646+
647+
func (v *VRGInstance) validateSecondaryPVCConflictForVolsync() bool {
648+
if !v.isSecondaryWithVolSyncProtectedPVCs() {
649+
return false
650+
}
651+
652+
// Validate that only replication destination PVCs match the label selector.
653+
for _, pvc := range v.volSyncPVCs {
654+
matchFound := false
655+
656+
for _, rdSpec := range v.instance.Spec.VolSync.RDSpec {
657+
if pvc.GetName() == rdSpec.ProtectedPVC.Name {
658+
matchFound = true
659+
660+
break // Found a match, no need to check further for this PVC
661+
}
662+
}
663+
664+
if !matchFound {
665+
return true // No match found for this PVC, conflict detected!
666+
}
667+
}
668+
669+
return false // No conflicts found
670+
}
671+
672+
func (v *VRGInstance) aggregateVolSyncClusterDataConflictCondition() *metav1.Condition {
673+
noClusterDataConflictCondition := &metav1.Condition{
674+
Status: metav1.ConditionTrue,
675+
Type: VRGConditionTypeNoClusterDataConflict,
676+
Reason: VRGConditionReasonConflictResolved,
677+
ObservedGeneration: v.instance.Generation,
678+
Message: "No PVC conflict detected for VolumeSync scheme",
679+
}
680+
681+
if v.validateSecondaryPVCConflictForVolsync() {
682+
return updateVRGNoClusterDataConflictCondition(v.instance.Generation,
683+
metav1.ConditionFalse, VRGConditionReasonClusterDataConflictSecondary,
684+
"A PVC that is not a replication destination should not match the label selector.",
685+
)
686+
}
687+
688+
return noClusterDataConflictCondition
689+
}

0 commit comments

Comments
 (0)