100 lines
3.6 KiB
Python
100 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""SysOps daily — approval requests for update scan + Gitea backup (no auto-scan)."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
import urllib.request
|
|
from datetime import datetime, timezone
|
|
|
|
COCKPIT_URL = "http://127.0.0.1:8600"
|
|
|
|
|
|
def _post(url: str, payload: dict | None = None, timeout: int = 60) -> dict:
|
|
data = json.dumps(payload or {}).encode("utf-8")
|
|
req = urllib.request.Request(
|
|
url,
|
|
data=data,
|
|
headers={"Content-Type": "application/json"},
|
|
method="POST",
|
|
)
|
|
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
|
return json.loads(resp.read().decode("utf-8"))
|
|
|
|
|
|
def _get(url: str, timeout: int = 30) -> dict:
|
|
with urllib.request.urlopen(url, timeout=timeout) as resp:
|
|
return json.loads(resp.read().decode("utf-8"))
|
|
|
|
|
|
def _already_pending(action_type: str) -> bool:
|
|
try:
|
|
data = _get(f"{COCKPIT_URL}/api/agents/approvals?status=pending&limit=50")
|
|
return any(
|
|
i.get("agent_key") == "sysops" and i.get("action_type") == action_type
|
|
for i in (data.get("items") or [])
|
|
)
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def main() -> int:
|
|
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
results: dict = {"date": today, "steps": []}
|
|
|
|
if not _already_pending("maintenance_scan"):
|
|
try:
|
|
scan_req = _post(
|
|
f"{COCKPIT_URL}/api/agents/requests",
|
|
{
|
|
"agent_key": "sysops",
|
|
"action_type": "maintenance_scan",
|
|
"title": f"Mag ik een update-scan uitvoeren op VM106? — {today}",
|
|
"query_payload": {
|
|
"scope": "vm106",
|
|
"checks": ["apt upgrades", "disk usage", "docker health", "proxmox reachability"],
|
|
"host": "10.4.7.18",
|
|
},
|
|
},
|
|
)
|
|
results["steps"].append({"maintenance_scan_request": scan_req})
|
|
print("Maintenance scan approval request:", (scan_req.get("request") or {}).get("id"))
|
|
except Exception as exc:
|
|
results["steps"].append({"maintenance_scan_error": str(exc)})
|
|
print("Maintenance scan request failed:", exc, file=sys.stderr)
|
|
else:
|
|
print("Maintenance scan request already pending — skipped")
|
|
results["steps"].append({"maintenance_scan_request": "already_pending"})
|
|
|
|
if not _already_pending("config_backup"):
|
|
try:
|
|
backup_req = _post(
|
|
f"{COCKPIT_URL}/api/agents/requests",
|
|
{
|
|
"agent_key": "sysops",
|
|
"action_type": "config_backup",
|
|
"title": f"Dagelijkse config backup naar Gitea — {today}",
|
|
"query_payload": {
|
|
"target": "gitea",
|
|
"repo": "aissa/foodlinkk-command-center",
|
|
"paths": ["docker-compose.yml", "migrations", "monitoring"],
|
|
},
|
|
},
|
|
)
|
|
results["steps"].append({"backup_request": backup_req})
|
|
print("Backup approval request:", (backup_req.get("request") or {}).get("id"))
|
|
except Exception as exc:
|
|
results["steps"].append({"backup_error": str(exc)})
|
|
print("Backup request failed:", exc, file=sys.stderr)
|
|
return 1
|
|
else:
|
|
print("Backup request already pending — skipped")
|
|
results["steps"].append({"backup_request": "already_pending"})
|
|
|
|
print(json.dumps(results, indent=2))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|