# node-vm: a single MAAS-managed OpenStack node VM (D-103's "OpenTofu creates
# the node-VM libvirt domains (SHIM -- Section 9)" -- Stage 3 / buildout-design
# Phase 2). BLANK disk, PXE-boot -- this is deliberately NOT the cloud-init +
# pre-built-image pattern (that's a separate, still-unbuilt module for Office1
# service VMs / OPNsense; see opentofu/README.md). MAAS enlists, commissions,
# and deploys these VMs after OpenTofu creates them; OpenTofu does not image
# them itself.
#
# Every attribute below is used exactly as shown in the provider's own
# examples/domain_with_network.tf and examples/alpine_cloudinit.tf (fetched
# and read directly this session, tag v0.9.8) -- attribute-style nested
# objects (`os = { ... }`, `devices = { ... }`), NOT classic HCL blocks. The
# ONE inference in this file, the per-device `boot` object's internal shape
# (`order`), is now BETTER-SUPPORTED after a 2026-07-09 audit pass (see
# opentofu/README.md): the provider is confirmed to code-generate its schema
# as a 1:1 mirror of libvirt's own domain XML, and libvirt's own official
# docs confirm the native XML element is exactly `<boot order='N'/>` (one
# attribute, `order`) -- consistent with every other single-attribute
# element already confirmed in this schema (e.g. `mtu = { size = N }` mirrors
# `<mtu size='N'/>`). Reasonably confident, not a blind guess anymore, but
# still not seen in an actual generated schema dump -- VERIFY with
# `tofu providers schema -json` before the first real apply regardless; if
# wrong, `tofu plan` will simply reject the attribute name, not silently
# misconfigure anything.

resource "libvirt_volume" "disk" {
  name     = "${var.vm_name}-disk.qcow2"
  pool     = var.pool_name
  capacity = var.disk_size_bytes
  format = {
    type = "qcow2"
  }
}

resource "libvirt_domain" "node" {
  name = var.vm_name
  # memory_unit is REQUIRED -- see the opnsense-edge module for the full write-up. On
  # dmacvicar/libvirt >=0.9, bare `memory` is interpreted in libvirt's default unit (KiB),
  # NOT MiB, so omitting this gives the guest 1024x too little RAM and it triple-faults
  # in its bootloader. (2026-07-12 incident.)
  memory      = var.memory_mib
  memory_unit = "MiB"
  vcpu        = var.vcpu
  type        = "kvm"
  running     = true

  # ACPI/APIC: with no `features` block libvirt renders `acpi=off` -- see the
  # opnsense-edge module for the full write-up. Especially important here: these are
  # the MAAS-managed node VMs, and MAAS drives power/shutdown via ACPI signalling.
  # Without ACPI a graceful `virsh shutdown` (and therefore MAAS power-off) does not
  # work -- the node would only ever hard-stop.
  features = {
    acpi = true
    apic = {}
  }

  os = {
    type         = "hvm"
    type_arch    = "x86_64"
    type_machine = "q35"
  }

  devices = {
    disks = [
      {
        source = {
          volume = {
            pool   = libvirt_volume.disk.pool
            volume = libvirt_volume.disk.name
          }
        }
        target = {
          dev = "vda"
          bus = "virtio"
        }
        driver = {
          type = "qcow2"
        }
        # boot.order shape UNVERIFIED (see file header) -- disk boots second,
        # network boots first (PXE).
        boot = {
          order = 2
        }
      }
    ]

    interfaces = [
      for i, net_name in var.network_names : {
        model = {
          type = "virtio"
        }
        source = {
          network = {
            network = net_name
          }
        }
        # only the first (PXE) interface gets an explicit boot order;
        # see the disk boot-order note above for the same caveat.
        boot = i == 0 ? { order = 1 } : null
      }
    ]
  }
}
