import paramiko import json SPACEPORT_VIPS = { ("infrastructure", "jenkins-lb"): "140.44.4.57", ("infrastructure", "coder"): "140.44.4.58", ("infrastructure", "homepage-lb"): "140.44.4.59", ("monitoring", "zabbix-zabbix-web"): "140.44.4.60", ("infrastructure", "semaphore-lb"): "140.44.4.61", ("kube-system", "traefik"): "140.44.4.62", ("infrastructure", "gitea-lb"): "140.44.4.63", ("monitoring", "zabbix-zabbix-server"): "140.44.4.64", ("infrastructure", "pihole-web"): "140.44.4.65", } def main(): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect('140.44.4.41', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10) print("=== PINNING SPACEPORT LOADBALANCER VIPS ===") for (ns, name), target_ip in SPACEPORT_VIPS.items(): patch = json.dumps({ "metadata": { "annotations": { "metallb.universe.tf/loadBalancerIP": target_ip } }, "spec": { "loadBalancerIP": target_ip } }) cmd = f"kubectl patch svc {name} -n {ns} --type=merge -p '{patch}'" stdin, stdout, stderr = ssh.exec_command(cmd) out = stdout.read().decode().strip() err = stderr.read().decode().strip() print(f"[{ns}/{name}] -> {target_ip}: {out} {err}") print("\n=== VERIFYING FINAL ALLOCATION STATE (SPACEPORT) ===") for (ns, name), target_ip in SPACEPORT_VIPS.items(): stdin, stdout, stderr = ssh.exec_command(f"kubectl get svc {name} -n {ns} -o json") svc = json.loads(stdout.read().decode()) current_ingress = [x.get('ip') for x in svc.get('status', {}).get('loadBalancer', {}).get('ingress', [])] spec_ip = svc.get('spec', {}).get('loadBalancerIP') ann_ip = svc.get('metadata', {}).get('annotations', {}).get('metallb.universe.tf/loadBalancerIP') status = "LOCKED" if (spec_ip == target_ip and ann_ip == target_ip and target_ip in current_ingress) else "MISMATCH" print(f"[{status}] {ns}/{name}: Ingress={current_ingress}, Spec={spec_ip}, Annotation={ann_ip}") ssh.close() if __name__ == '__main__': main()