Skip to content

fix(nvcf-self-managed-stack): set the LLM request router worker address - #653

Closed
vrv3814 wants to merge 3 commits into
mainfrom
fix/llm-request-router-worker-address
Closed

fix(nvcf-self-managed-stack): set the LLM request router worker address#653
vrv3814 wants to merge 3 commits into
mainfrom
fix/llm-request-router-worker-address

Conversation

@vrv3814

@vrv3814 vrv3814 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

TL;DR

On a self-managed install, every LLM function deploy failed during launch-spec
translation and no worker pod was created. The stack never emitted
api.remoteConfig.configData, so nvcf.llm-request-router.worker-address stayed
at the helm-nvcf-api chart default of "". This emits the field from the api
release and adds an override for split-cluster installs.

Additional Details

NVCA resolves the LLM request router address only from the worker environment
(LLM_REQUEST_ROUTER_ADDRESS, with STARGATE_ADDRESS as a legacy alias) and
fails fast when neither is set. That fail-fast is deliberate: the address is a
control-plane concern that must ride down from nvcf-api, so NVCA carries no
built-in default.

Nothing in the self-managed stack supplied it. global.yaml.gotmpl had no
remoteConfig passthrough on the api release, leaving the chart default empty.
Deploys ended as ERROR with the agent logging:

terminal error: LLM request router address is not set
(LLM_REQUEST_ROUTER_ADDRESS env or STARGATE_ADDRESS legacy env)

and the ICMSRequest in nvcf-backend sitting at RequestFailureAcknowledged.

How the pieces connect:

  • global.yaml.gotmpl now emits
    api.remoteConfig.configData.nvcf.llm-request-router.worker-address. It
    defaults to llm-request-router.nvcf.svc.cluster.local:50071, matching
    llmRequestRouter.service.grpcPort and the request router release namespace,
    whenever addons.llm.enabled is true.
  • New global.workerEndpoints.llmRequestRouterAddress overrides that default and
    applies regardless of the addon flag. Compute planes outside the control plane
    cluster cannot resolve the in-cluster service name, so they need a reachable
    address here. It sits alongside the existing worker endpoint values, which serve
    the same purpose for the other worker-facing services.
  • When the addon is off and no override is set, nothing is emitted, so the chart
    default is untouched and the stack does not advertise a router it never
    deployed.

Docs: docs/user/llm-function-enablement.md gains a "Request Router Worker
Address" section and a troubleshooting entry for the terminal error;
docs/user/csp-end-to-end-example-installation.md lists the new key in its
multi-cluster workerEndpoints sample.

Summary by CodeRabbit

  • New Features

    • Added optional external connectivity for the LLM request router, including gRPC and QUIC endpoints.
    • Added configurable Gateway API routing for gRPC and QUIC traffic, disabled by default.
    • Added support for per-instance advertised hostnames for multi-replica deployments.
    • Preserved in-cluster routing defaults when external exposure is not configured.
  • Documentation

    • Expanded setup, configuration, routing, and troubleshooting guidance for external and multi-cluster deployments.
  • Tests

    • Added offline validation for default, overridden, disabled, and externally exposed request-router configurations.

The self-managed stack never emitted api.remoteConfig.configData, so
nvcf.llm-request-router.worker-address stayed at the helm-nvcf-api chart
default of "". NVCA resolves the LLM request router only from the worker
environment and fails fast when it is unset, so every LLM function deploy
aborted during launch-spec translation with "LLM request router address is
not set" and no worker pod was created.

Emit the field from the api release: default to the in-cluster request
router at llm-request-router.nvcf.svc.cluster.local:50071 when the LLM
addon is enabled, and honor a new global.workerEndpoints.llmRequestRouterAddress
override for compute planes that run outside the control plane cluster.

Add an offline render test that asserts all four cases through the real
api release, plus a test target on the stack Makefile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: vemireddyv <vemireddyv@nvidia.com>
@vrv3814
vrv3814 requested review from a team as code owners August 4, 2026 07:04
@vrv3814
vrv3814 requested a review from FamousDirector August 4, 2026 07:04
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The self-managed stack now supports configurable LLM request-router worker addresses, external gRPC and QUIC dialing, optional Gateway API exposure, and advertised per-pod hostnames. Helm templates, documentation, and offline rendering tests cover default, enabled, disabled, and invalid configurations.

Changes

LLM request-router exposure

Layer / File(s) Summary
Worker address resolution and documentation
deploy/stacks/self-managed/environments/base.yaml, deploy/stacks/self-managed/global.yaml.gotmpl, docs/user/csp-end-to-end-example-installation.md, docs/user/llm-function-enablement.md
The stack resolves an explicit or in-cluster worker address and publishes it through API remote configuration. Documentation describes the worker endpoint, defaults, diagnostics, and verification steps.
External transport dialing
deploy/helm/llm-request-router/..., deploy/stacks/self-managed/environments/base.yaml, deploy/stacks/self-managed/global.yaml.gotmpl, docs/user/llm-function-enablement.md
The request-router chart accepts external gRPC and reverse-tunnel dial addresses. The deployment retains pod-IP fallback behavior and supports advertised per-pod hostnames for gRPC authority and QUIC SNI.
Gateway API route rendering
deploy/helm/gateway-routes/..., deploy/stacks/self-managed/environments/base.yaml, deploy/stacks/self-managed/global.yaml.gotmpl, docs/user/llm-function-enablement.md
The stack conditionally configures a shared gRPC route and dedicated QUIC Gateway. The chart renders GRPCRoute, UDPRoute, and cross-namespace ReferenceGrant resources.
Offline rendering validation
deploy/stacks/self-managed/tests/*, deploy/stacks/self-managed/Makefile
Offline shell tests verify worker-address resolution, external settings, route gating, Gateway validation, and chart resource rendering. The Makefile exposes both tests through a phony test target.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant StackConfig
  participant APIremoteConfig
  participant RouterDeployment
  participant GatewayRoutesChart
  participant ExternalPylon
  StackConfig->>APIremoteConfig: publish worker router address
  StackConfig->>RouterDeployment: configure external dial addresses and hostname
  RouterDeployment->>ExternalPylon: establish gRPC and QUIC connections
  StackConfig->>GatewayRoutesChart: configure Gateway listeners and routes
  GatewayRoutesChart->>ExternalPylon: forward gRPC and QUIC traffic
Loading

Possibly related PRs

  • NVIDIA/nvcf#214: Shares the LLM request-router Helm chart and rendering/test tooling used by this change.

Suggested reviewers: famousdirector

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title follows Conventional Commits format and accurately describes the primary change to set the LLM request router worker address.
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.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/llm-request-router-worker-address

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

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

…nal compute planes

Compute planes outside the control plane cluster cannot resolve
llm-request-router.nvcf.svc.cluster.local, and nothing in the stack exposed
the router. Setting only the worker address pointed workers at an unreachable
name.

Pylon uses two channels: a gRPC control channel on the router TCP port, and a
QUIC reverse tunnel on the router UDP port after the router issues a tunnel
target. Both have to reach the router, so exposure needs routes for each plus
addresses the router can advertise.

Add to the gateway-routes chart an opt-in TCPRoute for port 50071, a UDPRoute
for port 50072, and a shared ReferenceGrant, under
nvcfGatewayRoutes.routes.llmRequestRouter. The stack gates them on
addons.llm.enabled so a route never references a Service that was not
deployed, and requires the Gateway name and namespace when they are enabled.

Add to the request router chart transport.grpcPylonDialAddr and
transport.reverseTunnelPylonDialAddr for the shared addresses pylon dials.
Both default to empty and keep the existing in-cluster behavior, including the
POD_IP reverse tunnel address at replicaCount above 1. Surface them plus
kubernetes.advertisedHostnameTemplate through
addons.llm.requestRouter.external.

The advertised hostname stays the per-pod gRPC authority and QUIC SNI. These
routes forward on port alone, so they suit a single replica; above one, the
front end must route on that identity. Documented in the chart READMEs and in
the LLM function enablement guide, which also drops an earlier claim that
setting the worker address alone was enough for split-cluster.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: vemireddyv <vemireddyv@nvidia.com>
@vrv3814
vrv3814 requested a review from a team as a code owner August 4, 2026 07:45

@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.

Actionable comments posted: 1

🤖 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 `@deploy/stacks/self-managed/tests/llm-request-router-external-exposure.sh`:
- Around line 117-126: Update the enabled-render assertions in the test loop
around the gateway manifest to verify the specific LLM resource names for the
TCPRoute, UDPRoute, and ReferenceGrant, rather than only their kinds; ensure
`llm-request-router-grpc`, `llm-request-router-quic`, and
`allow-routes-to-llm-request-router` are each present. Update the
disabled-render check to assert none of those three named resources render when
the router is disabled, while preserving the existing QUIC listener attachment
assertion.
🪄 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: Enterprise

Run ID: 6b94d6e7-056e-44d6-894f-10a23eeeaa2b

📥 Commits

Reviewing files that changed from the base of the PR and between 9a64445 and f2fd13e.

📒 Files selected for processing (14)
  • deploy/helm/gateway-routes/README.md
  • deploy/helm/gateway-routes/chart/templates/referencegrant-llm-request-router.yaml
  • deploy/helm/gateway-routes/chart/templates/tcproute-llm-request-router.yaml
  • deploy/helm/gateway-routes/chart/templates/udproute-llm-request-router.yaml
  • deploy/helm/gateway-routes/chart/values.yaml
  • deploy/helm/llm-request-router/README.md
  • deploy/helm/llm-request-router/llm-request-router/templates/deployment.yaml
  • deploy/helm/llm-request-router/llm-request-router/values.yaml
  • deploy/stacks/self-managed/Makefile
  • deploy/stacks/self-managed/environments/base.yaml
  • deploy/stacks/self-managed/global.yaml.gotmpl
  • deploy/stacks/self-managed/tests/llm-request-router-external-exposure.sh
  • docs/user/csp-end-to-end-example-installation.md
  • docs/user/llm-function-enablement.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/user/csp-end-to-end-example-installation.md
  • deploy/stacks/self-managed/Makefile

Comment thread deploy/stacks/self-managed/tests/llm-request-router-external-exposure.sh Outdated
…s a GRPCRoute

The pylon control channel is gRPC over h2c, so a TCPRoute was the wrong shape
for it. Pylon dials the shared address handed to workers but sets the router's
advertised per-pod hostname as the request authority, which is exactly what a
GRPCRoute matches on.

Replace the TCPRoute with a GRPCRoute carrying hostnames. It attaches to the
shared Gateway like the nvcf-api and nvct-api gRPC routes, so the control
channel no longer needs its own TCP listener. Only the QUIC reverse tunnel
still needs a dedicated UDP listener, so gateways.llmRequestRouter becomes
gateways.llmRequestRouterQuic and covers just that hop.

This also gives the control channel a path to multi-replica: hostname matching
can reach a specific router pod, which port-based forwarding cannot. The QUIC
hop is unchanged and still forwards on port alone, so it remains the reason
external installs should stay at one replica.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: vemireddyv <vemireddyv@nvidia.com>

@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.

Actionable comments posted: 1

🤖 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 `@deploy/helm/gateway-routes/chart/values.yaml`:
- Around line 254-284: Add Helm validation for the llmRequestRouter
configuration so enabling ingress.gatewayApi.routes.llmRequestRouter with
addons.llm.requestRouter.replicaCount greater than one fails rendering unless
SNI-aware per-pod routing is configured; preserve the existing single-replica
behavior. Add a regression test covering the invalid multi-replica combination.
🪄 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: Enterprise

Run ID: f078e293-ec51-4e83-8e40-859f739c6da7

📥 Commits

Reviewing files that changed from the base of the PR and between f2fd13e and c84efe6.

📒 Files selected for processing (9)
  • deploy/helm/gateway-routes/README.md
  • deploy/helm/gateway-routes/chart/templates/grpcroute-llm-request-router.yaml
  • deploy/helm/gateway-routes/chart/templates/referencegrant-llm-request-router.yaml
  • deploy/helm/gateway-routes/chart/templates/udproute-llm-request-router.yaml
  • deploy/helm/gateway-routes/chart/values.yaml
  • deploy/stacks/self-managed/environments/base.yaml
  • deploy/stacks/self-managed/global.yaml.gotmpl
  • deploy/stacks/self-managed/tests/llm-request-router-external-exposure.sh
  • docs/user/llm-function-enablement.md
🚧 Files skipped from review as they are similar to previous changes (5)
  • deploy/stacks/self-managed/global.yaml.gotmpl
  • deploy/helm/gateway-routes/README.md
  • deploy/stacks/self-managed/environments/base.yaml
  • deploy/stacks/self-managed/tests/llm-request-router-external-exposure.sh
  • docs/user/llm-function-enablement.md

Comment on lines +254 to +284
# LLM request router routes for compute planes outside the control plane
# cluster. Pylon opens a gRPC control channel, registers, receives a tunnel
# target, then opens a QUIC reverse tunnel. Both hops are required.
# Disabled by default because most installs keep the router in-cluster.
#
# The gRPC hop is a GRPCRoute on the shared Gateway, matched by hostname.
# Pylon sets the router's advertised per-pod hostname as the request
# authority, so hostnames here must line up with the router's
# advertisedHostnameTemplate.
#
# The QUIC hop is a UDPRoute and forwards on port alone. At replicaCount 1
# that reaches the only router pod. Above 1 the router expects the reverse
# tunnel to come back to the pod named by the QUIC SNI, which a UDPRoute
# cannot honor.
llmRequestRouter:
enabled: false
grpc:
name: llm-request-router-grpc
hostnames:
- "llm-router.{{ .Values.nvcfGatewayRoutes.domain }}"
backend:
name: llm-request-router
namespace: nvcf
port: 50071
quic:
name: llm-request-router-quic
backend:
name: llm-request-router
namespace: nvcf
port: 50072
routeAnnotations: {}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Locate the router replica setting and any validation that couples it to
# external Gateway exposure.
rg -n -C 8 \
  'llmRequestRouter|llm-request-router|replicaCount|UDPRoute|external.*exposure' \
  deploy/stacks/self-managed deploy/helm

# Expect: a rendered-config test or template validation rejects enabled
# llmRequestRouter routes when the router replica count is greater than one.

Repository: NVIDIA/nvcf

Length of output: 50370


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- guidance ---'
find .. -name AGENTS.md -print

printf '%s\n' '--- relevant files ---'
git ls-files \
  'deploy/helm/llm-request-router/**' \
  'deploy/helm/gateway-routes/**' \
  'deploy/stacks/self-managed/**' | \
  grep -E '(^|/)(values|Chart|templates|README|test|schema|.*stack.*)\.' | \
  head -200

printf '%s\n' '--- exact references ---'
rg -n -C 5 \
  'llmRequestRouter|llm-request-router|advertisedHostnameTemplate|replicaCount' \
  deploy/stacks/self-managed deploy/helm/llm-request-router deploy/helm/gateway-routes \
  -g '!README.md' -g '!*.lock' -g '!charts/**' | \
  head -500

Repository: NVIDIA/nvcf

Length of output: 50367


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- repository guidance ---'
cat AGENTS.md 2>/dev/null || true

printf '%s\n' '--- stack router release ---'
sed -n '155,190p' deploy/stacks/self-managed/helmfile.d/02-core.yaml.gotmpl

printf '%s\n' '--- stack router and route value propagation ---'
sed -n '250,330p' deploy/stacks/self-managed/global.yaml.gotmpl

printf '%s\n' '--- router chart values ---'
sed -n '1,190p' deploy/helm/llm-request-router/llm-request-router/values.yaml

printf '%s\n' '--- router chart validation and replica templates ---'
rg -n -C 12 \
  'fail|required|replicaCount|disableDnsDiscovery|advertisedHostnameTemplate|StatefulSet' \
  deploy/helm/llm-request-router/llm-request-router/templates \
  deploy/helm/llm-request-router/llm-request-router/values.yaml

printf '%s\n' '--- route chart templates ---'
git ls-files deploy/helm/gateway-routes/chart/templates | xargs -r -n1 sh -c '
  echo "--- $0"
  sed -n "1,240p" "$0"
'

printf '%s\n' '--- external exposure test ---'
cat deploy/stacks/self-managed/tests/llm-request-router-external-exposure.sh

Repository: NVIDIA/nvcf

Length of output: 50370


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- all relevant value declarations and uses ---'
rg -n \
  '(^|[^A-Za-z])llmRequestRouter([^A-Za-z]|$)|(^|[^A-Za-z])replicaCount([^A-Za-z]|$)|UDPRoute|GRPCRoute' \
  deploy/stacks/self-managed deploy/helm/gateway-routes deploy/helm/llm-request-router \
  -g '*.yaml' -g '*.gotmpl' -g '*.tpl' -g '*.sh' |
  grep -vE 'README|charts/' |
  head -400

printf '%s\n' '--- router StatefulSet template ---'
find deploy/helm/llm-request-router/llm-request-router/templates -maxdepth 1 -type f -print |
  sort |
  while read -r file; do
    if grep -qE 'replicaCount|disableDnsDiscovery|advertisedHostnameTemplate|fail ' "$file"; then
      echo "--- $file"
      nl -ba "$file" | grep -C 18 -E 'replicaCount|disableDnsDiscovery|advertisedHostnameTemplate|fail '
    fi
  done

printf '%s\n' '--- Gateway route templates ---'
find deploy/helm/gateway-routes/chart/templates -maxdepth 1 -type f -print |
  sort |
  while read -r file; do
    if grep -qE 'llmRequestRouter|UDPRoute|GRPCRoute' "$file"; then
      echo "--- $file"
      nl -ba "$file" | grep -C 20 -E 'llmRequestRouter|UDPRoute|GRPCRoute'
    fi
  done

printf '%s\n' '--- focused external-exposure test ---'
nl -ba deploy/stacks/self-managed/tests/llm-request-router-external-exposure.sh |
  sed -n '1,180p'

Repository: NVIDIA/nvcf

Length of output: 36228


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- stack router values ---'
sed -n '680,750p' deploy/stacks/self-managed/global.yaml.gotmpl

printf '%s\n' '--- stack Gateway route values ---'
sed -n '1060,1180p' deploy/stacks/self-managed/global.yaml.gotmpl

printf '%s\n' '--- self-managed defaults ---'
sed -n '225,270p' deploy/stacks/self-managed/environments/base.yaml
sed -n '375,425p' deploy/stacks/self-managed/environments/base.yaml

printf '%s\n' '--- router deployment guard and replica wiring ---'
sed -n '20,115p' deploy/helm/llm-request-router/llm-request-router/templates/deployment.yaml

printf '%s\n' '--- Gateway route templates ---'
sed -n '1,90p' deploy/helm/gateway-routes/chart/templates/grpcroute-llm-request-router.yaml
sed -n '1,85p' deploy/helm/gateway-routes/chart/templates/udproute-llm-request-router.yaml
sed -n '1,70p' deploy/helm/gateway-routes/chart/templates/referencegrant-llm-request-router.yaml

printf '%s\n' '--- all cross-value fail checks ---'
grep -R -n -E 'fail |required .*llmRequestRouter|replicaCount.*llmRequestRouter|llmRequestRouter.*replicaCount' \
  deploy/stacks/self-managed deploy/helm/gateway-routes deploy/helm/llm-request-router \
  --include='*.yaml' --include='*.gotmpl' --include='*.tpl' --include='*.sh' || true

Repository: NVIDIA/nvcf

Length of output: 39316


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

global_template = Path("deploy/stacks/self-managed/global.yaml.gotmpl").read_text()
router_deployment = Path(
    "deploy/helm/llm-request-router/llm-request-router/templates/deployment.yaml"
).read_text()
grpc_route = Path(
    "deploy/helm/gateway-routes/chart/templates/grpcroute-llm-request-router.yaml"
).read_text()
udp_route = Path(
    "deploy/helm/gateway-routes/chart/templates/udproute-llm-request-router.yaml"
).read_text()
exposure_test = Path(
    "deploy/stacks/self-managed/tests/llm-request-router-external-exposure.sh"
).read_text()

checks = {
    "stack maps an independent router replica value": (
        'replicaCount: {{ dig "addons" "llm" "requestRouter" "replicaCount" 3 .Values }}'
        in global_template
    ),
    "stack maps an independent route enable value": (
        '$llmRequestRouterRouteEnabled := dig "ingress" "gatewayApi" "routes" '
        '"llmRequestRouter" "enabled" false .Values'
        in global_template
    ),
    "stack does not contain a combined route/replica guard": not re.search(
        r"(llmRequestRouterRouteEnabled|routes.*llmRequestRouter).*"
        r"(replicaCount|requestRouter)",
        global_template,
        re.DOTALL,
    ),
    "GRPCRoute gates only on route enablement": (
        "and .Values.nvcfGatewayRoutes.enabled "
        ".Values.nvcfGatewayRoutes.routes.llmRequestRouter.enabled"
        in grpc_route
    ),
    "UDPRoute gates only on route enablement": (
        "and .Values.nvcfGatewayRoutes.enabled "
        ".Values.nvcfGatewayRoutes.routes.llmRequestRouter.enabled"
        in udp_route
    ),
    "router chart guard does not mention Gateway routes": (
        "llmRequestRouter.discovery.disableDnsDiscovery" in router_deployment
        and "gatewayApi.routes" not in router_deployment
        and "UDPRoute" not in router_deployment
    ),
    "external exposure test has no replica-count rejection case": (
        "replicaCount" not in exposure_test
    ),
}

for name, result in checks.items():
    print(f"{'PASS' if result else 'FAIL'}: {name}")

if not all(checks.values()):
    raise SystemExit(1)
PY

Repository: NVIDIA/nvcf

Length of output: 528


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

global_lines = Path("deploy/stacks/self-managed/global.yaml.gotmpl").read_text().splitlines()
router_lines = Path(
    "deploy/helm/llm-request-router/llm-request-router/templates/deployment.yaml"
).read_text().splitlines()
grpc_route = Path(
    "deploy/helm/gateway-routes/chart/templates/grpcroute-llm-request-router.yaml"
).read_text()
udp_route = Path(
    "deploy/helm/gateway-routes/chart/templates/udproute-llm-request-router.yaml"
).read_text()
exposure_test = Path(
    "deploy/stacks/self-managed/tests/llm-request-router-external-exposure.sh"
).read_text()

def window(lines, start_marker, end_marker):
    start = next(i for i, line in enumerate(lines) if start_marker in line)
    end = next(i for i in range(start + 1, len(lines)) if end_marker in lines[i])
    return lines[start:end]

router_block = window(
    global_lines,
    "llmRequestRouter:",
    "llmApiGateway:",
)
route_block = window(
    global_lines,
    "$llmRequestRouterRouteEnabled",
    "$nvcfApiGrpcRouteHostnames",
)

fail_windows = []
for index, line in enumerate(global_lines):
    if "fail " in line or "required " in line:
        context = "\n".join(global_lines[max(0, index - 5): index + 6])
        if "llmRequestRouterRouteEnabled" in context and (
            "replicaCount" in context or "requestRouter" in context
        ):
            fail_windows.append(context)

checks = {
    "router replica value is independent of route enablement": (
        any("requestRouter" in line and "replicaCount" in line for line in router_block)
        and any("llmRequestRouterRouteEnabled" in line for line in route_block)
    ),
    "stack has no bounded route/replica validation window": not fail_windows,
    "GRPCRoute gates only on route enablement": (
        "and .Values.nvcfGatewayRoutes.enabled "
        ".Values.nvcfGatewayRoutes.routes.llmRequestRouter.enabled"
        in grpc_route
    ),
    "UDPRoute gates only on route enablement": (
        "and .Values.nvcfGatewayRoutes.enabled "
        ".Values.nvcfGatewayRoutes.routes.llmRequestRouter.enabled"
        in udp_route
    ),
    "router chart has no Gateway-route validation": (
        "gatewayApi.routes" not in "\n".join(router_lines)
        and "UDPRoute" not in "\n".join(router_lines)
    ),
    "external exposure test has no replica-count rejection case": (
        "replicaCount" not in exposure_test
    ),
}

for name, result in checks.items():
    print(f"{'PASS' if result else 'FAIL'}: {name}")

if not all(checks.values()):
    if fail_windows:
        print("\nUnexpected candidate validation windows:")
        print("\n---\n".join(fail_windows))
    raise SystemExit(1)
PY

Repository: NVIDIA/nvcf

Length of output: 274


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

global_text = Path("deploy/stacks/self-managed/global.yaml.gotmpl").read_text()
global_lines = global_text.splitlines()
router_deployment = Path(
    "deploy/helm/llm-request-router/llm-request-router/templates/deployment.yaml"
).read_text()
grpc_route = Path(
    "deploy/helm/gateway-routes/chart/templates/grpcroute-llm-request-router.yaml"
).read_text()
udp_route = Path(
    "deploy/helm/gateway-routes/chart/templates/udproute-llm-request-router.yaml"
).read_text()
exposure_test = Path(
    "deploy/stacks/self-managed/tests/llm-request-router-external-exposure.sh"
).read_text()

candidate_windows = []
for index, line in enumerate(global_lines):
    if "fail " in line or "required " in line:
        context = "\n".join(global_lines[max(0, index - 8): index + 9])
        if (
            "llmRequestRouterRouteEnabled" in context
            and "replicaCount" in context
        ):
            candidate_windows.append(context)

checks = {
    "stack emits an independent router replica value": (
        'replicaCount: {{ dig "addons" "llm" "requestRouter" "replicaCount" 3 .Values }}'
        in global_text
    ),
    "stack computes an independent route enable value": (
        '$llmRequestRouterRouteEnabled := dig "ingress" "gatewayApi" "routes" '
        '"llmRequestRouter" "enabled" false .Values'
        in global_text
    ),
    "stack has no route/replica validation window": not candidate_windows,
    "GRPCRoute gates only on route enablement": (
        "and .Values.nvcfGatewayRoutes.enabled "
        ".Values.nvcfGatewayRoutes.routes.llmRequestRouter.enabled"
        in grpc_route
    ),
    "UDPRoute gates only on route enablement": (
        "and .Values.nvcfGatewayRoutes.enabled "
        ".Values.nvcfGatewayRoutes.routes.llmRequestRouter.enabled"
        in udp_route
    ),
    "router chart has no Gateway-route validation": (
        "gatewayApi.routes" not in router_deployment
        and "UDPRoute" not in router_deployment
    ),
    "external exposure test has no replica-count rejection case": (
        "replicaCount" not in exposure_test
    ),
}

for name, result in checks.items():
    print(f"{'PASS' if result else 'FAIL'}: {name}")

if not all(checks.values()):
    if candidate_windows:
        print("\nCandidate validation windows:")
        print("\n---\n".join(candidate_windows))
    raise SystemExit(1)
PY

Repository: NVIDIA/nvcf

Length of output: 518


Add stack validation for multi-replica external router routes

When ingress.gatewayApi.routes.llmRequestRouter.enabled is true and addons.llm.requestRouter.replicaCount is greater than one, fail rendering or require SNI-aware per-pod routing. Add a regression test.

🤖 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 `@deploy/helm/gateway-routes/chart/values.yaml` around lines 254 - 284, Add
Helm validation for the llmRequestRouter configuration so enabling
ingress.gatewayApi.routes.llmRequestRouter with
addons.llm.requestRouter.replicaCount greater than one fails rendering unless
SNI-aware per-pod routing is configured; preserve the existing single-replica
behavior. Add a regression test covering the invalid multi-replica combination.

@vrv3814 vrv3814 closed this Aug 4, 2026
@vrv3814
vrv3814 deleted the fix/llm-request-router-worker-address branch August 4, 2026 09:26
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.

1 participant