diff --git a/deploy/stacks/self-managed/helmfile.d/01-dependencies.yaml.gotmpl b/deploy/stacks/self-managed/helmfile.d/01-dependencies.yaml.gotmpl index e456e84dd..def1ce71a 100644 --- a/deploy/stacks/self-managed/helmfile.d/01-dependencies.yaml.gotmpl +++ b/deploy/stacks/self-managed/helmfile.d/01-dependencies.yaml.gotmpl @@ -120,7 +120,7 @@ releases: <<: *dependency - name: openbao-server # this name MUST not change - version: 0.30.25 + version: 0.32.1 condition: openbao.enabled # From defaults.yaml or env overrides namespace: vault-system <<: *dependency # Inherits base values from the dependency template diff --git a/deploy/stacks/self-managed/helmfile.d/02-core.yaml.gotmpl b/deploy/stacks/self-managed/helmfile.d/02-core.yaml.gotmpl index 53ab1eb59..c14724212 100644 --- a/deploy/stacks/self-managed/helmfile.d/02-core.yaml.gotmpl +++ b/deploy/stacks/self-managed/helmfile.d/02-core.yaml.gotmpl @@ -168,7 +168,7 @@ releases: {{- $llmRequestRouterChartPath := dig "addons" "llm" "requestRouter" "chartPath" "" .Values }} chart: {{ $llmRequestRouterChartPath | default "nvcf/helm-nvcf-llm-request-router" | quote }} {{- if not $llmRequestRouterChartPath }} - version: 1.10.0 + version: 1.12.1 {{- end }} namespace: nvcf condition: addons.llm.enabled @@ -181,7 +181,7 @@ releases: - name: llm-api-gateway chart: nvcf/helm-nvcf-llm-api-gateway - version: 1.4.1 + version: 1.4.2 namespace: nvcf condition: addons.llm.enabled values: @@ -217,7 +217,7 @@ releases: {{- $gatewayRoutesChartPath := dig "ingress" "gatewayApi" "chartPath" "" .Values }} chart: {{ $gatewayRoutesChartPath | default "nvcf/nvcf-gateway-routes" | quote }} {{- if not $gatewayRoutesChartPath }} - version: 1.16.0 + version: 1.17.0 {{- end }} needs: - nvcf/notary-service diff --git a/deploy/stacks/self-managed/tests/cassandra-openbao-credential-wiring.sh b/deploy/stacks/self-managed/tests/cassandra-openbao-credential-wiring.sh index e018b30cc..5b58ccd5e 100755 --- a/deploy/stacks/self-managed/tests/cassandra-openbao-credential-wiring.sh +++ b/deploy/stacks/self-managed/tests/cassandra-openbao-credential-wiring.sh @@ -63,6 +63,21 @@ openbao_values="$work_dir/openbao-values.yaml" render_chart_values cassandra "$cassandra_values" render_chart_values openbao-server "$openbao_values" +# Verify that the Helmfile selects the published OpenBao wrapper pin. The +# manifest assertion below intentionally uses the local source chart because +# the unit suite does not have OCI registry credentials. +openbao_release="$(HELMFILE_ENV="$environment_name" \ + HELMFILE_CACHE_HOME="$work_dir/helmfile-cache" \ + helmfile "${helmfile_common[@]}" \ + --selector name=openbao-server \ + list --skip-charts --output json)" +openbao_chart_name="$(jq -r '.[0].chart // ""' <<<"$openbao_release")" +openbao_chart_version="$(jq -r '.[0].version // ""' <<<"$openbao_release")" +test "$openbao_chart_name" = 'nvcf/helm-nvcf-openbao-server' || + fail "expected default OpenBao chart, got ${openbao_chart_name:-missing}" +test "$openbao_chart_version" = '0.32.1' || + fail "expected default OpenBao version 0.32.1, got ${openbao_chart_version:-missing}" + cassandra_password="$(yq -r '.cassandra.serviceRolePassword // ""' "$cassandra_values")" test -n "$cassandra_password" || fail "Cassandra migrations received no application-role password" diff --git a/deploy/stacks/self-managed/tests/gateway-routes-local-chart.sh b/deploy/stacks/self-managed/tests/gateway-routes-local-chart.sh index 6b5352d91..377f13041 100755 --- a/deploy/stacks/self-managed/tests/gateway-routes-local-chart.sh +++ b/deploy/stacks/self-managed/tests/gateway-routes-local-chart.sh @@ -4,6 +4,80 @@ set -euo pipefail stack_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" chart_path="../../../helm/gateway-routes/chart" +default_result="$(cd "$stack_dir" && HELMFILE_ENV=base helmfile \ + --file helmfile.d/02-core.yaml.gotmpl \ + --environment default \ + --state-values-set ingress.gatewayApi.enabled=true \ + --state-values-set ingress.gatewayApi.controllerNamespace=gateway \ + --state-values-set ingress.gatewayApi.routes.llmWorker.enabled=true \ + --state-values-set ingress.gatewayApi.routes.llmWorker.backend.namespace=nvcf \ + --state-values-set-string global.workerEndpoints.llmRequestRouterAddress=http://llm-grpc-gw:50071 \ + --state-values-set-string addons.llm.requestRouter.backendRouter.pylonGrpcDialAddress=http://llm-grpc-gw:50071 \ + --state-values-set-string addons.llm.requestRouter.backendRouter.pylonReverseTunnelDialAddress=llm-quic-gw:50072 \ + --state-values-set addons.llm.requestRouter.grpcTls.allowInsecureHttp=true \ + --state-values-set ingress.gatewayApi.gateways.shared.name=shared-gw \ + --state-values-set ingress.gatewayApi.gateways.shared.namespace=gateway \ + --state-values-set ingress.gatewayApi.gateways.grpc.name=grpc-gw \ + --state-values-set ingress.gatewayApi.gateways.grpc.namespace=gateway \ + --state-values-set ingress.gatewayApi.gateways.llmGrpc.name=llm-grpc-gw \ + --state-values-set ingress.gatewayApi.gateways.llmGrpc.namespace=gateway \ + --state-values-set ingress.gatewayApi.gateways.llmGrpc.listenerName=llm-grpc \ + --state-values-set ingress.gatewayApi.gateways.llmQuic.name=llm-quic-gw \ + --state-values-set ingress.gatewayApi.gateways.llmQuic.namespace=gateway \ + --state-values-set ingress.gatewayApi.gateways.llmQuic.listenerName=llm-quic \ + --selector name=ingress \ + list --skip-charts --output json)" + +default_chart="$(jq -r '.[0].chart // ""' <<<"$default_result")" +default_version="$(jq -r '.[0].version // ""' <<<"$default_result")" +test "$default_chart" = 'nvcf/nvcf-gateway-routes' || { + echo "gateway-routes-local-chart: expected default chart, got ${default_chart:-missing}" >&2 + exit 1 +} +test "$default_version" = '1.17.0' || { + echo "gateway-routes-local-chart: expected default version 1.17.0, got ${default_version:-missing}" >&2 + exit 1 +} + +default_values="$(mktemp)" +trap 'rm -f "$default_values"' EXIT +(cd "$stack_dir" && HELMFILE_ENV=base helmfile \ + --file helmfile.d/02-core.yaml.gotmpl \ + --environment default \ + --state-values-set ingress.gatewayApi.enabled=true \ + --state-values-set ingress.gatewayApi.controllerNamespace=gateway \ + --state-values-set ingress.gatewayApi.routes.llmWorker.enabled=true \ + --state-values-set ingress.gatewayApi.routes.llmWorker.backend.namespace=nvcf \ + --state-values-set-string global.workerEndpoints.llmRequestRouterAddress=http://llm-grpc-gw:50071 \ + --state-values-set-string addons.llm.requestRouter.backendRouter.pylonGrpcDialAddress=http://llm-grpc-gw:50071 \ + --state-values-set-string addons.llm.requestRouter.backendRouter.pylonReverseTunnelDialAddress=llm-quic-gw:50072 \ + --state-values-set addons.llm.requestRouter.grpcTls.allowInsecureHttp=true \ + --state-values-set ingress.gatewayApi.gateways.shared.name=shared-gw \ + --state-values-set ingress.gatewayApi.gateways.shared.namespace=gateway \ + --state-values-set ingress.gatewayApi.gateways.grpc.name=grpc-gw \ + --state-values-set ingress.gatewayApi.gateways.grpc.namespace=gateway \ + --state-values-set ingress.gatewayApi.gateways.llmGrpc.name=llm-grpc-gw \ + --state-values-set ingress.gatewayApi.gateways.llmGrpc.namespace=gateway \ + --state-values-set ingress.gatewayApi.gateways.llmGrpc.listenerName=llm-grpc \ + --state-values-set ingress.gatewayApi.gateways.llmQuic.name=llm-quic-gw \ + --state-values-set ingress.gatewayApi.gateways.llmQuic.namespace=gateway \ + --state-values-set ingress.gatewayApi.gateways.llmQuic.listenerName=llm-quic \ + --selector name=ingress \ + write-values --output-file-template "$default_values" >/dev/null) + +test "$(yq -r '.nvcfGatewayRoutes.routes.llmWorker.enabled' "$default_values")" = 'true' || { + echo "gateway-routes-local-chart: default chart values did not enable the LLM worker routes" >&2 + exit 1 +} +test "$(yq -r '.nvcfGatewayRoutes.gateways.llmGrpc.listenerName' "$default_values")" = 'llm-grpc' || { + echo "gateway-routes-local-chart: default chart values did not configure the LLM TCP listener" >&2 + exit 1 +} +test "$(yq -r '.nvcfGatewayRoutes.gateways.llmQuic.listenerName' "$default_values")" = 'llm-quic' || { + echo "gateway-routes-local-chart: default chart values did not configure the LLM UDP listener" >&2 + exit 1 +} + result="$(cd "$stack_dir" && HELMFILE_ENV=base helmfile \ --file helmfile.d/02-core.yaml.gotmpl \ --environment default \ diff --git a/deploy/stacks/self-managed/tests/llm-router-split-cluster.sh b/deploy/stacks/self-managed/tests/llm-router-split-cluster.sh index 227374acd..a8381afba 100755 --- a/deploy/stacks/self-managed/tests/llm-router-split-cluster.sh +++ b/deploy/stacks/self-managed/tests/llm-router-split-cluster.sh @@ -253,6 +253,55 @@ assert_resource_field "$gateway_manifest" BackendTrafficPolicy llm-worker-grpc-s assert_resource_field "$gateway_manifest" BackendTrafficPolicy llm-worker-grpc-streams "$gateway_namespace" \ '.spec.timeout.http.requestTimeout' '0s' +# The source-tree chart override above keeps the manifest-focused assertions +# offline. Exercise the normal release path separately so a pin update cannot +# silently bypass the values contract used by the published chart. +default_source_environment_name="${environment_name}-default-source" +default_source_environment_file="$test_stack_dir/environments/$default_source_environment_name.yaml" +cp "$environment_file" "$default_source_environment_file" +printf '{}\n' >"$test_stack_dir/secrets/$default_source_environment_name-secrets.yaml" +yq -i 'del(.addons.llm.requestRouter.chartPath)' "$default_source_environment_file" + +default_source_release="$(HELMFILE_ENV="$default_source_environment_name" \ + HELMFILE_CACHE_HOME="$work_dir/helmfile-cache" \ + helmfile \ + --file "$test_stack_dir/helmfile.d/02-core.yaml.gotmpl" \ + --environment default \ + --selector name=llm-request-router \ + list --skip-charts --output json)" +default_source_chart="$(jq -r '.[0].chart // ""' <<<"$default_source_release")" +default_source_version="$(jq -r '.[0].version // ""' <<<"$default_source_release")" +test "$default_source_chart" = 'nvcf/helm-nvcf-llm-request-router' || + fail "expected default request-router chart, got ${default_source_chart:-missing}" +test "$default_source_version" = '1.12.1' || + fail "expected default request-router version 1.12.1, got ${default_source_version:-missing}" + +default_source_values="$work_dir/default-source-router-values.yaml" +HELMFILE_ENV="$default_source_environment_name" \ + HELMFILE_CACHE_HOME="$work_dir/helmfile-cache" \ + helmfile \ + --file "$test_stack_dir/helmfile.d/02-core.yaml.gotmpl" \ + --environment default \ + --selector name=llm-request-router \ + write-values \ + --output-file-template "$default_source_values" + +assert_file_value "$default_source_values" \ + '.llmRequestRouter.backendRouter.pylonGrpcDialAddress' \ + 'https://llm-grpc.example.com:50071' +assert_file_value "$default_source_values" \ + '.llmRequestRouter.backendRouter.pylonReverseTunnelDialAddress' \ + 'llm-quic.example.com:50072' +assert_file_value "$default_source_values" \ + '.llmRequestRouter.certificate.dnsNames[0]' \ + 'llm-request-router.nvcf.svc.cluster.local' +assert_file_value "$default_source_values" \ + '.llmRequestRouter.certificate.dnsNames[1]' \ + '*.llm-request-router-headless.nvcf.svc.cluster.local' +assert_file_value "$default_source_values" \ + '.llmRequestRouter.tls.quicInsecure' \ + 'false' + assert_partial_backend_override_rejected() { local missing_key="$1" local case_name="$2"