#!/usr/bin/env python3 import json, yaml, subprocess, os, sys, pathlib, glob REPO_ROOT = pathlib.Path(__file__).resolve().parents[1] sys.path.insert(0, str(REPO_ROOT / "scripts")) from baseline_contract import load_spec, profile_hostvars from inventory_contract import load_inventory def load_servers(): data = load_inventory(REPO_ROOT / 'inventory' / 'servers.yaml') servers = data.get('servers', []) return servers def load_baseline(): return load_spec(REPO_ROOT / 'spec' / 'server-baseline.yaml') def load_tf_outputs(): # Try to read terraform outputs to attach IPs, if available. try: out = subprocess.check_output( ['terraform', f'-chdir={REPO_ROOT / "terraform" / "hetzner"}', 'output', '-json'], stderr=subprocess.DEVNULL, text=True, ) j = json.loads(out) servers = j.get('servers', {}).get('value', {}) return servers # {name: ip} except Exception: return {} def load_host_vars(name): """Load host_vars/.yml if it exists. The inventory script is ansible/inventory_from_yaml.py. Ansible does not auto-load a host_vars directory next to a script inventory, so this has to emit hostvars itself. Look in ansible/inventory/host_vars first (where CoulombCore.yml actually lives), then the unused repo-root path. """ script_dir = os.path.dirname(__file__) candidates = [ os.path.join(script_dir, 'inventory', 'host_vars', f'{name}.yml'), os.path.join(script_dir, 'inventory', 'host_vars', f'{name}.yaml'), os.path.join(script_dir, '..', 'inventory', 'host_vars', f'{name}.yml'), os.path.join(script_dir, '..', 'inventory', 'host_vars', f'{name}.yaml'), ] for path in candidates: if os.path.exists(path): with open(path) as f: return yaml.safe_load(f) or {} return {} def main(): server_list = load_servers() baseline = load_baseline() tf = load_tf_outputs() host_names = [] hostvars = {} for s in server_list: name = s['name'] host_names.append(name) hvars = { "ansible_host": tf.get(name) or s.get('ip'), "ansible_user": s.get('ssh_user', 'admin'), } hvars.update(profile_hostvars(baseline, s['baseline_profile'])) if s.get('ssh_key'): hvars["ansible_ssh_private_key_file"] = s['ssh_key'] hvars.update(load_host_vars(name)) hostvars[name] = hvars inv = { "all": {"hosts": host_names}, "_meta": {"hostvars": hostvars} } print(json.dumps(inv)) if __name__ == "__main__": main()