Repository navigation
fix(cdi): omit the CDI clone strategy override when unset - #4138
Conversation
|
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:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 8 included reviews per hour; 2 remain after this review. 📝 WalkthroughWalkthroughThe CDI chart now omits ChangesCDI clone strategy configuration
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to Empty or null clone-strategy overrides are now omitted so CDI can select a StorageProfile-specific strategy, while default and explicit strategy behavior remain covered. 🚥 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 |
ef31220 to
b3d134f
Compare
829926b to
650ada1
Compare
templates/cdi-cr.yaml rendered cloneStrategyOverride unconditionally, so the chart's values offered no way to leave the choice to CDI's own per-StorageProfile selection. The CRD enum takes copy, snapshot and csi-clone and carries no empty member, so an empty value rendered cloneStrategyOverride: "" which that enum does not accept, and a null one rendered a bare key. Guard the field on a non-empty value, the way uploadProxyURLOverride is already guarded just below it. The default stays csi-clone, so a release that overrides nothing renders what it rendered before. Whether csi-clone is the right default is a separate question, untouched here. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <[email protected]>
650ada1 to
5db7738
Compare
Andrei Kvapil (kvaps)
left a comment
There was a problem hiding this comment.
Verdict
LGTM as of 5db773892. Cleanest of the four CDI-family PRs in this batch, and the test earns its place.
The premise checks out from the tree: packages/system/kubevirt-cdi-operator/templates/cdi-operator.yaml:101-108 (and the v1beta1 copy at :2624-2631) declares cloneStrategyOverride with enum: [copy, snapshot, csi-clone] and no empty member, while the template rendered {{ quote .Values.cloneStrategyOverride }} unconditionally — so an operator who set the value to "" produced cloneStrategyOverride: "", which that enum refuses at admission. There was no way to ask CDI to make its own per-StorageProfile choice.
Wrapping the line in {{- with }} is the right fix and omitting is the right target state rather than substituting something: upstream v1.66.1's own cdi-cr.yaml carries no cloneStrategyOverride at all, and with the field absent CDI falls back to the per-StorageProfile cloneStrategy. Both "" and ~ take the falsy branch, so the key is absent rather than set to a different value.
The test is non-vacuous and I had it checked by execution rather than by reading: reverting the template to the unconditional line turns two cases red (omits the field when no strategy is configured, omits the field when the strategy is null), and the suite also pins the opposite direction with a configured snapshot passing through unchanged, so a template that dropped the field unconditionally would not satisfy it either. The null case cannot pass vacuously — if set: cloneStrategyOverride: null were a no-op the chart default csi-clone would render and the assertion would fail. 9/9 green at head.
No upgrade impact: values.yaml:9 keeps csi-clone as the default, so every existing cluster renders identically and the change only adds a state that was previously unreachable.
It composes with #4107 rather than colliding: no file overlap, and that PR's CR_SHA256 pins the upstream asset rather than the in-tree file, so this edit does not invalidate it. Its tests/local_templates_test.yaml asserts csi-clone against the chart default, which still holds.
One nit, pre-existing and not yours: packages/system/kubevirt-cdi/Makefile declares test: twice with identical recipes, so make warns and uses the last. #4107 removes the duplicate; whichever of these lands first could just as easily take it.
…4796) ## What this PR does A VM disk created from a golden image into a StorageClass other than the image's one can hang forever: its temporary clone PVC stays unbound, and the user sees nothing. With the default `csi-clone` strategy, CDI checks the source and target classes for a common provisioner, a matching volume mode and room to expand. It never compares class names. So a target class backed by the same provisioner gets no host-assisted fallback, and the clone is left to the CSI driver. LINSTOR creates it next to the source data, so on a target class that does not allow remote volume access from every node (a node-local class, for example) the PVC may never bind. The vm-disk chart now refuses such a disk at render time and tells the user which StorageClass to set. The check follows CDI's own clone planner. The effective strategy comes from the CDI override, or else from the target StorageProfile. It has to be `csi-clone`, or `snapshot` when CDI gets a VolumeSnapshotClass of the provisioner. Once the snapshot path has such a class it runs the same checks as csi-clone, and LINSTOR ships one. Both classes have to share a driver (the golden's is read from its PV, as CDI does), the volume modes have to match, and the target class has to allow expansion. On top of that the chart refuses only a LINSTOR target whose `allowRemoteVolumeAccess`, read the way linstor-csi reads it, is not true; without the parameter that means a layer list with no DRBD or NVMe layer. A remote-accessible LINSTOR class and other drivers render. When the provisioner or the volume mode differs, CDI falls back to a host-assisted copy, which completes, so the disk renders as before. A target class without expansion is left alone too, see the follow-ups. The class check compares nothing when a lookup it needs returns nothing: under `helm template`, before the golden PVC exists, or without the CDI resource. An empty `storageClass` is compared as the class CDI would pick for a kubevirt DataVolume, which is the default virt class, otherwise the Kubernetes default class. Existing disks are exempt, because their DataVolume spec is immutable. A disk counts as existing when its DataVolume or its PVC exists, since CDI can garbage-collect a completed DataVolume. Under `snapshot`, a snapshot class that both StorageProfiles name but that does not exist is refused too, for any driver, because CDI then fails to plan the clone instead of falling back. This is a breaking change: a new disk in a LINSTOR class without remote access from every node rendered before and is refused now, and so is one whose StorageProfiles name a snapshot class that does not exist. The first case can include a clone that would happen to work: on a class with `Immediate` binding, which I have not verified, or when the node the clone is placed on already holds a replica of the golden image. The way out is the golden image's class or the `copy` clone strategy. How this covers the three fix directions in the issue: 1. Omitting `cloneStrategyOverride` when it is empty already landed on main in #4138: the template skips the field for an empty or null value, the values schema accepts the empty string, and the chart tests pin both. This PR does not touch it. 2. I kept `csi-clone` as the default on purpose. Same-class clones are the common case, and `csi-clone` is the fast path for them. Changing the default is a separate decision, tracked in #4850. 3. vm-disk refuses the mismatch where the clone can hang, as described above. That is narrower than the issue proposed, which was to refuse every mismatch: every case CDI falls back on completes, and a clone into a remote-accessible LINSTOR class should complete too. The last part comes from reading the CDI and linstor-csi sources, I have not run it on a cluster. Follow-ups this PR does not cover: - When several classes claim the default, CDI picks the newest one. The chart does not reproduce that tie-break and compares nothing in that case. - The chart does not compare sizes. A target class without volume expansion is never refused for remote access, even when the disk is no larger than the golden image and CDI would attempt the clone. - Under `snapshot` on a cluster that does not serve the snapshot API, StorageProfiles naming a snapshot class still make CDI fail, and the chart does not look that class up. - A disk cloned from another disk (`source.disk`) into another class of the same provisioner can hang the same way, and nothing refuses it yet. - Whether `csi-clone` should remain the platform default now that it can be turned off: #4850. Closes #2908 ### Screenshots Not a 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: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: No values, schema or ApplicationDefinition change. Re-check notes for the next CDI and linstor-csi bumps sit next to the version pins in the kubevirt-cdi-operator and linstor Makefiles. The new note in the vm-disk README reaches the website through the regular reference-page regeneration. ### Release note ```release-note fix(vm-disk)!: a new disk from a golden image is now refused with a clear error when CDI would CSI-clone it into another LINSTOR StorageClass that does not allow remote volume access from every node. Before, such a disk could stay pending forever with no error. A clone that would have landed on a node already holding a replica of the golden image is refused as well; use the golden image's StorageClass or the copy clone strategy. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Prevented image-backed disks from being rendered when CDI’s selected clone strategy cannot safely clone across differing storage classes, including applicable LINSTOR remote-access and snapshot-class checks. * Existing DataVolumes and same-namespace PVCs are not blocked by these checks. Disk creation can proceed when required information is unavailable or the selected strategy supports the operation. * **Documentation** * Clarified when image-backed disks may be refused and recommended using the golden image’s storage class or the copy strategy as alternatives. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
What this PR does
cdi-cr.yamlrenderedcloneStrategyOverrideunconditionally, so there was no way to let CDI pick a clone strategy per StorageProfile. The CRD enum iscopy/snapshot/csi-clonewith no empty member, so neither obvious workaround got there: an empty value renderedcloneStrategyOverride: "", which that enum does not accept, and a null one rendered a bare key. Both checked againstmainwithhelm templaterather than assumed.Now the key is guarded on a non-empty value, same as
uploadProxyURLOverridejust below it in the same file. With the field absent, CDI reads the target StorageClass's StorageProfile and uses its clone strategy.Default stays
csi-clone. Rendered at the default and diffed againstmain, the output is byte-identical, so nothing already deployed moves.Tests
tests/clone_strategy_test.yamlpins both directions: absent when the value is empty, absent when it is null,csi-cloneon the chart default,snapshotthrough unchanged. It sits alongside the existingimporter-resourcesandstandalone_render_testsuites, with its own file and suite name and no shared test names;make testruns all three.I checked the suite can fail rather than assuming it works. Reverting the guard reddens the two absent-field cases, deleting the field outright reddens the default and passthrough cases, hardcoding the value reddens the passthrough case, and rendering a bare key reddens all four. The two sibling suites stay green through every one of those, so the reds are attributable to this suite.
The null case is pinned as an input rather than argued from
withtreating null and empty alike. It cannot pass vacuously: flipping its assertion to expect the default returnsunknown path, not acsi-clonemismatch, which is what shows the null actually reaches the template instead of the assertion passing on a value that never arrived.Known gaps
copyis accepted by the enum but no test drives it, so the suite does not pin that it reaches the CR. Concretely: wrapping the guard in{{- if ne . "copy" }}, which silently drops that one strategy, still passes all nine tests. Named here rather than fixed so the boundary is visible to the next reader instead of being rediscovered.Scope
Context: #2908. This is the first of the three directions that issue lists, so it does not close it and carries no
Closes. The default is deliberately left atcsi-clone, since whether that is the right default is the second direction and a separate decision. The third,vm-diskwarning on a cross-StorageClass request, is untouched. An operator who has not setcloneStrategyOverride: ""sees the reported symptom exactly as before.Screenshots
Not a UI change.
Downstream repositories
Walked the trigger map against the diff. It is one guarded key in a
packages/systemchart, a values comment, and a test suite: no package added or renamed, novalues.schema.json(this chart has none), noApplicationDefinition, no namespace, nothing underhack/, no platform values key. Theccpentry covershack/package.mkand make-target behaviour, and this touches neither. Nothing in the map reaches it.Release note