Virtual Machine Disk
A Virtual Machine Disk
storageClassandsourceare annotated as immutable in the chart schema — seedocs/storage-immutability.mdfor the contract and which consumers enforce it.DataVolume.specis immutable in CDI, so the chart also fails the release on an attemptedstorageClass/sourceedit of an existing disk rather than silently reusing the old spec; delete and recreate the disk to change either field.
Whether CDI has finished populating the disk shows up in the
WorkloadsReadycondition, not inReady, which follows the Helm release and does not wait on the DataVolume:WorkloadsReadystaysFalsewhile an import, clone or upload is in flight and when the DataVolume fails. Its message names the DataVolume and the phase it is in, followed by the error CDI reports for the pod populating the disk when there is one, such as a 404 or an unresolvable host on an HTTP source: CDI keeps retrying such an import, so its phase staysImportInProgress, and the error is shown between retries rather than while a retry is running.kubectl get vmdisksshows the condition in theWORKLOADScolumn, and the console badge readsDataVolumeNotReadyuntil it isTrue. A disk created before this behaviour was introduced keeps its old release settings, under whichReadymay wait on the DataVolume, until its application is next updated. Asource.uploaddisk readsFalsefrom the moment it is created untilvirtctl image-uploadcompletes, because CDI reports waiting for the upload and receiving it as one phase. A disk counts as ready while it waits for its consumer withbindImmediatelyoff on aWaitForFirstConsumerclass, because that is a state such a disk is supposed to rest in.
bindImmediatelyis on by default, so a disk’s volume is provisioned when the disk is created rather than deferred to the first consumer. That default exists because a VMDisk is a standalone object with a lifecycle of its own: on aWaitForFirstConsumerStorageClass a disk that no VM has attached yet would otherwise never populate at all. It costs something on a node-pinned class such aslocal, where the CDI worker pod becomes the first consumer and the volume lands where that pod was scheduled rather than where the VM will run, so a VM whose placement is constrained (anodeSelector, a resource request only one node satisfies, or the Windows affinity applied by_cluster.scheduling.dedicatedNodesForWindowsVMs) can stay unschedulable against a node-affinity conflict, andstorageClassis immutable so the only exit is deleting and recreating the disk. TurnbindImmediatelyoff for a disk a VMInstance will consume on such a class: KubeVirt then renders a temporary launcher pod carrying the VM’s own affinity and node selector, and the volume binds where the VM can actually run. The chart defaultreplicatedbindsImmediateregardless, so neither setting changes anything there.
A disk created from
source.imageshould use the StorageClass its golden image lives in,replicatedin the default layout. When CDI clones with thecsi-clonestrategy, the platform default, into a different StorageClass of the same CSI driver with the same volume mode and room to expand, it does not fall back to a host-assisted copy and leaves the clone to the driver. Thesnapshotstrategy does the same when it gets a VolumeSnapshotClass of that driver: the class both StorageProfiles name, or, when they do not name the same one, any class of the driver. LINSTOR creates that clone next to the source data, so on a target class that does not allow remote volume access from every node, such as a node-local class, the clone may never bind. The chart refuses such a new disk when the golden’s driver and the target class’s provisioner are both LINSTOR and the target’sallowRemoteVolumeAccessis not a value linstor-csi reads as true (1,tortrue, in any of the cases Go’sstrconv.ParseBoolaccepts); any other value is a list of rules, and the chart counts it as access from anywhere only when one rule names nofromSamelabel. Without that parameter it reads the target’s layer list the way linstor-csi does, which allows remote access when it has a DRBD or NVMe layer, and a class that sets no layer list has DRBD. Undersnapshot, it also refuses a disk whose golden and target StorageProfiles name the same VolumeSnapshotClass when that class does not exist and the golden’s driver is the target class’s provisioner, whatever the driver: CDI then fails to plan the clone instead of falling back. Both refusals compare only what they can look up: without the golden image’s PVC, thecdiresource or the target’s StorageClass nothing is compared. The remote access refusal also needs the target’s StorageProfile with a claim property set and the golden’s driver, taken from its bound PV or else from its StorageClass; when any of them is missing, the disk renders. Neither applies to a disk whose DataVolume or PVC already exists. Use the golden image’s StorageClass instead, or ask the platform administrator to setcloneStrategyOverride: copyin thekubevirt-cdipackage, which clones through a host-assisted copy in every case. The remote access refusal leaves alone a target class that allows remote volume access, a driver other than LINSTOR, a target class of another driver, a different volume mode, a class without volume expansion,snapshotthat gets no VolumeSnapshotClass of the driver, and thecopystrategy. An emptystorageClassis compared as the class CDI would pick for it: the class annotatedstorageclass.kubevirt.io/is-default-virt-class, otherwise the class annotatedstorageclass.kubernetes.io/is-default-class; when several classes carry the annotation that decides, nothing is compared.
Parameters
Common parameters
| Name | Description | Type | Value |
|---|---|---|---|
source | The source image location used to create a disk. | object | {} |
source.image | Use image by name from default collection. | *object | null |
source.image.name | Name of the image to use. | string | "" |
source.upload | Upload local image. | *object | null |
source.http | Download image from an HTTP source. | *object | null |
source.http.url | URL to download the image. | string | "" |
source.disk | Clone an existing vm-disk. | *object | null |
source.disk.name | Name of the vm-disk to clone. | string | "" |
optical | Defines if disk should be considered optical. | bool | false |
storage | The size of the disk allocated for the virtual machine. | quantity | 5Gi |
storageClass | StorageClass used to store the data. | string | replicated |
bindImmediately | Provision the volume at disk creation instead of waiting for a consumer. | bool | true |