mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 03:10:46 +08:00
Size DB pool, CLI budget, and WebCRT session caps for concurrent operators while keeping hard ceilings and env overrides. Co-authored-by: Cursor <cursoragent@cursor.com>
129 lines
3.9 KiB
Python
129 lines
3.9 KiB
Python
"""Config sync shared helpers and policy ensure/prune."""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from datetime import datetime
|
|
from typing import Any
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from .config_sync_schemas import (
|
|
ConfigSyncCycleOut,
|
|
ConfigSyncPolicyOut,
|
|
ConfigSyncTargetRef,
|
|
ConfigSyncTaskOut,
|
|
)
|
|
from .models import ConfigSyncCycle, ConfigSyncPolicy, ConfigSyncTask
|
|
from .timeutil import utcnow_naive
|
|
|
|
_log = logging.getLogger("netx.config_sync")
|
|
|
|
POLICY_ID = 1
|
|
DEFAULT_CYCLE_KEEP = 30
|
|
|
|
|
|
def _utcnow() -> datetime:
|
|
return utcnow_naive()
|
|
|
|
|
|
def ensure_policy(db: Session) -> ConfigSyncPolicy:
|
|
row = db.get(ConfigSyncPolicy, POLICY_ID)
|
|
if row is None:
|
|
row = ConfigSyncPolicy(id=POLICY_ID, enabled=False)
|
|
db.add(row)
|
|
db.commit()
|
|
db.refresh(row)
|
|
return row
|
|
|
|
|
|
def prune_config_sync_cycles(db: Session, *, keep: int = DEFAULT_CYCLE_KEEP) -> int:
|
|
"""Delete finished cycles beyond ``keep`` (newest kept). Active cycles always retained."""
|
|
keep = max(0, min(200, int(keep)))
|
|
finished = (
|
|
db.query(ConfigSyncCycle)
|
|
.filter(ConfigSyncCycle.status.in_(("success", "fail", "cancelled")))
|
|
.order_by(ConfigSyncCycle.created_at.desc())
|
|
.all()
|
|
)
|
|
to_drop = finished if keep == 0 else finished[keep:]
|
|
if not to_drop:
|
|
return 0
|
|
dropped = 0
|
|
for cycle in to_drop:
|
|
cid = str(cycle.id)
|
|
db.query(ConfigSyncTask).filter(ConfigSyncTask.cycle_id == cid).delete(
|
|
synchronize_session=False
|
|
)
|
|
db.delete(cycle)
|
|
dropped += 1
|
|
if dropped:
|
|
db.commit()
|
|
return dropped
|
|
|
|
|
|
def _cycle_keep_value(row: ConfigSyncPolicy) -> int:
|
|
return max(0, min(200, int(getattr(row, "cycle_keep", None) or DEFAULT_CYCLE_KEEP)))
|
|
|
|
|
|
def _targets_from_json(raw: Any) -> list[ConfigSyncTargetRef]:
|
|
items: list[ConfigSyncTargetRef] = []
|
|
if not isinstance(raw, list):
|
|
return items
|
|
for x in raw:
|
|
if not isinstance(x, dict):
|
|
continue
|
|
src = str(x.get("source") or "").strip().lower()
|
|
tid = str(x.get("id") or "").strip()
|
|
if src not in ("managed", "ume") or not tid:
|
|
continue
|
|
items.append(ConfigSyncTargetRef(source=src, id=tid)) # type: ignore[arg-type]
|
|
return items
|
|
|
|
|
|
def policy_to_out(row: ConfigSyncPolicy) -> ConfigSyncPolicyOut:
|
|
return ConfigSyncPolicyOut(
|
|
enabled=bool(row.enabled),
|
|
interval_days=max(1, int(row.interval_days or 3)),
|
|
concurrency=max(1, min(32, int(row.concurrency or 5))),
|
|
scope_mode=str(row.scope_mode or "all"),
|
|
selected_targets=_targets_from_json(row.selected_targets),
|
|
history_keep=max(0, min(30, int(row.history_keep if row.history_keep is not None else 3))),
|
|
cycle_keep=_cycle_keep_value(row),
|
|
updated_at=row.updated_at,
|
|
)
|
|
|
|
|
|
|
|
def cycle_to_out(row: ConfigSyncCycle) -> ConfigSyncCycleOut:
|
|
return ConfigSyncCycleOut(
|
|
id=str(row.id),
|
|
trigger_mode=str(row.trigger_mode or ""),
|
|
status=str(row.status or ""),
|
|
concurrency=int(row.concurrency or 0),
|
|
planned_count=int(row.planned_count or 0),
|
|
success_count=int(row.success_count or 0),
|
|
fail_count=int(row.fail_count or 0),
|
|
skip_count=int(row.skip_count or 0),
|
|
error_message=str(row.error_message or ""),
|
|
started_at=row.started_at,
|
|
ended_at=row.ended_at,
|
|
created_at=row.created_at,
|
|
)
|
|
|
|
|
|
def task_to_out(row: ConfigSyncTask) -> ConfigSyncTaskOut:
|
|
return ConfigSyncTaskOut(
|
|
id=str(row.id),
|
|
cycle_id=str(row.cycle_id),
|
|
source=str(row.source),
|
|
target_id=str(row.target_id),
|
|
ne_name=str(row.ne_name or ""),
|
|
ne_ip=str(row.ne_ip or ""),
|
|
vendor=str(row.vendor or ""),
|
|
status=str(row.status or ""),
|
|
message=str(row.message or ""),
|
|
started_at=row.started_at,
|
|
ended_at=row.ended_at,
|
|
)
|
|
|
|
|