Skip to content

Commit 6ec40cf

Browse files
Merge pull request #2827 from Nordix/tuomo/fix-bmo-optional-flakyness
🌱 E2E: Fix race condition in upgrade tests
2 parents 107cf2e + 6fe0f3b commit 6ec40cf

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

test/e2e/common.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,40 @@ func PatchBMHForProvisioning(ctx context.Context, input PatchBMHForProvisioningI
142142
return helper.Patch(ctx, input.bmh)
143143
}
144144

145+
// WaitForBmhReconciled waits for the BMO controller to process a BMH update.
146+
// This is used after BMO deployment rollout to ensure the controller is actually
147+
// processing events before making further changes. It works by adding/updating
148+
// an annotation and waiting for the status.lastUpdated timestamp to change,
149+
// which proves the controller reconciled the BMH.
150+
func WaitForBmhReconciled(ctx context.Context, c client.Client, bmh metal3api.BareMetalHost, intervals ...interface{}) {
151+
// Get the current BMH state
152+
key := types.NamespacedName{Namespace: bmh.Namespace, Name: bmh.Name}
153+
currentBmh := &metal3api.BareMetalHost{}
154+
Expect(c.Get(ctx, key, currentBmh)).To(Succeed())
155+
initialLastUpdated := currentBmh.Status.LastUpdated
156+
157+
// Touch the BMH with an annotation update to trigger a reconcile
158+
helper, err := patch.NewHelper(currentBmh, c)
159+
Expect(err).NotTo(HaveOccurred())
160+
if currentBmh.Annotations == nil {
161+
currentBmh.Annotations = make(map[string]string)
162+
}
163+
currentBmh.Annotations["e2e.metal3.io/reconcile-check"] = metav1.Now().Format("2006-01-02T15:04:05Z")
164+
Expect(helper.Patch(ctx, currentBmh)).To(Succeed())
165+
166+
// Wait for lastUpdated to change, proving the controller processed our update
167+
Eventually(func(g Gomega) {
168+
updatedBmh := &metal3api.BareMetalHost{}
169+
g.Expect(c.Get(ctx, key, updatedBmh)).To(Succeed())
170+
// Check that lastUpdated has changed (controller reconciled)
171+
g.Expect(updatedBmh.Status.LastUpdated).NotTo(BeNil(), "BMH status.lastUpdated should not be nil")
172+
if initialLastUpdated != nil {
173+
g.Expect(updatedBmh.Status.LastUpdated.Before(initialLastUpdated)).To(BeFalse(),
174+
"BMH status.lastUpdated should have been updated by controller")
175+
}
176+
}, intervals...).Should(Succeed())
177+
}
178+
145179
// DeleteBmhsInNamespace deletes all BMHs in the given namespace.
146180
func DeleteBmhsInNamespace(ctx context.Context, deleter client.Client, namespace string) {
147181
bmh := metal3api.BareMetalHost{}

test/e2e/upgrade_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,14 @@ func RunUpgradeTest(ctx context.Context, input *BMOIronicUpgradeInput, upgradeCl
319319
})
320320
}
321321

322+
// After deployment rollout, wait for the BMO controller to actually be processing events.
323+
// There's a race condition where the deployment is "available" but the new pod hasn't
324+
// acquired the leader lease yet or hasn't started its watches. If we patch the BMH
325+
// during this window, the controller may miss the update event.
326+
By("Waiting for BMO controller to be ready to process events")
327+
WaitForBmhReconciled(ctx, upgradeClusterProxy.GetClient(), bmh,
328+
e2eConfig.GetIntervals("default", "wait-deployment")...)
329+
322330
By("Patching the BMH to test provisioning")
323331
// Using Eventually here since the webhook can take some time after the deployment is ready
324332
Eventually(func() error {

0 commit comments

Comments
 (0)