# MAAS As-Built Reference (VR0 / Baldurkeep)

**Purpose:** Authoritative, captured snapshot of the MAAS substrate and the four
OpenStack KVM hosts, so a rebuild (or the next DC-DC region) can REPLAY the
host enrollment + interface carve instead of re-deriving it from live state.

**Status:** Captured 2026-06-26 from live MAAS during the host re-enrollment
recovery. ASCII + LF. Append-only; correct in-place only for measured drift.

**Trust order:** LIVE MAAS > this doc > committed bundle. Every per-host value
here was measured live this session. IDs (subnet/space/fabric/interface) DRIFT
across cutovers and re-enrollments -- **resolve by CIDR / hostname, never by a
stored ID.** (PATTERN-1, lib-net.sh.)

---

## 1. Six network planes (post D-052 / D-053)

Resolve by CIDR. Subnet/space IDs intentionally omitted -- they drift (the D-052
cutover moved metal-internal off its old id; re-enrollment re-mints fabrics).

| space | CIDR | VLAN / fabric | gateway | role |
|---|---|---|---|---|
| provider-public | 10.12.4.0/22 | untagged / 1_provider | 10.12.4.1 | public API VIPs + FIP/ext_net |
| metal-admin | 10.12.8.0/22 | untagged / 2_metal (PXE/DHCP) | 10.12.8.1 | operator/MAAS/PXE/admin API |
| metal-internal | 10.12.12.0/22 | **tagged VID 103 / 2_metal** | none | ALL OpenStack east-west (db/amqp/rpc/internal API/OVN-DB) |
| data-tenant | 10.12.16.0/22 | untagged / 4_data | none | OVN geneve overlay |
| storage | 10.12.32.0/22 | untagged / 8_storage | none | Ceph public |
| replication | 10.12.36.0/22 | untagged / 9_replication | none | Ceph cluster |

Notes:
- metal-internal rides the **same L2 (2_metal)** as metal-admin, tagged VID 103,
  carried on host bridge `br-internal` (over `br-metal.103`). It is the ONLY
  tagged plane and the ONLY container-services plane that needs a bridge.
- Fabric cosmetic names (4_data / 8_storage / 9_replication) are reshuffled vs
  the libvirt network names and are irrelevant: Juju binds by SPACE NAME + CIDR
  + VLAN, all of which are correct.
- Spaceless / not bound: `f_oob` 10.12.60.0/22; LXD `fabric-4`
  10.37.195.0/24 + ULA fd42:8019:9206:57de::/64.
- Gateways: only provider-public and metal-admin route. A gateway on any other
  plane is the D-052 "spurious-gw" defect class -- clear to none.
- DNS resolver for the internal planes: 10.12.8.1.
- VIP reserves: provider-public/metal-admin/metal-internal each 10.12.x.2-.100.
  FIP pool 10.12.5.0-.7.254. PXE DHCP 10.12.9.0-.11.254. mgmt reserves
  10.12.4.101-.110 + 10.12.8.101-.110.

---

## 2. The four KVM hosts -- identity (hostname-keyed; system_id DRIFTS)

| hostname | libvirt domain / power_id | host octet | boot NIC (2_metal) MAC |
|---|---|---|---|
| openstack0 | openstack0 | .40 | 52:54:00:4f:1c:0b |
| openstack1 | openstack1 | .41 | 52:54:00:83:25:1f |
| openstack2 | openstack2 | .42 | 52:54:00:23:bd:72 |
| openstack3 | openstack3 | .43 | 52:54:00:b2:7b:30 |

system_ids are minted fresh on every (re-)enrollment -- do NOT hardcode them.
Resolve at runtime by hostname (scripts/lib-hosts.sh `host_sysid`). The dead
pre-2026-06-26 ids were 4na83t/qdbqd6/h8frng/tmsafc.

### Full per-host NIC inventory (libvirt domain XML; fixed MACs)

libvirt source-network -> MAAS plane (the libvirt net NAMES are pre-cutover;
the CIDRs were re-IP'd onto the same L2 segments, so e.g. `3_data` now carries
data-tenant 10.12.16.0/22):

| libvirt net | host NIC | plane | bridge/type |
|---|---|---|---|
| 1_provider | enp1s0 | provider-public | br-ex (OVS) |
| 2_metal (boot) | enp7s0 | metal-admin + metal-internal(VID103) | br-metal (OVS), br-metal.103 (vlan), br-internal (std bridge) |
| 3_data | enp8s0 | data-tenant | raw NIC |
| 4_storage | enp9s0 | storage | raw NIC |
| 5_replication | enp10s0 | replication | raw NIC |
| 8_lbaas | enp11s0 | idle (undefined; ex-lbaas) | raw NIC, no link |

MAC inventory (host: provider / metal-boot / data / storage / replication / lbaas):
- openstack0: 3d:fd:54 / 4f:1c:0b / 07:41:0a / d0:ed:e0 / 8f:ba:61 / d9:af:46
- openstack1: 9d:63:77 / 83:25:1f / 4e:71:6c / 42:50:8b / 86:78:ab / c6:56:12
- openstack2: 89:7f:ce / 23:bd:72 / 24:70:08 / b8:5d:a3 / 28:bc:8c / b5:1e:61
- openstack3: 99:fc:c2 / b2:7b:30 / c7:94:e9 / 41:cd:6b / bc:98:b0 / 6f:f5:ca
  (all prefixed 52:54:00:)

---

## 3. virsh power (non-secret) + enrollment

- power_type: virsh
- power_address: `qemu+ssh://logxen@10.12.64.1/system`  (MAAS -> libvirt over
  SSH on the OOB host address; mirrors the surviving juju/lxd/tailscale machines)
- power_id: the libvirt domain name == the hostname
- power_pass: **read interactively; never stored.** The libvirt SSH password was
  exposed in plaintext on 2026-06-26 (`maas machine power-parameters` echoes it)
  -- **ROTATE that credential after the rebuild.** Never use `power-parameters`
  for templating; read `power_type` and reconstruct the address pattern instead.

Enrollment behaviour: `machines create` AUTO-COMMISSIONS (New -> Commissioning ->
Ready) by PXE off the 2_metal boot NIC. The libvirt domains must already exist
(this re-creates MAAS objects, not VMs). On commission, MAAS auto-discovers all
six raw NICs; the five non-boot NICs land on transient auto-fabrics
(fabric-NN, "Unconfigured") -- normal; the interface carve re-homes them by CIDR.

Procedure: `scripts/reenroll-hosts.sh` (gated, idempotent, discover-assert-pin).
Constants: `scripts/lib-hosts.sh`.

**Post-commission, before deploy:** re-apply the MAAS tag `openstack` to all four
(the bundle places units via constraint `tags=openstack`; the tag applies to no
machines after re-enrollment).

---

## 4. Per-host interface carve target (Strategy-B reconstruction)

After commission, MAAS has only the raw NICs. Rebuild this tree (octet N =
.40/.41/.42/.43 by host index). Build order is forced by parentage.

| MAAS interface | type | parent | VLAN | space | static |
|---|---|---|---|---|---|
| enp1s0 | physical | - | untagged | provider-public | (carries br-ex) |
| br-ex | bridge **OVS** | enp1s0 | untagged | provider-public | 10.12.4.N |
| enp7s0 | physical | - | untagged | metal-admin | (carries br-metal) |
| br-metal | bridge **OVS** | enp7s0 | untagged | metal-admin | 10.12.8.N |
| br-metal.103 | vlan | br-metal | 103 | metal-internal | (carries br-internal) |
| br-internal | bridge **standard** | br-metal.103 | 103 | metal-internal | 10.12.12.N |
| enp8s0 | physical | - | untagged | data-tenant | 10.12.16.N |
| enp9s0 | physical | - | untagged | storage | 10.12.32.N |
| enp10s0 | physical | - | untagged | replication | 10.12.36.N |
| enp11s0 | physical | - | untagged | undefined (idle) | (none) |

Build order: physicals (auto-discovered) -> br-ex / br-metal (OVS) ->
br-metal.103 (vlan) -> br-internal (std bridge) -> statics on
br-ex/br-metal/br-internal/enp8/enp9/enp10. Link by CIDR (re-homes the NIC onto
the correct fabric/space).

CAVEAT: confirm each `bridge_type` (OVS vs standard) verbatim from a captured
machine-release JSON before carving -- it changes how MAAS renders netplan and
is the one value not to take from memory.

Deployed-host bridge facts (for reference; created by Juju/LXD at deploy, NOT by
MAAS): storage/replication appear as Linux bridges br-enp9s0/br-enp10s0;
br-ex/br-metal/br-internal are OVS; data-tenant runs on raw enp8s0.

---

## 5. MAAS substrate facts (stable)

- MAAS 3.7.2; controller `maas.maas`, Region+Rack, Non-HA(3 VLANs).
- Pool `default`; zone `default`. Images synced (amd64): 24.04, 22.04, 20.04.
  Hosts deploy on 22.04 (Jammy).
- Surviving (untouched) machines: capi-mgmt (lxd pod, Ready), juju/lxd/tailscale
  (virsh, owner logxen). The LXD pod composes only capi-mgmt; the four OpenStack
  hosts are virsh-individual (NOT pod-composed).
- Tags present: openstack (apply to the 4 hosts), capi-mgmt, virtual,
  pod-console-logging, juju, lxd, tailscale.

---

## 6. DC-DC reuse notes

Region-specific (re-derive per region): the 10.12.x CIDRs, the boot/NIC MACs,
the virsh power_address, the host octets, the libvirt host OOB address.

Structural (replays unchanged across regions): the six-plane model and its
roles; metal-internal as a tagged VID-103 bridged stack over the metal plane;
the per-host interface tree shape (OVS provider/metal + std-bridge internal +
raw data/storage/replication); hostname-keyed identity with runtime system_id
resolution; auto-commission-on-create; tag `openstack` re-apply before deploy;
`default-space` must resolve to a LIVE space (a stale default-space globally
poisons `network-get`).
