Skip to content

fix(e2e): make kubernetes test retries effective by cleaning up stale resources - #2062

Merged
Andrei Kvapil (kvaps) merged 2 commits into
mainfrom
fix/e2e-kubernetes-flaky-retry
Feb 17, 2026
Merged

Andrei Kvapil (kvaps) merged 2 commits into
mainfrom
fix/e2e-kubernetes-flaky-retry

Conversation

@lexfrei

@lexfrei Aleksei Sviridkin (lexfrei) commented Feb 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add pre-creation cleanup of backend deployment/service and NFS pod/PVC in run-kubernetes.sh, so E2E test retries start fresh instead of reusing stuck resources from a failed attempt
  • Increase the tenant deployment wait timeout from 90s to 300s to handle CI resource pressure, aligning with other timeouts in the same function (control plane 4m, TCP 5m, NFS pod 5m)

Context

When kubernetes-previous (or kubernetes-latest) E2E test fails at the kubectl wait deployment --timeout=90s step, set -eu causes immediate exit before cleanup. On retry, kubectl apply sees the stuck deployment as "unchanged", making retries 2 and 3 guaranteed to fail against the same stuck pod.

This was observed in run 22076291555 where kubernetes-previous failed 3/3 attempts while passing in 5/6 other recent runs.

Test plan

  • E2E tests pass (kubernetes-latest and kubernetes-previous)
  • First clean run: --ignore-not-found cleanup commands are no-ops, no side effects
  • Retry after failure: stale deployment is deleted before re-creation, fresh pod is scheduled

Summary by CodeRabbit

  • Chores
    • Improved test deployment reliability with more robust pre/post-test resource cleanup (including storage-related resources) to prevent leftovers from prior runs.
    • Made environment configuration handling more consistent to avoid misreads of cluster credentials.
    • Increased initialization and load balancer wait timeouts to reduce flaky failures during provisioning and validation.

@dosubot dosubot Bot added the size/S This PR changes 10-29 lines, ignoring generated files label Feb 16, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello Aleksei Sviridkin (@lexfrei), I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the robustness and reliability of Kubernetes end-to-end tests. By proactively clearing out potentially stale resources before test execution and extending critical wait times, it addresses common causes of flaky test failures, particularly in CI environments. These changes ensure that test retries are effective and that the test suite can better handle varying resource availability.

Highlights

  • E2E Test Reliability: Implemented pre-creation cleanup for backend deployment/service and NFS pod/PVC in run-kubernetes.sh to ensure E2E test retries start with a fresh environment, preventing failures due to stuck resources from previous attempts.
  • Increased Timeout: Increased the tenant deployment wait timeout from 90 seconds to 300 seconds to better accommodate potential CI resource pressure, aligning with other existing timeouts in the test suite.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • hack/e2e-apps/run-kubernetes.sh
    • Added kubectl delete commands for backend deployment and service before their creation to clean up any leftover resources from previous failed test runs.
    • Increased the kubectl wait deployment timeout for the tenant backend from 90 seconds to 300 seconds.
    • Added kubectl delete commands for NFS test pod and PVC before their creation to ensure a clean state for NFS tests.
    • Updated kubectl apply and kubectl wait commands to consistently quote the tenantkubeconfig-${test_name} variable for improved shell script robustness.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@dosubot dosubot Bot added the kind/bug Categorizes issue or PR as related to a bug label Feb 16, 2026
@coderabbitai

coderabbitai Bot commented Feb 16, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This change updates the Kubernetes e2e test script to consistently quote kubeconfig references, add pre-emptive cleanup of backend and NFS resources, extend backend readiness and LoadBalancer wait timeouts, and ensure NFS resources are cleaned on failure and post-test.

Changes

Cohort / File(s) Summary
Kubernetes E2E Test Script
hack/e2e-apps/run-kubernetes.sh
Consistently quote tenantkubeconfig in all kubectl --kubeconfig invocations and file redirections; add pre-deployment deletion of previous backend Deployment/Service with ignore-not-found and timeout; introduce explicit cleanup of NFS test Pod and PVC on failure and after tests; increase backend readiness wait from 90s to 300s and extend LoadBalancer readiness/post-deploy checks; update several kubectl apply/delete/wait sequences to use quoted kubeconfig and unified cleanup flow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I tidy the cluster with careful paws,
Quoting configs, closing old flaws,
Removing NFS leaves left behind,
Waiting longer, patient and kind,
Tests start anew — fresh hop, fresh code.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(e2e): make kubernetes test retries effective by cleaning up stale resources' accurately describes the main changes: adding cleanup of stale backend/NFS resources and increasing timeouts to make E2E test retries work properly.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/e2e-kubernetes-flaky-retry

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request effectively addresses a source of flakiness in the E2E tests by introducing cleanup steps for stale resources before test execution. This ensures that retries start from a clean state. The increase in the deployment wait timeout is also a reasonable adjustment to account for potential resource pressure in CI environments. The added quoting for variables in kubectl commands is a good shell scripting practice that improves robustness. I have a couple of suggestions to improve the debuggability of the new cleanup commands.

Comment thread hack/e2e-apps/run-kubernetes.sh Outdated
Comment on lines +136 to +139
kubectl delete deployment --kubeconfig "tenantkubeconfig-${test_name}" "${test_name}-backend" \
-n tenant-test --ignore-not-found --timeout=60s 2>/dev/null || true
kubectl delete service --kubeconfig "tenantkubeconfig-${test_name}" "${test_name}-backend" \
-n tenant-test --ignore-not-found --timeout=60s 2>/dev/null || true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

For better debuggability, consider removing 2>/dev/null. The || true already ensures that the script won't exit on failure, but hiding the error message from kubectl can make it harder to diagnose issues if the cleanup fails for a reason other than the resource not existing (e.g., connection issues with the API server). Seeing the error output would be valuable for troubleshooting.

Suggested change
kubectl delete deployment --kubeconfig "tenantkubeconfig-${test_name}" "${test_name}-backend" \
-n tenant-test --ignore-not-found --timeout=60s 2>/dev/null || true
kubectl delete service --kubeconfig "tenantkubeconfig-${test_name}" "${test_name}-backend" \
-n tenant-test --ignore-not-found --timeout=60s 2>/dev/null || true
kubectl delete deployment --kubeconfig "tenantkubeconfig-${test_name}" "${test_name}-backend" \
-n tenant-test --ignore-not-found --timeout=60s || true
kubectl delete service --kubeconfig "tenantkubeconfig-${test_name}" "${test_name}-backend" \
-n tenant-test --ignore-not-found --timeout=60s || true

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done — removed 2>/dev/null from all cleanup commands in the latest force-push. || true is sufficient to prevent script termination.

Comment thread hack/e2e-apps/run-kubernetes.sh Outdated
Comment on lines +228 to +231
kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pod nfs-test-pod \
-n tenant-test --ignore-not-found --timeout=60s 2>/dev/null || true
kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pvc nfs-test-pvc \
-n tenant-test --ignore-not-found --timeout=60s 2>/dev/null || true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Similar to the cleanup for backend resources, consider removing 2>/dev/null here for better debuggability. The || true already prevents script termination on failure, but showing kubectl's error output could be helpful for troubleshooting if the cleanup fails for reasons other than the resource not being found.

Suggested change
kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pod nfs-test-pod \
-n tenant-test --ignore-not-found --timeout=60s 2>/dev/null || true
kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pvc nfs-test-pvc \
-n tenant-test --ignore-not-found --timeout=60s 2>/dev/null || true
kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pod nfs-test-pod \
-n tenant-test --ignore-not-found --timeout=60s || true
kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pvc nfs-test-pvc \
-n tenant-test --ignore-not-found --timeout=60s || true

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done — same fix applied here. Removed 2>/dev/null, keeping || true for error suppression with visible diagnostics.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 Fix all issues with AI agents
Verify each finding against the current code and only fix it if needed.


In `@hack/e2e-apps/run-kubernetes.sh`:
- Around line 224-225: The script mixes quoted and unquoted kubeconfig
arguments; standardize by quoting all occurrences of
tenantkubeconfig-${test_name} passed to kubectl (e.g., in the kubectl delete
deployment/service commands and other kubectl calls referencing --kubeconfig
tenantkubeconfig-${test_name}) so replace unquoted uses with "--kubeconfig"
"tenantkubeconfig-${test_name}" or keep the single token "--kubeconfig
tenantkubeconfig-${test_name}" but ensure the tenantkubeconfig-${test_name}
value is wrapped in quotes everywhere to match the newly modified lines and
avoid inconsistent styling.
🧹 Nitpick comments (1)
🤖 Fix all nitpicks with AI agents
Verify each finding against the current code and only fix it if needed.


In `@hack/e2e-apps/run-kubernetes.sh`:
- Around line 224-225: The script mixes quoted and unquoted kubeconfig
arguments; standardize by quoting all occurrences of
tenantkubeconfig-${test_name} passed to kubectl (e.g., in the kubectl delete
deployment/service commands and other kubectl calls referencing --kubeconfig
tenantkubeconfig-${test_name}) so replace unquoted uses with "--kubeconfig"
"tenantkubeconfig-${test_name}" or keep the single token "--kubeconfig
tenantkubeconfig-${test_name}" but ensure the tenantkubeconfig-${test_name}
value is wrapped in quotes everywhere to match the newly modified lines and
avoid inconsistent styling.
hack/e2e-apps/run-kubernetes.sh (1)

224-225: Inconsistent kubeconfig quoting across the script.

The new/modified lines properly quote "tenantkubeconfig-${test_name}", but the unchanged kubectl calls (e.g., lines 224-225, 250, 253, 275, 278, 287-288) still use the unquoted form. Not a bug in practice, but you could unify the style while you're here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hack/e2e-apps/run-kubernetes.sh` around lines 224 - 225, The script mixes
quoted and unquoted kubeconfig arguments; standardize by quoting all occurrences
of tenantkubeconfig-${test_name} passed to kubectl (e.g., in the kubectl delete
deployment/service commands and other kubectl calls referencing --kubeconfig
tenantkubeconfig-${test_name}) so replace unquoted uses with "--kubeconfig"
"tenantkubeconfig-${test_name}" or keep the single token "--kubeconfig
tenantkubeconfig-${test_name}" but ensure the tenantkubeconfig-${test_name}
value is wrapped in quotes everywhere to match the newly modified lines and
avoid inconsistent styling.

… resources

When the kubernetes E2E test fails at the deployment wait step, set -eu
causes immediate exit before cleanup. On retry, kubectl apply outputs
"unchanged" for the stuck deployment, making retries 2 and 3 guaranteed
to fail against the same stuck pod.

Add pre-creation cleanup of backend deployment/service and NFS test
resources using --ignore-not-found, so retries start fresh. Also
increase the deployment wait timeout from 90s to 300s to handle CI
resource pressure, aligning with other timeouts in the same function.

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
Quote all tenantkubeconfig-${test_name} references in run-kubernetes.sh
for consistent shell scripting style. The only exception is line 195
inside a sh -ec "..." double-quoted string where inner quotes would
break the outer quoting.

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
@dosubot dosubot Bot added size/M This PR changes 30-99 lines, ignoring generated files and removed size/S This PR changes 10-29 lines, ignoring generated files labels Feb 16, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 Fix all issues with AI agents
Verify each finding against the current code and only fix it if needed.


In `@hack/e2e-apps/run-kubernetes.sh`:
- Around line 194-199: The timeout subshell calling kubectl get svc uses an
unquoted kubeconfig path (--kubeconfig tenantkubeconfig-${test_name}); update
that invocation (the timeout ... sh -ec block that runs kubectl get svc
${test_name}-backend) to quote the kubeconfig argument so it becomes
--kubeconfig "tenantkubeconfig-${test_name}" to match the rest of the script and
avoid word-splitting for test_name values with spaces or special chars.
- Around line 224-225: The success-path cleanup uses kubectl delete for the
backend deployment and service (commands invoking kubectl delete deployment
"${test_name}-backend" and kubectl delete service "${test_name}-backend"), but
unlike the pre-creation cleanup it doesn't tolerate missing resources; update
both kubectl delete commands to be defensive by adding --ignore-not-found (or
append || true) so failures won't abort the remaining NFS cleanup and final
teardown.
- Around line 287-288: Update the success-path NFS cleanup commands so failures
don't abort the script: append "|| true" (or use "--ignore-not-found") to the
kubectl delete calls for the pod and pvc—specifically modify the `kubectl
--kubeconfig "tenantkubeconfig-${test_name}" delete pod nfs-test-pod -n
tenant-test` and `kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete
pvc nfs-test-pvc -n tenant-test` commands to tolerate non-fatal failures (e.g.,
`... delete pod ... || true` and `... delete pvc ... || true`).
🧹 Nitpick comments (3)
🤖 Fix all nitpicks with AI agents
Verify each finding against the current code and only fix it if needed.


In `@hack/e2e-apps/run-kubernetes.sh`:
- Around line 194-199: The timeout subshell calling kubectl get svc uses an
unquoted kubeconfig path (--kubeconfig tenantkubeconfig-${test_name}); update
that invocation (the timeout ... sh -ec block that runs kubectl get svc
${test_name}-backend) to quote the kubeconfig argument so it becomes
--kubeconfig "tenantkubeconfig-${test_name}" to match the rest of the script and
avoid word-splitting for test_name values with spaces or special chars.
- Around line 224-225: The success-path cleanup uses kubectl delete for the
backend deployment and service (commands invoking kubectl delete deployment
"${test_name}-backend" and kubectl delete service "${test_name}-backend"), but
unlike the pre-creation cleanup it doesn't tolerate missing resources; update
both kubectl delete commands to be defensive by adding --ignore-not-found (or
append || true) so failures won't abort the remaining NFS cleanup and final
teardown.
- Around line 287-288: Update the success-path NFS cleanup commands so failures
don't abort the script: append "|| true" (or use "--ignore-not-found") to the
kubectl delete calls for the pod and pvc—specifically modify the `kubectl
--kubeconfig "tenantkubeconfig-${test_name}" delete pod nfs-test-pod -n
tenant-test` and `kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete
pvc nfs-test-pvc -n tenant-test` commands to tolerate non-fatal failures (e.g.,
`... delete pod ... || true` and `... delete pvc ... || true`).
hack/e2e-apps/run-kubernetes.sh (3)

194-199: Unquoted kubeconfig path in LoadBalancer wait subshell.

The kubeconfig path is quoted everywhere else in this PR, but this timeout subshell on line 195 still uses unquoted --kubeconfig tenantkubeconfig-${test_name}. This is pre-existing, but since you're doing a quoting consistency pass it would be easy to fix here too.

Suggested fix
   # Wait for LoadBalancer to be provisioned (IP or hostname)
   timeout 90 sh -ec "
-    until kubectl get svc ${test_name}-backend --kubeconfig tenantkubeconfig-${test_name} -n tenant-test \
+    until kubectl get svc ${test_name}-backend --kubeconfig \"tenantkubeconfig-${test_name}\" -n tenant-test \
       -o jsonpath='{.status.loadBalancer.ingress[0]}' | grep -q .; do
       sleep 5
     done
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hack/e2e-apps/run-kubernetes.sh` around lines 194 - 199, The timeout subshell
calling kubectl get svc uses an unquoted kubeconfig path (--kubeconfig
tenantkubeconfig-${test_name}); update that invocation (the timeout ... sh -ec
block that runs kubectl get svc ${test_name}-backend) to quote the kubeconfig
argument so it becomes --kubeconfig "tenantkubeconfig-${test_name}" to match the
rest of the script and avoid word-splitting for test_name values with spaces or
special chars.

224-225: Same consideration applies to backend cleanup on the success path.

If these delete commands fail, lines 227+ (NFS cleanup and final teardown) are skipped. Consider adding --ignore-not-found || true for defensive consistency, same as the pre-creation cleanup pattern above.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hack/e2e-apps/run-kubernetes.sh` around lines 224 - 225, The success-path
cleanup uses kubectl delete for the backend deployment and service (commands
invoking kubectl delete deployment "${test_name}-backend" and kubectl delete
service "${test_name}-backend"), but unlike the pre-creation cleanup it doesn't
tolerate missing resources; update both kubectl delete commands to be defensive
by adding --ignore-not-found (or append || true) so failures won't abort the
remaining NFS cleanup and final teardown.

287-288: Consider adding || true to success-path NFS cleanup to protect downstream cleanup.

If the delete pod or delete pvc command fails here (e.g., resource already gone, API timeout), set -eu will exit the script before reaching lines 291–299, skipping the machine deployment wait, Helm release checks, and — most importantly — the final kubectl delete kuberneteses on line 299. Adding || true (or --ignore-not-found) would make this consistent with the failure-path cleanup on lines 281–282 and prevent orphaned tenant resources.

Suggested fix
   # Cleanup NFS test resources in tenant cluster
-  kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pod nfs-test-pod -n tenant-test --wait
-  kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pvc nfs-test-pvc -n tenant-test
+  kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pod nfs-test-pod -n tenant-test --wait --ignore-not-found || true
+  kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pvc nfs-test-pvc -n tenant-test --ignore-not-found || true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hack/e2e-apps/run-kubernetes.sh` around lines 287 - 288, Update the
success-path NFS cleanup commands so failures don't abort the script: append "||
true" (or use "--ignore-not-found") to the kubectl delete calls for the pod and
pvc—specifically modify the `kubectl --kubeconfig
"tenantkubeconfig-${test_name}" delete pod nfs-test-pod -n tenant-test` and
`kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pvc nfs-test-pvc -n
tenant-test` commands to tolerate non-fatal failures (e.g., `... delete pod ...
|| true` and `... delete pvc ... || true`).

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Feb 17, 2026
@kvaps
Andrei Kvapil (kvaps) merged commit c6090c5 into main Feb 17, 2026
8 checks passed
@kvaps
Andrei Kvapil (kvaps) deleted the fix/e2e-kubernetes-flaky-retry branch February 17, 2026 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/bug Categorizes issue or PR as related to a bug lgtm This PR has been approved by a maintainer size/M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants