Skip to content

e2e: add controller recovery test - #152

Open
ptalgulk01 wants to merge 1 commit into
bootc-dev:mainfrom
ptalgulk01:e2e-controller-recovery
Open

e2e: add controller recovery test#152
ptalgulk01 wants to merge 1 commit into
bootc-dev:mainfrom
ptalgulk01:e2e-controller-recovery

Conversation

@ptalgulk01

Copy link
Copy Markdown
Collaborator

Summary

  • Add TestControllerRecovery e2e test that verifies the controller recovers after being killed and completes a pending rollout
  • The test scales the controller deployment to zero, patches the pool to a new image, then restores the controller and asserts the rollout completes

Context

Part of the e2e test planning in #69 (scenario 5: kill controller/daemon during rollout).

Manual testing also revealed that scenarios 4 (faulty node after reboot) and 8 (cross-distro bad image) both fail — the controller has no reboot timeout and doesn't correlate Node.Ready status, so nodes stuck after reboot are never marked degraded. Those need feature work before tests can be written.

Test plan

  • make e2e V=1 RUN=TestControllerRecovery passes locally (159s)

@ptalgulk01

Copy link
Copy Markdown
Collaborator Author

/cc @alicefr @HarshwardhanPatil07

Comment thread test/e2e/bootcnode_test.go Outdated
Comment on lines +640 to +665
// Phase 3: Patch pool to update image while controller is down.
updateRef := env.NodeImageUpdateDigestedPullSpec()

poolModified := pool.DeepCopy()
poolModified.Spec.Image.Ref = updateRef
g.Expect(env.Client.Patch(ctx, poolModified, client.MergeFrom(pool))).To(Succeed())
*pool = *poolModified

t.Logf("Patched pool to update image %s while controller is down", updateRef)

// Wait briefly to confirm nothing happens while controller is down.
g.Consistently(func() (bootcv1alpha1.BootcNodeStatus, error) {
var bn bootcv1alpha1.BootcNode
err := env.Client.Get(ctx, client.ObjectKey{Name: nodeName}, &bn)
return bn.Status, err
}).WithTimeout(10*time.Second).WithPolling(2*time.Second).Should(
HaveField("Booted.ImageDigest", Equal(env.NodeImageDigest())),
"node should not update while controller is down",
)

// Phase 4: Scale controller back to one.
g.Expect(env.Client.Get(ctx, deployKey, controllerDeploy)).To(Succeed())
modified = controllerDeploy.DeepCopy()
one := int32(1)
modified.Spec.Replicas = &one
g.Expect(env.Client.Patch(ctx, modified, client.MergeFrom(controllerDeploy))).To(Succeed())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test never interrupts an active rollout

The image changes while the controller is already stopped, so restart simply begins a new rollout.

@HarshwardhanPatil07 HarshwardhanPatil07 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will need to sign DCO

@ptalgulk01
ptalgulk01 force-pushed the e2e-controller-recovery branch from e14d71b to f5b290b Compare September 2, 2026 16:41
Signed-off-by: Prachiti Talgulkar <ptalgulk01@users.noreply.github.com>
@ptalgulk01
ptalgulk01 force-pushed the e2e-controller-recovery branch from f5b290b to 307a246 Compare September 7, 2026 11:35

t.Logf("Rollout in progress; interrupting the controller")

// Phase 4: Scale the controller to zero, interrupting the active rollout.

@alicefr alicefr Sep 11, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should pause the pool at this stage. I'm afraid that if the pulling is fast enough, the node might go in rebooting before scale down the controller, and it is a possible source for race conditions. Would it make sense to pause it when we detect the staging, scale down the operator and unpause it?

Comment on lines +659 to +692
deployKey := client.ObjectKey{
Namespace: "bootc-operator",
Name: "bootc-operator-controller-manager",
}
// Restore replicas on cleanup in case the test fails while scaled down.
t.Cleanup(func() {
var d appsv1.Deployment
if err := env.Client.Get(ctx, deployKey, &d); err != nil {
return
}
if d.Spec.Replicas != nil && *d.Spec.Replicas == 0 {
restore := d.DeepCopy()
one := int32(1)
restore.Spec.Replicas = &one
_ = env.Client.Patch(ctx, restore, client.MergeFrom(&d))
}
})

controllerDeploy := &appsv1.Deployment{}
g.Expect(env.Client.Get(ctx, deployKey, controllerDeploy)).To(Succeed())

down := controllerDeploy.DeepCopy()
zero := int32(0)
down.Spec.Replicas = &zero
g.Expect(env.Client.Patch(ctx, down, client.MergeFrom(controllerDeploy))).To(Succeed())

g.Eventually(func() (int32, error) {
var d appsv1.Deployment
err := env.Client.Get(ctx, deployKey, &d)
return d.Status.AvailableReplicas, err
}).WithTimeout(1*time.Minute).Should(BeZero(),
"expected controller to scale to zero")

t.Logf("Controller scaled to zero mid-rollout")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you create an helper function for scaling up and down the controller? It could be reused by other tests and it makes the entire test more readable

Comment on lines +711 to +724
g.Expect(env.Client.Get(ctx, deployKey, controllerDeploy)).To(Succeed())
up := controllerDeploy.DeepCopy()
one := int32(1)
up.Spec.Replicas = &one
g.Expect(env.Client.Patch(ctx, up, client.MergeFrom(controllerDeploy))).To(Succeed())

g.Eventually(func() (int32, error) {
var d appsv1.Deployment
err := env.Client.Get(ctx, deployKey, &d)
return d.Status.AvailableReplicas, err
}).WithTimeout(2*time.Minute).Should(Equal(int32(1)),
"expected controller to scale back to one")

t.Logf("Controller restored; waiting for the interrupted rollout to finish")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also could be replaced by the helper function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants