[2.25] Backport of the kueue integration and upgrade tests for the workbenches component - #2142
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughChangesKueue notebook integration and upgrade coverage
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
The following are automatically added/executed:
Available user actions:
Supported labels{'/lgtm', '/build-push-pr-image', '/cherry-pick', '/wip', '/verified', '/hold'} |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (7)
utilities/kueue_utils.py (1)
9-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winKueue label keys are defined in three places.
utilities/constants.pyalready holdsLabels.Kueue.QUEUE_NAMEandLabels.Kueue.MANAGED. This PR adds a second copy inutilities/kueue_utils.pyand a third private copy in the integration test. The shared root cause is the absence of one source of truth, so a future key change can leave the copies out of sync and turn label assertions into no-ops.
utilities/kueue_utils.py#L9-L10: reference or re-exportLabels.Kueue.QUEUE_NAMEinstead of redefiningKUEUE_QUEUE_NAME_LABEL, and confirm whetherKUEUE_MANAGED_LABELshould equalLabels.Kueue.MANAGEDor is a distinct pod-level key.tests/workbenches/notebooks_server/controller/test_kueue_integration.py#L43-L44: delete_KUEUE_QUEUE_NAME_LABELand_KUBEFLOW_STOPPED_ANNOTATION, and importKUEUE_QUEUE_NAME_LABELfromutilities.kueue_utilsandKUBEFLOW_STOPPED_ANNOTATIONfromtests/workbenches/notebooks_server/controller/utils.py.As per coding guidelines: "Avoid code duplication by creating meaningful utilities".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@utilities/kueue_utils.py` around lines 9 - 10, The Kueue label and annotation keys are duplicated across utilities and integration tests. In utilities/kueue_utils.py lines 9-10, reference or re-export Labels.Kueue.QUEUE_NAME for KUEUE_QUEUE_NAME_LABEL and verify whether KUEUE_MANAGED_LABEL should use Labels.Kueue.MANAGED or remain a distinct pod-level key; in tests/workbenches/notebooks_server/controller/test_kueue_integration.py lines 43-44, remove the private _KUEUE_QUEUE_NAME_LABEL and _KUBEFLOW_STOPPED_ANNOTATION definitions and import the shared KUEUE_QUEUE_NAME_LABEL and KUBEFLOW_STOPPED_ANNOTATION symbols.Source: Coding guidelines
tests/workbenches/notebooks_server/controller/conftest.py (2)
209-210: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRename this fixture to a noun.
kueue_statefulset_framework_checkreads as an action. The repository requires noun fixture names. Considerkueue_statefulset_frameworkorkueue_statefulset_integration.As per coding guidelines: "Fixture names MUST be nouns (e.g., storage_secret, not create_secret)".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/workbenches/notebooks_server/controller/conftest.py` around lines 209 - 210, Rename the kueue_statefulset_framework_check fixture to a noun-based name, preferably kueue_statefulset_framework, and update every reference to the fixture consistently without changing its behavior.Source: Coding guidelines
98-163: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse
wait_for_notebook_pod_readyin this fixture.This file already imports helpers from
tests/workbenches/notebooks_server/controller/utils.py. That module now provideswait_for_notebook_pod_ready(lines 281-310), which performs the same wait, diagnostic collection, and assertion split. Keeping both copies means future fixes must land twice.Import the helper and pass the desired timeout.
♻️ Proposed refactor
- _ERR_POD_NOT_READY = ( - "Pod '{pod_name}-0' failed to reach Ready state within 10 minutes.\n" - "Pod Phase: {pod_phase}\n" - "Original Error: {original_error}\n" - "Pod information collected to must-gather directory for debugging." - ) - _ERR_POD_NOT_CREATED = "Pod '{pod_name}-0' was not created. Check notebook controller logs." - notebook_pod = Pod( client=unprivileged_client, namespace=default_notebook.namespace, name=f"{default_notebook.name}-0", ) - try: - notebook_pod.wait() - ... - raise AssertionError(_ERR_POD_NOT_CREATED.format(pod_name=default_notebook.name)) from e + wait_for_notebook_pod_ready( + notebook_pod=notebook_pod, + context="Default notebook", + timeout=Timeout.TIMEOUT_10MIN, + ) return notebook_podAs per coding guidelines: "Avoid code duplication by creating meaningful utilities".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/workbenches/notebooks_server/controller/conftest.py` around lines 98 - 163, Replace the duplicated wait, diagnostics, and assertion logic in the notebook_pod fixture with the existing wait_for_notebook_pod_ready helper from the controller utilities module. Import that helper and invoke it with notebook_pod and the desired 10-minute timeout, preserving the fixture’s returned Ready pod behavior.Source: Coding guidelines
tests/workbenches/notebooks_server/controller/upgrade/test_upgrade_kueue.py (2)
254-293: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRename the class or move the pre-upgrade tests.
TestPostUpgradeKueueStoppedcontainstest_kueue_stopped_notebook_has_zero_replicasandtest_kueue_stopped_notebook_pod_absent, and both carry@pytest.mark.pre_upgrade. The class name states post-upgrade only. The neighbouring classes separate the two phases (TestPreUpgradeKueueNotebook,TestPostUpgradeKueueNotebook).Split the pre-upgrade tests into a
TestPreUpgradeKueueStoppedclass, or rename this class to cover both phases.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/workbenches/notebooks_server/controller/upgrade/test_upgrade_kueue.py` around lines 254 - 293, Move the pre-upgrade tests test_kueue_stopped_notebook_has_zero_replicas and test_kueue_stopped_notebook_pod_absent from TestPostUpgradeKueueStopped into a TestPreUpgradeKueueStopped class, preserving their `@pytest.mark.pre_upgrade` markers and fixture usage; keep TestPostUpgradeKueueStopped reserved for post-upgrade tests.
233-251: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueExtract the Workload admission assertion.
Both blocks perform the same four steps: list
Workloadobjects in the namespace, filter by notebook name, check theAdmittedcondition, and comparestatus.admission.clusterQueue.tests/workbenches/notebooks_server/controller/test_kueue_integration.pyalready defines_get_notebook_workloadand_workload_is_admittedfor this purpose.Move those two helpers to a shared location and call them from both classes.
Also applies to: 429-445
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/workbenches/notebooks_server/controller/upgrade/test_upgrade_kueue.py` around lines 233 - 251, Extract the duplicated Workload lookup and admission checks from the upgrade test into a shared helper location, reusing the existing `_get_notebook_workload` and `_workload_is_admitted` behavior from `test_kueue_integration.py`. Update both test classes, including the corresponding block at the later referenced section, to call the shared helpers instead of listing, filtering, and asserting admission inline; preserve the existing ClusterQueue validation.tests/workbenches/notebooks_server/controller/upgrade/conftest.py (2)
972-989: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMove the Workload garbage-collection assertion out of teardown.
pytest.failinside a fixture teardown reports an error against the fixture finalizer, not against a named test. The failure is hard to attribute, and it runs only whenteardown_resourcesis true, so the check disappears in retain-resources runs. The behaviour under test here is a product guarantee: Kueue must garbage-collectWorkloadobjects after the notebook StatefulSet is deleted.Add a dedicated post-upgrade test that deletes the notebook and asserts the
Workloadcleanup. Keep the teardown limited to deletion, and log a warning if Workloads remain.♻️ Proposed teardown simplification
if teardown_resources: nb.client = admin_client nb.clean_up() try: for sample in TimeoutSampler( wait_timeout=60, sleep=5, func=lambda: list(Workload.get(client=admin_client, namespace=upgrade_kueue_namespace.name)), ): if not sample: break except TimeoutExpiredError: remaining = list(Workload.get(client=admin_client, namespace=upgrade_kueue_namespace.name)) - pytest.fail( - f"Kueue did not clean up {len(remaining)} Workload(s) within 60s after notebook deletion: " - f"{[wl.name for wl in remaining]}. " - f"This indicates Kueue is not garbage-collecting Workloads for deleted StatefulSets." - ) + LOGGER.warning( + f"Kueue did not clean up {len(remaining)} Workload(s) within 60s after notebook deletion: " + f"{[wl.name for wl in remaining]}" + )I can draft the dedicated test if you want.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/workbenches/notebooks_server/controller/upgrade/conftest.py` around lines 972 - 989, Move the Workload garbage-collection assertion from the teardown block in the upgrade fixture into a dedicated post-upgrade test with a named test function. Have that test delete the notebook, poll until Workloads in upgrade_kueue_namespace are gone, and fail the test with the existing diagnostic when cleanup times out. Keep fixture teardown limited to deleting resources, and replace teardown-time failure with a warning when Workloads remain.
1166-1166: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse the shared timeout constant.
The sibling fixture at line 425 uses
Timeout.TIMEOUT_2MINfor the same wait.Timeoutis already imported.♻️ Proposed change
- notebook_pod.wait_deleted(timeout=120) + notebook_pod.wait_deleted(timeout=Timeout.TIMEOUT_2MIN)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/workbenches/notebooks_server/controller/upgrade/conftest.py` at line 1166, Update the cleanup wait in the affected fixture to pass the shared Timeout.TIMEOUT_2MIN constant to notebook_pod.wait_deleted instead of the hard-coded 120 value, matching the sibling fixture’s existing timeout usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/workbenches/notebooks_server/controller/conftest.py`:
- Around line 251-283: Initialize the Kueue configuration’s integrations section
once after loading config_data, using an empty mapping when it is absent, and
reuse that reference for reading frameworks and writing frameworks/podOptions.
Update the relevant logic around config_data and frameworks_list so missing
integrations sections are created safely; add the required Any import if the
chosen typing annotation needs it.
In `@tests/workbenches/notebooks_server/controller/utils.py`:
- Around line 40-43: Update the HardwareProfile class docstring to reference
infrastructure.opendatahub.io/v1alpha1 instead of v1, matching the apiVersion
used by its consumers.
---
Nitpick comments:
In `@tests/workbenches/notebooks_server/controller/conftest.py`:
- Around line 209-210: Rename the kueue_statefulset_framework_check fixture to a
noun-based name, preferably kueue_statefulset_framework, and update every
reference to the fixture consistently without changing its behavior.
- Around line 98-163: Replace the duplicated wait, diagnostics, and assertion
logic in the notebook_pod fixture with the existing wait_for_notebook_pod_ready
helper from the controller utilities module. Import that helper and invoke it
with notebook_pod and the desired 10-minute timeout, preserving the fixture’s
returned Ready pod behavior.
In `@tests/workbenches/notebooks_server/controller/upgrade/conftest.py`:
- Around line 972-989: Move the Workload garbage-collection assertion from the
teardown block in the upgrade fixture into a dedicated post-upgrade test with a
named test function. Have that test delete the notebook, poll until Workloads in
upgrade_kueue_namespace are gone, and fail the test with the existing diagnostic
when cleanup times out. Keep fixture teardown limited to deleting resources, and
replace teardown-time failure with a warning when Workloads remain.
- Line 1166: Update the cleanup wait in the affected fixture to pass the shared
Timeout.TIMEOUT_2MIN constant to notebook_pod.wait_deleted instead of the
hard-coded 120 value, matching the sibling fixture’s existing timeout usage.
In `@tests/workbenches/notebooks_server/controller/upgrade/test_upgrade_kueue.py`:
- Around line 254-293: Move the pre-upgrade tests
test_kueue_stopped_notebook_has_zero_replicas and
test_kueue_stopped_notebook_pod_absent from TestPostUpgradeKueueStopped into a
TestPreUpgradeKueueStopped class, preserving their `@pytest.mark.pre_upgrade`
markers and fixture usage; keep TestPostUpgradeKueueStopped reserved for
post-upgrade tests.
- Around line 233-251: Extract the duplicated Workload lookup and admission
checks from the upgrade test into a shared helper location, reusing the existing
`_get_notebook_workload` and `_workload_is_admitted` behavior from
`test_kueue_integration.py`. Update both test classes, including the
corresponding block at the later referenced section, to call the shared helpers
instead of listing, filtering, and asserting admission inline; preserve the
existing ClusterQueue validation.
In `@utilities/kueue_utils.py`:
- Around line 9-10: The Kueue label and annotation keys are duplicated across
utilities and integration tests. In utilities/kueue_utils.py lines 9-10,
reference or re-export Labels.Kueue.QUEUE_NAME for KUEUE_QUEUE_NAME_LABEL and
verify whether KUEUE_MANAGED_LABEL should use Labels.Kueue.MANAGED or remain a
distinct pod-level key; in
tests/workbenches/notebooks_server/controller/test_kueue_integration.py lines
43-44, remove the private _KUEUE_QUEUE_NAME_LABEL and
_KUBEFLOW_STOPPED_ANNOTATION definitions and import the shared
KUEUE_QUEUE_NAME_LABEL and KUBEFLOW_STOPPED_ANNOTATION symbols.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: ea32c4a3-1b25-485f-a109-9e1a3c5012d9
📒 Files selected for processing (7)
tests/workbenches/notebooks_server/controller/conftest.pytests/workbenches/notebooks_server/controller/test_kueue_integration.pytests/workbenches/notebooks_server/controller/upgrade/conftest.pytests/workbenches/notebooks_server/controller/upgrade/kueue_constants.pytests/workbenches/notebooks_server/controller/upgrade/test_upgrade_kueue.pytests/workbenches/notebooks_server/controller/utils.pyutilities/kueue_utils.py
0dee92e to
7ad4454
Compare
|
@coderabbitai full review |
✅ Action performedFull review finished. Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 33 minutes. |
Add resource classes for Kueue CRDs following the openshift-python-wrapper class-generator pattern: - ResourceFlavor (kueue.x-k8s.io, cluster-scoped) - LocalQueue (kueue.x-k8s.io, namespaced) - ClusterQueue (kueue.x-k8s.io, cluster-scoped) - Workload (kueue.x-k8s.io, namespaced) - Kueue (kueue.openshift.io, cluster-scoped) Co-authored-by: Cursor <cursoragent@cursor.com>
…tilities/resources Remove ResourceFlavor, LocalQueue, ClusterQueue, Workload, and Kueue class definitions from kueue_utils.py and re-export them from utilities/resources/ where they are now properly defined. This keeps existing `from utilities.kueue_utils import ClusterQueue` imports working while the canonical definitions live under utilities/resources/. Co-authored-by: Cursor <cursoragent@cursor.com>
Verify that Notebook workbenches are properly managed by the Red Hat build of Kueue operator: admission control, resource constraints (quota gating), and stop/start lifecycle with Kueue labels preserved. Adapted for 2.25 branch: - Uses oauth-proxy style notebook (route_host/username parameters) - Uses simple_logger instead of structlog - Adds HardwareProfile, wait_for_notebook_pod_ready, KUBEFLOW_STOPPED_ANNOTATION to utils.py - Extends build_notebook_dict with extra_labels and resources parameters Cherry-picked from backportTests33: d73f0e0 Signed-off-by: Jan Stourac <jstourac@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Verify that Kueue-managed notebook workbenches survive a platform upgrade: running notebooks retain their pod and management labels, queue infrastructure (ClusterQueue, LocalQueue, ResourceFlavor) persists, stopped notebooks remain stopped, and new kueue-managed notebooks can be created on the upgraded platform. Adapted for 2.25 branch: - Added route_host/username to kueue notebook fixtures (oauth-proxy) - Added KUEUE_*_LABEL constants to utilities/kueue_utils.py - Dropped HTTPRoute/ReferenceGrant imports (3.3+ only) Cherry-picked from backportTests33: 3d53293 Signed-off-by: Jan Stourac <jstourac@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
The labels kueue.x-k8s.io/cluster-queue-name and kueue.x-k8s.io/local-queue-name are observability aids introduced in upstream Kueue v0.17.0 (RH Kueue Operator >= 1.4). They do not affect workload admission, pod scheduling, or any functional behavior. Asserting their presence caused the entire kueue upgrade test suite to fail on environments running RH Kueue Operator v1.3.x (upstream v0.16.5), cascading into 9+ test errors/failures despite Kueue functioning correctly. The remaining assertions (kueue.x-k8s.io/managed, queue-name) along with workload admission checks are sufficient to validate Kueue integration across all supported operator versions. Signed-off-by: Jan Stourac <jstourac@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
The RHOAI 2.25 cluster only serves HardwareProfile at infrastructure.opendatahub.io/v1alpha1 (Technology Preview), not v1. The kind_dict body must match the API version the cluster serves. Signed-off-by: Jan Stourac <jstourac@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
On RHOAI 2.25 (Kueue v1beta1), the kueue.x-k8s.io/managed label is not added to pods — only kueue.x-k8s.io/queue-name is present. Adapt all assertions across integration tests and upgrade tests to only require the queue-name label, which is present on all Kueue versions. Signed-off-by: Jan Stourac <jstourac@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
The managed/embedded Kueue on RHOAI 2.25 does not have pod/statefulset frameworks enabled by default. Without them, Kueue never creates Workload CRs for StatefulSet-based notebooks. The kueue_statefulset_framework_check fixture now: - Tries the Kueue CR (unmanaged mode) first - Falls back to reading the kueue-manager-config ConfigMap (managed mode) - Patches the config to add pod+statefulset frameworks if missing - Sets opendatahub.io/managed=false to prevent operator reconciliation - Restarts the Kueue controller to apply the change - Restores the original config on teardown Signed-off-by: Jan Stourac <jstourac@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
After deleting a notebook, wait for Kueue to garbage-collect the associated Workload objects. Fail with a clear message if Kueue doesn't clean them up within 60 seconds — this indicates a potential issue with Kueue's reconciliation of StatefulSet-backed workloads. Without this, orphaned Workloads hold kueue.x-k8s.io/resource-in-use finalizers on the ClusterQueue and ResourceFlavor, blocking their deletion and causing teardown timeouts. Signed-off-by: Jan Stourac <jstourac@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
7ad4454 to
ca5e20e
Compare
|
Status of building tag 2.25: success. |
Pull Request
Summary
Backport into the 2.25 branch of the:
with some necessary changes to adapt to the 2.25 product reality and some extra specific modifications. Two of the commits from here may be actually migrated to a newer branches too eventually.
Basically this is backport of the #2108 with those extra adaptations for 2.25 world.
Related Issues
https://redhat.atlassian.net/browse/RHOAIENG-73662
Please review and indicate how it has been tested
Additional Requirements
Summary by CodeRabbit