@@ -5,11 +5,13 @@ package controllers
55
66import (
77 "fmt"
8+ "time"
89
910 "k8s.io/apimachinery/pkg/api/meta"
1011 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1112
1213 rmn "github.com/ramendr/ramen/api/v1alpha1"
14+ rmnutil "github.com/ramendr/ramen/internal/controller/util"
1315)
1416
1517func updateProtectedConditionUnknown (drpc * rmn.DRPlacementControl , clusterName string ) {
@@ -29,16 +31,17 @@ func updateDRPCProtectedCondition(
2931 drpc * rmn.DRPlacementControl ,
3032 vrg * rmn.VolumeReplicationGroup ,
3133 clusterName string ,
34+ vrgs map [string ]* rmn.VolumeReplicationGroup ,
3235) {
3336 if updateVRGClusterDataReady (drpc , vrg , clusterName ) {
3437 return
3538 }
3639
37- if updateDRPCProtectedForReplicationState (drpc , vrg , clusterName ) {
40+ if updateDRPCProtectedForReplicationState (drpc , vrg , clusterName , vrgs ) {
3841 return
3942 }
4043
41- if updateVRGNoClusterDataConflict (drpc , vrg , clusterName ) {
44+ if updateVRGNoClusterDataConflict (drpc , vrg , vrgs ) {
4245 return
4346 }
4447
@@ -65,13 +68,19 @@ func updateDRPCProtectedForReplicationState(
6568 drpc * rmn.DRPlacementControl ,
6669 vrg * rmn.VolumeReplicationGroup ,
6770 clusterName string ,
71+ vrgs map [string ]* rmn.VolumeReplicationGroup ,
6872) bool {
73+ var fromCluster string
74+
75+ drpc .Status .ResourceConditions .Conditions , fromCluster = mergeVRGsConditions (
76+ vrgs , vrg , VRGConditionTypeDataReady )
77+
6978 switch vrg .Spec .ReplicationState {
7079 case rmn .Primary :
71- return updateVRGDataReadyAsPrimary (drpc , vrg , clusterName ) ||
80+ return updateVRGDataReadyAsPrimary (drpc , vrg , fromCluster ) ||
7281 updateVRGDataProtectedAsPrimary (drpc , vrg , clusterName )
7382 case rmn .Secondary :
74- return updateVRGDataReadyAsSecondary (drpc , vrg , clusterName ) ||
83+ return updateVRGDataReadyAsSecondary (drpc , vrg , fromCluster ) ||
7584 updateVRGDataProtectedAsSecondary (drpc , vrg , clusterName )
7685 }
7786
@@ -186,8 +195,13 @@ func updateVRGDataProtectedAsPrimary(drpc *rmn.DRPlacementControl,
186195// - Returns a bool that is true if status was updated, and false otherwise
187196func updateVRGNoClusterDataConflict (drpc * rmn.DRPlacementControl ,
188197 vrg * rmn.VolumeReplicationGroup ,
189- clusterName string ,
198+ vrgs map [ string ] * rmn. VolumeReplicationGroup ,
190199) bool {
200+ var clusterName string
201+
202+ drpc .Status .ResourceConditions .Conditions , clusterName = mergeVRGsConditions (
203+ vrgs , vrg , VRGConditionTypeNoClusterDataConflict )
204+
191205 return genericUpdateProtectedForCondition (drpc , vrg , clusterName , VRGConditionTypeNoClusterDataConflict ,
192206 "workload data protection" , "checking for workload data conflict" , "conflicting workload data" )
193207}
@@ -306,3 +320,87 @@ func updateMiscVRGStatus(drpc *rmn.DRPlacementControl,
306320
307321 return ! updated
308322}
323+
324+ // findConflictCondition selects the appropriate condition from VRGs based on the conflict type.
325+ func findConflictCondition (vrgs map [string ]* rmn.VolumeReplicationGroup ,
326+ conflictType string ,
327+ ) (* metav1.Condition , string ) {
328+ var selectedCondition * metav1.Condition
329+
330+ var clusterName string
331+
332+ for _ , vrg := range vrgs {
333+ condition := meta .FindStatusCondition (vrg .Status .Conditions , conflictType )
334+ if condition != nil && condition .Status == metav1 .ConditionFalse {
335+ // Prioritize primary VRG's condition if available
336+ clusterName = vrg .GetAnnotations ()[DestinationClusterAnnotationKey ]
337+ if isVRGPrimary (vrg ) {
338+ return condition , clusterName // Exit early if primary VRG condition is found
339+ }
340+
341+ // Assign the first non-primary VRG's condition if no primary found yet
342+ if selectedCondition == nil {
343+ selectedCondition = condition
344+ }
345+ }
346+ }
347+
348+ return selectedCondition , clusterName
349+ }
350+
351+ // mergeVRGsConditions assigns conditions from a given VRG while prioritizing conflict conditions.
352+ func mergeVRGsConditions (vrgs map [string ]* rmn.VolumeReplicationGroup ,
353+ vrg * rmn.VolumeReplicationGroup , conflictType string ,
354+ ) ([]metav1.Condition , string ) {
355+ conditions := & vrg .Status .Conditions
356+ conflictCondition , clusterName := findConflictCondition (vrgs , conflictType )
357+
358+ // Ensure the conflict condition is present in the conditions list
359+ if conflictCondition != nil {
360+ setConflictStatusCondition (conditions , * conflictCondition )
361+ }
362+
363+ return * conditions , clusterName
364+ }
365+
366+ func setConflictStatusCondition (existingConditions * []metav1.Condition ,
367+ newCondition metav1.Condition ,
368+ ) metav1.Condition {
369+ if existingConditions == nil {
370+ existingConditions = & []metav1.Condition {}
371+ }
372+
373+ existingCondition := rmnutil .FindCondition (* existingConditions , newCondition .Type )
374+ if existingCondition == nil {
375+ newCondition .LastTransitionTime = metav1 .NewTime (time .Now ())
376+ * existingConditions = append (* existingConditions , newCondition )
377+
378+ return newCondition
379+ }
380+
381+ if existingCondition .Status != newCondition .Status ||
382+ existingCondition .Reason != newCondition .Reason {
383+ existingCondition .Status = newCondition .Status
384+ existingCondition .Reason = newCondition .Reason
385+ existingCondition .LastTransitionTime = metav1 .NewTime (time .Now ())
386+ }
387+
388+ defaultValue := "none"
389+ if newCondition .Reason == "" {
390+ newCondition .Reason = defaultValue
391+ }
392+
393+ if newCondition .Message == "" {
394+ newCondition .Message = defaultValue
395+ }
396+
397+ existingCondition .Reason = newCondition .Reason
398+ existingCondition .Message = newCondition .Message
399+ // TODO: Why not update lastTranTime if the above change?
400+
401+ if existingCondition .ObservedGeneration != newCondition .ObservedGeneration {
402+ existingCondition .LastTransitionTime = metav1 .NewTime (time .Now ())
403+ }
404+
405+ return * existingCondition
406+ }
0 commit comments