# opentofu/ -- VR1 (DC-DC) infrastructure-as-code

Owns create/destroy of the "physical" layer per D-103: libvirt domains (node
VMs), all virtual networks (dark-fiber mesh, per-DC planes, ISP-edge), the
OPNsense edge VMs, and the Office1 service VMs. Runs from the Office1 operator
VM against the vcloud host libvirt. See `docs/dc-dc-buildout-design.md` and
`docs/dc-dc-deployment-workflow.md` (Stage 1-2, tooling gap register item 2)
for the surrounding plan.

**Status: SCAFFOLD, UNVALIDATED.** No `tofu`/`terraform` binary was available
in the session that authored this -- nothing here has been run through
`tofu init`/`validate`/`plan`, let alone `apply`. Before trusting any of it:

```
bash scripts/opentofu-validate.sh
```

on a machine with the binary and network access to the provider registry, and
read the result before proceeding.

## Scope of this delivery

Built:
- `modules/dc-planes` -- the six per-DC plane segments (D-052/D-100) as
  isolated `libvirt_network` resources.
- `modules/mesh-link` -- one inter-site L2 segment per leg of the D-100
  dark-fiber triangle (DC1<->DC2, DC1<->Office1, DC2<->Office1).
- `modules/dc-storage-pool` -- a directory-backed `libvirt_pool` per DC/Office1
  for future node-VM disk images.
- Root wiring for DC1 (planes + pool, using DC1's inherited DC0 CIDRs) and
  Office1 (pool only), plus all three mesh links.

Deliberately NOT built yet, and why:
- **`libvirt_domain` (the actual node VMs).** The provider's current schema for
  this resource turned out to be a large (~40 top-level argument), deeply
  nested rewrite that closely mirrors raw libvirt domain XML (`numa_tune`,
  `launch_security`, `memory_backing`, a `devices` block containing `disks`,
  `interfaces`, `filesystems`, `graphics`, etc.) -- materially different from
  older, commonly-referenced examples of this provider. Doc-summarization
  tools available this session could not give high-confidence, verbatim field
  names for the nested `devices.interfaces`/`devices.disks` shape specifically.
  Authoring this blind risks exactly the "fabricated flag/value" failure mode
  this repo's operating discipline calls out as the cardinal sin. **Next
  action:** on a machine with the `tofu` binary, run
  `tofu providers schema -json` (after `terraform init`) and read the actual
  `libvirt_domain` schema directly, or start from the provider's own
  `examples/` directory in its GitHub repo, before writing this module.
- **`libvirt_volume` (per-VM disk images).** Follows directly from the domain
  module above; deferred with it.
- **DC2's plane networks.** D-101 has not assigned DC2's supernet yet (it's an
  explicit open sub-item). `main.tf` has the DC2 module block written and
  commented out, ready to uncomment once NetBox assigns real CIDRs -- do not
  fill in a guessed default to make it "work" sooner.
- **`tc netem` WAN simulation.** `libvirt_network` has no netem-equivalent
  argument; this is an OS-level `tc qdisc` setting applied to the bridge
  interface a `mesh-link` module creates, which needs either a `null_resource`
  provisioner or a small companion script -- not yet written. The exact
  parameters are themselves a Phase-0 open item (D-100), so this was going to
  need a second pass regardless.
- **OPNsense edges -- four separable pieces, not one, all currently blocked or
  unstarted:** (a) the network substrate is done (`modules/mesh-link`, above);
  (b) the VM/image itself is blocked on the deferred domain module, and no
  image source (official OPNsense qcow2/ISO vs. a custom build) has been
  chosen; (c) OPNsense's own routing/firewall config is a `config.xml` the
  libvirt provider never touches -- pre-baked image vs. cloud-init first-boot
  vs. API/CLI-driven provisioner is an open choice, not started; (d) `tc
  netem` WAN simulation is a separate OS-level `tc qdisc` setting with no
  Terraform-native equivalent at all, needing its own provisioner/script, and
  whose parameters are still an unruled D-100 open item -- a decision, not
  just scripting, is needed first. Full breakdown in
  `docs/dc-dc-deployment-workflow.md` gap register item 4.
- **MAAS-region / NetBox / GitBucket service VMs.** Depend on the deferred
  domain module (they're VMs too).

## Schema notes (read before extending)

Verified this session against the provider's actual current docs
(`docs/resources/*.md` in `dmacvicar/terraform-provider-libvirt`, tag
`v0.9.8`, fetched 2026-07-09) -- NOT from training-data memory of older
provider versions, which would have been wrong:

- `libvirt_network`'s isolation control lives at `forward.mode` (a NESTED
  block field), not a top-level `mode` argument as older examples show. This
  scaffold OMITS the `forward` block entirely for isolated planes/links
  (documented native-libvirt behavior for a private, unforwarded switch)
  rather than guess a `mode = "none"` value this session could not confirm is
  still valid. Re-check this specific choice first if `tofu validate` objects.
- `domain` and `mtu` on `libvirt_network` are nested blocks (`domain { name =
  ... }`, `mtu { size = ... }`), not flat string/number arguments.
- `libvirt_pool`'s `target` is a nested block (`target { path = ... }`), types
  like `dir` are native libvirt storage-pool vocabulary (stable, long-standing,
  not provider-specific) -- reasonably high confidence.

## Conventions carried from the rest of this repo

- No hardcoded repo name (repo-lint L9 would need extending to cover `.tf`
  files if this becomes a recurring class of finding -- not yet done, flag if
  it comes up).
- Every variable without a safe, already-ratified default requires explicit
  input (no invented fallbacks) -- same "never use an inferred value"
  discipline as everywhere else in this repo.
- DC1's plane CIDRs are a second, hand-maintained copy of
  `scripts/lib-net.sh`'s `PLANE_CIDRS`. Keep them in sync manually until a
  generator exists to derive one from the other (DOCFIX candidate, not
  actioned).
