netx/netx_api/ume_token_router.py
oliver 6dc3946bc6 Split UME routes and managed-NE service by domain.
Keep thin facades for existing imports, tighten CSV import required columns, and restore Chinese WebCRT connection labels in status responses.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-02 17:03:42 +08:00

164 lines
4.9 KiB
Python

"""UME token + alarm subscription routes."""
from __future__ import annotations
import logging
from datetime import datetime, timezone
from typing import Any
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import or_
from sqlalchemy.orm import Session
from .config import settings
from .db import get_db
from .key_alert_config import (
get_key_alert_monitor_config,
invalidate_key_alert_config_cache,
set_key_alert_monitor_config,
)
from .key_alert_matcher import (
invalidate_key_alert_rule_cache,
normalize_match_type,
parse_rule_ne_types_payload,
rule_match_type,
rule_match_value,
rule_ne_types,
rule_storage_key,
serialize_rule_ne_types,
)
from .models import (
UmeAlarmCurrent,
UmeAlarmHistory,
UmeInventoryNE,
UmeKeyAlertForwardLog,
UmeKeyAlertRule,
UmeSyncJob,
)
from .oclaw_alarm_forwarder import (
forwarder_status,
request_forwarder_reconnect,
)
from .ume_alarm_ws import (
cancel_alarm_subscription_manual,
clear_local_alarm_subscription_manual,
establish_alarm_subscription_manual,
get_alarms_coordination_status,
get_subscription_status,
get_ws_connection_status,
get_ws_logs,
request_ws_reconnect,
)
from .ume_support import (
UME_KNOWN_RUNTIME_TASKS,
_aggregate_rows,
_ensure_utc,
_list_runtime_tasks,
_request_force_sync_after_resume,
_runtime_pause_task,
_runtime_resume_task,
_ume_alarm_host_name,
_ume_alarm_ne_group_key,
_ume_client,
_ume_error_kind,
_clear_force_resume_hints,
)
from .ume_sync_service import sync_alarms_current, sync_alarms_history_full, sync_inventory_full
from .ume_token_store import clear_shared_token
_log = logging.getLogger("netx.ume.router")
router = APIRouter(tags=["ume"])
@router.get("/v1/ume/token/status")
def ume_token_status() -> dict[str, Any]:
client = _ume_client()
st = client.token_status()
return {"ok": True, **st}
@router.post("/v1/ume/token/refresh")
def ume_token_refresh() -> dict[str, Any]:
client = _ume_client()
try:
before = client.token_status()
token = client.refresh_if_needed()
after = client.token_status()
return {
"ok": True,
"token": token,
"changed": bool(before.get("token_preview") != after.get("token_preview")),
**after,
}
except Exception as exc:
msg = str(exc)[:240]
return {"ok": False, "error_kind": _ume_error_kind(msg), "error": msg}
@router.post("/v1/ume/token/disconnect")
def ume_token_disconnect() -> dict[str, Any]:
client = _ume_client()
ok = bool(client.logout_token())
st = client.token_status()
return {"ok": ok, **st}
@router.get("/v1/ume/alarm-subscription/status")
def ume_alarm_subscription_status(limit: int = 80) -> dict[str, Any]:
st = get_subscription_status()
ws_task = _UME_RUNTIME_TASKS.get("alarms_current_ws_consumer") or {}
log_limit = max(10, min(int(limit or 80), 100))
return {
"ok": True,
**st,
**get_alarms_coordination_status(),
"ws_connection": get_ws_connection_status(),
"ws_consumer_status": str(ws_task.get("status") or ""),
"ws_consumer_last_error": str(ws_task.get("last_error") or ""),
"ws_consumer_last_run_at": ws_task.get("last_run_at"),
"ws_logs": get_ws_logs(limit=log_limit),
}
@router.post("/v1/ume/alarm-subscription/establish")
def ume_alarm_subscription_establish(
payload: dict[str, Any] | None = None,
db: Session = Depends(get_db),
) -> dict[str, Any]:
client = _ume_client()
body = payload or {}
force_reestablish = bool(body.get("force_reestablish"))
try:
st = establish_alarm_subscription_manual(client, db, force_reestablish=force_reestablish)
return {"ok": True, "created": not bool(st.get("already_exists")), **st}
except Exception as exc:
msg = str(exc)[:240]
raise HTTPException(status_code=502, detail=msg) from exc
@router.post("/v1/ume/alarm-subscription/cancel")
def ume_alarm_subscription_cancel(
payload: dict[str, Any] | None = None,
db: Session = Depends(get_db),
) -> dict[str, Any]:
client = _ume_client()
body = payload or {}
force_clear_local = bool(body.get("force_clear_local"))
try:
st = cancel_alarm_subscription_manual(client, db, force_clear_local=force_clear_local)
if st.get("needs_local_cleanup"):
return st
return {"ok": True, **st}
except Exception as exc:
msg = str(exc)[:240]
raise HTTPException(status_code=502, detail=msg) from exc
@router.post("/v1/ume/alarm-subscription/clear-local")
def ume_alarm_subscription_clear_local(db: Session = Depends(get_db)) -> dict[str, Any]:
try:
st = clear_local_alarm_subscription_manual(db)
return {"ok": True, "cleared_local": True, **st}
except Exception as exc:
msg = str(exc)[:240]
raise HTTPException(status_code=502, detail=msg) from exc