Skip to content

Commit e68a2d3

Browse files
authored
Merge branch 'main' into docs/aks-socket-ifname-and-pod-name
2 parents 2b2307c + 3ba53ce commit e68a2d3

59 files changed

Lines changed: 3435 additions & 162 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/RENOVATE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Self-hosted Renovate keeps the project's dependencies up to date across `go.mod`
99

1010
- Configuration: [`.github/renovate.json5`](renovate.json5)
1111
- Workflow: [`.github/workflows/renovate.yaml`](workflows/renovate.yaml)
12-
- Companion script: [`tools/update-chainsaw-checksums`](../tools/update-chainsaw-checksums)
12+
- Companion scripts: [`tools/update-chainsaw-checksums`](../tools/update-chainsaw-checksums), [`tools/update-helmfile-checksums`](../tools/update-helmfile-checksums), [`tools/update-helm-diff-checksums`](../tools/update-helm-diff-checksums)
1313

1414
Policy choices (schedule, cooldown, auto-merge scope, group consolidation) are documented inline in `renovate.json5`. This doc covers what's covered, how to extend coverage, and the known gotchas.
1515

@@ -25,6 +25,8 @@ Policy choices (schedule, cooldown, auto-merge scope, group consolidation) are d
2525
| `.settings.yaml` (28 tool entries) | custom regex manager (`# renovate:` annotations) |
2626
| `.settings.yaml` `nvkind` SHA | dedicated git-refs digest customManager (`# renovate-digest:`) |
2727
| `.settings.yaml` `chainsaw_checksums` | `postUpgradeTasks``tools/update-chainsaw-checksums` |
28+
| `.settings.yaml` `helmfile_checksums` | `postUpgradeTasks``tools/update-helmfile-checksums` |
29+
| `.settings.yaml` `helm_diff_checksums` | `postUpgradeTasks``tools/update-helm-diff-checksums` |
2830
| `.go-version` (Go toolchain) | dedicated `golang-version` customManager (`go-toolchain` group) |
2931

3032
The `go` directive in `go.mod` is intentionally not bumped — the Go toolchain version is owned by `.go-version`. Makefile (`GOTOOLCHAIN`), the `load-versions` composite action, `install-karpenter-kwok`, and validator Dockerfiles (`--build-arg GO_VERSION`) all read from that single file.

.github/actions/e2e/action.yml

Lines changed: 96 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -43,38 +43,98 @@ runs:
4343
- name: Install E2E testing tools
4444
uses: ./.github/actions/install-e2e-tools
4545

46-
- name: Create Kind cluster
47-
shell: bash
48-
run: make cluster-create
49-
50-
- name: Deploy aicrd to Kind
46+
- name: Create Kind cluster and deploy aicrd
5147
shell: bash
5248
env:
5349
GOFLAGS: -mod=vendor
5450
run: |
55-
# Build and push aicrd image (replaces Tilt custom_build)
51+
# If any `wait` below fails, `set -e` (GitHub's default shell flags)
52+
# exits this script immediately - any background job not yet reached
53+
# by its own `wait` would otherwise keep running. Most consequential
54+
# for pid_cluster specifically: the job's always()-run Cleanup step
55+
# (`make cluster-delete`) could then race a still-in-flight
56+
# `make cluster-create`. Kill whatever is still alive on any exit.
57+
cleanup_background_jobs() {
58+
local rc=$?
59+
for pid in "$pid_cluster" "$pid_dep" "$pid_perf" "$pid_conf" "$pid_cli" "$pid_aicr" "$pid_validators"; do
60+
[ -n "$pid" ] && kill -0 "$pid" 2>/dev/null && kill "$pid" 2>/dev/null
61+
done
62+
exit "$rc"
63+
}
64+
trap cleanup_background_jobs EXIT
65+
66+
# This step folds what used to be two separate steps (Create Kind
67+
# cluster / Deploy aicrd) into one, so GitHub's per-step red-X no
68+
# longer says at a glance which phase failed. Group markers fold the
69+
# log into the same phases instead.
70+
echo "::group::cluster-and-builds"
71+
# cluster-create (~35s locally; Kind bring-up + registry) and the
72+
# host compiles below touch none of each other's inputs/outputs, so
73+
# launch everything in the background up front. Each later command
74+
# waits only on the specific PID(s) its own inputs actually depend
75+
# on: aicrd's ko build needs just the cluster/registry (not the
76+
# validator/CLI binaries), so it must not be gated behind builds it
77+
# doesn't read from - an earlier version of this step wait'ed on all
78+
# four build PIDs before it, which measured ~19s slower in CI than
79+
# the original sequential script for no reason: nothing here reads
80+
# dist/validator/* or dist/e2e/aicr until the docker build step below.
81+
pid_cluster=""; pid_dep=""; pid_perf=""; pid_conf=""; pid_cli=""; pid_aicr=""; pid_validators=""
82+
make cluster-create > /tmp/cluster-create.log 2>&1 &
83+
pid_cluster=$!
84+
85+
mkdir -p dist/validator dist/e2e
86+
for phase in deployment performance conformance; do
87+
mkdir -p "validators/${phase}/testdata"
88+
done
89+
90+
# Compile validator binaries + the host aicr CLI on the runner (Go
91+
# build cache hit) while the cluster comes up. This is also much
92+
# faster than building inside Docker (no cache sharing there). Go's
93+
# build cache is safe for concurrent use by simultaneous go
94+
# commands, including ko's own internal compile of aicrd below.
95+
CGO_ENABLED=0 go build -trimpath -o dist/validator/deployment ./validators/deployment &
96+
pid_dep=$!
97+
CGO_ENABLED=0 go build -trimpath -o dist/validator/performance ./validators/performance &
98+
pid_perf=$!
99+
CGO_ENABLED=0 go build -trimpath -o dist/validator/conformance ./validators/conformance &
100+
pid_conf=$!
101+
go build -o dist/e2e/aicr ./cmd/aicr &
102+
pid_cli=$!
103+
104+
# aicrd only needs the cluster/registry - build and push it (replaces
105+
# Tilt custom_build) as soon as that's ready, not gated behind the
106+
# unrelated validator/CLI builds above.
107+
#
108+
# cluster-create's output was redirected to a file above so it
109+
# wouldn't interleave with the concurrent builds; print it on
110+
# failure too (not just success), since a failed `wait` here is the
111+
# most common, most opaque failure on this step and would otherwise
112+
# exit via the EXIT trap with zero diagnostic output.
113+
wait $pid_cluster || { cat /tmp/cluster-create.log; exit 1; }
114+
cat /tmp/cluster-create.log
115+
echo "::endgroup::"
116+
117+
echo "::group::deploy-aicrd"
56118
KO_DOCKER_REPO=localhost:5001/aicrd ko build --bare --tags=tilt ./cmd/aicrd
57119
58120
# Apply namespace first (must exist before deployment references it)
59121
kubectl apply -f tilt/k8s/namespace.yaml
60122
kubectl apply -f tilt/k8s/
61-
62-
# Build images + CLI binary in parallel while deployment starts
123+
echo "::endgroup::"
124+
125+
echo "::group::validator-images"
126+
# The validator images COPY the binaries built above, so wait for
127+
# those specifically (not pid_cli, which nothing here needs) before
128+
# building them.
129+
wait $pid_dep
130+
wait $pid_perf
131+
wait $pid_conf
132+
133+
# Build + push the remaining images. Validator binaries are already
134+
# compiled above; this is just the COPY-only image build + push.
63135
KO_DOCKER_REPO=localhost:5001/aicr ko build --bare --tags=local ./cmd/aicr &
64136
pid_aicr=$!
65-
# Compile validator binaries on host (Go build cache hit) then COPY-only images.
66-
# This is much faster than building inside Docker (no cache sharing).
67137
(
68-
mkdir -p dist/validator
69-
CGO_ENABLED=0 go build -trimpath -o dist/validator/deployment ./validators/deployment &
70-
CGO_ENABLED=0 go build -trimpath -o dist/validator/performance ./validators/performance &
71-
CGO_ENABLED=0 go build -trimpath -o dist/validator/conformance ./validators/conformance &
72-
wait
73-
# Build per-phase COPY-only images and push to local registry.
74-
# Ensure testdata dirs exist (conformance has none).
75-
for phase in deployment performance conformance; do
76-
mkdir -p "validators/${phase}/testdata"
77-
done
78138
for phase in deployment performance conformance; do
79139
docker build -t "localhost:5001/aicr-validators/${phase}:latest" -f - . <<DOCKERFILE
80140
FROM nvcr.io/nvidia/distroless/static:v4.0.0@sha256:d90158b69e250d2018f32622b5c622925202ee97224a990a54b63811cb1e3d69
@@ -99,10 +159,14 @@ runs:
99159
docker push "localhost:5001/aicr-validators/aiperf-bench:latest"
100160
) &
101161
pid_validators=$!
102-
go build -o dist/e2e/aicr ./cmd/aicr &
103-
pid_cli=$!
104-
wait $pid_aicr $pid_validators $pid_cli
105-
162+
# Separate waits, not `wait $pid_aicr $pid_validators`: bash returns
163+
# only the LAST pid's exit status from a combined wait, so a failed
164+
# pid_aicr would be silently masked whenever pid_validators succeeds.
165+
wait $pid_aicr
166+
wait $pid_validators
167+
echo "::endgroup::"
168+
169+
echo "::group::rollout-and-verify"
106170
# Wait for deployment rollout (may already be ready)
107171
kubectl rollout status deployment/aicrd -n aicr --timeout=120s
108172
@@ -112,6 +176,13 @@ runs:
112176
curl -sf http://localhost:5001/v2/aicr-validators/performance/tags/list
113177
curl -sf http://localhost:5001/v2/aicr-validators/conformance/tags/list
114178
curl -sf http://localhost:5001/v2/aicr-validators/aiperf-bench/tags/list
179+
echo "::endgroup::"
180+
181+
# Not needed by anything above, but its output (dist/e2e/aicr) is
182+
# used by a later step (AICR_BIN) - wait now so a build failure here
183+
# fails this step instead of surfacing as a confusing missing-binary
184+
# error two steps later, and so the step's own exit code reflects it.
185+
wait $pid_cli
115186
116187
- name: Set up fake GPU environment
117188
shell: bash
@@ -151,6 +222,7 @@ runs:
151222
shell: bash
152223
run: |
153224
mkdir -p /tmp/debug-artifacts
225+
cp /tmp/cluster-create.log /tmp/debug-artifacts/cluster-create.log 2>/dev/null || true
154226
kubectl get all --all-namespaces > /tmp/debug-artifacts/all-resources.txt || true
155227
kubectl get events --all-namespaces --sort-by='.lastTimestamp' > /tmp/debug-artifacts/events.txt || true
156228
kubectl logs -n aicr -l app.kubernetes.io/name=aicrd --tail=500 > /tmp/debug-artifacts/aicrd-logs.txt || true

.github/renovate.json5

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,16 @@
319319
},
320320
},
321321

322+
// ---- helm-diff bumps refresh per-arch SHA256 checksums via post-upgrade script ----
323+
{
324+
matchDepNames: ["databus23/helm-diff"],
325+
postUpgradeTasks: {
326+
commands: ["./tools/update-helm-diff-checksums {{{newVersion}}}"],
327+
fileFilters: [".settings.yaml"],
328+
executionMode: "update",
329+
},
330+
},
331+
322332
// ---- aiperf-bench base image is capped below python 3.14 ----
323333
// PR #1906 auto-bumped this to 3.14 and broke the UAT validator image
324334
// build (aiperf's pyzmq/uvloop had no cp314 wheels, and the single-stage

.github/workflows/codeql.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
4040
with:
4141
go-version: ${{ steps.versions.outputs.go }}
42-
cache: false # vendor/ provides deps; disable to save disk on constrained runners
42+
cache: true
4343
- uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
4444
with:
4545
languages: go

.github/workflows/merge-gate.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ jobs:
296296
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
297297
with:
298298
go-version: ${{ steps.versions.outputs.go }}
299-
cache: false
299+
cache: true
300300
- uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
301301
with:
302302
languages: go
@@ -528,7 +528,7 @@ jobs:
528528
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
529529
with:
530530
go-version: ${{ steps.versions.outputs.go }}
531-
cache: false
531+
cache: true
532532
- name: Verify committed BOM versions and variants match the recipes
533533
env:
534534
GOFLAGS: -mod=vendor
@@ -579,7 +579,7 @@ jobs:
579579
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
580580
with:
581581
go-version: ${{ steps.versions.outputs.go }}
582-
cache: false
582+
cache: true
583583
- name: Verify committed tuning-status table is up to date
584584
env:
585585
GOFLAGS: -mod=vendor
@@ -661,7 +661,7 @@ jobs:
661661
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
662662
with:
663663
go-version: ${{ steps.versions.outputs.go }}
664-
cache: false
664+
cache: true
665665
- name: Verify committed coverage matrix is up to date
666666
env:
667667
GOFLAGS: -mod=vendor

.github/workflows/renovate.yaml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,18 @@ jobs:
122122
# checksums getting committed alongside a version bump (the version
123123
# changes but the helmfile_checksums/chainsaw_checksums block does
124124
# not), which then breaks E2E/CLI E2E at the sha256 verify step.
125-
RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS: '["^\\./tools/update-[a-z]+-checksums "]'
125+
# `[a-z-]+` (not `[a-z]+`) so hyphenated tool names match too, e.g.
126+
# tools/update-helm-diff-checksums.
127+
#
128+
# The stale-checksum symptom above is not uniform across the three
129+
# tools. A hook that runs but *fails* (renamed asset, egress blip)
130+
# leaves the new version pinned against the old checksums, and only
131+
# helmfile/chainsaw fail a PR-gating job for it — qualification.yaml
132+
# feeds their sha256 into setup-build-tools, which verifies it.
133+
# helm_diff_checksums is read solely by tests/uat/lib/phases.sh, so a
134+
# stale helm-diff pin stays green on every PR check and first surfaces
135+
# in nightly UAT, across all clouds. Renovate's "Artifact update
136+
# problem" warning in the PR body is the signal to heed; helm-diff is
137+
# deliberately not auto-merged, so a human sees it.
138+
RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS: '["^\\./tools/update-[a-z-]+-checksums "]'
126139
LOG_LEVEL: ${{ inputs.logLevel || 'info' }}

.settings.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ testing_tools:
8484
helm: 'v4.2.4'
8585
# renovate: datasource=github-releases depName=databus23/helm-diff depType=testing_tools
8686
helm_diff: 'v3.15.11'
87+
# helm_diff_checksums are refreshed automatically by tools/update-helm-diff-checksums
88+
# via Renovate postUpgradeTasks whenever the helm-diff version above is bumped.
89+
# The darwin_* keys name GOOS (matching the sibling blocks); upstream labels
90+
# those release assets "macos".
91+
helm_diff_checksums:
92+
linux_amd64: 'ed54aa5a14a51a6e44cf8ab6020aaa9e56779b4d33bc2adf07abea6b240a5e7c'
93+
linux_arm64: '1c38c487ec348fe5ef2b10c61deddff79f0fa5bfbab762b302874578e6dc2d2c'
94+
darwin_amd64: '833e1054d0cfe28bbd6f2edc4c1d5b786968b7732f8df6fe99b67c3bf12bf7bb'
95+
darwin_arm64: 'ba489cc4a5998ad259fbc18c454f2319da26ba4c8f469e7acb587a07e61072cd'
8796
# renovate: datasource=github-releases depName=helmfile/helmfile depType=testing_tools
8897
helmfile: 'v1.7.4'
8998
# helmfile_checksums are refreshed automatically by tools/update-helmfile-checksums

Makefile

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ CTLPTL_CONFIG_FILE = .ctlptl.yaml
3434
REGISTRY_PORT = 5001
3535
REGISTRY_NAME = ctlptl-registry
3636

37+
# Kind node image (single source of truth: .settings.yaml testing.kind_node_image).
38+
# .ctlptl.yaml intentionally does not hardcode this — cluster-create injects it so
39+
# local dev and CI can never pin a second, drifting copy of the version. No
40+
# hardcoded fallback here: cluster-create fails closed on an empty read
41+
# instead of silently degrading to a stale image (see its yq-missing check).
42+
KIND_NODE_IMAGE ?= $(shell yq -r '.testing.kind_node_image' .settings.yaml 2>/dev/null)
43+
3744
# Default target
3845
all: help
3946

@@ -819,7 +826,19 @@ cluster-create: ## Creates local Kind cluster with registry
819826
echo " or: go install sigs.k8s.io/kind@latest"; \
820827
exit 1; \
821828
fi
822-
ctlptl apply -f $(CTLPTL_CONFIG_FILE)
829+
@if ! command -v yq >/dev/null 2>&1; then \
830+
echo "Error: yq is not installed."; \
831+
echo "Install: brew install yq"; \
832+
echo " or: go install github.com/mikefarah/yq/v4@latest"; \
833+
exit 1; \
834+
fi
835+
@if [ -z "$(KIND_NODE_IMAGE)" ]; then \
836+
echo "Error: could not resolve testing.kind_node_image from .settings.yaml."; \
837+
echo "Check the key exists and .settings.yaml is valid YAML."; \
838+
exit 1; \
839+
fi
840+
@echo "Pinning Kind node image: $(KIND_NODE_IMAGE) (from .settings.yaml)"
841+
img="$(KIND_NODE_IMAGE)" yq eval-all '(select(.kind == "Cluster") | .kindV1Alpha4Cluster.nodes[]).image = strenv(img)' $(CTLPTL_CONFIG_FILE) | ctlptl apply -f -
823842
@echo "Waiting for nodes to be ready..."
824843
@kubectl wait --for=condition=ready nodes --all --timeout=300s
825844
@echo "Cluster created. Registry at localhost:$(REGISTRY_PORT)"
@@ -854,10 +873,6 @@ KWOK_VERSION ?= $(shell yq -r '.testing_tools.kwok' .settings.yaml 2>/dev/null)
854873
ifeq ($(KWOK_VERSION),)
855874
KWOK_VERSION := v0.7.0
856875
endif
857-
KIND_NODE_IMAGE ?= $(shell yq -r '.testing.kind_node_image' .settings.yaml 2>/dev/null)
858-
ifeq ($(KIND_NODE_IMAGE),)
859-
KIND_NODE_IMAGE := kindest/node:v1.32.0
860-
endif
861876
CTLPTL_KWOK_CONFIG_FILE := .ctlptl-kwok.yaml
862877

863878
.PHONY: kwok-cluster

api/aicr/v1/server.yaml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2622,6 +2622,13 @@ components:
26222622
mode:
26232623
type: string
26242624
enum: [disabled, customer-managed, aicr-provided]
2625+
runtimeInventory:
2626+
type: object
2627+
required: [mode]
2628+
properties:
2629+
mode:
2630+
type: string
2631+
enum: [enabled, disabled]
26252632
componentRefs:
26262633
type: array
26272634
items:
@@ -2812,7 +2819,10 @@ components:
28122819
allOf:
28132820
- $ref: "#/components/schemas/RecipeResponseBase/properties/configuration"
28142821
- type: object
2815-
required: [slurm]
2822+
# At least one section, but not any particular one: a recipe may
2823+
# record a runtime-inventory selection without Slurm accounting, or
2824+
# the reverse. Requiring `slurm` rejected the former outright.
2825+
minProperties: 1
28162826
additionalProperties: false
28172827
properties:
28182828
slurm:
@@ -2828,6 +2838,14 @@ components:
28282838
mode:
28292839
type: string
28302840
enum: [disabled, customer-managed, aicr-provided]
2841+
runtimeInventory:
2842+
type: object
2843+
required: [mode]
2844+
additionalProperties: false
2845+
properties:
2846+
mode:
2847+
type: string
2848+
enum: [enabled, disabled]
28312849

28322850
ProfileRecipeResponse:
28332851
allOf:

docs/contributor/recipe.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,22 @@ spec:
345345
value: ">= v25.10.0"
346346
```
347347

348+
Host-managed driver floors (GKE COS / A4X Max and similar platforms where
349+
`driver.enabled: false`) use a separate deployment constraint,
350+
`Deployment.gpu-driver.version` (e.g. `">= 580.95.05"`).
351+
`check-nvidia-smi` evaluates it against the nvidia-smi banner on each
352+
verified node; when the constraint is absent the check keeps its
353+
banner-presence behavior and does not invent a floor (#1995).
354+
When the constraint is set but the host driver cannot be measured —
355+
unreadable nvidia-smi banner, no GPU nodes, all GPU nodes cordoned, or
356+
GPU nodes busy with workloads — the check fails closed rather than
357+
Skip. Skip on those paths is preserved only when no floor is
358+
configured. The value must carry a comparison operator (`>=`, `>`,
359+
`<=`, `<`) to behave as a floor; a bare version is exact string match,
360+
so a newer driver would fail. The constraint name is an exact match;
361+
a typo silently disables the floor (shared with
362+
`Deployment.gpu-operator.version`).
363+
348364
For a query `{service: eks, accelerator: gb200, intent: training}`,
349365
the resolver returns three independent maximal leaves —
350366
`gb200-eks-training` (matched by explicit criteria), `gb200-any`

0 commit comments

Comments
 (0)