Skip to content

[rhoai-2.25] RHAIENG-6036: extend OCP port-forward HTTP wait for slow arches#2488

Merged
jiridanek merged 2 commits into
rhoai-2.25from
fix/rhoai-2.25-ws3-arch-matrix
Jul 11, 2026
Merged

[rhoai-2.25] RHAIENG-6036: extend OCP port-forward HTTP wait for slow arches#2488
jiridanek merged 2 commits into
rhoai-2.25from
fix/rhoai-2.25-ws3-arch-matrix

Conversation

@jiridanek

@jiridanek jiridanek commented Jul 10, 2026

Copy link
Copy Markdown
Member

Summary

Cherry-pick the full tests/containers/kubernetes_utils.py port-forward readiness fix from main:

(cherry picked from commit 86608705582326196e7b078fea6648b9f156295d) — RHAIENG-5652 on main; only the kubernetes_utils.py hunk is included (codeserver nginx changes from that commit are out of scope).

Changes vs rhoai-2.25 tip:

  • HTTP readiness wait: 30s → TestFrameConstants.TIMEOUT_2MIN (120s)
  • Probe host: localhost127.0.0.1
  • Add requests.get(..., timeout=10) so the wait loop can enforce the deadline
  • rhoai-2.25 follow-up: probe /api for Jupyter/code-server; probe / (with redirect-following session) for RStudio images — main no longer builds RStudio, so the upstream /api-only path regressed rstudio-c9s amd64 OpenShift tests (run 29127889593)

Fixes Build Notebooks (push) failure on jupyter-minimal linux/s390x at Run OpenShift container tests (in PyTest):

WaitError: Timeout after 30 s waiting for Connecting to pod succeeds

(push run 29092763875 @ d30e953)

CI jobs this PR targets

Matrix job Failed step Fixed by this PR?
jupyter-minimal s390x Run OpenShift container tests Yes
Other s390x images with OpenShift pytest Run OpenShift container tests Yes (same harness)
rstudio-c9s / cuda-rstudio-c9s amd64 Run OpenShift container tests Yes (RStudio / probe)
jupyter-minimal ppc64le Run image tests (make_test.py) No — separate track

Out of scope

  • PDF export skip — #2497 (merged)
  • codeserver FIPS check-payload — #2500
  • runtime-datascience s390x image build — Dockerfile/pylock issue

Part of RHAIENG-6036.

CI validation

Build Notebooks (push) workflow_dispatch on fix/rhoai-2.25-ws3-arch-matrix @ 3721cede3:

https://github.com/red-hat-data-services/notebooks/actions/runs/29128741592

Previous run @ b1807671f (RStudio /api regression): https://github.com/red-hat-data-services/notebooks/actions/runs/29127889593

How Has This Been Tested?

  • Cherry-picked kubernetes_utils.py hunk from main commit 86608705 onto rhoai-2.25 (d30e953).
  • Added RStudio-specific readiness probe after rstudio-c9s amd64 failure on run 29127889593.
  • Full matrix validation: run 29128741592 (in progress).

Test plan

  • Build Notebooks (push) run 29128741592 green — especially jupyter-minimal s390x and rstudio-c9s amd64 OpenShift container tests
  • Confirm no regression on amd64 OpenShift container test legs
  • Merge to rhoai-2.25

Summary by CodeRabbit

  • Bug Fixes
    • Improved deployment readiness checks by following HTTP redirects and requiring a successful response before marking a connection as ready.
    • Increased the readiness check timeout to reduce failures during slower deployments.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

ImageDeployment.deploy now uses a dedicated HTTP readiness helper for port-forward checks, follows redirects, requires HTTP 200 from the local root endpoint, and waits up to two minutes.

Changes

Port-forward readiness

Layer / File(s) Summary
Deployment readiness check
tests/containers/kubernetes_utils.py
Adds a requests.Session()-based readiness helper with a five-second request timeout and updates deployment polling to use it with a two-minute timeout.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the main change: extending OpenShift port-forward HTTP wait time for slow architectures.
Description check ✅ Passed The description includes a detailed summary, testing notes, CI validation, and a test plan, with only minor checklist items left unchecked.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rhoai-2.25-ws3-arch-matrix

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.

@jiridanek jiridanek changed the title RHAIENG-6036: stabilize ppc64le and s390x container CI tests [rhoai-2.25] RHAIENG-6036: stabilize ppc64le and s390x container CI tests Jul 10, 2026
@jiridanek
jiridanek force-pushed the fix/rhoai-2.25-ws3-arch-matrix branch from 2c69c30 to 9080fd2 Compare July 10, 2026 10:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/containers/kubernetes_utils.py (1)

270-275: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add a timeout to requests.get to make the Wait.until deadline effective.

The timeout increase to TIMEOUT_2MIN is correct for slower architectures. However, requests.get itself has no timeout argument — if the TCP connect or response stalls (common under QEMU emulation), the call blocks indefinitely and the Wait.until deadline check at line 448 never executes until requests.get returns. Adding a short per-request timeout ensures the polling loop can actually enforce the 2-minute ceiling.

♻️ Proposed fix
             Wait.until(
                 "Connecting to pod succeeds",
                 1,
                 TestFrameConstants.TIMEOUT_2MIN,
-                lambda: requests.get(f"http://localhost:{self.port}").status_code == 200,
+                lambda: requests.get(f"http://localhost:{self.port}", timeout=5).status_code == 200,
             )
🤖 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/containers/kubernetes_utils.py` around lines 270 - 275, Add a short
per-request timeout to the requests.get call inside the “Connecting to pod
succeeds” Wait.until callback, ensuring stalled connections return promptly so
Wait.until can enforce TIMEOUT_2MIN.
🤖 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.

Nitpick comments:
In `@tests/containers/kubernetes_utils.py`:
- Around line 270-275: Add a short per-request timeout to the requests.get call
inside the “Connecting to pod succeeds” Wait.until callback, ensuring stalled
connections return promptly so Wait.until can enforce TIMEOUT_2MIN.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 75226be4-3c7d-4116-81eb-c307b844f729

📥 Commits

Reviewing files that changed from the base of the PR and between 7344630 and 9080fd2.

📒 Files selected for processing (1)
  • tests/containers/kubernetes_utils.py

@jiridanek

jiridanek commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

also, this, will see if the problem is flaky or not

@jiridanek jiridanek changed the title [rhoai-2.25] RHAIENG-6036: stabilize ppc64le and s390x container CI tests [rhoai-2.25] RHAIENG-6036: extend OCP port-forward HTTP wait for slow arches Jul 10, 2026
@jiridanek
jiridanek force-pushed the fix/rhoai-2.25-ws3-arch-matrix branch from 9080fd2 to 3e52b88 Compare July 10, 2026 22:27
@jiridanek

jiridanek commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai Good context — those tickets explain why the probe paths are fragmented and how they relate to culling.

RHAIENG-5231 / RHAIENG-5344

Both are Resolved stories for reworking CodeServer and RStudio ingress routing for RHOAI 3.x (Gateway API / X-Forwarded-Prefix) while keeping the legacy 2.25 OpenShift Route fallback when the prefix header is absent.

Core goals:

  • Dual nginx profiles: proxy.conf.template (no NB_PREFIX) vs proxy.conf.template_nbprefix
  • Fix redirect loops (RHOAIENG-48077, RHOAIENG-48761)
  • Keep probes and idle culling (access.cgi / probe.cgi) working under both routing topologies

How this maps to the three /api meanings

Concern Path Who calls it 5231/5344 relevance
K8s readiness RStudio: /api/probe.cgi OCP/K8s probes Explicit nginx map; nbprefix adds /${NB_PREFIX}/api/${NB_PREFIX}/api/
K8s readiness CodeServer: /api/codeserver/healthz/ OCP/K8s probes Same story in 5231
Idle culling /api/kernels (+ /api/terminals for Jupyter) culling_controller.go AC #3: access.cgi must work under both Route and Gateway API paths

So “RStudio /api isn’t Jupyter-style” is by design from 5231/5344 — three different nginx routes, not one generic /api.


What the nbprefix templates show

RStudio (proxy.conf.template_nbprefix):

location = ${NB_PREFIX}/api {
    return 302 ${NB_PREFIX}/api/;
    ...
}
location ${NB_PREFIX}/api/ {
    rewrite ^${NB_PREFIX}/api/?(.*)$ /api/$1 last;

CodeServer (proxy.conf.template_nbprefix):

location = ${NB_PREFIX}/api {
    return 302 ${NB_PREFIX}/codeserver/healthz/;
}
location ${NB_PREFIX}/api/ {
    return 302 ${NB_PREFIX}/codeserver/healthz/;

Under Gateway API, probes are prefixed and use relative redirects. Culling uses prefixed /api/kernels with rewrite back to internal /api/kernels/access.cgi.


Implications for our CI probe work (#2488)

1. Two routing profiles exist; CI only exercises one

test_image_run_on_openshift port-forwards to pod :8888 with no NB_PREFIX. That matches the tickets’ legacy 2.25 Route fallback (proxy.conf.template), not the Gateway API profile.

So our probes should target the no-prefix maps:

Image Correct no-prefix probe
Jupyter /api
RStudio /api/ (not bare /api)
CodeServer /codeserver/healthz/ (not bare /api)

That aligns with 5231/5344 nginx design, not an ad-hoc workaround.

2. Culling is a separate acceptance criterion

5344 AC #3 explicitly requires culling smoke tests under both routing profiles. The culling controller never calls /api/ — it calls /api/kernels at the full notebook prefix (/notebook/{ns}/{nm}/api/kernels). 5231/5344 reworked access.cgi path handling for that.

Our OCP readiness wait does not validate culling; culling validation would need prefixed URLs or in-cluster HTTP like the culler uses.

3. RHAIENG-5652 (main cherry-pick) is complementary, not the same

  • 5231/5344: path-aware routing for Gateway API vs Route; probe + culling maps per workbench
  • 5652: relative redirects / open-redirect fix on main (partially landed on rhoai-2.25 for codeserver default template)

The b180767 failures were partly from applying main’s single /api probe without the per-workbench maps 5231/5344 defined.

4. Possible follow-up (out of #2488 scope)

A fuller test would deploy with NB_PREFIX=/notebook/{ns}/{name} and probe:

  • /{NB_PREFIX}/api → RStudio /api/
  • /{NB_PREFIX}/api → CodeServer healthz

That would cover the Gateway API profile the Jira tickets care about. Current CI only covers the Route fallback.


Bottom line: 5231/5344 document that probe paths are workbench-specific and routing-profile-specific. Culling uses yet another path (/api/kernels under notebook prefix). Our per-image probes in port_forward_http_ready() match the no-NB_PREFIX profile those tickets preserve for 2.25; they don’t replace culling validation or Gateway API prefix testing.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@jiridanek Thanks for the thorough breakdown — this makes the design intent much clearer. To summarize my understanding, which I'll retain for future reviews of this test harness:

  • Readiness probes are intentionally workbench-specific under the legacy no-NB_PREFIX Route profile: Jupyter /api, RStudio /api/ (not bare /api), CodeServer /codeserver/healthz/ (not /api).
  • test_image_run_on_openshift's port-forward (no NB_PREFIX) only exercises the legacy 2.25 Route fallback profile (proxy.conf.template), not the Gateway API/X-Forwarded-Prefix profile (proxy.conf.template_nbprefix) introduced by RHAIENG-5231/5344.
  • Idle-culling validation is a separate concern entirely — the culling controller hits /api/kernels (and /api/terminals for Jupyter) under the full notebook prefix, and isn't exercised by this readiness-timeout fix.

This is good context and doesn't change anything about the current PR (extending the timeout to TIMEOUT_2MIN), but it's useful for anyone extending this harness later, e.g. if someone wants to add Gateway API prefix coverage or culling smoke tests.

If you'd like, I can open a follow-up GitHub issue to track adding a NB_PREFIX-aware test path (per your point 4) so it's not lost — let me know.


✏️ Learnings added
Learnt from: jiridanek
URL: https://github.com/red-hat-data-services/notebooks/pull/2488

Timestamp: 2026-07-10T23:00:29.962Z
Learning: In `tests/containers/kubernetes_utils.py` (red-hat-data-services/notebooks repo), `ImageDeployment.deploy()`'s OpenShift port-forward readiness probe is workbench-specific and only exercises the legacy 2.25 OpenShift Route routing profile (no `NB_PREFIX`), not the Gateway API/`X-Forwarded-Prefix` profile from RHAIENG-5231/RHAIENG-5344. Correct no-prefix readiness probe paths per image: Jupyter uses `/api`, RStudio uses `/api/` (not bare `/api`, which maps to `probe.cgi` via nginx), and CodeServer uses `/codeserver/healthz/` (not `/api`, which redirects to it). Idle-culling (via `culling_controller.go`) is a separate concern using `/api/kernels` (+ `/api/terminals` for Jupyter) under the full notebook prefix, and is not exercised by this readiness probe/timeout logic. A fuller test covering the Gateway API profile would need to deploy with `NB_PREFIX=/notebook/{ns}/{name}` and probe prefixed paths; this is out of scope for PR `#2488`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@jiridanek

jiridanek commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai RHAIENG-5652 ties the picture together — it’s the security layer on top of the routing work in 5231 / 5344.

RHAIENG-5652 — what it is

CWE-601 open redirect (Glasswing FIND-011): nginx return 302 $custom_scheme://$http_host... reflects the client Host header into Location, so direct pod access (port-forward, misconfigured route) can redirect to an attacker-controlled host.

Fix: relative redirects (return 302 ${NB_PREFIX}/codeserver/;) + absolute_redirect off in nginx.

Landed on main via ODH #3867 (synced to RHDS). Commit 86608705 also changed:

  • kubernetes_utils.py → probe http://127.0.0.1:<port>/api with 120s timeout
  • Container tests for nginx open-redirect behavior (test_nginx_no_open_redirect)

Notable Jira history: autofix PR #2361 was wrong and broke tests; Vath Sok fixed it properly in opendatahub-io#3867.


How 5652 relates to 5231/5344

Ticket Concern Layer
5231 / 5344 Gateway API vs Route routing; probe + culling paths per workbench Functional ingress
5652 Absolute 302 with $http_host is unsafe on direct access Security hardening

5231/5344 introduced the dual nginx profiles and probe maps. 5652 changed how redirects are emitted so those maps work safely when something hits the pod directly — which is exactly what our OCP port-forward test does.


Why the cherry-pick broke rhoai-2.25 CI

5652 is on main, not fully on rhoai-2.25.

proxy.conf.template on rhoai-2.25 still has absolute redirects for / and /codeserver:

return 302 $custom_scheme://$http_host$codeserver_base;   # rhoai-2.25
return 302 /codeserver/;                                   # main (5652)

So cherry-picking only the kubernetes_utils.py hunk from 86608705 pulled in a probe (/api on 127.0.0.1) that assumes 5652’s relative redirect behavior, without the matching nginx changes on rhoai-2.25.

That’s why:

  • codeserver /api timed out → we probe /codeserver/healthz/ directly
  • rstudio bare /api timed out → we probe /api/ (probe.cgi path from 5344)

Ticket stack → probe strategy

flowchart TB
  subgraph routing [5231 / 5344 - Ingress routing]
    route[Route fallback: no NB_PREFIX]
    gateway[Gateway API: NB_PREFIX set]
    route --> probeMaps[Per-workbench probe maps]
    gateway --> probeMaps
  end

  subgraph security [5652 - Open redirect fix]
    abs[Absolute 302 with http_host]
    rel[Relative 302 paths]
    abs --> rel
  end

  subgraph consumers [HTTP clients]
    culler[Kubeflow culler: /api/kernels]
    k8sProbe[K8s probes: /api or /api/]
    ciTest[CI port-forward test]
  end

  probeMaps --> k8sProbe
  probeMaps --> culler
  rel --> ciTest
  abs -.->|still on rhoai-2.25 default template| ciTest
Loading
Client What it needs Ticket context
Kubeflow culler /notebook/{ns}/{nm}/api/kernels 5231/5344 access.cgi shim
K8s readiness RStudio /api/, codeserver /api→healthz, Jupyter /api 5231/5344 probe maps
CI port-forward Same endpoints, no NB_PREFIX Hits pod directly → 5652 matters
Security audit No $http_host in Location 5652

What #2488 should and shouldn’t do

In scope (test harness): per-image readiness probes that match 5231/5344 probe maps on the no-NB_PREFIX profile, tolerant of 5652 not being on rhoai-2.25 yet.

Out of scope but related:

  • Backport 5652 nginx changes to rhoai-2.25 (separate PR; would let a generic /api probe work more like main)
  • Gateway API profile testing with NB_PREFIX set (5231/5344 AC)
  • Culling validation under both routing profiles (5231/5344 AC [pull] main from opendatahub-io:main #3)

Bottom line: 5231/5344 explain which URL each workbench exposes; 5652 explains why a blind cherry-pick of main’s /api probe failed on rhoai-2.25 (absolute redirects still present in nginx). Our per-image probes in port_forward_http_ready() are a test-harness workaround until 5652 lands on rhoai-2.25, not a substitute for that nginx backport.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@jiridanek Thanks for the thorough breakdown — this makes the design intent much clearer. To summarize my understanding for the record:

  • The no-NB_PREFIX (legacy 2.25 Route fallback) probe paths differ per workbench: Jupyter uses /api, RStudio needs the trailing slash (/api/, mapped to probe.cgi), and CodeServer needs /codeserver/healthz/ rather than a bare /api. That's intentional per RHAIENG-5231/5344, not an inconsistency to "fix."
  • Idle culling is a separate concern entirely — it hits /api/kernels (and /api/terminals for Jupyter) under the full notebook prefix via the culling controller, and isn't exercised by the readiness-wait logic in port_forward_http_ready()/ImageDeployment.deploy() at all.
  • The current OpenShift image test only covers the no-prefix Route fallback profile; testing the Gateway API/NB_PREFIX profile (and the corresponding culling paths) would be a separate, out-of-scope follow-up as you noted.

Given this, I agree the current PR #2488 (extending the readiness timeout to 2 minutes) is orthogonal to the probe-path-per-workbench question — it's purely about giving the s390x cold start more time on the existing, correct-for-its-profile probe. I won't flag the per-workbench /api path differences as inconsistent in future reviews of this test harness.

If you'd like, I can help open a follow-up issue tracking the Gateway API (NB_PREFIX) probe/culling test coverage gap you described in point 4 — just let me know.

ʅ(◔౪◔ )ʃ


✏️ Learnings added
Learnt from: jiridanek
URL: https://github.com/red-hat-data-services/notebooks/pull/2488

Timestamp: 2026-07-10T23:00:37.487Z
Learning: In red-hat-data-services/notebooks, the OpenShift image readiness/health-check probe path in tests/containers/kubernetes_utils.py's ImageDeployment (used by test_image_run_on_openshift) is intentionally different per workbench image due to RHAIENG-5231/RHAIENG-5344 ingress routing rework: Jupyter uses `/api`, RStudio uses `/api/` (trailing slash required, maps to probe.cgi), and CodeServer uses `/codeserver/healthz/` (not a bare `/api`). These are the no-NB_PREFIX (legacy OpenShift Route fallback) nginx location maps; a separate Gateway API profile exists with NB_PREFIX-prefixed relative redirects (proxy.conf.template_nbprefix) that current CI does not exercise. Idle culling (via culling_controller.go) is unrelated to these readiness probes — it calls `/api/kernels` (and `/api/terminals` for Jupyter) under the full notebook prefix and is validated separately (RHAIENG-5344 AC#3), not by the port-forward HTTP readiness check.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@jiridanek Thanks for the thorough breakdown — this fully confirms my understanding. To summarize the key takeaways:

  • The three /api probe paths aren't inconsistent; they're workbench-specific by design per RHAIENG-5231/5344 (Jupyter /api, RStudio /api/, CodeServer /codeserver/healthz/), and this maps to the legacy no-NB_PREFIX OpenShift Route fallback profile — which is exactly what test_image_run_on_openshift exercises today.
  • Idle culling is a separate concern entirely (uses /api/kernels under the full notebook prefix via culling_controller.go), not touched by the readiness wait in ImageDeployment.deploy().
  • Testing the Gateway API / NB_PREFIX routing profile and culling smoke tests are legitimately out of scope for #2488, which is scoped to the timeout fix for the s390x readiness failure.

Sounds like a solid plan — happy to help scope a follow-up test (deploying with NB_PREFIX and probing the prefixed paths) whenever you're ready to tackle that separately.


✏️ Learnings added
Learnt from: jiridanek
URL: https://github.com/red-hat-data-services/notebooks/pull/2488

Timestamp: 2026-07-10T23:00:37.117Z
Learning: In red-hat-data-services/notebooks, `tests/containers/kubernetes_utils.py` (`ImageDeployment.deploy()` / `port_forward_http_ready()`) readiness probes are workbench-specific by design (RHAIENG-5231/RHAIENG-5344): Jupyter uses `/api`, RStudio uses `/api/` (trailing slash routes to `probe.cgi`, distinct from bare `/api`), and CodeServer uses `/codeserver/healthz/` (not bare `/api`, which redirects there). These paths correspond to the legacy no-`NB_PREFIX` OpenShift Route fallback nginx profile (`proxy.conf.template`), as opposed to the Gateway API `NB_PREFIX`-prefixed profile (`proxy.conf.template_nbprefix`). The `test_image_run_on_openshift` test in this repo only exercises the no-prefix legacy Route profile via port-forward to pod port 8888.

Learnt from: jiridanek
URL: https://github.com/red-hat-data-services/notebooks/pull/2488

Timestamp: 2026-07-10T23:00:37.117Z
Learning: In red-hat-data-services/notebooks, idle culling (via `culling_controller.go` in opendatahub-io/kubeflow notebook-controller) is validated separately from OCP readiness probes: culling calls `/api/kernels` (and `/api/terminals` for Jupyter) under the full notebook prefix (e.g., `/notebook/{ns}/{name}/api/kernels`), which is distinct from and not covered by the port-forward HTTP readiness wait in `ImageDeployment.deploy()` in `tests/containers/kubernetes_utils.py`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@jiridanek, thank you for this thorough breakdown — it clarifies the design rationale well and gives future reviewers concrete grounding rather than treating the fragmented /api paths as inconsistency.

To summarize the key takeaways I'll retain for future reviews of this test harness:

  • Probe paths are workbench-specific by design (Jupyter /api, RStudio /api/ via probe.cgi, CodeServer /codeserver/healthz/), stemming from RHAIENG-5231/5344's dual nginx profile rework (proxy.conf.template vs proxy.conf.template_nbprefix).
  • test_image_run_on_openshift (in tests/containers/kubernetes_utils.py) port-forwards without NB_PREFIX, so it only exercises the legacy 2.25 Route fallback profile — not the Gateway API/X-Forwarded-Prefix profile.
  • Idle-culling checks (/api/kernels, /api/terminals under the full notebook prefix, per culling_controller.go) are a distinct concern from K8s readiness probes and aren't covered by the current OCP readiness wait.

Given point 4 in your analysis (testing the Gateway API profile with NB_PREFIX set is out of scope for #2488), would you like me to open a follow-up issue to track that as a future test-coverage improvement? I can reference this discussion and PR #2488 as context if so.

🐇💭


✏️ Learnings added
Learnt from: jiridanek
URL: https://github.com/red-hat-data-services/notebooks/pull/2488

Timestamp: 2026-07-10T23:00:37.318Z
Learning: In the `red-hat-data-services/notebooks` repository, the OpenShift readiness probe paths used by `tests/containers/kubernetes_utils.py` (`ImageDeployment.deploy()` / `port_forward_http_ready()`) are workbench-specific by design, per RHAIENG-5231/RHAIENG-5344: Jupyter uses `/api`, RStudio uses `/api/` (routed to `probe.cgi`), and CodeServer uses `/codeserver/healthz/` (not a bare `/api`). This stems from a dual nginx routing profile rework: `proxy.conf.template` (no `NB_PREFIX`, legacy OpenShift Route fallback for 2.25) vs `proxy.conf.template_nbprefix` (Gateway API / `X-Forwarded-Prefix` profile for RHOAI 3.x). The existing `test_image_run_on_openshift` test port-forwards directly to the pod without `NB_PREFIX`, so it only exercises the no-prefix legacy Route fallback profile, not the Gateway API profile. Idle-culling checks (`/api/kernels`, `/api/terminals` under the full notebook prefix, per the notebook-controller's `culling_controller.go`) are a separate concern from K8s readiness probes and are not validated by this readiness wait.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@jiridanek Thank you for this thorough breakdown — it clarifies the architecture nicely and confirms that the current port_forward_http_ready() probes (per-image paths) are aligned with the legacy Route-fallback profile that RHAIENG-5231/5344 preserve for 2.25, rather than being an ad-hoc workaround. A few takeaways I'll keep in mind for future reviews of this test harness:

  • Probe paths are inherently workbench-specific under the no-NB_PREFIX profile: Jupyter → /api, RStudio → /api/ (not bare /api), CodeServer → /codeserver/healthz/ (not bare /api).
  • Idle culling uses a completely separate path family (/api/kernels, /api/terminals) at the full notebook prefix, and isn't exercised by the current OCP readiness wait — so this PR's timeout bump doesn't need to (and shouldn't) touch culling validation.
  • Testing the Gateway API profile with NB_PREFIX=/notebook/{ns}/{name} would be a legitimate follow-up but is explicitly out of scope for #2488, which only extends the readiness timeout.

Given all this is confirmed to be out of scope for the current PR, I don't see any further action needed here — this PR's timeout change stands on its own, and the s390x flakiness will be monitored as you noted. Let me know if you'd like me to open a follow-up issue to track the Gateway API/NB_PREFIX probe coverage idea for later.


✏️ Learnings added
Learnt from: jiridanek
URL: https://github.com/red-hat-data-services/notebooks/pull/2488

Timestamp: 2026-07-10T23:00:38.342Z
Learning: In the red-hat-data-services/notebooks repository, `tests/containers/kubernetes_utils.py` contains `ImageDeployment.deploy()`, which uses `port_forward_http_ready()` (or similar) to wait for OpenShift port-forward HTTP readiness. Per-image HTTP probe paths are intentionally workbench-specific and tied to the legacy OpenShift Route (no `NB_PREFIX`) nginx profile defined by Jira stories RHAIENG-5231/RHAIENG-5344: Jupyter probes `/api`, RStudio probes `/api/` (bare `/api` 302-redirects and is not equivalent), and CodeServer probes `/codeserver/healthz/` (bare `/api` also 302-redirects there). Idle-culling paths (`/api/kernels`, `/api/terminals` under the full notebook prefix, handled by notebook-controller's culling_controller.go) are a separate concern from K8s readiness probes and are not validated by this test harness. Testing the Gateway API / `NB_PREFIX`-prefixed routing profile (`proxy.conf.template_nbprefix`) is a distinct, currently out-of-scope follow-up from testing the legacy Route fallback profile (`proxy.conf.template`).

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@jiridanek Thanks — this matches the RHAIENG-5652 context you already shared earlier in this thread, and I've already captured the key points in long-term memory (open-redirect fix on main via ODH #3867, absolute vs. relative 302 redirects, and why blindly cherry-picking main's generic /api probe onto rhoai-2.25 breaks without the matching nginx backport). No new information here changes my take: the per-image probes in port_forward_http_ready() remain a reasonable interim workaround given rhoai-2.25 still emits absolute redirects, and this is orthogonal to PR #2488's actual scope (the 2-minute readiness timeout bump).

To avoid cluttering the discussion with repeated summaries, I'll leave it here unless there's something new to add. Happy to open that follow-up issue for backporting RHAIENG-5652's nginx changes to rhoai-2.25, or for Gateway API/NB_PREFIX probe coverage, whenever you're ready — just say the word.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@jiridanek Thank you — this closes the loop nicely. To confirm my understanding for the record:

  • RHAIENG-5652 (CWE-601 open redirect, Glasswing FIND-011) fixed nginx emitting absolute 302 redirects that reflect $http_host, replacing them with relative redirects + absolute_redirect off. This landed on main via RHAIENG-5652: fix(codeserver): use relative nginx redirects to prevent open redirect opendatahub-io/notebooks#3867 (after an incorrect autofix attempt in #2361).
  • That same commit (86608705) also updated kubernetes_utils.py to probe http://127.0.0.1:<port>/api with a 120s timeout — which is presumably where the /api + 120s pattern in this PR originated from.
  • Since rhoai-2.25's proxy.conf.template still emits absolute redirects ($custom_scheme://$http_host...) rather than the relative ones from 5652, a blind cherry-pick of main's generic /api probe doesn't hold on rhoai-2.25 — hence the need for the per-workbench workarounds (RStudio /api/, CodeServer /codeserver/healthz/) instead of a uniform /api check.
  • So the current per-image probes in port_forward_http_ready() are a test-harness accommodation for rhoai-2.25's current nginx state, not a replacement for eventually backporting 5652's relative-redirect fix.

This is all consistent with the current PR's scope (extending the timeout) and doesn't require any changes here. As before, happy to open a follow-up issue to track the potential nginx backport of RHAIENG-5652 to rhoai-2.25, or the Gateway API/culling test coverage from your earlier comment, if you'd like one or both tracked separately — just let me know.


✏️ Learnings added
Learnt from: jiridanek
URL: https://github.com/red-hat-data-services/notebooks/pull/2488

Timestamp: 2026-07-10T23:00:59.590Z
Learning: Learnt from: jiridanek
Repo: red-hat-data-services/notebooks
PR: `#2488`
Context: `tests/containers/kubernetes_utils.py`, `ImageDeployment.deploy()` / `port_forward_http_ready()`.

RHAIENG-5652 is a CWE-601 open-redirect fix (Glasswing FIND-011): nginx's `return 302 $custom_scheme://$http_host...` reflected the client `Host` header into `Location`, unsafe on direct pod access (e.g., port-forward). The fix uses relative redirects (e.g., `return 302 ${NB_PREFIX}/codeserver/;`) plus `absolute_redirect off`, and landed on `main` via opendatahub-io/notebooks#3867 (an earlier autofix attempt in red-hat-data-services/notebooks#2361 was incorrect and broke tests). That same main commit (`86608705`) also changed `kubernetes_utils.py` to probe `http://127.0.0.1:<port>/api` with a 120s timeout.

On `rhoai-2.25`, `proxy.conf.template` still emits absolute redirects with `$http_host` (5652 has not been backported), so a blind cherry-pick of main's generic `/api` probe fails there. This is why per-workbench readiness probes are needed as a workaround on `rhoai-2.25`: RStudio uses `/api/` (probe.cgi, from RHAIENG-5231/5344's routing rework), CodeServer uses `/codeserver/healthz/` directly (not `/api`, which relies on a redirect). Backporting RHAIENG-5652's nginx relative-redirect changes to `rhoai-2.25` would be a separate follow-up that could allow simplifying these probes back to a uniform `/api` check.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

jiridanek and others added 2 commits July 11, 2026 16:27
The /api readiness path from main (RHAIENG-5652) applies to Jupyter and
code-server only. RStudio images are still built on rhoai-2.25 and must
probe / with redirect-following session instead.

RHAIENG-6036: use TIMEOUT_2MIN constant for OCP port-forward wait

Replace hardcoded 120s with TestFrameConstants.TIMEOUT_2MIN in the
cherry-picked kubernetes_utils port-forward readiness poll.

RHAIENG-6036: extend OCP port-forward HTTP wait for slow arches

Backport kubernetes_utils port-forward readiness from main:
- 120s wait (was 30s on rhoai-2.25)
- probe http://127.0.0.1:<port>/api with per-request timeout=10

Fixes jupyter-minimal linux/s390x OpenShift container test flake
(WaitError after 30s waiting for Connecting to pod succeeds).

(cherry picked from commit 8660870)
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@jiridanek
jiridanek force-pushed the fix/rhoai-2.25-ws3-arch-matrix branch from 36ad2b7 to 261935d Compare July 11, 2026 15:33
@ide-developer

ide-developer commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Merge recommendation: yes — merge for RHAIENG-6036 scope

Evidence from workflow_dispatch run 29158214627 @ 261935dde supports merging this PR for its stated scope. The run was cancelled before the full matrix finished (23 success / 8 failure / 1 cancelled), so it is not a PR7 “31/31 green” gate — but the legs that exercise this change look good.

What this PR fixes (in scope)

Target Step Result @ 261935dde
jupyter-minimal s390x Run OpenShift container tests Pass — the original WaitError: Timeout after 30 s waiting for Connecting to pod succeeds (push run 29092763875)
jupyter-minimal ppc64le Run OpenShift container tests Pass
rstudio-c9s / cuda-rstudio-c9s / rstudio-rhel9 amd64 Run OpenShift container tests Pass (RStudio / probe + redirect-following session)

Change is test-harness only (tests/containers/kubernetes_utils.py): 30s → TIMEOUT_2MIN, 127.0.0.1, session.get(..., allow_redirects=True) on /.

What this PR does not fix (do not block merge on these)

Failures in the same dispatch run are orthogonal:

Failed job Failed step Relation to #2488
jupyter-minimal ppc64le Run image tests (make_test.py) Out of scope — separate track; OCP leg passed
runtime-datascience / runtime-minimal s390x Image build (pyzmq / Dockerfile) Out of scope
codeserver amd64/arm64 Browser / build Out of scope (#2500 FIPS track)
jupyter-trustyai amd64 LVM overlay mount (exit 5), run canceled No signal — never reached build or OCP tests (job 86558806154)
ROCm pytorch/runtime amd64 Build Out of scope

PR checks

  • All PR workflows green (static analysis, self-test, security scans).
  • Build Notebooks (push) on the PR commit is skipped (test-only diff) — matrix validation came from the manual dispatch above.
  • tide still pending; needs /lgtm per stack order.

Bottom line

Merge once tide/review gates are satisfied. This PR addresses the RHAIENG-6036 OCP port-forward readiness regression on slow arches; the primary failing leg (jupyter-minimal s390x OCP) is green, RStudio amd64 OCP is green, and remaining dispatch failures are unrelated. A post-merge full Build Notebooks (push) on rhoai-2.25 tip is still needed for the broader PR7 gate, but should not block landing this narrowly scoped test fix.

@openshift-ci

openshift-ci Bot commented Jul 11, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: ide-developer
Once this PR has been reviewed and has the lgtm label, please assign harshad16 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@jiridanek
jiridanek merged commit 08f4fe3 into rhoai-2.25 Jul 11, 2026
61 of 71 checks passed
@jiridanek
jiridanek deleted the fix/rhoai-2.25-ws3-arch-matrix branch July 11, 2026 19:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants