Skip to content

Commit a19ca55

Browse files
committed
Add unit-test for lease held by another entity scenario
Check that we enter this scenario and act properly by exceeding max retries and having failed manitenance event. Before the fix the obtainLease function always returned (false, err) for any error, including AlreadyHeldError. In the reconciler, the condition err != nil && updateOwnedLeaseFailed was never true, so ErrorOnLeaseCount was never incremented — it was actually reset to 0 in the fallthrough if err != nil block. Now obtainLease function returns (true, err) specifically for AlreadyHeldError, so ErrorOnLeaseCount properly increments on each reconcile. After 4 iterations (> 3), the node is uncordoned and maintenance transitions to Failed.
1 parent d8b7eed commit a19ca55

2 files changed

Lines changed: 34 additions & 2 deletions

File tree

controllers/controllers_suite_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ var _ = BeforeSuite(func() {
9494
Client: k8sClient,
9595
Scheme: scheme.Scheme,
9696
MgrConfig: cfg,
97-
LeaseManager: &mockLeaseManager{mockManager},
97+
LeaseManager: &mockLeaseManager{Manager: mockManager},
9898
Recorder: fakeRecorder,
9999
logger: ctrl.Log.WithName("unit test"),
100100
}

controllers/nodemaintenance_controller_test.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,37 @@ var _ = Describe("Node Maintenance", func() {
260260
verifyNoEvent(corev1.EventTypeNormal, utils.EventReasonSucceedMaintenance, utils.EventMessageSucceedMaintenance)
261261
})
262262
})
263+
When("lease is already held by another entity", func() {
264+
BeforeEach(func() {
265+
originalLeaseManager := r.LeaseManager
266+
r.LeaseManager = &mockLeaseManager{
267+
Manager: originalLeaseManager.(*mockLeaseManager).Manager,
268+
requestLeaseErr: lease.AlreadyHeldError{},
269+
}
270+
DeferCleanup(func() {
271+
r.LeaseManager = originalLeaseManager
272+
})
273+
274+
nm = getTestNM("node-maintenance-lease-held", taintedNodeName)
275+
Expect(k8sClient.Create(ctx, nm)).To(Succeed())
276+
DeferCleanup(k8sClient.Delete, ctx, nm)
277+
})
278+
It("should increment ErrorOnLeaseCount and fail maintenance after exceeding max retries", func() {
279+
By("Waiting for ErrorOnLeaseCount to exceed the threshold and phase to become Failed")
280+
maintenance := &v1beta1.NodeMaintenance{}
281+
Eventually(func(g Gomega) {
282+
g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(nm), maintenance)).To(Succeed())
283+
g.Expect(maintenance.Status.ErrorOnLeaseCount).To(BeNumerically(">", maxAllowedErrorToUpdateOwnedLease))
284+
g.Expect(maintenance.Status.Phase).To(Equal(v1beta1.MaintenanceFailed))
285+
}, "3s", "250ms").Should(Succeed())
286+
287+
By("Verifying maintenance failed event was emitted")
288+
verifyEvent(corev1.EventTypeWarning, utils.EventReasonFailedMaintenance, utils.EventMessageFailedMaintenance)
289+
290+
By("Verifying LastError mentions lease contention")
291+
Expect(maintenance.Status.LastError).To(ContainSubstring("failed to extend lease owned by us"))
292+
})
293+
})
263294
})
264295
})
265296

@@ -413,8 +444,9 @@ func clearEvents() {
413444

414445
type mockLeaseManager struct {
415446
lease.Manager
447+
requestLeaseErr error
416448
}
417449

418450
func (mock *mockLeaseManager) RequestLease(_ context.Context, _ client.Object, _ time.Duration) error {
419-
return nil
451+
return mock.requestLeaseErr
420452
}

0 commit comments

Comments
 (0)