Newer
Older
openstack-caracal-dc-dc / docs / changelog-20260710-opentofu-scaffold-first-validation.md

Changelog 2026-07-10 -- DOCFIX-179: OpenTofu scaffold, first real validation + apply

Context. First-ever execution of the opentofu/ tree against a real tofu binary (OpenTofu v1.12.3), on the vcloud host, executing runbooks/dc-dc-phase0-vcloud-prep.md Steps 8-11. The tree had carried a SCAFFOLD, UNVALIDATED banner since authoring (no tofu had ever run it). Two real bugs blocked tofu init/plan; both fixed here, then the Stage-1 module slice was validated, planned, and applied clean (13 libvirt objects).

What changed

FIX 1 -- per-module required_providers (the tofu init blocker)

  • tofu init failed: child modules use libvirt_*/maas_* resources but did not declare their own required_providers, so OpenTofu inferred the libvirt_ prefix as hashicorp/libvirt (nonexistent) instead of dmacvicar/libvirt. Provider SOURCE mapping is NOT inherited by child modules -- only provider CONFIGURATION is.
  • Added versions.tf (source-only; version stays pinned at the root) to every module using a provider resource: 8 libvirt modules (dc-planes, mesh-link, dc-storage-pool, office1-network, node-vm, base-image, cloudinit-vm, opnsense-edge) + 1 maas module (maas-vm-host). netem-link uses only the built-in terraform_data, so it needs none. Fixed comprehensively (all modules, not just Stage 1's four) so Stage 2/3 do not re-hit it.

FIX 2 -- tofu fmt (the whole never-fmt'd scaffold)

  • tofu fmt -recursive opentofu/ normalized 11 files (attribute alignment, comment reflow) that had drifted because no tofu had ever formatted them.

CHANGE 3 -- provider "maas" deferred to Stage 3

  • The root provider "maas" block forced tofu plan to demand maas_api_url AND the sensitive maas_api_key for a Stage-1 plan that creates ZERO MAAS resources -- which would bake a fake key into phase0.tfplan and terraform.tfstate (the DOCFIX-175 plaintext-secret surface). Operator ruled (2026-07-10) to fix structurally rather than use the runbook's placeholder workaround. Removed the provider "maas" block from main.tf and the maas_api_url/maas_api_key variables from variables.tf, with in-file notes to re-add them at Stage 3 (when maas-vm-host is instantiated). maas stays in the ROOT versions.tf required_providers (version pinned, .terraform.lock.hcl complete for Stage 3).

FIX 4 -- repo-lint must skip OpenTofu's .terraform/ provider cache

  • After the first real tofu init, repo-lint FAILED L1 (ASCII) on a downloaded provider plugin's README inside opentofu/.terraform/. DOCFIX-175 gitignored .terraform/ for git, but repo_lint.py's all_text() scans the filesystem, not git. Added ".terraform" in p.parts to all_text()'s skip set (alongside .git/__pycache__) -- third-party, gitignored, not repo content. tests/repo-lint/run-tests.sh -> 34/34 PASS.

Result

  • tofu validate -> Success. tofu plan -> 13 to add / 0 / 0, with NO MAAS vars required. tofu apply -> 13 added, 0 changed, 0 destroyed (6 DC1 planes + dc1/office1/dc2 pools + office1-local + 3 mesh legs, all MTU 9000).
  • .terraform.lock.hcl is now generated -- commit it (pins provider hashes: dmacvicar/libvirt 0.9.8, canonical/maas 2.7.2).
  • opentofu/README.md status banner updated: Stage-1 module slice VALIDATED + APPLIED; the not-yet-instantiated Stage 2/3 modules remain UNVALIDATED.

Verification

  • bash scripts/opentofu-validate.sh (== tofu fmt -check + init + validate) -> clean after the fixes.
  • bash scripts/repo-lint.sh -> 0 fail.

Revert

  • git rm opentofu/modules/*/versions.tf (the 9 added files) -- restores the original tofu init inference failure.
  • Re-add the provider "maas" block to main.tf and the two maas_* variables to variables.tf from this changelog / git history.
  • tofu fmt reverts are cosmetic; git checkout the 11 files to undo.
  • (Live infra: runbooks/dc-dc-teardown-rollback.md / tofu destroy -- not part of a repo revert.)

Follow-up (logged)

  • Stage 3's runbook must re-add the provider "maas" block + the two variables when it wires maas-vm-host -- noted in main.tf/variables.tf in-file.