Skip to content

fix: trigger cloudinit volume replacement on content change only - #8

Merged
xnoto merged 1 commit into
mainfrom
fix/cloudinit-content-hash-trigger
May 22, 2026
Merged

fix: trigger cloudinit volume replacement on content change only#8
xnoto merged 1 commit into
mainfrom
fix/cloudinit-content-hash-trigger

Conversation

@xnoto

@xnoto xnoto commented May 22, 2026

Copy link
Copy Markdown
Contributor

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

PR #7's replace_triggered_by on libvirt_cloudinit_disk didn't actually
fix cross-host apply: when the local /tmp ISO is missing, the provider
reports the disk as "deleted", tofu plans a "create" (not a "replace")
for it, and replace_triggered_by does not fire on a create that follows
drift detection. The dependent libvirt_volume.cloudinit then still
planned an in-place url update and apply died on:

  Error: Update Not Supported
  Storage volumes cannot be updated. All changes require replacement.

Switch the trigger to the cloud-init *content* itself, captured in a
terraform_data resource that hashes the rendered meta_data/user_data/
network_config. The libvirt_volume.cloudinit now ignores changes to
the volatile `create` block (the url that points at /tmp) and is only
replaced when the content hash genuinely changes — which is what we
actually want.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@xnoto
xnoto merged commit f6626b7 into main May 22, 2026
1 check passed
@xnoto
xnoto deleted the fix/cloudinit-content-hash-trigger branch May 22, 2026 05:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant