Files
homelab/scripts/validate_plan.py
T

84 lines
2.9 KiB
Python

import json
import sys
def validate_plan(plan_path):
try:
with open(plan_path, 'r') as f:
plan = json.load(f)
except FileNotFoundError:
print(f"Error: Plan file {plan_path} not found.")
sys.exit(1)
resource_changes = plan.get('resource_changes', [])
# 1. Validation: Gitea Server Protection
# Gitea server ID is 114, so expected address is proxmox_lxc.lxc["114"]
# We also check for name just in case.
gitea_deleted = False
# 2. Validation: Runner Availability
# We need to ensure at least one runner exists after apply.
active_runners = 0
print("Validating Plan...")
for change in resource_changes:
address = change.get('address', '')
actions = change.get('change', {}).get('actions', [])
after = change.get('change', {}).get('after', {})
# Check if it is being deleted
is_deleted = "delete" in actions and "create" not in actions # pure delete
# Check for Gitea Server (ID 114)
if 'proxmox_lxc.lxc["114"]' in address:
if is_deleted:
print(f"[FAIL] Plan attempts to destroy the Gitea Server ({address})!")
gitea_deleted = True
else:
print(f"[PASS] Gitea Server ({address}) is safe (Actions: {actions}).")
# Check for Gitea Runners
# We identify runners by tag "gitea-runner" or name convention if tag isn't available in `after` (e.g. unknown).
# However, `after` should contain tags if it's not a delete.
# If it is a delete, we check `before`.
is_runner = False
tags = ""
# Check 'after' state for surviving/new resources
if not is_deleted and after:
tags = after.get('tags', '')
# Check 'before' state for deleted resources (just for logging/logic if needed)
# Logic: We only care about what remains or is created.
if not is_deleted:
# If tags are computed/unknown, we might need to fallback to name or address
# Runners are usually created via loop in locals, so names are predictable "gitea-runner-X"
# Address format: proxmox_lxc.lxc["900"], proxmox_lxc.lxc["901"], etc.
name = after.get('name', '') if after else ''
if "gitea-runner" in tags or "gitea-runner" in name:
is_runner = True
if is_runner:
active_runners += 1
if gitea_deleted:
sys.exit(1)
print(f"Active runners after apply: {active_runners}")
if active_runners < 1:
print("[FAIL] Plan results in zero active Gitea Runners!")
sys.exit(1)
print("[PASS] Plan validation successful.")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python validate_plan.py <path_to_plan.json>")
sys.exit(1)
validate_plan(sys.argv[1])