Files
gatehouse-api/gatehouse_app/jobs/zerotier_reconciliation_job.py
T

83 lines
3.0 KiB
Python

"""ZeroTier reconciliation scheduled job.
This module implements the scheduled job for reconciling portal network state
with the ZeroTier controller. It is designed to be run periodically (every
1-2 minutes via cron) to:
1. Expire activation sessions past their TTL and deauthorize the corresponding ZT members
2. Sync observed ZeroTier membership state into zerotier_memberships cache
3. Reconcile portal membership state against ZT controller state
4. Flag unknown ZT members (not in portal)
5. Detect and repair drift (ZT says authorized but portal says inactive, and vice versa)
Usage:
python manage.py run_zerotier_reconciliation
Or call directly:
from gatehouse_app.jobs.zerotier_reconciliation_job import run_reconciliation
run_reconciliation()
Cron example (every 2 minutes):
*/2 * * * * cd /path/to/app && python manage.py run_zerotier_reconciliation
"""
import logging
from datetime import datetime, timezone
from typing import Optional
from gatehouse_app.services import zerotier_reconciliation_service
logger = logging.getLogger(__name__)
def run_reconciliation() -> dict:
"""Run full ZeroTier reconciliation across all networks and activations.
Returns:
Dictionary with reconciliation results:
- expired_activations: number of activation sessions expired
- networks_processed: number of portal networks reconciled
- errors: number of networks that had errors
"""
logger.info(f"[ZT Reconcile] Starting reconciliation at {datetime.now(timezone.utc).isoformat()}")
results = {
"expired_activations": 0,
"networks_processed": 0,
"authorized": 0,
"deauthorized": 0,
"deleted_memberships": 0,
"delete_errors": 0,
"errors": 0,
}
try:
expired = zerotier_reconciliation_service.reconcile_expired_activations()
results["expired_activations"] = expired
except Exception as exc:
logger.error(f"[ZT Reconcile] Error expiring activations: {exc}")
try:
summary = zerotier_reconciliation_service.reconcile_all()
results["networks_processed"] = summary.get("networks_processed", 0)
results["authorized"] = summary.get("authorized", 0)
results["deauthorized"] = summary.get("deauthorized", 0)
results["deleted_memberships"] = summary.get("deleted_memberships", 0)
results["delete_errors"] = summary.get("delete_errors", 0)
results["errors"] = summary.get("errors", 0)
except Exception as exc:
logger.error(f"[ZT Reconcile] Error during network reconciliation: {exc}")
results["errors"] += 1
logger.info(
f"[ZT Reconcile] Complete at {datetime.now(timezone.utc).isoformat()}: "
f"expired={results['expired_activations']} "
f"networks={results['networks_processed']} "
f"authorized={results['authorized']} "
f"deauthorized={results['deauthorized']} "
f"purged={results['deleted_memberships']} "
f"errors={results['errors']}"
)
return results