84 lines
2.9 KiB
Python
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])
|