Newer
Older
openstack-caracal-dc-dc / opentofu / main.tf
# Root module: wires the network + storage-pool layer for VR1 (Stage 1-2 of
# docs/dc-dc-deployment-workflow.md). See opentofu/README.md for full scope,
# what is deliberately deferred, and why.

provider "libvirt" {
  uri = var.libvirt_uri
}

# ---- The provider "maas" CONFIG block is deliberately DEFERRED to Stage 3
# (DOCFIX-179, decided on the first real `tofu plan`). No module instantiated in
# Stage 1-2 uses the maas provider (modules/maas-vm-host is a Stage-3 module,
# commented out below), yet a configured provider "maas" block here forced
# `tofu plan` to demand maas_api_url AND the SENSITIVE maas_api_key for a plan
# that creates ZERO MAAS resources -- which would bake a fake key into
# plan/state (the DOCFIX-175 plaintext-secret surface). maas stays in
# versions.tf's required_providers (version pinned, lock-file complete); Stage 3
# re-adds this provider block + its two variables when it actually instantiates
# modules/maas-vm-host. modules/netem-link is likewise not instantiated yet
# (needs a real bridge/SSH target + netem params). See gap register items
# 2/4/11 and opentofu/README.md. ----

# ---- DC1: inherits the DC0 six-plane v4 layout unchanged (D-101) ----

module "dc1_planes" {
  source        = "./modules/dc-planes"
  dc_name       = "dc1"
  domain_suffix = var.domain_suffix
  mtu           = var.underlay_mtu
  planes        = var.dc1_planes
}

module "dc1_storage" {
  source      = "./modules/dc-storage-pool"
  dc_name     = "dc1"
  target_path = var.dc1_pool_path
}

# ---- DC2: PLANES deferred (operator ruling 2026-07-10, Option B) -- wait for
# NetBox to assign D-101's supernet/ULA/GUA before wiring dc2_planes. Do NOT
# fill in guessed CIDRs to make it "work" sooner. When NetBox assigns it, add a
# `dc2_planes` variable (same shape as `dc1_planes`) and uncomment this block.
# The storage pool + mesh legs are NOT address-dependent, so they ARE wired now.
#
# module "dc2_planes" {
#   source        = "./modules/dc-planes"
#   dc_name       = "dc2"
#   domain_suffix = var.domain_suffix
#   mtu           = var.underlay_mtu
#   planes        = var.dc2_planes
# }

module "dc2_storage" {
  source      = "./modules/dc-storage-pool"
  dc_name     = "dc2"
  target_path = var.dc2_pool_path
}

# ---- Office1 headend: its own storage pool for MAAS-region/NetBox/GitBucket
# service-VM disks (D-103). Office1 does not get a dc-planes module -- the
# six-plane template is per-OpenStack-DC, not per-headend. ----

module "office1_storage" {
  source      = "./modules/dc-storage-pool"
  dc_name     = "office1"
  target_path = var.office1_pool_path
}

# ---- Office1-local network (closes tooling gap register item #12): the
# shared L2 segment the three Office1 service VMs (MAAS-region, NetBox,
# GitBucket), the vcloud host's own management interface, and Office1's own
# OPNsense edge's LAN side (gap #16) all attach to. See
# modules/office1-network/main.tf's header for the design decision (a new
# module, not a reused host bridge) and opentofu/README.md for the full
# writeup. Instantiated for real here (unlike office1_opnsense below): it
# needs no value beyond domain_suffix/underlay_mtu, both already real,
# required inputs elsewhere in this file -- the same reasoning that already
# lets the three mesh-link legs be instantiated today. ----

module "office1_network" {
  source        = "./modules/office1-network"
  domain_suffix = var.domain_suffix
  mtu           = var.underlay_mtu
}

# ---- Office1's own OPNsense edge (closes tooling gap register item #16 --
# decision: YES, Office1 gets a fourth modules/opnsense-edge call alongside
# DC1/DC2, and Stage 2's runbook (runbooks/dc-dc-phase1-office1-standup.md)
# owns creating it -- see that runbook's new Step 4b and its "Open questions"
# section for the full reasoning). NOT instantiated below -- commented out on
# purpose, mirroring the identical NOT-YET-REAL status of module
# "dc1_opnsense"/"dc2_opnsense" (see runbooks/dc-dc-phase2-tofu-dc-substrate.md
# Step 5's own template, which is ALSO still all placeholders, nothing
# committed here either). Every value below needs to be real before this is
# uncommented -- do not fill in invented specs to wire it in sooner:
#
# module "office1_opnsense" {
#   source           = "./modules/opnsense-edge"
#   vm_name          = "office1-opnsense"
#   memory_mib       = <REAL VALUE -- OPNsense's own sizing guidance, not invented>
#   vcpu             = <REAL VALUE>
#   pool_name        = module.office1_storage.pool_name
#   disk_size_bytes  = <REAL VALUE>
#   base_volume_path = "<real prepared base image path -- scripts/opnsense-prep-image.sh output>"
#   config_iso_path  = "<real config ISO path -- scripts/opnsense-build-config-iso.sh output, built from a real Office1 config.xml>"
#   lan_network_name = module.office1_network.network_name
#   wan_network_name = <UNRESOLVED -- see docs/dc-dc-deployment-workflow.md
#     tooling gap register item #17 (NEW, added alongside this delivery):
#     no dedicated ISP-uplink/WAN-side network exists for ANY site's OPNsense
#     edge yet, DC1/DC2 included -- runbooks/dc-dc-phase2-tofu-dc-substrate.md
#     Step 5's own dc1_opnsense template has the IDENTICAL unresolved
#     wan_network_name placeholder. Do NOT default this to a mesh-link
#     network: D-100's own sub-item ruling is explicit that the three
#     mesh legs carry MANAGEMENT TRAFFIC ONLY (Office1<->DC fiber = MAAS/
#     Juju/operator), not a simulated ISP uplink -- wiring an edge's WAN
#     side to a mesh leg would misrepresent the topology, not just
#     placeholder it. Resolve gap #17 (a dedicated per-site ISP-edge
#     network, analogous in shape to this same office1-network module or
#     mesh-link) before uncommenting this block for Office1 OR for DC1/DC2.>
# }

# ---- The D-100 dark-fiber mesh triangle: DC1<->DC2, DC1<->Office1,
# DC2<->Office1 -- mesh, not star. All three legs created now even though DC2
# itself is not yet wired above: the LINK is independent of whether DC2's
# plane networks exist yet, and Phase 0's gate wants "virtual networks present
# and isolated as designed" before Phase 2 needs them. ----

module "mesh_dc1_dc2" {
  source    = "./modules/mesh-link"
  link_name = "dc1-dc2"
  mtu       = var.underlay_mtu
}

module "mesh_dc1_office1" {
  source    = "./modules/mesh-link"
  link_name = "dc1-office1"
  mtu       = var.underlay_mtu
}

module "mesh_dc2_office1" {
  source    = "./modules/mesh-link"
  link_name = "dc2-office1"
  mtu       = var.underlay_mtu
}