Skip to content

Run:ai platform: LoadBalancer address and opt-in Gateway API exposure, with tests - #1432

Merged
michael-balint merged 10 commits into
masterfrom
dholt/runai-lb-gateway
Oct 24, 2026
Merged

michael-balint merged 10 commits into
masterfrom
dholt/runai-lb-gateway

Conversation

@dholt

@dholt dholt commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #1425 (review request for LoadBalancer and Kubernetes Gateway API coverage). Closes #1426.

  • roles/runai: in platform mode with runai_platform_ingress_service_type: LoadBalancer (the default), wait for the service's external address and use it for the hosts entry, CoreDNS entry and API helper; stop with a clear message if none appears (runai_platform_ingress_ip or NodePort remain available).
  • New opt-in runai_platform_exposure: gateway following the Run:ai Gateway API guide: installs the Gateway API CRDs (v1.4.0, standard channel) and KGateway (v2.2.1) only when absent, records ownership per release, creates one TLS Gateway, and installs the control plane and cluster with Ingress off and Gateway API on. Uninstall removes only what the role installed and leaves controllers or CRDs that other workloads still use. The default (ingress) is unchanged.
  • scripts/validation/validate_runai.py: new --exposure ingress|gateway reports and enforces which path was reached.
  • Docs: LoadBalancer and Gateway API setup, MetalLB strict ARP note for IPVS kube-proxy, and the 26.11 test scope.

Validation

  • Offline: tests/runai/run-tests.sh, Gateway lifecycle and platform tests, validator unit tests (including regression tests for each fix on this branch).
  • Live, one GPU node, Kubernetes with kube-proxy in iptables mode, MetalLB with a single-address pool:
    • ingress exposure with a LoadBalancer service: validator --exposure ingress, ok: true (cluster Connected, project created and deleted, GPU job ran); uninstall verified clean.
    • Gateway API exposure (KGateway): validator --exposure gateway, ok: true (same checks); uninstall verified clean, no Gateway API CRDs or controller namespace left behind.
  • Not covered: reaching the LoadBalancer address from another machine, IPVS mode, multi-node; GPU fraction checks were skipped (see the existing known limit in the docs).

dholt and others added 10 commits October 19, 2026 09:17
Platform mode now waits for the ingress service's external address when the
service type is LoadBalancer and uses it for the hosts entry, the CoreDNS
entry and the API helper. runai_platform_exposure: gateway installs pinned
Gateway API CRDs (v1.4.0) and KGateway (v2.2.1), creates one Gateway and
points the Run:ai charts at it. Uninstall removes only what the role added.
Default stays ingress. Offline tests cover both paths.
…way)

Adds exposure_reached (ingress, gateway or unknown) by matching the address
the control plane was reached on against Gateway and ingress-service
addresses, and --exposure to fail when the requested path is not the one in
use. Unit tests cover both paths and the mismatches.
Discover owned controller releases during uninstall without requiring\nthe original exposure option. Preserve foreign releases and shared\nGateway resources; link validator addresses to Run:ai routes.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Refresh the branch base without changing Run:ai files.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Document new and existing cluster configuration and the iptables-only
release validation scope.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Pass the JSONPath through command argv so its range space, annotation
key escapes, string comparison and newline quotes reach kubectl intact.
Record argument boundaries in the offline kubectl double and verify the
exact ownership selector through the real Ansible removal tasks.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Place CRD resources before annotation assignments and skip xargs when no
resources match. Build the uninstall namespace list without an omit
placeholder, which otherwise reaches kubectl on Ansible 2.17.

Make the offline kubectl and Helm doubles reject malformed arguments and
unknown commands. Exercise the complete Gateway platform install, rerun
and removal path with real Ansible tasks, local TLS generation and an
offline API transport, covering both path and host routing.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Clean up the runtime HMAC Secret after uninstalling an unused controller
owned by the role, before removing its ownership record. Helm does not
manage this object. Preserve foreign controllers and unrelated Secrets.

Exercise scoped cleanup, repeated removal, default absent, foreign users,
and CRD-only ownership through the offline Ansible lifecycle tests.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Signed-off-by: Doug Holt <dholt@nvidia.com>
…xposure

Signed-off-by: Doug Holt <dholt@nvidia.com>
Comment thread scripts/validation/tests/test_runai.py Dismissed
Comment thread scripts/validation/tests/test_runai.py Dismissed
Comment thread scripts/validation/tests/test_runai_gateway_regressions.py Dismissed
Comment thread scripts/validation/tests/test_runai_gateway_regressions.py Dismissed
@dholt

dholt commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

@michael-balint friendly reminder: this adds the LoadBalancer and Gateway API coverage you asked for on #1425 (tracked in #1426). Both exposure modes passed the Run:ai platform-mode validator in a live run, and all checks are green on the current head. Could you take a look when you have a moment? Thanks!

@michael-balint
michael-balint merged commit 6bd681f into master Oct 24, 2026
39 of 40 checks passed
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.

Run:ai: test LoadBalancer and Kubernetes Gateway API exposure

3 participants