@@ -5,8 +5,10 @@ package controllers
55
66import (
77 "fmt"
8+ "time"
89
910 rmn "github.com/ramendr/ramen/api/v1alpha1"
11+ rmnutil "github.com/ramendr/ramen/internal/controller/util"
1012 "k8s.io/apimachinery/pkg/api/meta"
1113 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1214)
@@ -28,16 +30,17 @@ func updateDRPCProtectedCondition(
2830 drpc * rmn.DRPlacementControl ,
2931 vrg * rmn.VolumeReplicationGroup ,
3032 clusterName string ,
33+ vrgs map [string ]* rmn.VolumeReplicationGroup ,
3134) {
3235 if updateVRGClusterDataReady (drpc , vrg , clusterName ) {
3336 return
3437 }
3538
36- if updateDRPCProtectedForReplicationState (drpc , vrg , clusterName ) {
39+ if updateDRPCProtectedForReplicationState (drpc , vrg , clusterName , vrgs ) {
3740 return
3841 }
3942
40- if updateVRGNoClusterDataConflict (drpc , vrg , clusterName ) {
43+ if updateVRGNoClusterDataConflict (drpc , vrg , vrgs ) {
4144 return
4245 }
4346
@@ -64,13 +67,19 @@ func updateDRPCProtectedForReplicationState(
6467 drpc * rmn.DRPlacementControl ,
6568 vrg * rmn.VolumeReplicationGroup ,
6669 clusterName string ,
70+ vrgs map [string ]* rmn.VolumeReplicationGroup ,
6771) bool {
72+ var fromCluster string
73+
74+ drpc .Status .ResourceConditions .Conditions , fromCluster = mergeVRGsConditions (
75+ vrgs , vrg , VRGConditionTypeDataReady )
76+
6877 switch vrg .Spec .ReplicationState {
6978 case rmn .Primary :
70- return updateVRGDataReadyAsPrimary (drpc , vrg , clusterName ) ||
79+ return updateVRGDataReadyAsPrimary (drpc , vrg , fromCluster ) ||
7180 updateVRGDataProtectedAsPrimary (drpc , vrg , clusterName )
7281 case rmn .Secondary :
73- return updateVRGDataReadyAsSecondary (drpc , vrg , clusterName ) ||
82+ return updateVRGDataReadyAsSecondary (drpc , vrg , fromCluster ) ||
7483 updateVRGDataProtectedAsSecondary (drpc , vrg , clusterName )
7584 }
7685
@@ -185,8 +194,13 @@ func updateVRGDataProtectedAsPrimary(drpc *rmn.DRPlacementControl,
185194// - Returns a bool that is true if status was updated, and false otherwise
186195func updateVRGNoClusterDataConflict (drpc * rmn.DRPlacementControl ,
187196 vrg * rmn.VolumeReplicationGroup ,
188- clusterName string ,
197+ vrgs map [ string ] * rmn. VolumeReplicationGroup ,
189198) bool {
199+ var clusterName string
200+
201+ drpc .Status .ResourceConditions .Conditions , clusterName = mergeVRGsConditions (
202+ vrgs , vrg , VRGConditionTypeNoClusterDataConflict )
203+
190204 return genericUpdateProtectedForCondition (drpc , vrg , clusterName , VRGConditionTypeNoClusterDataConflict ,
191205 "workload data protection" , "checking for workload data conflict" , "conflicting workload data" )
192206}
@@ -305,3 +319,87 @@ func updateMiscVRGStatus(drpc *rmn.DRPlacementControl,
305319
306320 return ! updated
307321}
322+
323+ // findConflictCondition selects the appropriate condition from VRGs based on the conflict type.
324+ func findConflictCondition (vrgs map [string ]* rmn.VolumeReplicationGroup ,
325+ conflictType string ,
326+ ) (* metav1.Condition , string ) {
327+ var selectedCondition * metav1.Condition
328+
329+ var clusterName string
330+
331+ for _ , vrg := range vrgs {
332+ condition := meta .FindStatusCondition (vrg .Status .Conditions , conflictType )
333+ if condition != nil && condition .Status == metav1 .ConditionFalse {
334+ // Prioritize primary VRG's condition if available
335+ clusterName = vrg .GetAnnotations ()[DestinationClusterAnnotationKey ]
336+ if isVRGPrimary (vrg ) {
337+ return condition , clusterName // Exit early if primary VRG condition is found
338+ }
339+
340+ // Assign the first non-primary VRG's condition if no primary found yet
341+ if selectedCondition == nil {
342+ selectedCondition = condition
343+ }
344+ }
345+ }
346+
347+ return selectedCondition , clusterName
348+ }
349+
350+ // mergeVRGsConditions assigns conditions from a given VRG while prioritizing conflict conditions.
351+ func mergeVRGsConditions (vrgs map [string ]* rmn.VolumeReplicationGroup ,
352+ vrg * rmn.VolumeReplicationGroup , conflictType string ,
353+ ) ([]metav1.Condition , string ) {
354+ conditions := & vrg .Status .Conditions
355+ conflictCondition , clusterName := findConflictCondition (vrgs , conflictType )
356+
357+ // Ensure the conflict condition is present in the conditions list
358+ if conflictCondition != nil {
359+ setConflictStatusCondition (conditions , * conflictCondition )
360+ }
361+
362+ return * conditions , clusterName
363+ }
364+
365+ func setConflictStatusCondition (existingConditions * []metav1.Condition ,
366+ newCondition metav1.Condition ,
367+ ) metav1.Condition {
368+ if existingConditions == nil {
369+ existingConditions = & []metav1.Condition {}
370+ }
371+
372+ existingCondition := rmnutil .FindCondition (* existingConditions , newCondition .Type )
373+ if existingCondition == nil {
374+ newCondition .LastTransitionTime = metav1 .NewTime (time .Now ())
375+ * existingConditions = append (* existingConditions , newCondition )
376+
377+ return newCondition
378+ }
379+
380+ if existingCondition .Status != newCondition .Status ||
381+ existingCondition .Reason != newCondition .Reason {
382+ existingCondition .Status = newCondition .Status
383+ existingCondition .Reason = newCondition .Reason
384+ existingCondition .LastTransitionTime = metav1 .NewTime (time .Now ())
385+ }
386+
387+ defaultValue := "none"
388+ if newCondition .Reason == "" {
389+ newCondition .Reason = defaultValue
390+ }
391+
392+ if newCondition .Message == "" {
393+ newCondition .Message = defaultValue
394+ }
395+
396+ existingCondition .Reason = newCondition .Reason
397+ existingCondition .Message = newCondition .Message
398+ // TODO: Why not update lastTranTime if the above change?
399+
400+ if existingCondition .ObservedGeneration != newCondition .ObservedGeneration {
401+ existingCondition .LastTransitionTime = metav1 .NewTime (time .Now ())
402+ }
403+
404+ return * existingCondition
405+ }
0 commit comments