#!/usr/bin/env python3
# tests/carve-host-interfaces/make_fixtures.py
# Emits fix/*.json for the carve-host-interfaces.sh harness -- Pattern A
# (D-060: br-ex OVS on enp1s0; br-metal/.103/br-internal; raw data/storage/
# replication statics). Rewritten 2026-07-03 from the retired D-057 fixtures.
# ASCII + LF.
import json, os

HERE = os.path.dirname(os.path.abspath(__file__))
FIX = os.path.join(HERE, "fix")
os.makedirs(FIX, exist_ok=True)

def w(name, obj):
    with open(os.path.join(FIX, name), "w") as f:
        json.dump(obj, f, indent=2); f.write("\n")

def vl(vid, vid_id, fab): return {"id": vid_id, "vid": vid, "fabric": fab}

SUBS = [
    {"cidr": "10.12.4.0/22",  "id": 1, "vlan": vl(0,   5001, "fabric-prov")},
    {"cidr": "10.12.8.0/22",  "id": 2, "vlan": vl(0,   5002, "fabric-metal")},
    {"cidr": "10.12.12.0/22", "id": 3, "vlan": vl(103, 5003, "fabric-metal")},
    {"cidr": "10.12.16.0/22", "id": 4, "vlan": vl(0,   5004, "fabric-data")},
    {"cidr": "10.12.32.0/22", "id": 5, "vlan": vl(0,   5005, "fabric-stor")},
    {"cidr": "10.12.36.0/22", "id": 6, "vlan": vl(0,   5006, "fabric-repl")},
]
w("sub_ok.json", SUBS)
# metal-internal on the wrong VID -> hard gate
bad = [dict(s) for s in SUBS]
for s in bad:
    if s["cidr"] == "10.12.12.0/22": s["vlan"] = vl(99, 5003, "fabric-metal")
w("sub_wrongvid.json", bad)
# a plane subnet missing entirely -> hard gate
w("sub_missing.json", [s for s in SUBS if s["cidr"] != "10.12.16.0/22"])

def nic(name, nid, vlan, links=None, typ="physical"):
    return {"name": name, "id": nid, "type": typ, "vlan": vlan,
            "links": links or []}

def link(lid, cidr, ip=None, mode="dhcp"):
    return {"id": lid, "subnet": {"cidr": cidr},
            "ip_address": ip, "mode": mode}

# FRESH: post-commissioning tree -- L3 on the physical NICs, no bridges yet
w("if_fresh.json", [
    nic("enp1s0",  100, vl(0, 5001, "fabric-prov"),
        [link(900, "10.12.4.0/22")]),                       # commissioning DHCP on the uplink
    nic("enp7s0",  101, vl(0, 5002, "fabric-metal"),
        [link(901, "10.12.8.0/22", "10.12.8.40", "static")]),  # PXE link
    nic("enp8s0",  102, vl(0, 5004, "fabric-data")),
    nic("enp9s0",  103, vl(0, 5005, "fabric-stor")),
    nic("enp10s0", 104, vl(0, 5006, "fabric-repl")),
    nic("enp11s0", 105, vl(0, 5001, "fabric-prov")),        # ex-lbaas, idle
])

# DONE: completed Pattern A -- re-run must be all-SKIP, zero WOULD
w("if_done.json", [
    nic("enp1s0",  100, vl(0, 5001, "fabric-prov")),
    nic("br-ex",   200, vl(0, 5001, "fabric-prov"),
        [link(910, "10.12.4.0/22", "10.12.4.40", "static")], typ="bridge"),
    nic("enp7s0",  101, vl(0, 5002, "fabric-metal")),
    nic("br-metal", 201, vl(0, 5002, "fabric-metal"),
        [link(911, "10.12.8.0/22", "10.12.8.40", "static")], typ="bridge"),
    nic("br-metal.103", 202, vl(103, 5003, "fabric-metal"), typ="vlan"),
    nic("br-internal", 203, vl(103, 5003, "fabric-metal"),
        [link(912, "10.12.12.0/22", "10.12.12.40", "static")], typ="bridge"),
    nic("enp8s0",  102, vl(0, 5004, "fabric-data"),
        [link(913, "10.12.16.0/22", "10.12.16.40", "static")]),
    nic("enp9s0",  103, vl(0, 5005, "fabric-stor"),
        [link(914, "10.12.32.0/22", "10.12.32.40", "static")]),
    nic("enp10s0", 104, vl(0, 5006, "fabric-repl"),
        [link(915, "10.12.36.0/22", "10.12.36.40", "static")]),
    nic("enp11s0", 105, vl(0, 5001, "fabric-prov")),
])

w("machines.json", [{"hostname": "openstack0", "system_id": "abc100"}])
w("machine.json", {"status_name": "Ready"})
