feat(vip): lock MetalLB LoadBalancer VIPs across Aerodrome and Spaceport (Pillar 2 completed)
This commit is contained in:
53
scripts/audit_and_pin_vips.py
Normal file
53
scripts/audit_and_pin_vips.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import paramiko
|
||||
import json
|
||||
|
||||
TARGET_VIPS = {
|
||||
("monitoring", "uptime-lb"): "140.44.4.28",
|
||||
("infra", "authentik-lb"): "140.44.4.29",
|
||||
("awx", "awx-lb"): "140.44.4.30",
|
||||
("infra", "technitium-npm-vip-service"): "140.44.4.31",
|
||||
("default", "grafana-lb"): "140.44.4.32",
|
||||
("infra", "unified-npm-vip-service"): "140.44.4.33",
|
||||
("kube-system", "traefik"): "140.44.4.34",
|
||||
("infra", "ak-outpost-authentik-ldap-outpost"): "140.44.4.35",
|
||||
("longhorn-system", "longhorn-frontend-lb"): "140.44.4.36",
|
||||
}
|
||||
|
||||
def main():
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
print("=== PINNING AERODROME LOADBALANCER VIPS ===")
|
||||
for (ns, name), target_ip in TARGET_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 ===")
|
||||
for (ns, name), target_ip in TARGET_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()
|
||||
29
scripts/check_aerodrome_vip_details.py
Normal file
29
scripts/check_aerodrome_vip_details.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import paramiko
|
||||
import json
|
||||
|
||||
def main():
|
||||
s = paramiko.SSHClient()
|
||||
s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
s.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet')
|
||||
|
||||
_, o, _ = s.exec_command('kubectl get svc -A -o json')
|
||||
data = json.loads(o.read().decode())
|
||||
print("=== AERODROME LOADBALANCER SERVICES ===")
|
||||
for item in data.get('items', []):
|
||||
if item.get('spec', {}).get('type') == 'LoadBalancer':
|
||||
name = item['metadata']['name']
|
||||
ns = item['metadata']['namespace']
|
||||
lb_ip = item.get('spec', {}).get('loadBalancerIP')
|
||||
ing = [x.get('ip') for x in item.get('status', {}).get('loadBalancer', {}).get('ingress', [])]
|
||||
annotations = item['metadata'].get('annotations', {})
|
||||
print(f"- {ns}/{name}: status_ingress={ing}, spec_loadBalancerIP={lb_ip}, metallb_annotations={list(annotations.keys())}")
|
||||
|
||||
_, o, _ = s.exec_command('kubectl get ipaddresspools.metallb.io -A -o yaml 2>/dev/null || kubectl get cm -n metallb-system config -o yaml 2>/dev/null || true')
|
||||
print("\n=== METALLB CONFIG ===")
|
||||
print(o.read().decode())
|
||||
|
||||
s.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
53
scripts/pin_spaceport_vips.py
Normal file
53
scripts/pin_spaceport_vips.py
Normal file
@@ -0,0 +1,53 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user