Skip to content

feat(platform): auto-wire KubeVirt permittedHostDevices and HostDevices feature gate when gpu-operator is enabled - #2768

Merged
Aleksei Sviridkin (lexfrei) merged 7 commits into
mainfrom
feat/kubevirt-gpu-wiring
Jun 9, 2026
Merged

Aleksei Sviridkin (lexfrei) merged 7 commits into
mainfrom
feat/kubevirt-gpu-wiring

Conversation

@lexfrei

@lexfrei Aleksei Sviridkin (lexfrei) commented May 28, 2026 •

Copy link
Copy Markdown
Contributor

Closes #2765.

What this PR does

Makes the passthrough and vGPU variants of cozystack.gpu-operator produce a KubeVirt CR that is immediately usable, without an out-of-band kubectl patch. Today the gpu-operator stack reports green, nvidia.com/<model> shows up under node .status.allocatable, but every VirtualMachine referencing the resource via domain.devices.hostDevices is rejected by the admission webhook because HostDevices is not in developerConfiguration.featureGates and the resource is not listed under permittedHostDevices. That manual reconciliation is now driven by the platform.

The change has three parts.

packages/system/kubevirt now parameterizes the KubeVirt CR template. developerConfiguration.featureGates keeps its existing static defaults and appends .Values.extraFeatureGates; spec.configuration.permittedHostDevices renders verbatim from .Values.permittedHostDevices when set; spec.configuration.mediatedDevicesConfiguration does the same. Defaults stay empty so the rendered CR is byte-identical to the previous template when no overrides are supplied. The chart's make update target re-applies the four sed transforms after fetching the upstream CR, so refreshing the KubeVirt release version stays a single command.

packages/core/platform adds two defaults tables under files/. gpu-passthrough-defaults.yaml covers Hopper (H100/H200), Ada Lovelace (L4/L40/L40S), Ampere (A100 PCIe/SXM, A40, A30, A10), Turing (T4) and Volta (V100/V100S); PCI vendor:device pairs are stable, resourceName slugs follow the <arch>_<model>_<form>_<mem> convention nvidia-sandbox-device-plugin generates as of v25.x, and externalResourceProvider: true is set everywhere because those resources are advertised by the sandbox plugin rather than KubeVirt's in-tree device plugin. gpu-vgpu-defaults.yaml covers the Pascal–Ampere mdev profile range (A100-40C/80C, A40-24Q/48Q, A30-24C, A10-24Q, V100D-32C, T4-16Q) — the same family span the upstream vgpu-device-manager walks /sys/class/mdev_bus/ for. Ada Lovelace and Blackwell SR-IOV vGPU is intentionally out of scope for the default table and is expected to be advertised via the user-override hook described below.

templates/bundles/iaas.yaml now selects between the two tables via a new bundles.iaas.gpuOperatorVariant knob (default for passthrough, vgpu for mediated; default is passthrough). The same variant flows through to the gpu-operator Package CR, replacing the previous always-default call. When the package is enabled, the platform injects HostDevices into extraFeatureGates plus the chosen defaults into permittedHostDevices for the kubevirt component's values. Operators extend or replace via top-level platform values:

gpu:
  replaceDefaults: false              # append (default) vs. wipe-and-replace
  permittedHostDevices:
    pciHostDevices: []                # cluster-specific PCI passthrough entries
    mediatedDevices: []               # cluster-specific vGPU entries
  mediatedDevicesConfiguration: {}    # extra mediated-device types / per-node mappings

docs/gpu-vgpu.md is updated to drop the manual kubectl patch step and describe the auto-wiring contract, the per-variant defaults, the escape hatches, and the sandbox-device-plugin resourceName slug convention so an operator whose node publishes a different name knows where to override.

Test coverage

helm-unittest covers eight branches in packages/core/platform/tests/bundles_gpu_kubevirt_wiring_test.yaml: gpu-operator disabled emits no extras; gpu-operator enabled at default variant emits the HostDevices gate plus pciHostDevices; vgpu variant switches to mediatedDevices plus mediatedDevicesConfiguration; user overrides append by default; replaceDefaults: true wipes the platform table; an unknown variant fails fast with a descriptive error. packages/system/kubevirt/tests/kubevirt_cr_test.yaml pins the empty-values render and the three populated shapes at the CR template level. make helm-unit-tests passes locally on the full repo.

Release note

feat(platform): the KubeVirt CR is now auto-configured for GPU host-device passthrough (HostDevices feature gate plus permittedHostDevices populated from NVIDIA defaults) whenever cozystack.gpu-operator is in bundles.enabledPackages. Operators no longer need a manual kubectl patch to make VMs schedule against a GPU. The variant is selected via bundles.iaas.gpuOperatorVariant (default: passthrough; vgpu: mediated). Extend or replace the NVIDIA defaults via .gpu.permittedHostDevices and .gpu.replaceDefaults.

**Upgrade note:** the bundle now OWNS spec.configuration.permittedHostDevices on the KubeVirt CR. If you previously hand-edited it (kubectl edit kubevirt), the first reconcile after upgrade overwrites your manual entries with the rendered NVIDIA default table. Before upgrading, move any custom entries into .gpu.permittedHostDevices (set .gpu.replaceDefaults: true to keep only your list) and verify each resourceName against what your nodes advertise (kubectl describe node <node> | grep nvidia.com/) — the default table now carries the exact slug the sandbox device plugin generates, which upper-cases the card's PCI-IDs name and keeps the Tesla/GL tokens (e.g. a Tesla T4 is nvidia.com/TU104GL_TESLA_T4), but a different plugin build can publish a different string; a mismatch makes the admission webhook reject GPU VMs on their next restart or migration.

Summary by CodeRabbit

  • New Features

    • Bundle-managed GPU Operator with selectable passthrough vs vGPU variants; platform now injects GPU settings into KubeVirt and forwards vGPU manager overrides when enabled.
    • Default platform mappings for PCI passthrough and vGPU mediated-device resources added.
  • Documentation

    • Expanded GPU/vGPU deployment guide with bundle-managed vs manual guidance, wiring/precedence rules, resource-name conventions, and verification steps.
  • Tests

    • New and expanded tests for bundle→KubeVirt wiring, variant behaviors, default/override merging, and idempotent template parameterization.
  • Chores

    • Added Helm test target and hardened KubeVirt template update/idempotency checks.

@coderabbitai

coderabbitai Bot commented May 28, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b81ee240-bd16-44ab-998f-2a86c4e761f0

📥 Commits

Reviewing files that changed from the base of the PR and between bf8cda4 and 117d317.

📒 Files selected for processing (11)
  • docs/gpu-vgpu.md
  • packages/core/platform/files/gpu-passthrough-defaults.yaml
  • packages/core/platform/files/gpu-vgpu-defaults.yaml
  • packages/core/platform/templates/bundles/iaas.yaml
  • packages/core/platform/tests/bundles_gpu_kubevirt_wiring_test.yaml
  • packages/core/platform/values.yaml
  • packages/system/kubevirt/Makefile
  • packages/system/kubevirt/templates/kubevirt-cr.yaml
  • packages/system/kubevirt/tests/kubevirt_cr_test.yaml
  • packages/system/kubevirt/tests/update_idempotency_test.sh
  • packages/system/kubevirt/values.yaml
✅ Files skipped from review due to trivial changes (3)
  • packages/core/platform/files/gpu-passthrough-defaults.yaml
  • packages/system/kubevirt/values.yaml
  • docs/gpu-vgpu.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/system/kubevirt/templates/kubevirt-cr.yaml
  • packages/system/kubevirt/tests/kubevirt_cr_test.yaml
  • packages/core/platform/values.yaml
  • packages/core/platform/templates/bundles/iaas.yaml

📝 Walkthrough

Walkthrough

Platform auto-wires KubeVirt feature gates and permittedHostDevices for NVIDIA passthrough and vGPU modes when cozystack.gpu-operator is enabled, adds bundle knobs to select variant and vGPU manager settings, provides platform device defaults, and adds tests and templating support.

Changes

GPU operator and KubeVirt integration

Layer / File(s) Summary
Documentation and user guidance
docs/gpu-vgpu.md
Updated to explain bundle-managed vGPU/passthrough flows, how gpu.vgpuManager forwards into emitted Package CRs, and when manual KubeVirt wiring is required.
NVIDIA GPU defaults
packages/core/platform/files/gpu-passthrough-defaults.yaml, packages/core/platform/files/gpu-vgpu-defaults.yaml
New YAML defaults mapping NVIDIA PCI vendor:device IDs to resourceName for passthrough and mapping vGPU mdevNameSelectors to resourceNames with externalResourceProvider: true.
iaas bundle wiring and operator forwarding
packages/core/platform/templates/bundles/iaas.yaml
Builds kubevirtValues, validates bundles.iaas.gpuOperatorVariant, selects/merges passthrough or vGPU defaults with user inputs (honoring replaceDefaults), injects HostDevices gate and permittedHostDevices/mediatedDevicesConfiguration, and emits cozystack.gpu-operator only when GPU is enabled while forwarding vGPU-specific overrides.
Platform bundle GPU wiring tests
packages/core/platform/tests/bundles_gpu_kubevirt_wiring_test.yaml
Extensive suite validating disabled/enabled behavior, default vs vGPU variants, merge/replace semantics, nil/null robustness, resourceName generation, forwarding of vgpuManager and imagePullSecrets, and package precedence.
Platform and KubeVirt values schema
packages/core/platform/values.yaml, packages/system/kubevirt/values.yaml
Adds bundles.iaas.gpuOperatorVariant and a gpu block with replaceDefaults, permittedHostDevices, mediatedDevicesConfiguration, vgpuManager and vgpuDeviceManager.enabled; KubeVirt values expose cpuAllocationRatio, extraFeatureGates, permittedHostDevices, and mediatedDevicesConfiguration.
KubeVirt chart templates and build
packages/system/kubevirt/Makefile, packages/system/kubevirt/templates/kubevirt-cr.yaml
Makefile adds helm unittest and reworks update for idempotent parameterization patches; kubevirt CR template appends .Values.extraFeatureGates into spec.configuration.developerConfiguration.featureGates.
KubeVirt CR parameterization & update idempotency tests
packages/system/kubevirt/tests/kubevirt_cr_test.yaml, packages/system/kubevirt/tests/update_idempotency_test.sh
Tests rendering of cpuAllocationRatio, correct concatenation of extraFeatureGates, verbatim emission of permittedHostDevices and mediatedDevicesConfiguration, and ensures make update reinserts missing template blocks idempotently.

Sequence Diagram

sequenceDiagram
  participant Platform
  participant IaaSBundle
  participant KubeVirtChart
  participant GPUOperator
  participant KubeVirt

  Platform->>IaaSBundle: bundles.iaas.gpuOperatorVariant + gpu.* values
  IaaSBundle->>IaaSBundle: validate variant and select defaults
  IaaSBundle->>IaaSBundle: merge or replace user device lists
  alt Passthrough
    IaaSBundle->>KubeVirtChart: kubevirtValues with extraFeatureGates and pciHostDevices
  else vGPU
    IaaSBundle->>KubeVirtChart: kubevirtValues with extraFeatureGates and mediatedDevicesConfiguration
    IaaSBundle->>GPUOperator: forward vgpuManager and vgpuDeviceManager settings
  end
  KubeVirtChart->>KubeVirt: Rendered CR with featureGates and permittedHostDevices
  GPUOperator->>KubeVirt: publishes device resources via sandbox-device-plugin
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Suggested labels

size/L, area/kubernetes

Suggested reviewers

  • kvaps
  • lllamnyp
  • androndo
  • IvanHunters
  • sircthulhu

Poem

🐰 In racks where silent GPUs hum,

vGPUs and passthroughs dance as one,
Bundles whisper configs into KubeVirt's ear,
Nodes grant resources, admissions cheer,
This rabbit hops — the GPU is near!

🚥 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 accurately summarizes the main change: auto-wiring KubeVirt permittedHostDevices and HostDevices feature gate when gpu-operator is enabled, which is the primary objective of the PR.
Linked Issues check ✅ Passed The PR fully addresses #2765 requirements: auto-wiring HostDevices feature gate and permittedHostDevices with appropriate GPU entries for both passthrough and vGPU variants through parameterized KubeVirt templates and platform bundle logic.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the GPU auto-wiring objective: KubeVirt template parameterization, GPU defaults files, bundle integration, platform values, tests, and documentation updates supporting the core requirement.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/kubevirt-gpu-wiring

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions github-actions Bot added size/XL This PR changes 500-999 lines, ignoring generated files area/platform Issues or PRs related to platform infrastructure (bundle, flux, talos, installer) kind/feature Categorizes issue or PR as related to a new feature labels May 28, 2026
@lexfrei
Aleksei Sviridkin (lexfrei) force-pushed the feat/kubevirt-gpu-wiring branch 2 times, most recently from 4d1bd0c to 796f362 Compare May 28, 2026 17:43
@github-actions github-actions Bot added size/XXL This PR changes 1000+ lines, ignoring generated files and removed size/XL This PR changes 500-999 lines, ignoring generated files labels May 28, 2026
@lexfrei
Aleksei Sviridkin (lexfrei) force-pushed the feat/kubevirt-gpu-wiring branch 3 times, most recently from 5286e0b to ae699f9 Compare May 28, 2026 18:20
@lexfrei
Aleksei Sviridkin (lexfrei) marked this pull request as ready for review May 28, 2026 18:21
@dosubot dosubot Bot added area/virtualization Issues or PRs related to virtualization (kubevirt, cdi, vmi, vm-import) kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API labels May 28, 2026
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Actionable comments posted: 0

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request automates the KubeVirt configuration required for GPU support in Cozystack. By dynamically injecting the necessary feature gates and device definitions into the KubeVirt CR based on the enabled GPU operator variant, it eliminates the need for manual post-deployment patching. The changes also introduce configurable defaults for common NVIDIA hardware and provide escape hatches for cluster-specific overrides.

Highlights

  • Automated KubeVirt Configuration: Automatically wires the HostDevices feature gate and populates permittedHostDevices in the KubeVirt CR when the cozystack.gpu-operator is enabled, removing the need for manual patching.
  • GPU Variant Support: Introduces the bundles.iaas.gpuOperatorVariant knob to toggle between default (passthrough) and vgpu (mediated) modes, allowing for flexible GPU deployment strategies.
  • Default GPU Configuration Tables: Adds pre-populated default tables for common NVIDIA datacenter GPUs, simplifying cluster setup while allowing for user-defined overrides.
  • Enhanced Test Coverage: Added comprehensive helm-unittest suites to validate bundle wiring and KubeVirt CR template rendering.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request implements GPU host-device wiring for VirtualMachine workloads in Cozystack, enabling automatic injection of PCI passthrough and mediated vGPU configurations into the KubeVirt CR when the gpu-operator package is enabled. It introduces default configuration files for both GPU variants, updates the iaas bundle template, and adds comprehensive unit tests. The review feedback highlights potential nil pointer dereference risks in the iaas.yaml template when accessing nested keys under .Values.gpu if they are omitted or null. It is recommended to define safe helper variables at the top of the template to handle these values safely.

Comment on lines +5 to +8
{{- $kubevirtValues := dict -}}
{{- if .Values.resources.cpuAllocationRatio -}}
{{- $_ := set $kubevirtComponents "kubevirt" (dict "values" (dict "cpuAllocationRatio" (.Values.resources.cpuAllocationRatio | int))) -}}
{{- $_ := set $kubevirtValues "cpuAllocationRatio" (.Values.resources.cpuAllocationRatio | int) -}}
{{- end -}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

To prevent potential nil pointer dereference errors when .Values.gpu or its nested keys are omitted or set to null in user-supplied values, we should define safe helper variables at the top of the template.

In Go templates, expressions like (.Values.gpu).permittedHostDevices are evaluated before the default function is called. If .Values.gpu is nil, evaluating any field on it will immediately cause a template rendering error.

Defining these helper variables at the top of the file makes them safely available throughout the entire template.

{{- $kubevirtValues := dict -}}
{{- if .Values.resources.cpuAllocationRatio -}}
{{- $_ := set $kubevirtValues "cpuAllocationRatio" (.Values.resources.cpuAllocationRatio | int) -}}
{{- end -}}
{{- $gpuValues := .Values.gpu | default dict -}}
{{- $permittedHostDevices := $gpuValues.permittedHostDevices | default dict -}}
{{- $vgpuDeviceManager := $gpuValues.vgpuDeviceManager | default dict -}}
{{- $deviceManagerOn := $vgpuDeviceManager.enabled | default false -}}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The .Values.gpu accesses here are intentionally fully parenthesized, which is nil-safe. (((.Values.gpu).permittedHostDevices).pciHostDevices) yields an invalid value that default then absorbs when any hop is nil, whereas the bare .Values.gpu.permittedHostDevices.pciHostDevices panics with nil pointer evaluating interface {}.permittedHostDevices on the first nil hop. I added regression cases (gpu: null in both variants and blank sub-keys) plus a comment so the parentheses aren't flattened away; a mutation check confirms they fail the moment the parentheses are removed. The same applies to the other threads on this file (lines 41/71/121).

Comment on lines +38 to +41
{{- $userPci := default (list) (((.Values.gpu).permittedHostDevices).pciHostDevices) -}}
{{- $userMdev := default (list) (((.Values.gpu).permittedHostDevices).mediatedDevices) -}}
{{- $userMdevConfig := default (dict) (.Values.gpu).mediatedDevicesConfiguration -}}
{{- $replace := default false (.Values.gpu).replaceDefaults -}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Use the safe helper variables defined at the top of the template to avoid nil pointer dereferences when accessing nested keys under .Values.gpu.

{{- $userPci := $permittedHostDevices.pciHostDevices | default list -}}
{{- $userMdev := $permittedHostDevices.mediatedDevices | default list -}}
{{- $userMdevConfig := $gpuValues.mediatedDevicesConfiguration | default dict -}}
{{- $replace := $gpuValues.replaceDefaults | default false -}}

Comment on lines +70 to +71
{{- $deviceManagerOn := default false (((.Values.gpu).vgpuDeviceManager).enabled) -}}
{{- if and (not $replace) $deviceManagerOn -}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Use the globally defined $deviceManagerOn helper variable instead of re-evaluating the nested path, which is prone to nil pointer dereferences.

{{- if and (not $replace) $deviceManagerOn -}}

Comment on lines +114 to +121
{{- $vgpuMgr := default (dict) (.Values.gpu).vgpuManager -}}
{{- $imageCustomized := and (hasKey $vgpuMgr "image") (ne (default "" $vgpuMgr.image) "vgpu-manager") -}}
{{- if or $vgpuMgr.repository $vgpuMgr.version $imageCustomized $vgpuMgr.imagePullSecrets -}}
{{- $_ := set $gpuOperatorOverrides "vgpuManager" $vgpuMgr -}}
{{- end -}}
{{- if (((.Values.gpu).vgpuDeviceManager).enabled) -}}
{{- $_ := set $gpuOperatorOverrides "vgpuDeviceManager" (dict "enabled" true) -}}
{{- end -}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Use the safe helper variables $gpuValues and $deviceManagerOn to prevent nil pointer dereferences when configuring the GPU Operator overrides.

{{- $vgpuMgr := $gpuValues.vgpuManager | default dict -}}
{{- $imageCustomized := and (hasKey $vgpuMgr "image") (ne (default "" $vgpuMgr.image) "vgpu-manager") -}}
{{- if or $vgpuMgr.repository $vgpuMgr.version $imageCustomized $vgpuMgr.imagePullSecrets -}}
{{- $_ := set $gpuOperatorOverrides "vgpuManager" $vgpuMgr -}}
{{- end -}}
{{- if $deviceManagerOn -}}
{{- $_ := set $gpuOperatorOverrides "vgpuDeviceManager" (dict "enabled" true) -}}
{{- end -}}

@kvaps

Copy link
Copy Markdown
Member

Migration note: auto-wiring silently overwrites hand-edited permittedHostDevices

Flagging an upgrade-time footgun for operators who already run GPU passthrough on the old manual flow, with a concrete real-world example. Not a blocker — the override path covers it — but it's silent today and worth an explicit upgrade warning.

Mechanism. Before this PR, templates/kubevirt-cr.yaml did not carry permittedHostDevices at all, so operators injected it by hand (kubectl edit kubevirt) and Helm never reconciled the field away. After this PR the template owns the field, so on the first reconcile post-upgrade Helm renders permittedHostDevices from the platform defaults (files/gpu-passthrough-defaults.yaml + .gpu.permittedHostDevices) and overwrites whatever the operator set manually.

For fleets whose cards match the default table exactly, this is seamless. The trap is resourceName drift: the table is a static list and the resource names must match what the node's nvidia-sandbox-device-plugin actually advertises. Older NVIDIA naming (TESLA_*) is the common case that diverges.

Concrete example. A real fleet with four passthrough cards:

Card PCI resourceName in use Default table Result on upgrade
L40S 10DE:26B9 nvidia.com/AD102GL_L40S same ✅ seamless
A100 PCIe 80GB 10DE:20B5 nvidia.com/GA100_A100_PCIE_80GB same ✅ seamless
A100 SXM4 80GB 10DE:20B2 nvidia.com/GA100_A100_SXM4_80GB same ✅ seamless
Tesla T4 10DE:1EB8 nvidia.com/TU104GL_TESLA_T4 nvidia.com/TU104GL_T4 ❌ breaks

PCI matches for the T4, but the table renames it TU104GL_T4. After upgrade the CR permits TU104GL_T4 while the node still advertises TU104GL_TESLA_T4 — so existing T4 VMs are rejected by the admission webhook on the next restart/migration, and nothing is allocatable under the permitted name. The change is invisible until a VM reschedules.

Suggested mitigations (docs-only, no code change required):

  1. Add an upgrade note to the release-note block and to website#556: "The platform now manages spec.configuration.permittedHostDevices. If you previously hand-edited it, move your entries into .gpu.permittedHostDevices and verify each resourceName against what your node advertises (kubectl describe node <node> | grep nvidia.com/) before upgrading — custom names (e.g. the legacy TESLA_* slugs) are otherwise overwritten by the default table and those VMs stop scheduling."
  2. Recommend replaceDefaults: true with a curated list for such fleets, rather than appending — appending a second entry for the same pciVendorSelector (default TU104GL_T4 + override TU104GL_TESLA_T4 on 10DE:1EB8) yields two resourceNames for one selector, which KubeVirt resolves non-deterministically.

The wiring logic itself looks correct; this is purely about making the takeover of a previously hand-managed field non-silent at upgrade.

@kvaps Andrei Kvapil (kvaps) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Requesting changes to gate the merge on one migration-safety item — the wiring logic itself is correct and I'm happy with it.

This PR makes templates/kubevirt-cr.yaml take ownership of spec.configuration.permittedHostDevices, which until now was hand-managed by operators (kubectl edit kubevirt). On the first reconcile after upgrade, Helm overwrites those manual entries with the rendered default table. Fleets whose resourceNames diverge from the static table — the common case being the legacy NVIDIA TESLA_* naming — will have running VMs silently rejected by the admission webhook on their next restart/migration.

Concrete example and the full breakdown are in #2768 (comment) (Tesla T4: table renames 10DE:1EB8 to TU104GL_T4 while real nodes advertise TU104GL_TESLA_T4).

This needs to be resolved before merge — it doesn't have to be code. Any of:

  • an explicit upgrade note in the release-note block + website#556 telling operators to move hand-edited entries into .gpu.permittedHostDevices and verify each resourceName against kubectl describe node | grep nvidia.com/ before upgrading, and/or
  • whatever you think is the right way to make the takeover of a previously hand-managed field non-silent.

Once there's a clear migration story for operators who already hand-edited permittedHostDevices, I'm good to approve.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/system/kubevirt/Makefile (3)

30-30: 💤 Low value

Clarify the error message for missing template file.

The error message says "drop a hand-merged upstream CR there first" but could be more explicit about what "hand-merged" means and where to source the upstream CR from.

📝 Suggested improvement
-	`@test` -f templates/kubevirt-cr.yaml || { echo "ERROR: templates/kubevirt-cr.yaml not found — drop a hand-merged upstream CR there first" >&2; exit 1; }
+	`@test` -f templates/kubevirt-cr.yaml || { echo "ERROR: templates/kubevirt-cr.yaml not found — manually merge upstream KubeVirt CR changes into that file first (see comments above for workflow)" >&2; exit 1; }
🤖 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 `@packages/system/kubevirt/Makefile` at line 30, Update the error message in
the Makefile check for templates/kubevirt-cr.yaml so it explicitly tells the
user what "hand-merged upstream CR" means and where to get it; change the echo
in the test that checks templates/kubevirt-cr.yaml to say something like "ERROR:
templates/kubevirt-cr.yaml not found — please place the upstream kubevirt CR
here (manually merged from the upstream release CR, e.g. fetch from the kubevirt
repository or the vendor's release tarball)". Refer to the test command that
checks for templates/kubevirt-cr.yaml in the Makefile and ensure the message
gives clear sourcing guidance and action to perform.

28-28: 💤 Low value

Provide concrete macOS sed guidance.

The comment mentions running under a Linux container or using gsed on macOS, but doesn't provide the specific command. Since GNU sed is a hard requirement (BSD sed's -i syntax and behavior differs), adding a concrete example would help macOS developers.

📝 Suggested improvement
-# GNU sed is required — on macOS run under a Linux container or via gsed.
+# GNU sed is required — on macOS install via `brew install gnu-sed` and use `gmake SED=gsed update` or run in a Linux container.

Note: This assumes the Makefile could be extended to support a SED variable, or alternatively just document the gsed command directly if the pattern is simple enough for users to adapt manually.

🤖 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 `@packages/system/kubevirt/Makefile` at line 28, Update the Makefile comment to
give concrete macOS guidance: mention installing GNU sed (e.g., via Homebrew as
"brew install gnu-sed") and show how to use it by either exporting/setting a SED
variable (SED=gsed) or invoking gsed explicitly in the Makefile targets that
rely on GNU sed; reference adding a SED variable and replacing plain "sed" calls
with "$(SED)" (or documenting to call "gsed -i" instead) so macOS users have an
exact command to run.

33-36: ⚡ Quick win

Consider documenting sed pattern assumptions.

The sed patterns rely on specific anchors (developerConfiguration:, - VMExport, evictionStrategy:) that could change in future upstream KubeVirt releases. While the sanity checks at lines 41-44 will catch missing anchors, documenting the exact anchor requirements in the comments would help future maintainers understand what to verify during manual upstream merges.

📋 Suggested documentation addition

Add after line 26:

+#   4. When hand-merging, preserve these exact anchor lines (required by sed):
+#      - 'namespace: kubevirt' → patched to 'namespace: cozy-kubevirt'
+#      - '    developerConfiguration:' → cpuAllocationRatio inserted after
+#      - '      - VMExport' → extraFeatureGates appended after
+#      - '    evictionStrategy:' → permittedHostDevices/mediatedDevices inserted before
 #
 # GNU sed is required — on macOS run under a Linux container or via gsed.
🤖 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 `@packages/system/kubevirt/Makefile` around lines 33 - 36, Add a short comment
above the sed/grep block that documents the expected anchors and context in
templates/kubevirt-cr.yaml (specifically the presence of
"developerConfiguration:", the list item "- VMExport", and the
"evictionStrategy:" field) and explain that the sed commands rely on those exact
anchors and indentation; mention that these anchors must be verified when
merging upstream and reference the sanity checks that follow the block so
maintainers know where to look if anchors change.
🤖 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 `@packages/system/kubevirt/Makefile`:
- Around line 41-44: The grep sanity checks in the Makefile are emitting
misleading messages (they search for template directives like '{{- if
.Values.cpuAllocationRatio }}' but error text mentions anchors such as
'developerConfiguration:'), so update each failing-branch message to reference
the actual template directive being checked (e.g., '{{- if
.Values.cpuAllocationRatio }}', '{{- range .Values.extraFeatureGates }}', '{{-
with .Values.permittedHostDevices }}', '{{- with
.Values.mediatedDevicesConfiguration }}') and/or state "template directive not
found" so the error accurately reflects a missing template insertion rather than
a missing anchor; modify the error strings in the lines containing the grep
calls to include the exact pattern being searched and a brief context like
"template directive '...pattern...' not found in templates/kubevirt-cr.yaml".

---

Nitpick comments:
In `@packages/system/kubevirt/Makefile`:
- Line 30: Update the error message in the Makefile check for
templates/kubevirt-cr.yaml so it explicitly tells the user what "hand-merged
upstream CR" means and where to get it; change the echo in the test that checks
templates/kubevirt-cr.yaml to say something like "ERROR:
templates/kubevirt-cr.yaml not found — please place the upstream kubevirt CR
here (manually merged from the upstream release CR, e.g. fetch from the kubevirt
repository or the vendor's release tarball)". Refer to the test command that
checks for templates/kubevirt-cr.yaml in the Makefile and ensure the message
gives clear sourcing guidance and action to perform.
- Line 28: Update the Makefile comment to give concrete macOS guidance: mention
installing GNU sed (e.g., via Homebrew as "brew install gnu-sed") and show how
to use it by either exporting/setting a SED variable (SED=gsed) or invoking gsed
explicitly in the Makefile targets that rely on GNU sed; reference adding a SED
variable and replacing plain "sed" calls with "$(SED)" (or documenting to call
"gsed -i" instead) so macOS users have an exact command to run.
- Around line 33-36: Add a short comment above the sed/grep block that documents
the expected anchors and context in templates/kubevirt-cr.yaml (specifically the
presence of "developerConfiguration:", the list item "- VMExport", and the
"evictionStrategy:" field) and explain that the sed commands rely on those exact
anchors and indentation; mention that these anchors must be verified when
merging upstream and reference the sanity checks that follow the block so
maintainers know where to look if anchors change.
🪄 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: Pro

Run ID: e7d9e363-d687-4997-b604-65f7b57e7428

📥 Commits

Reviewing files that changed from the base of the PR and between ae699f9 and 883513b.

📒 Files selected for processing (10)
  • docs/gpu-vgpu.md
  • packages/core/platform/files/gpu-passthrough-defaults.yaml
  • packages/core/platform/files/gpu-vgpu-defaults.yaml
  • packages/core/platform/templates/bundles/iaas.yaml
  • packages/core/platform/tests/bundles_gpu_kubevirt_wiring_test.yaml
  • packages/core/platform/values.yaml
  • packages/system/kubevirt/Makefile
  • packages/system/kubevirt/templates/kubevirt-cr.yaml
  • packages/system/kubevirt/tests/kubevirt_cr_test.yaml
  • packages/system/kubevirt/values.yaml
✅ Files skipped from review due to trivial changes (1)
  • docs/gpu-vgpu.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/core/platform/files/gpu-passthrough-defaults.yaml
  • packages/system/kubevirt/values.yaml
  • packages/system/kubevirt/templates/kubevirt-cr.yaml
  • packages/core/platform/values.yaml
  • packages/system/kubevirt/tests/kubevirt_cr_test.yaml
  • packages/core/platform/files/gpu-vgpu-defaults.yaml
  • packages/core/platform/templates/bundles/iaas.yaml

Comment thread packages/system/kubevirt/Makefile Outdated
Aleksei Sviridkin (lexfrei) added a commit to cozystack/website that referenced this pull request Jun 5, 2026
…-wires permittedHostDevices

Step 2 of the GPU Passthrough guide instructed operators to
`kubectl edit kubevirt -n cozy-kubevirt` and hand-paste a
permittedHostDevices.pciHostDevices block. cozystack/cozystack#2768
removes the need for that step: when cozystack.gpu-operator is in
bundles.enabledPackages, the platform now mirrors the chosen GPU
variant into the KubeVirt CR automatically — appending HostDevices
to the feature-gate list and rendering a starter NVIDIA pciHostDevices
table covering Hopper, Ada Lovelace, Ampere, Turing and Volta.

The new step 2 documents the contract (what the platform auto-injects
and why), the verification recipe, the escape hatch via
.gpu.permittedHostDevices / .gpu.replaceDefaults, and the manual
Package-CR override path used by operators who need overrides the
bundle does not expose (driver settings, custom node selectors,
validator / dcgmExporter tweaks) — in that flow they also hand-craft
the matching cozystack.kubevirt Package CR.

Only next/virtualization/gpu.md is updated; v1.4 and earlier
describe releases that still require the manual patch and stay
as-is.

Assisted-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
@lexfrei

Copy link
Copy Markdown
Contributor Author

Andrei Kvapil (@kvaps) addressed the migration-safety ask. The release-note block now carries an explicit upgrade note: the bundle takes ownership of spec.configuration.permittedHostDevices, so operators who hand-edited it must move their entries into .gpu.permittedHostDevices (with .gpu.replaceDefaults: true to keep only their own list) and verify each resourceName against kubectl describe node <node> | grep nvidia.com/ before upgrading — calling out the TU104GL_T4 vs legacy TU104GL_TESLA_T4 slug drift. The operator-facing migration steps landed in cozystack/website#556 ("Upgrading from a hand-edited KubeVirt CR" section plus the "My GPU isn't in the default table" callout). Re-requesting review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@packages/system/kubevirt/Makefile`:
- Line 36: The current Makefile sed insertion uses a single guard checking for
{{- with .Values.permittedHostDevices }} before inserting both the
permittedHostDevices and mediatedDevicesConfiguration blocks, so if
mediatedDevicesConfiguration is absent it won't be reinserted; change this to
two independent idempotent checks: one that greps for '{{- with
.Values.permittedHostDevices }}' and only inserts the permittedHostDevices block
into templates/kubevirt-cr.yaml, and a second that greps for '{{- with
.Values.mediatedDevicesConfiguration }}' and only inserts the
mediatedDevicesConfiguration block, keeping the same insertion point (before the
evictionStrategy line) and preserving indentation and toYaml | nindent 6
formatting so both checks are independent and safe to reapply.
🪄 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: Pro

Run ID: f804232a-32d9-422c-adde-28c26c1e36d2

📥 Commits

Reviewing files that changed from the base of the PR and between 883513b and bf8cda4.

📒 Files selected for processing (10)
  • docs/gpu-vgpu.md
  • packages/core/platform/files/gpu-passthrough-defaults.yaml
  • packages/core/platform/files/gpu-vgpu-defaults.yaml
  • packages/core/platform/templates/bundles/iaas.yaml
  • packages/core/platform/tests/bundles_gpu_kubevirt_wiring_test.yaml
  • packages/core/platform/values.yaml
  • packages/system/kubevirt/Makefile
  • packages/system/kubevirt/templates/kubevirt-cr.yaml
  • packages/system/kubevirt/tests/kubevirt_cr_test.yaml
  • packages/system/kubevirt/values.yaml
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/core/platform/files/gpu-passthrough-defaults.yaml
  • packages/core/platform/files/gpu-vgpu-defaults.yaml
  • docs/gpu-vgpu.md
  • packages/core/platform/tests/bundles_gpu_kubevirt_wiring_test.yaml
  • packages/system/kubevirt/templates/kubevirt-cr.yaml
  • packages/system/kubevirt/values.yaml
  • packages/core/platform/templates/bundles/iaas.yaml

Comment thread packages/system/kubevirt/Makefile Outdated
@myasnikovdaniil

Copy link
Copy Markdown
Contributor

removing from a roadmap as not roadmap related content

The KubeVirt CR's developerConfiguration.featureGates list, the
permittedHostDevices block, and mediatedDevicesConfiguration are now
driven by chart values:

  - extraFeatureGates is appended after the static default set so
    HostDevices (or any other future gate) can be enabled without
    forking the template.
  - permittedHostDevices is rendered verbatim when set, allowing the
    pciHostDevices (passthrough) and mediatedDevices (vGPU) shapes the
    KubeVirt admission webhook requires for VMs that reference a GPU
    by resourceName.
  - mediatedDevicesConfiguration is rendered verbatim when set,
    carrying mediatedDeviceTypes / nodeMediatedDeviceTypes for the
    vGPU profile auto-creation loop.

Defaults stay empty so the rendered CR is byte-identical to the
previous template when no overrides are supplied.

The Makefile's update target re-applies the four sed transforms
in-place on templates/kubevirt-cr.yaml — it does not download anything
from upstream KubeVirt because the published CR is a near-empty stub
and would clobber the hand-curated cozystack defaults. To refresh from
a newer upstream release the operator hand-merges the new fields into
the in-tree template, then runs `make update` to re-assert the four
cozystack parameterization patches; grep sanity-checks at the end of
the target fail loudly if any anchor (developerConfiguration,
- VMExport, evictionStrategy) gets dropped during the hand-merge.

Companion helm-unittest coverage pins the default render and the
three populated shapes.

Signed-off-by: Aleksei Sviridkin <[email protected]>
…tor is enabled

When cozystack.gpu-operator is in bundles.enabledPackages, the platform
now mirrors the chosen GPU variant into the KubeVirt CR — the HostDevices
feature gate is appended to developerConfiguration.featureGates, and a
starter permittedHostDevices block is filled from a per-variant defaults
table. Without this, a passthrough-variant GPU shows up under
.status.allocatable on the node but the KubeVirt admission webhook
rejects every VM that references it as a hostDevices.deviceName.

Two defaults tables ship under packages/core/platform/files/:

  - gpu-passthrough-defaults.yaml covers Hopper (H100/H200), Ada
    Lovelace (L4/L40/L40S), Ampere (A100 PCIe/SXM, A40, A30, A10),
    Turing (T4), Volta (V100/V100S). PCI vendor:device pairs are
    stable; resourceName slugs mirror nvidia-sandbox-device-plugin's
    <arch>_<model>_<form>_<mem> convention. externalResourceProvider
    is set on every entry because the resources are advertised by
    the sandbox-device-plugin DaemonSet, not by KubeVirt itself.

  - gpu-vgpu-defaults.yaml covers the Pascal-Ampere mdev profile
    range the upstream vgpu-device-manager walks /sys/class/mdev_bus/
    for. Ada Lovelace and Blackwell SR-IOV vGPU is out of scope for
    the chart's default list (NVIDIA driver path differs) and is
    expected to be advertised via the user-override hook below.

bundles.iaas.gpuOperatorVariant picks which table applies (default =
passthrough, vgpu = mediated). The same variant flows through to the
gpu-operator Package CR, replacing the previous always-default call.

Operators extend or replace the defaults via .gpu in platform values:

  gpu:
    replaceDefaults: false
    permittedHostDevices:
      pciHostDevices: [...]
      mediatedDevices: [...]
    mediatedDevicesConfiguration: {...}

replaceDefaults: false (the default) appends the user list to the
NVIDIA table; true drops the table entirely for clusters with only
non-NVIDIA accelerators or a strict allowlist requirement.

Companion helm-unittest suite covers the eight branches: no gpu
package emits no extras; gpu-operator at default variant emits the
HostDevices gate plus pciHostDevices; vgpu variant emits the
HostDevices gate plus mediatedDevices and mediatedDevicesConfiguration;
user overrides append by default; replaceDefaults wipes; unknown
variant fails fast.

Signed-off-by: Aleksei Sviridkin <[email protected]>
The platform now wires permittedHostDevices and the HostDevices feature
gate into the KubeVirt CR automatically whenever cozystack.gpu-operator
is in bundles.enabledPackages. The KubeVirt configuration section now
describes the auto-wiring contract, the per-variant defaults, the
.gpu.permittedHostDevices / .gpu.replaceDefaults escape hatches, and
calls out the sandbox-device-plugin resourceName slug convention so
operators know where to look when a node's allocatable name does not
match the platform default.

Signed-off-by: Aleksei Sviridkin <[email protected]>
The .Values.gpu accesses in the iaas bundle are fully parenthesized
((( .Values.gpu ).x).y) so the field walk stays nil-safe when an operator
nulls the whole gpu block or leaves a sub-key blank (an empty YAML key
parses to null, which Helm then drops from .Values). A bare dotted walk
would panic with "nil pointer evaluating interface {}.<field>" on the
first nil hop.

Add regression cases covering gpu: null in both passthrough and vgpu
variants plus blank sub-keys, and a comment warning against flattening
the parenthesized form. A mutation check confirms the cases fail with the
nil-pointer panic the moment the parentheses are removed.

Assisted-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
The update target gated the insertion of both the permittedHostDevices
and mediatedDevicesConfiguration directives behind a single
`grep permittedHostDevices` guard. A hand-merge from a newer upstream
KubeVirt CR that dropped only mediatedDevicesConfiguration left
permittedHostDevices in place, so the guard skipped the combined sed and
mediatedDevicesConfiguration was never reinserted — then the sanity-check
tail aborted the target with a non-zero exit instead of self-healing.

Split the two directives into independent guarded inserts so each
self-heals on its own. Reword the sanity-check failures to name the
directive that failed to land and the anchor its insert keys off, instead
of implying the anchor itself is missing.

Add a shell regression test that strips one directive at a time and
asserts `make update` restores it without duplicating the other; the
update target gains a CR_FILE override so the test can drive it against a
throwaway copy. Wired into the package test target and guarded to skip on
BSD sed.

Assisted-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
…the plugin advertises

The auto-injected permittedHostDevices only works if each resourceName
equals what nvidia-sandbox-device-plugin advertises on the node; otherwise
the admission webhook rejects the VM — the very manual step this bundle
removes. Several defaults did not match the slug the plugin
(nvcr.io/nvidia/kubevirt-gpu-device-plugin) derives from the PCI-IDs
database name, which uppercases the name and keeps the die suffix, the
Tesla brand and the form-factor/memory tokens:

  10DE:1EB8  TU104GL_T4          -> TU104GL_TESLA_T4
  10DE:20B7  GA100_A30           -> GA100GL_A30_PCIE
  10DE:2331  GH100_H100_PCIE_80GB-> GH100_H100_PCIE
  10DE:2321  GH100_H100_NVL_94GB -> GH100_H100L_94GB
  10DE:1DB1/1DB4/1DF6 + new 1DB5 -> GV100GL_TESLA_V100_* family

Device 10DE:1DB1 was also mislabelled: it is the SXM2 16GB part, not the
32GB one — the 32GB SXM2 V100 is a distinct device (10DE:1DB5) that was
missing entirely. Relabel 1DB1 as 16GB and add 1DB5.

Restate the header comment as the actual generation rule and pin the
corrected slugs (T4, A30, both V100 SXM2 parts) with a regression test
that also asserts the tidy/short forms never reappear.

Assisted-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
The vgpu defaults shipped a mediatedDevicesConfiguration block whose
mediatedDeviceTypes were hardcoded nvidia-NNN ids. Those ids are not
stable identifiers — they are the per-(SKU, driver) indices under which a
host enumerates mdev types in /sys/.../mdev_supported_types/, so the same
profile gets a different number on a different card or driver branch.
Auto-injecting them made KubeVirt try to create mdev types that usually
do not exist on the operator's nodes, and duplicated work the GPU
Operator's vGPU Device Manager already does.

Delegate mdev creation to the vGPU Device Manager, which is name-based and
stable, and keep only the name-based permittedHostDevices.mediatedDevices
exposure list (mdevNameSelector) in the defaults. KubeVirt-driven creation
stays available through the .gpu.mediatedDevicesConfiguration override for
operators who supply host-verified type ids; document the lookup recipe.

Update the bundle wiring, the gpu/vgpu values comments, the vGPU guide and
the tests accordingly (the default vgpu path now emits no
mediatedDevicesConfiguration; the override path is covered explicitly).

Assisted-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
@lexfrei

Copy link
Copy Markdown
Contributor Author

Andrei Kvapil (@kvaps) the migration-safety ask is covered — the release-note upgrade block plus the website migration section route operators through .gpu.permittedHostDevices. Reviewing it surfaced a correctness bug in the default table worth flagging.

I verified the resourceName slugs against the kubevirt-gpu-device-plugin source and the pci.ids bundled in the v1.5.0 image the gpu-operator package ships. The plugin builds the slug by upper-casing the device's PCI-IDs name and stripping the brackets — it keeps the GL die suffix and the Tesla brand. So a vanilla node advertises nvidia.com/TU104GL_TESLA_T4, not TU104GL_T4. The table had the shortened forms for the T4, A30, H100 PCIe/NVL and the whole V100 family, so the auto-wiring would have rendered a permittedHostDevices that doesn't match the node — exactly the webhook rejection this PR removes. I corrected those 8 entries to the strings the plugin emits and pinned them with a test; the migration-note example is corrected the same way.

Also addressed while here:

  • 10DE:1DB1 was labelled V100 SXM2 32GB but it's the 16GB part; the 32GB SXM2 is a distinct device 10DE:1DB5, which was missing. Relabelled 1DB1 and added 1DB5.
  • make update couldn't self-heal a CR where a hand-merge dropped only one of the permittedHostDevices / mediatedDevicesConfiguration blocks — split into independent guards with a shell regression test.
  • The bundle now tolerates a null .gpu block (parenthesized nil-safe access, pinned by tests).
  • The vGPU defaults no longer hardcode numeric mediatedDeviceTypes — those nvidia-NNN ids are per-(SKU, driver) sysfs indices with no portable value, so mdev creation is delegated to the name-based vGPU Device Manager, with a documented .gpu.mediatedDevicesConfiguration override for KubeVirt-driven creation.

Re-requesting review.

@kvaps Andrei Kvapil (kvaps) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Re-review — my prior blocker is resolved. The passthrough default now uses the correct resourceName slug (TU104GL_TESLA_T4, not the _T4 I flagged), the release-note carries an explicit upgrade note that the iaas bundle now owns permittedHostDevices (move custom entries into .gpu.permittedHostDevices or set .gpu.replaceDefaults: true, and verify each resourceName against kubectl describe node | grep nvidia.com/ before upgrading), and the replaceDefaults/permittedHostDevices escape hatch is implemented and test-pinned. Nil-safety is real and covered (null/empty-gpu cases). No values.schema.json drift (platform chart has none). CI green.

LGTM.

@lexfrei
Aleksei Sviridkin (lexfrei) merged commit 1d747b3 into main Jun 9, 2026
14 of 15 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the feat/kubevirt-gpu-wiring branch June 9, 2026 23:02
Aleksei Sviridkin (lexfrei) added a commit to cozystack/website that referenced this pull request Jun 22, 2026
…-wires permittedHostDevices

Step 2 of the GPU Passthrough guide instructed operators to
`kubectl edit kubevirt -n cozy-kubevirt` and hand-paste a
permittedHostDevices.pciHostDevices block. cozystack/cozystack#2768
removes the need for that step: when cozystack.gpu-operator is in
bundles.enabledPackages, the platform now mirrors the chosen GPU
variant into the KubeVirt CR automatically — appending HostDevices
to the feature-gate list and rendering a starter NVIDIA pciHostDevices
table covering Hopper, Ada Lovelace, Ampere, Turing and Volta.

The new step 2 documents the contract (what the platform auto-injects
and why), the verification recipe, the escape hatch via
.gpu.permittedHostDevices / .gpu.replaceDefaults, and the manual
Package-CR override path used by operators who need overrides the
bundle does not expose (driver settings, custom node selectors,
validator / dcgmExporter tweaks) — in that flow they also hand-craft
the matching cozystack.kubevirt Package CR.

Only next/virtualization/gpu.md is updated; v1.4 and earlier
describe releases that still require the manual patch and stay
as-is.

Assisted-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
Aleksei Sviridkin (lexfrei) added a commit to cozystack/website that referenced this pull request Jul 1, 2026
…-wires permittedHostDevices

Step 2 of the GPU Passthrough guide instructed operators to
`kubectl edit kubevirt -n cozy-kubevirt` and hand-paste a
permittedHostDevices.pciHostDevices block. cozystack/cozystack#2768
removes the need for that step: when cozystack.gpu-operator is in
bundles.enabledPackages, the platform now mirrors the chosen GPU
variant into the KubeVirt CR automatically — appending HostDevices
to the feature-gate list and rendering a starter NVIDIA pciHostDevices
table covering Hopper, Ada Lovelace, Ampere, Turing and Volta.

The new step 2 documents the contract (what the platform auto-injects
and why), the verification recipe, the escape hatch via
.gpu.permittedHostDevices / .gpu.replaceDefaults, and the manual
Package-CR override path used by operators who need overrides the
bundle does not expose (driver settings, custom node selectors,
validator / dcgmExporter tweaks) — in that flow they also hand-craft
the matching cozystack.kubevirt Package CR.

Only next/virtualization/gpu.md is updated; v1.4 and earlier
describe releases that still require the manual patch and stay
as-is.

Assisted-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
Aleksei Sviridkin (lexfrei) added a commit to cozystack/website that referenced this pull request Jul 3, 2026
…-wires permittedHostDevices (#556)

Companion to
[cozystack/cozystack#2768](cozystack/cozystack#2768).

Rewrites step 2 of the GPU Passthrough guide. Until now the page
instructed operators to run `kubectl edit kubevirt -n cozy-kubevirt` and
hand-paste a `permittedHostDevices.pciHostDevices` block — that is the
friction that ticket #2765 asked the platform to remove. With
cozystack/cozystack#2768 landed, the bundle mirrors the chosen GPU
variant into the KubeVirt CR automatically: `HostDevices` is appended to
the feature-gate list and a starter NVIDIA `pciHostDevices` table
(Hopper, Ada Lovelace, Ampere, Turing, Volta) is rendered alongside the
operator's `.gpu.permittedHostDevices` extensions.

The new step 2 documents:

- The contract — what the platform auto-injects and why (`HostDevices`
gate, NVIDIA default table, `externalResourceProvider: true` semantics).
- How to verify (`kubectl -n cozy-kubevirt get kubevirt kubevirt -o yaml
| yq ...`).
- The escape hatch — `gpu.replaceDefaults`,
`gpu.permittedHostDevices.pciHostDevices`, plus the consequence of
`replaceDefaults: true` with an empty list (no admittable GPU VMs).
- The manual Package-CR override path — when an operator hand-crafts
`cozystack.gpu-operator` outside the bundle for advanced overrides, they
also hand-craft `cozystack.kubevirt` with the matching
`extraFeatureGates` / `permittedHostDevices`. The manual override takes
precedence over the bundle render.

Only `next/virtualization/gpu.md` is touched. The released doc versions
(`v1.4` and earlier) describe earlier Cozystack releases that still
require the manual `kubectl edit`, and stay as-is.

### Release note

```release-note
docs(gpu): the GPU Passthrough guide no longer instructs operators to manually patch the KubeVirt CR — Cozystack now auto-wires the HostDevices feature gate and a starter NVIDIA permittedHostDevices table whenever cozystack.gpu-operator is enabled in bundles.enabledPackages. Operators extend or replace the defaults via .gpu.permittedHostDevices and .gpu.replaceDefaults.
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Updated GPU virtualization guide to remove a manual edit step and
explain automated configuration when the GPU package is enabled.
* Added verification commands to inspect rendered GPU settings and
detailed how to extend or fully replace NVIDIA defaults via package
values.
* Included upgrade guidance for prior manual setups and documented a
manual override path for non-bundled deployments.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/platform Issues or PRs related to platform infrastructure (bundle, flux, talos, installer) area/virtualization Issues or PRs related to virtualization (kubevirt, cdi, vmi, vm-import) kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API kind/feature Categorizes issue or PR as related to a new feature size/XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(platform): auto-wire KubeVirt permittedHostDevices + HostDevices feature gate when gpu-operator is enabled

3 participants