fix: replace cloudinit volume when its source disk changes - #7
Merged
Conversation
libvirt_cloudinit_disk.commoninit renders the cloud-init ISO under a local /tmp path that lives in state via its `path` attribute. Any tofu invocation on a host that doesn't have that file — CI runners vs. a developer laptop, or a host that has been rebooted since /tmp was wiped — sees the file missing and marks the disk for recreation. That changes the URL referenced by libvirt_volume.cloudinit.create.content, and the dmacvicar/libvirt provider can't update libvirt_volume in place: Error: Update Not Supported Storage volumes cannot be updated. All changes require replacement. Add replace_triggered_by so the volume cycles automatically when the disk does, instead of forcing every operator to remember `-replace=...libvirt_volume.cloudinit` on each cross-host apply. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
xnoto
added a commit
that referenced
this pull request
May 22, 2026
## Summary PR #7's `replace_triggered_by = [libvirt_cloudinit_disk.commoninit]` didn't actually fix cross-host applies. When the provider's local `/tmp` ISO is missing on the apply host (CI runner vs. laptop, post-reboot `/tmp` wipe), the disk's `Read` returns "not found", tofu drops it from state, and the next plan shows the disk as **created** (not **replaced**). `replace_triggered_by` does **not** fire on a create-following-drift, so the dependent `libvirt_volume.cloudinit` still planned an in-place `url` update and apply died on: ``` Error: Update Not Supported Storage volumes cannot be updated. All changes require replacement. ``` This change moves the trigger to the cloud-init *content* itself, captured in a `terraform_data` whose `input` is `sha256` of the rendered `meta_data` + `user_data` + `network_config`. The volume now: - `ignore_changes = [create]` — absorbs the volatile `/tmp` path drift entirely - `replace_triggered_by = [terraform_data.cloudinit_content]` — replaces only when cloud-init content has actually changed ## One-time upgrade churn On first apply for any existing consumer, the new `terraform_data` resource is created. Because `replace_triggered_by` treats a create as a planned action, the existing `libvirt_volume.cloudinit` will be replaced once. That's a cdrom swap — harmless on running VMs (cloud-init only runs on first boot). After this one event, the volume is stable unless cloud-init content actually changes. ## Test plan - [ ] pre-commit (`make test`) green - [ ] Downstream `tfroot-libvirt` plan no longer shows `libvirt_volume.cloudinit ... will be updated in-place` followed by an Update Not Supported error at apply - [ ] Subsequent applies on a different host (CI runner vs. laptop) are no-ops for the cloudinit pair as long as content is unchanged 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
libvirt_cloudinit_disk.commoninitrenders its ISO under a local/tmppath stored in state via thepathattribute. Any tofu invocation on a host that doesn't have that file — CI runner pods (fresh/tmpeach run), a different developer laptop, or a host where/tmpwas wiped on reboot — sees the file missing and recreates the disk. That changes the URL referenced bylibvirt_volume.cloudinit.create.content, and the dmacvicar/libvirt provider can't updatelibvirt_volumein place:This adds a
replace_triggered_byto the volume so it cycles automatically when the disk does, instead of forcing every operator to remember-replace=module.<name>.libvirt_volume.cloudiniton every cross-host apply.Test plan
make test) greentfroot-libvirtplans showlibvirt_volume.cloudinitreplaced (not in-place updated) whenlibvirt_cloudinit_disk.commoninitis rebuiltNotes
libvirt_domain.vm(replace_triggered_by = [libvirt_volume.boot]), applied to the cloudinit pairing.libvirt_domain.vm— only the volume.🤖 Generated with Claude Code