Repository navigation
feat(vm-instance): allow attaching a disk to a running VM - #3978
lf (lfinmauritius) wants to merge 1 commit into
Conversation
A disk added to `disks` of an existing VMInstance never reaches the running guest. KubeVirt classifies the change as non-live-updatable, sets `RestartRequired` on the VirtualMachine, and the volume only appears after the guest is restarted. A blank disk is worse: its PVC binds on `WaitForFirstConsumer`, and the only consumer that could bind it is the VMI that is not getting the volume. KubeVirt supports this declaratively behind the `DeclarativeHotplugVolumes` feature gate (Alpha since v1.6.0, Beta in v1.9.0), and requires the volume to carry `hotpluggable: true`. The chart cannot express it: `disks[]` exposes only `name` and `bus`, so no consumer of the aggregated API can ask for a hot-attach. This adds an optional `disks[].hotpluggable` that renders it. The bus is not free here. `ValidateHotplugDiskConfiguration` in pkg/storage/admitters/storagehotplug.go refuses a hotplugged disk whose bus is neither `scsi` nor `virtio`, and nothing defaults an empty bus before that admitter runs - every hotplug test upstream passes an explicit bus. The template therefore fails early, naming the disk, rather than letting the VM patch be rejected later: a rejection at that point leaves the HelmRelease in UpgradeFailed, and a stuck release keeps every subsequent change from reaching the machine, a restart included. `bootOrder` needs no change, the same admitter only requires it to be greater than zero. Rendering is unchanged when `hotpluggable` is unset. Generated files are updated accordingly, and unit tests cover the rendered field, its absence, both accepted buses and the two refusals. The field is inert until the cluster enables `DeclarativeHotplugVolumes`. That gate is documented as incompatible with the deprecated `HotplugVolumes` one - "if both are declared, HotplugVolumes will have precedence" - so the deprecated gate has to be removed, not merely complemented. Co-Authored-By: Claude Opus 5 <[email protected]> Signed-off-by: Loïc Fontaine <[email protected]>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughThe VM instance disk API and chart schemas add an optional ChangesHotpluggable disk support
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant DiskValues
participant vm_yaml as vm.yaml
participant DataVolume
DiskValues->>vm_yaml: provide bus and hotpluggable values
vm_yaml->>vm_yaml: validate the bus
vm_yaml->>DataVolume: render hotpluggable: true for valid disks
Merge Risk: 🔵 Low · up to The new disk option enables live attachment only when the cluster has DeclarativeHotplugVolumes enabled; the platform’s default configuration does not currently enable that gate, so using the option without platform alignment can fail instead of attaching the disk. The change is mergeable with explicit owner awareness and follow-up on feature-gate support. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Same content as fork branch feat/vm-instance-cozyplane-static-ip (commit 5187e11), applied on the v1.6.1 bundle: values field, template block, test suite, and the schema, README and RD regenerated with cozyvalues-gen v1.6.0 + hack/update-crd.sh. The RD keeps the helm-install-disable-wait annotation (cozystack#3735) and the hotpluggable schema (cozystack#3978).
Same content as fork branch feat/vm-instance-cozyplane-static-ip (commit 4ddc400), applied on the v1.6.1 bundle: values field, template block, test suite, and the schema, README and RD regenerated with cozyvalues-gen v1.6.0 + hack/update-crd.sh. The RD keeps the helm-install-disable-wait annotation (cozystack#3735), the hotpluggable schema (cozystack#3978) and its kubevirt chartRef.
## What this PR does Guards the Kube-OVN `IP` lookup behind API discovery. The `vm-instance` chart now renders on clusters using another CNI instead of trying to query a CRD that is not installed. The Helm regression suite mocks the IP object through `kubernetesProvider` and pins both sides: with `kubeovn.io/v1/IP` advertised the annotations carry the mocked MAC and IP, without it they are absent even though the object exists, which is the branch the guard adds. helm-unittest's fake lookup never errors on an unserved kind, so only the second case distinguishes the guard; it fails on main and passes here. Open PRs #3991, #3978, #3931, and #3900 touch the same template. Their current hunks do not alter this lookup; #3900 adds secondary-interface annotations immediately after it, so it is the only nearby merge hunk to watch. ### Screenshots Not applicable; there is no UI change. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: ### Release note ```release-note fix(virtual-machine): render VM instances on clusters where the Kube-OVN IP API is not installed. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * VM instances now render correctly in environments without the Kube-OVN IP capability. * OVN IP lookups and MAC/IP annotations are only generated when the required Kube-OVN API is available. * MAC/IP annotations are omitted when the capability is unavailable, even if an IP object exists. * **Tests** * Added coverage for both supported and unsupported Kube-OVN IP discovery scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Aleksei Sviridkin (lexfrei)
left a comment
There was a problem hiding this comment.
lf (@lfinmauritius) NOT LGTM: on current main this field does nothing, so it has to wait for the platform to switch to declarative hotplug.
Adding a disk to a running VM without a reboot is a real need, and the bus check is right. But the platform still enables the deprecated HotplugVolumes gate (packages/system/kubevirt/templates/kubevirt-cr.yaml). As your own note says, virt-controller skips declarative hotplug while that gate is on. So a tenant who ticks hotpluggable in the dashboard today gets the same RestartRequired as without it. A checkbox that silently has no effect is worse than no checkbox.
The switch is in progress in #4453, which drops HotplugVolumes and handles the kubevirt-csi removevolume path you described (together with #4451). Once it merges, this becomes a small and useful change. Before that:
- Rebase after #4453 lands. The branch already conflicts with main in
packages/apps/vm-instance/README.mdand the generatedpackages/system/vm-instance-rd/cozyrds/vm-instance.yaml, so re-runmake generate. - Drop "Requires the DeclarativeHotplugVolumes feature gate on the cluster" from the field description. A tenant cannot act on it, and after #4453 it is always true.
- Replace
Co-Authored-By: Claude Opus 5 <[email protected]>withAssisted-by: LLM, seedocs/agents/contributing.md.
What this PR does
A disk added to
disksof an existingVMInstancenever reaches the running guest. KubeVirt classifies the change as non-live-updatable, setsRestartRequiredon theVirtualMachine, and the volume only shows up after the guest is restarted. A blank disk is worse: its PVC binds onWaitForFirstConsumer, and the only consumer that could bind it is the VMI that is not getting the volume. So adding a data disk to a live workload requires a reboot, which defeats the point of a hot-attach for anything built on the aggregated API.KubeVirt supports this declaratively behind the
DeclarativeHotplugVolumesfeature gate (Alpha since v1.6.0, Beta in v1.9.0), and the user guide requires the volume to carryhotpluggable: true:The chart cannot express it —
disks[]exposes onlynameandbus— so no consumer of the aggregated API can ask for a hot-attach. This adds an optionaldisks[].hotpluggablethat renders it.Why the template refuses some buses
ValidateHotplugDiskConfiguration(pkg/storage/admitters/storagehotplug.go) rejects a hotplugged disk whose bus is neitherscsinorvirtio, and nothing defaults an empty bus before that admitter runs —getDiskBusreturns the field as written, and every hotplug test intests/storage/hotplug.gopasses an explicit bus.So
hotpluggable: truewithbus: sata, or with no bus at all, would render fine and then be refused at admission. That failure is expensive: it leaves theHelmReleaseinUpgradeFailed, and a stuck release keeps every subsequent change from reaching the machine — a restart included. The template therefore fails early and names the disk.bootOrderneeds no change: the same admitter only requires it to be greater than zero, and the chart already emitsadd $i 1.busitself is untouched, and a non-hotpluggable disk with no bus keeps renderingdisk: {}exactly as #2643 intended.Verification
helm unittest .— 5 new cases: the rendered field, its absence, both accepted buses, and the two refusals with their message.make generateoutput committed:values.schema.json,README.md, theApplicationDefinitionandapi/apps/v1alpha1/vminstance/types.go.A note for platform operators, beyond this PR
The field is inert until a cluster enables
DeclarativeHotplugVolumes, and that gate is documented as incompatible with the deprecatedHotplugVolumesone — "if both are declared,HotplugVolumeswill have precedence until the time thatHotplugVolumesis retired".packages/system/kubevirt/templates/kubevirt-cr.yamldeclaresHotplugVolumes(andtests/kubevirt_cr_test.yamlpins it), so switching is not additive.It is also not free. The tenant CSI driver reaches the VMI
removevolumesubresource directly in the orphan-detach path added by #2866 (packages/apps/kubernetes/images/kubevirt-csi-driver/controller.go,RemoveVolumeFromVMI), and that path is gated on the deprecatedHotplugVolumesalone —ephemeralHotplugSupported()inpkg/virt-api/rest/volumes.goignoresDeclarativeHotplugVolumes, andvmiVolumePatchthen answersVMI %s/%s is owned by a VM. The normal attach and detach paths (AddVolumeToVM/RemoveVolumeFromVM, VM subresource) keep working under either gate; only that one breaks. Happy to open a separate issue for it if that is the right place.Screenshots
No console code. The field reaches the dashboard through the schema-driven form (RJSF renders
type: booleanas a checkbox fromvalues.schema.json), so there is nothing to change inpackages/system/dashboard/images/console— and nothing I can screenshot before the chart is deployed. I can attach one once it is running if that is wanted.Downstream repositories
Walked the trigger map in
docs/agents/contributing.mdagainst the diff, file by file.vm-instanceis already in the websiteMakefile'sVMSlist, so the release bot regenerates its reference page from this package'sREADME.md, which this PR updates. No page is hand-written for it.The provider hand-models
disks[]as{name, bus}ininternal/provider/vminstance_schema.go, in both the resource and the data source, plus its model and expand/flatten pair. Filed as an issue rather than a PR there: itsapi/apps/v1alpha1pin has to move past this merge first, and shipping the attribute before that would hand users a Terraform field that silently does nothing.Release note
Summary by CodeRabbit
New Features
hotpluggabledisk option.scsiorvirtiobuses and requires the appropriate feature gate.Bug Fixes
Documentation
Assisted by Codex