WIP: feat(collector): project AKS GPU pool driver mode into the snapshot - #1968
WIP: feat(collector): project AKS GPU pool driver mode into the snapshot#1968yuanchen8911 wants to merge 1 commit into
Conversation
Recipe evidence checkNo leaf overlays affected by this PR. This gate is warning-only and never blocks merge. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds an Estimated code review effort: 4 (Complex) | ~60 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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 `@docs/user/cli-reference.md`:
- Line 103: Update the --aks-gpu-pools documentation entry to include a runnable
example that exports node pools with az aks nodepool list -o json into
pools.json and invokes aicr snapshot --aks-gpu-pools pools.json. Also document
the 1 MiB input-size limit while preserving the existing behavior and mode
details.
In `@pkg/collector/k8s/aksgpupools.go`:
- Around line 151-162: Update readAKSAgentPools and its projection callers to
accept and propagate ctx, reject non-regular inputs before opening the path, and
preserve the existing error behavior for invalid files. Replace the
uninterruptible read flow with cancellation-aware processing that checks
ctx.Done() during long-running input handling, while retaining the
MaxAKSGPUPoolsBytes limit.
In `@pkg/collector/k8s/k8s.go`:
- Around line 80-91: Update Collect to pass the successfully parsed aksGPUPools
subtype into emptyK8sMeasurement() on both getClient() and discovery failure
paths. Preserve the existing parsing and error propagation while ensuring
Kubernetes fallback measurements retain the explicit pool projection.
In `@pkg/snapshotter/snapshot.go`:
- Around line 154-156: Update the snapshot collection flow around
parseAKSGPUPoolsPathEnv and collector.WithAKSGPUPoolsPath so missing, malformed,
or oversized explicitly configured AKS pool files propagate as fatal errors
instead of being swallowed by collectSafe. Pre-validate the configured pool
input or distinguish its INVALID_REQUEST result during collection, while
preserving collectSafe’s non-fatal behavior for ordinary collector degradation.
🪄 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: ASSERTIVE
Plan: Enterprise
Run ID: b272054f-7bbc-4e4a-9f23-eea141e8c1be
📒 Files selected for processing (11)
docs/user/cli-reference.mdpkg/cli/snapshot.gopkg/collector/factory.gopkg/collector/k8s/aksgpupools.gopkg/collector/k8s/aksgpupools_test.gopkg/collector/k8s/k8s.gopkg/defaults/timeouts.gopkg/k8s/agent/job.gopkg/k8s/agent/types.gopkg/snapshotter/agent.gopkg/snapshotter/snapshot.go
9d55dc2 to
50b5fbb
Compare
There was a problem hiding this comment.
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 `@pkg/collector/k8s/aksgpupools.go`:
- Around line 162-196: Harden readAKSAgentPools against pathname swaps by
replacing the separate Lstat-then-Open validation with an atomic open using
no-follow/nonblocking flags, then validate the opened file descriptor is regular
before reading. Preserve the existing size limit and error behavior, and ensure
FIFO or symlink substitutions cannot cause a blocking read.
🪄 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: ASSERTIVE
Plan: Enterprise
Run ID: cdcab19f-8940-4ad1-aa9c-c86019d8cf6b
📒 Files selected for processing (11)
docs/user/cli-reference.mdpkg/cli/snapshot.gopkg/collector/factory.gopkg/collector/k8s/aksgpupools.gopkg/collector/k8s/aksgpupools_test.gopkg/collector/k8s/k8s.gopkg/defaults/timeouts.gopkg/k8s/agent/job.gopkg/k8s/agent/types.gopkg/snapshotter/agent.gopkg/snapshotter/snapshot.go
50b5fbb to
4dd7e51
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (1)
pkg/snapshotter/snapshot.go (1)
154-163: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftPreserve fail-loud behavior for the read that actually feeds the snapshot.
Pre-validating the path does not protect the subsequent collector read. A file replacement or deletion between reads is converted by
collectSafeinto a successful snapshot with no AKS GPU-pool measurement, contradicting the documented explicit-input contract.
pkg/snapshotter/snapshot.go#L154-L163: pass the parsed input into collection or propagate failures for explicitly configured AKS input.pkg/cli/snapshot.go#L517-L523: perform host-file validation only in local mode so Job mode reaches its intended host-pathINVALID_REQUESTrejection.🤖 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 `@pkg/snapshotter/snapshot.go` around lines 154 - 163, The explicit AKS GPU-pool input must fail if the collector’s actual read fails, rather than being softened by collectSafe. In pkg/snapshotter/snapshot.go lines 154-163, pass the parsed path into collection or propagate read errors for explicitly configured input. In pkg/cli/snapshot.go lines 517-523, restrict host-file validation to local mode so Job mode preserves its host-path INVALID_REQUEST behavior.
🤖 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.
Duplicate comments:
In `@pkg/snapshotter/snapshot.go`:
- Around line 154-163: The explicit AKS GPU-pool input must fail if the
collector’s actual read fails, rather than being softened by collectSafe. In
pkg/snapshotter/snapshot.go lines 154-163, pass the parsed path into collection
or propagate read errors for explicitly configured input. In pkg/cli/snapshot.go
lines 517-523, restrict host-file validation to local mode so Job mode preserves
its host-path INVALID_REQUEST behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: c7d64cd1-5b8a-4e02-852e-41f1dc8d69dc
📒 Files selected for processing (13)
docs/contributor/collector.mddocs/user/cli-reference.mdpkg/cli/snapshot.gopkg/collector/factory.gopkg/collector/k8s/aksgpupools.gopkg/collector/k8s/aksgpupools_test.gopkg/collector/k8s/k8s.gopkg/collector/k8s/providerpools.gopkg/defaults/timeouts.gopkg/k8s/agent/job.gopkg/k8s/agent/types.gopkg/snapshotter/agent.gopkg/snapshotter/snapshot.go
a340d6c to
4302992
Compare
Add the K8s.aks-gpu-pools.gpu-driver reading (ADR-015 DD3): aicr snapshot --aks-gpu-pools <file> reads an operator-supplied 'az aks nodepool list -o json' dump and projects every NVIDIA GPU agent pool's gpuProfile.driver into the K8s measurement — Install (the AKS Driver-only preinstall, also the documented default when gpuProfile is absent), None (--gpu-driver none), Managed for fully AKS-managed pools, and Mixed when pools disagree. Managed, Mixed, and unknown values deliberately match no profile constraint, so profile-qualified resolution fails closed naming the observed state; no GPU pools omits the reading entirely. AMD accelerators are excluded: the NG family plus AMD sizes living inside the NVIDIA prefixes (MI300X/MI325X in ND, Radeon Pro V620/V710 in NV), so an NVIDIA Install pool beside an AMD pool does not falsely read Mixed. The projection is pure file processing, so it runs at the snapshot orchestration layer, not in a collector: local mode projects before any collector runs, and agent Job mode projects controller-side before deploying — the file never enters the pod — then merges the subtype into the returned snapshot and rewrites the Job's result ConfigMap (Cleanup never deletes it) so no pre-merge artifact persists. aicr validate accepts the same flag for live capture, with the projection failing before any cluster mutation. The file is explicit operator input, so every read or decode failure (including top-level JSON null) is an error rather than a degraded measurement: a typoed path must not masquerade as 'reading unavailable' and steer a profile decision. The read is size-bounded (os.Open + io.LimitReader, 1 MiB) and gated to regular files (Lstat: no FIFOs or symlinks). The bounded reader (providerpools.go) is the shared layer for future per-provider projections (e.g. GKE), each with its own namespaced subtype. The public Go SDK carries the same input: the pkg/client/v1 facade AgentConfig gains AKSGPUPoolsPath, translated through toInternalAgentConfig, so Client.CollectSnapshot can produce the reading the documented collect-then-resolve workflow needs. The reading is inert until a recipe declaration references it: no in-tree recipe does yet. The AKS gpuStack adoption (NVIDIA#1967) consumes it; the shared contract is pinned by TestReadingShapeMatchesProfileContract. Part of NVIDIA#1761 (rollout PR 2, projection half). Signed-off-by: Yuan Chen <yuanchen97@gmail.com>
4302992 to
d7b94ce
Compare
|
Recombined into #1967 per the sequencing discussion: the projection and the adopter proved inseparable in practice (the reading is inert without the declaration, the declaration's snapshot-qualified path is broken without the reading, and review findings repeatedly crossed the PR boundary). The final content of this branch (head d7b94ce, all review rounds addressed) is contained verbatim in #1967's combined commit. Review history stays here for reference; #1761's rollout plan is updated accordingly. |
Summary
Add the
K8s.aks-gpu-pools.gpu-driversnapshot reading:aicr snapshot --aks-gpu-pools <file>projects an operator-suppliedaz aks nodepool list -o jsondump into the K8s measurement, recording each GPU agent pool'sgpuProfile.driverownership mode per ADR-015 DD3.Motivation / Context
The projection half of rollout PR 2 under the ADR-015 implementation umbrella #1761 (ADR-015: recipe configuration profiles, Deferred Decision 3), split out per the sequencing recorded on #1761. The AKS
gpuStackprofile (#1967) requires a distinguishing snapshot signal for its two values; DD3 resolves that signal as the AgentPoolgpuProfile.driverproperty, and PR 2 must supply "a bounded, explicit way to add that projection to a snapshot without adding Azure SDK/auth coupling to the generic profile core."This PR is that mechanism: explicit operator input, no Azure SDK, no auth. The reading is inert until a declaration references it — no in-tree recipe does yet — so this can merge independently of #1933.
Fixes: N/A
Related: #1761, #1967 (consumer; merges after this and #1933)
Type of Change
Component(s) Affected
cmd/aicr,pkg/cli)pkg/collector,pkg/snapshotter)docs/,examples/)Implementation Notes
Projection semantics (
pkg/collector/k8s/aksgpupools.go):Standard_NC*/ND*/NV*), minus AMD accelerators: theNGfamily, MI300X/MI325X (ND sizes AKS requires creating with--gpu-driver none), and Radeon Pro V620/V710 (NV sizes). Without the marker exclusion, a supported NVIDIA-Install + AMD-MI300X cluster would falsely projectMixed. Known limitation (documented in code): detection is prefix+marker based, so a hypothetical future NVIDIA family outside NC/ND/NV would be skipped; the AgentPool object carries no vendor field to do better.gpuProfile.driverwhen set; absent or nullgpuProfilefollows the provider's documentedInstalldefault; a pool withgpuProfile.nvidiapresent projects asManaged(fully AKS-managed, out of AICR scope).Mixed.Managed,Mixed, and unknown provider strings deliberately match no declared profile constraint, so profile-qualified resolution fails closed naming the observed state.gpu-driverkey is omitted; constraint evaluation reports the reading unavailable and fails closed.gpu-pool-countand a sortedgpu-poolsroster (name=mode,...) accompany the reading for diagnostics.The projection runs at the orchestration layer, not in a collector. It is pure file processing, so it never enters the cluster:
pkg/snapshotterprojects the file up front (a bad file fails the run in milliseconds, before any deploy or collection) and attaches the subtype to the K8s measurement. In agent Job mode the controller-side CLI merges the projection into the snapshot the Job returns — the file never needs to be visible in-pod, so Job mode works with no ConfigMap forwarding. The Job's result ConfigMap is then rewritten with the merged bytes (Cleanup deletes Job+RBAC but never that ConfigMap, so without the rewrite a stale projection-less snapshot would persist there — including when the ConfigMap is the user-requested output). This replaces the earlier collector-field + env-forwarding design and its Job-mode rejection: the reading is now producible by the ordinaryaicr snapshotworkflow in both modes, which #1967's mandatory constraint requires.aicr validateaccepts the same flag for its live-capture path.Fail-loud contract. The file arrives via an explicit flag, so open/decode/size failures (including a top-level JSON
null, whichjson.Unmarshalwould otherwise silently accept into a slice) are errors that fail the snapshot run — never a degraded measurement, and never subject to the snapshotter's degrade-to-warning collector policy. The read is size-bounded (os.Open+io.LimitReader, 1 MiB cap inpkg/defaults) and gated to regular files (Lstat: no FIFOs, no symlinks).Design choice for review — explicit input vs. automatic acquisition. This lands the ADR-friendly floor: the operator runs
az aks nodepool list -g <rg> --cluster-name <name> -o jsonand passes the file. Anazshell-out or IMDS-based acquisition would be a convenience follow-up, not a replacement — the explicit path stays as the airgap-friendly, auth-free baseline either way.Generalization path (GKE and beyond). The concept extends to other clouds, split deliberately across two layers:
gpuDriverInstallationConfig). A new provider adds its own projector emitting its own namespaced subtype (gke-gpu-poolsbesideaks-gpu-pools) — no cross-provider pools schema, so each subtype's fail-closed constraint semantics stay exact.readBoundedPoolsFile(pkg/collector/k8s/providerpools.go) carries the bounded fail-loud read (Lstat regular-file gate +os.Open+io.LimitReader); the flag plumbing pattern and the orchestration pre-flight are reused as-is.--gke-gpu-pools, …), never a generic flag with a provider discriminator — the flag name tells the operator which cloud CLI command produces the input, and the parser knows the schema without sniffing.The pattern is documented for contributors in
docs/contributor/collector.md("Provider Node-Pool Projections").Public SDK surface. The
pkg/client/v1facadeAgentConfigcarriesAKSGPUPoolsPath(translated intoInternalAgentConfig, pinned by an SDK-level test), soClient.CollectSnapshotcan produce the reading through the documented collect-then-resolve workflow. This is deliberately different fromClusterConfigPath/DiscoverNetwork, which stay off the facade — those are optional in-pod network enrichments, whereas this is controller-side input that AKS profile-qualified resolution requires.Shared contract with #1967.
TestReadingShapeMatchesProfileContractpins the reading to the literal subtype/key/values the AKS declaration's constraints name, so drift between the two PRs surfaces as a test failure.Remaining work before undraft
azshell-out / node-label alternatives).docs/integrator/aks-gpu-setup.mdsnippet showing theazcommand + flag in the snapshot flow ("Recording the pool mode in snapshots" under GPU Driver Setup).make qualifyfull gate.Testing
Table-driven projection tests cover: all-Install, all-None, absent and null
gpuProfiledefaulting toInstall,Mixed,Managed, unknown-value preservation, VM-family filtering (NV in; NG, MI300X-class ND, and Radeon NV AMD sizes out; AMD-only cluster omits the reading), and the no-GPU-pools omission. Fail-loud tests cover missing file, wrong JSON shape (the{"value":[]}trap), top-level JSONnull, malformed JSON, the size cap, and non-regular files. Orchestration tests pin both modes: local-modeMeasureattaches the subtype and fails before any collector runs on a bad file; the Job-modemergeAKSGPUPoolsround-trip lands the subtype on the returned snapshot. Coverage:pkg/collector/k8s89.5%.Risk Assessment
Rollout notes: No behavior change unless
--aks-gpu-poolsis passed; the reading is inert until a recipe declaration references it (#1967).Checklist
make testwith-race)make lint)git commit -S) — GPG signing info