Populate terragrunt-enc: encapi ENC data as code
terragrunt-enc is the single source of truth for encapi ENC data (Puppet statuses, roles, and node classifications), managed with Terraform/Terragrunt. It supersedes Cobbler classification for Puppet and the terraform-incus dual-write prototype (PR #39). - Add modules/encapi (encapi_status / encapi_role / encapi_node, nodes FK-ordered after their role and status). - Add config/encapi leaf: 3 statuses, 51 roles, and 143 node assignments (130 container VMs env production + 13 prodnxsr physicals env develop), all YAML-driven. - Add config/root.hcl (consul backend infra/terraform/enc/<leaf>/state) and the encapi provider from the artifactapi registry (v0.1.0). - Add Makefile, Woodpecker pre-commit/plan/apply pipelines, pre-commit config, ci/extract_incus_nodes.py, and expand the README.
This commit is contained in:
Executable
+84
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Regenerate the container-VM portion of config/encapi/nodes.yaml from a
|
||||
checkout of terraform-incus.
|
||||
|
||||
encapi is the single source of truth for Puppet ENC data, but the 130 container
|
||||
VMs are *defined* in terraform-incus (config/instances/<host>/config.yaml). This
|
||||
script lifts that classification into plain config data here:
|
||||
|
||||
certname = <dir basename>.<cobbler_domain> (cobbler_domain = main.unkin.net)
|
||||
role = cobbler_mgmt_classes[0] (default roles::base)
|
||||
environment = production
|
||||
|
||||
It only rewrites the "container VMs" block; the prodnxsr physical nodes below
|
||||
the marker are maintained by hand and left untouched.
|
||||
|
||||
Usage:
|
||||
python3 ci/extract_incus_nodes.py --incus-repo /path/to/terraform-incus
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
sys.exit("PyYAML required: pip install pyyaml")
|
||||
|
||||
PHYS_MARKER = "# --- prodnxsr physical nodes (develop) ---"
|
||||
VM_MARKER = "# --- container VMs (production) ---"
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--incus-repo", required=True,
|
||||
help="Path to a terraform-incus checkout")
|
||||
ap.add_argument("--domain", default="main.unkin.net")
|
||||
ap.add_argument("--nodes-file",
|
||||
default=os.path.join(os.path.dirname(__file__),
|
||||
"..", "config", "encapi", "nodes.yaml"))
|
||||
args = ap.parse_args()
|
||||
|
||||
inst = os.path.join(args.incus_repo, "config", "instances")
|
||||
dirs = sorted(d for d in os.listdir(inst)
|
||||
if os.path.isdir(os.path.join(inst, d))
|
||||
and os.path.exists(os.path.join(inst, d, "config.yaml")))
|
||||
|
||||
vm_lines = []
|
||||
for d in dirs:
|
||||
with open(os.path.join(inst, d, "config.yaml")) as f:
|
||||
cfg = yaml.safe_load(f) or {}
|
||||
classes = cfg.get("cobbler_mgmt_classes") or []
|
||||
role = classes[0] if classes else "roles::base"
|
||||
vm_lines.append(f"{d}.{args.domain}:")
|
||||
vm_lines.append(f" role: {role}")
|
||||
vm_lines.append(" environment: production")
|
||||
|
||||
nodes_file = os.path.abspath(args.nodes_file)
|
||||
with open(nodes_file) as f:
|
||||
existing = f.read().splitlines()
|
||||
|
||||
# Preserve everything from the physical-nodes marker onward.
|
||||
try:
|
||||
idx = existing.index(PHYS_MARKER)
|
||||
except ValueError:
|
||||
sys.exit(f"marker not found in {nodes_file}: {PHYS_MARKER!r}")
|
||||
tail = existing[idx:]
|
||||
|
||||
# Preserve only the top-of-file comment block, stopping at the VM marker.
|
||||
header = []
|
||||
for ln in existing[:idx]:
|
||||
if ln == VM_MARKER:
|
||||
break
|
||||
header.append(ln)
|
||||
while header and header[-1] == "":
|
||||
header.pop()
|
||||
|
||||
out = header + ["", VM_MARKER] + vm_lines + ["", *tail]
|
||||
with open(nodes_file, "w") as f:
|
||||
f.write("\n".join(out).rstrip("\n") + "\n")
|
||||
print(f"wrote {len(dirs)} container VM records to {nodes_file}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user