Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions internal/controller/controllers_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,12 @@ func updateDRClusterConfigMWStatus(k8sClient client.Client, apiReader client.Rea
}

func updateMWAsApplied(k8sClient client.Client, apiReader client.Reader, key types.NamespacedName) {
mw := &workv1.ManifestWork{}

// Wait for ManifestWork to exist and be stable
Eventually(func() bool {
mw := &workv1.ManifestWork{}
err := apiReader.Get(context.TODO(), key, mw)

return err == nil
return err == nil && mw.ResourceVersion != ""
}, timeout, interval).Should(BeTrue(),
fmt.Sprintf("failed to get manifest %s for DRCluster %s", key.Name, key.Namespace))

Expand All @@ -160,6 +160,9 @@ func updateMWAsApplied(k8sClient client.Client, apiReader client.Reader, key typ
}

retryErr := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
// Always get a fresh copy of the MW to avoid UID mismatches from concurrent updates
mw := &workv1.ManifestWork{}

err := apiReader.Get(context.TODO(), key, mw)
if err != nil {
return err
Expand Down
41 changes: 36 additions & 5 deletions internal/controller/drplacementcontrol_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package controllers_test
import (
"context"
"fmt"
"reflect"
"runtime"
"strings"
"time"
Expand Down Expand Up @@ -793,9 +794,33 @@ func createDRClustersAsync() {
createDRClusters(asyncClusters)
}

//nolint:gocognit
func createDRPolicy(inDRPolicy *rmn.DRPolicy) {
// Try to create the DRPolicy, but handle AlreadyExists gracefully
err := k8sClient.Create(context.TODO(), inDRPolicy)
Expect(err).NotTo(HaveOccurred())
if err != nil {
if k8serrors.IsAlreadyExists(err) {
// DRPolicy already exists, update it to trigger reconciliation if spec differs
existingDRPolicy := &rmn.DRPolicy{}
err = k8sClient.Get(context.TODO(),
types.NamespacedName{Name: inDRPolicy.Name}, existingDRPolicy)
Expect(err).NotTo(HaveOccurred())

// Update spec if it differs to trigger reconciliation
if !reflect.DeepEqual(existingDRPolicy.Spec, inDRPolicy.Spec) {
existingDRPolicy.Spec = inDRPolicy.Spec
err = k8sClient.Update(context.TODO(), existingDRPolicy)
Expect(err).NotTo(HaveOccurred())
}

// Copy the existing policy back to inDRPolicy for validation
*inDRPolicy = *existingDRPolicy
} else {
// Some other error occurred
Expect(err).NotTo(HaveOccurred())
}
}

Eventually(func() bool {
drpolicy := &rmn.DRPolicy{}
Expect(apiReader.Get(context.TODO(), types.NamespacedName{Name: inDRPolicy.Name}, drpolicy)).To(Succeed())
Expand Down Expand Up @@ -1192,8 +1217,10 @@ func waitForDRPCProtected(namespace string) {
drpc := getLatestDRPC(namespace)
_, cond := getDRPCCondition(&drpc.Status, rmn.ConditionProtected)

return cond != nil && cond.Status == metav1.ConditionTrue
}, timeout, interval).Should(BeTrue())
return cond != nil &&
cond.ObservedGeneration <= drpc.Generation &&
cond.Status == metav1.ConditionTrue
}, timeout*2, interval).Should(BeTrue())
}

func getPlacementDecision(plName, plNamespace string) *clrapiv1beta1.PlacementDecision {
Expand Down Expand Up @@ -1263,6 +1290,7 @@ func verifyDRPCStatusPreferredClusterExpectation(namespace string, drState rmn.D

return d.ClusterName == East1ManagedCluster &&
idx != -1 &&
condition.ObservedGeneration <= updatedDRPC.Generation &&
condition.Reason == string(drState) &&
len(updatedDRPC.Status.ResourceConditions.ResourceMeta.ProtectedPVCs) == ProtectedPVCCount
}
Expand Down Expand Up @@ -2835,14 +2863,17 @@ func checkConditionAllowFailover(namespace string) {
drpc = getLatestDRPC(namespace)
for _, availableCondition = range drpc.Status.Conditions {
if availableCondition.Type != rmn.ConditionPeerReady {
if availableCondition.Status == metav1.ConditionTrue {
// Verify condition is for current generation to avoid stale conditions
if availableCondition.ObservedGeneration <= drpc.Generation &&
availableCondition.Status == metav1.ConditionTrue {
return true
}
}
}

return false
}, timeout, interval).Should(BeTrue(), fmt.Sprintf("Condition '%+v'", availableCondition))
}, timeout, interval).Should(
BeTrue(), fmt.Sprintf("Condition '%+v' for DRPC generation %d", availableCondition, drpc.Generation))

Expect(drpc.Status.Phase).To(Equal(rmn.WaitForUser))
}
Expand Down
Loading