69 lines
2.5 KiB
Python
69 lines
2.5 KiB
Python
"""DNS gate logic — Spec 019."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from typing import Any
|
|
|
|
from app.migration import store
|
|
|
|
GATE_MIN_RATIO = float(os.getenv("MIGRATION_GATE_MIN_RATIO", "0.99"))
|
|
|
|
|
|
def evaluate_job(conn, job_id: int) -> dict[str, Any]:
|
|
job = store.get_job(conn, job_id)
|
|
if not job:
|
|
return {"gate": "blocked", "reason": "job_not_found"}
|
|
|
|
mailboxes = job.get("mailboxes") or []
|
|
checks: list[tuple[str, str, str]] = []
|
|
|
|
if not mailboxes:
|
|
checks.append(("mailboxes_present", "fail", "Nenhuma mailbox no job"))
|
|
gate = "blocked"
|
|
else:
|
|
ratios = []
|
|
for mb in mailboxes:
|
|
src = max(mb.get("messages_source") or 0, 1)
|
|
dst = mb.get("messages_dest") or 0
|
|
ratio = dst / src if src else 0.0
|
|
ratios.append(ratio)
|
|
if ratio < GATE_MIN_RATIO:
|
|
checks.append(
|
|
(
|
|
f"sync_{mb['email']}",
|
|
"warn" if ratio >= 0.9 else "fail",
|
|
f"{mb['email']}: {ratio * 100:.1f}% sincronizado",
|
|
)
|
|
)
|
|
avg = sum(ratios) / len(ratios) if ratios else 0.0
|
|
checks.append(("count_ratio", "pass" if avg >= GATE_MIN_RATIO else "warn", f"Média {avg * 100:.1f}%"))
|
|
|
|
if job.get("approved_by"):
|
|
checks.append(("manual_approval", "pass", f"Aprovado por {job['approved_by']}"))
|
|
gate = "ready_for_dns" if avg >= GATE_MIN_RATIO else "warning"
|
|
elif avg >= GATE_MIN_RATIO:
|
|
checks.append(("manual_approval", "fail", "Aguarda aprovação ops_lead"))
|
|
gate = "warning"
|
|
elif avg >= 0.9:
|
|
gate = "warning"
|
|
else:
|
|
gate = "blocked"
|
|
|
|
for check_id, status, message in checks:
|
|
store.add_gate_check(conn, job_id, check_id, status, message)
|
|
|
|
store.update_job(conn, job_id, migration_gate=gate, phase=job.get("phase") or "cutover_ready")
|
|
return {"gate": gate, "checks": [{"check_id": c[0], "status": c[1], "message": c[2]} for c in checks]}
|
|
|
|
|
|
def approve_gate(conn, job_id: int, approved_by: str) -> dict[str, Any]:
|
|
from datetime import datetime, timezone
|
|
|
|
now = datetime.now(timezone.utc).isoformat()
|
|
store.update_job(conn, job_id, approved_by=approved_by, approved_at=now, phase="cutover_ready")
|
|
result = evaluate_job(conn, job_id)
|
|
if result["gate"] in ("warning", "ready_for_dns"):
|
|
store.update_job(conn, job_id, migration_gate="ready_for_dns")
|
|
result["gate"] = "ready_for_dns"
|
|
return result
|