mirror of
https://github.com/hansjone/netx.git
synced 2026-10-11 12:53:17 +08:00
Remove UME equipment-holder table; inventory is NE-only
Drop ume_inventory_equipment_holder on startup; remove ORM model and sync/reconcile paths. Sync status API/UI no longer expose deleted_inventory_holders. Nested holder data remains in ne raw_json if UME returns it. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a025245c8f
commit
ac1f573508
5 changed files with 5 additions and 69 deletions
|
|
@ -277,6 +277,8 @@ def on_startup() -> None:
|
||||||
# Safe for Postgres (IF NOT EXISTS); ignored on failure.
|
# Safe for Postgres (IF NOT EXISTS); ignored on failure.
|
||||||
try:
|
try:
|
||||||
with engine.begin() as conn:
|
with engine.begin() as conn:
|
||||||
|
# Removed from ORM: drop legacy holder table if present (was optional nested UME data).
|
||||||
|
conn.exec_driver_sql("DROP TABLE IF EXISTS ume_inventory_equipment_holder")
|
||||||
conn.exec_driver_sql("ALTER TABLE alarms_norm ADD COLUMN IF NOT EXISTS relevancy VARCHAR(128) DEFAULT ''")
|
conn.exec_driver_sql("ALTER TABLE alarms_norm ADD COLUMN IF NOT EXISTS relevancy VARCHAR(128) DEFAULT ''")
|
||||||
conn.exec_driver_sql("ALTER TABLE alarms_norm ADD COLUMN IF NOT EXISTS l3vpn_peer_ne VARCHAR(256) DEFAULT ''")
|
conn.exec_driver_sql("ALTER TABLE alarms_norm ADD COLUMN IF NOT EXISTS l3vpn_peer_ne VARCHAR(256) DEFAULT ''")
|
||||||
conn.exec_driver_sql("ALTER TABLE alarms_norm ADD COLUMN IF NOT EXISTS service VARCHAR(256) DEFAULT ''")
|
conn.exec_driver_sql("ALTER TABLE alarms_norm ADD COLUMN IF NOT EXISTS service VARCHAR(256) DEFAULT ''")
|
||||||
|
|
@ -498,7 +500,7 @@ def ume_sync(payload: dict[str, Any] | None = None, db: Session = Depends(get_db
|
||||||
|
|
||||||
def _ume_sync_job_details_counts(row: UmeSyncJob) -> dict[str, int]:
|
def _ume_sync_job_details_counts(row: UmeSyncJob) -> dict[str, int]:
|
||||||
"""Parse ``details_json`` from sync jobs (inventory / alarms) for delete-reconcile stats."""
|
"""Parse ``details_json`` from sync jobs (inventory / alarms) for delete-reconcile stats."""
|
||||||
out = {"deleted_inventory_ne": 0, "deleted_inventory_holders": 0, "deleted_current_alarms": 0}
|
out = {"deleted_inventory_ne": 0, "deleted_current_alarms": 0}
|
||||||
raw = str(getattr(row, "details_json", "") or "").strip()
|
raw = str(getattr(row, "details_json", "") or "").strip()
|
||||||
if not raw:
|
if not raw:
|
||||||
return out
|
return out
|
||||||
|
|
@ -512,10 +514,6 @@ def _ume_sync_job_details_counts(row: UmeSyncJob) -> dict[str, int]:
|
||||||
out["deleted_inventory_ne"] = max(0, int(obj.get("deleted_inventory_ne") or 0))
|
out["deleted_inventory_ne"] = max(0, int(obj.get("deleted_inventory_ne") or 0))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
try:
|
|
||||||
out["deleted_inventory_holders"] = max(0, int(obj.get("deleted_inventory_holders") or 0))
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
try:
|
try:
|
||||||
out["deleted_current_alarms"] = max(0, int(obj.get("deleted_stale_current_alarms") or 0))
|
out["deleted_current_alarms"] = max(0, int(obj.get("deleted_stale_current_alarms") or 0))
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -550,7 +548,6 @@ def ume_sync_status(
|
||||||
"inserted_count": int(r.inserted_count or 0),
|
"inserted_count": int(r.inserted_count or 0),
|
||||||
"updated_count": int(r.updated_count or 0),
|
"updated_count": int(r.updated_count or 0),
|
||||||
"deleted_inventory_ne": int(del_counts["deleted_inventory_ne"]),
|
"deleted_inventory_ne": int(del_counts["deleted_inventory_ne"]),
|
||||||
"deleted_inventory_holders": int(del_counts["deleted_inventory_holders"]),
|
|
||||||
"deleted_current_alarms": int(del_counts["deleted_current_alarms"]),
|
"deleted_current_alarms": int(del_counts["deleted_current_alarms"]),
|
||||||
"error_message": str(r.error_message or ""),
|
"error_message": str(r.error_message or ""),
|
||||||
"started_at": (_ensure_utc(r.started_at) or datetime.now(timezone.utc)).isoformat(),
|
"started_at": (_ensure_utc(r.started_at) or datetime.now(timezone.utc)).isoformat(),
|
||||||
|
|
|
||||||
|
|
@ -163,19 +163,6 @@ class UmeInventoryNE(Base):
|
||||||
raw_json: Mapped[str] = mapped_column(Text, default="{}")
|
raw_json: Mapped[str] = mapped_column(Text, default="{}")
|
||||||
|
|
||||||
|
|
||||||
class UmeInventoryEquipmentHolder(Base):
|
|
||||||
__tablename__ = "ume_inventory_equipment_holder"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
||||||
ne_id: Mapped[str] = mapped_column(ForeignKey("ume_inventory_ne.ne_id"), index=True)
|
|
||||||
holder_name: Mapped[str] = mapped_column(String(256), index=True, default="")
|
|
||||||
holder_type: Mapped[str] = mapped_column(String(128), default="")
|
|
||||||
holder_state: Mapped[str] = mapped_column(String(128), default="")
|
|
||||||
first_seen_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
||||||
last_seen_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, index=True)
|
|
||||||
raw_json: Mapped[str] = mapped_column(Text, default="{}")
|
|
||||||
|
|
||||||
|
|
||||||
class UmeAlarmCurrent(Base):
|
class UmeAlarmCurrent(Base):
|
||||||
__tablename__ = "ume_alarms_current"
|
__tablename__ = "ume_alarms_current"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ from .models import (
|
||||||
UmeAlarmBatch,
|
UmeAlarmBatch,
|
||||||
UmeAlarmCurrent,
|
UmeAlarmCurrent,
|
||||||
UmeAlarmHistory,
|
UmeAlarmHistory,
|
||||||
UmeInventoryEquipmentHolder,
|
|
||||||
UmeInventoryNE,
|
UmeInventoryNE,
|
||||||
UmeSyncJob,
|
UmeSyncJob,
|
||||||
)
|
)
|
||||||
|
|
@ -226,65 +225,21 @@ def sync_inventory_full(db: Session, client: UMEClient, *, trigger_mode: str = "
|
||||||
existing.last_seen_at = now
|
existing.last_seen_at = now
|
||||||
existing.raw_json = json.dumps(row, ensure_ascii=False, default=str)
|
existing.raw_json = json.dumps(row, ensure_ascii=False, default=str)
|
||||||
|
|
||||||
# Optional: holders may not exist in current UME deployment; keep best-effort.
|
|
||||||
# This pass keeps schema warm for later detailed holder endpoint integration.
|
|
||||||
holder_payload: list[dict[str, Any]] = []
|
|
||||||
for ne in ne_rows:
|
|
||||||
holders = _pick(ne, "equipment-holder", "equipment-holders")
|
|
||||||
if isinstance(holders, list):
|
|
||||||
for h in holders:
|
|
||||||
if isinstance(h, dict):
|
|
||||||
h2 = dict(h)
|
|
||||||
if "ne-id" not in h2:
|
|
||||||
h2["ne-id"] = _pick(ne, "ne-id", "ne_id", "id")
|
|
||||||
holder_payload.append(h2)
|
|
||||||
for h in holder_payload:
|
|
||||||
ne_id = _s(_pick(h, "ne-id", "ne_id"))
|
|
||||||
holder_name = _s(_pick(h, "name", "holder-name"))
|
|
||||||
if not ne_id or not holder_name:
|
|
||||||
continue
|
|
||||||
existing_holder = (
|
|
||||||
db.query(UmeInventoryEquipmentHolder)
|
|
||||||
.filter(
|
|
||||||
UmeInventoryEquipmentHolder.ne_id == ne_id,
|
|
||||||
UmeInventoryEquipmentHolder.holder_name == holder_name,
|
|
||||||
)
|
|
||||||
.one_or_none()
|
|
||||||
)
|
|
||||||
if existing_holder is None:
|
|
||||||
existing_holder = UmeInventoryEquipmentHolder(
|
|
||||||
ne_id=ne_id,
|
|
||||||
holder_name=holder_name,
|
|
||||||
first_seen_at=now,
|
|
||||||
)
|
|
||||||
db.add(existing_holder)
|
|
||||||
existing_holder.holder_type = _s(_pick(h, "type", "holder-type"))
|
|
||||||
existing_holder.holder_state = _s(_pick(h, "state", "holder-state"))
|
|
||||||
existing_holder.last_seen_at = now
|
|
||||||
existing_holder.raw_json = json.dumps(h, ensure_ascii=False, default=str)
|
|
||||||
|
|
||||||
db.flush()
|
db.flush()
|
||||||
deleted_holders = deleted_ne = 0
|
deleted_ne = 0
|
||||||
if _snapshot_reconcile_ok(inv_meta):
|
if _snapshot_reconcile_ok(inv_meta):
|
||||||
if seen_ne_ids:
|
if seen_ne_ids:
|
||||||
deleted_holders = int(
|
|
||||||
db.query(UmeInventoryEquipmentHolder)
|
|
||||||
.filter(~UmeInventoryEquipmentHolder.ne_id.in_(list(seen_ne_ids)))
|
|
||||||
.delete(synchronize_session=False)
|
|
||||||
)
|
|
||||||
deleted_ne = int(
|
deleted_ne = int(
|
||||||
db.query(UmeInventoryNE)
|
db.query(UmeInventoryNE)
|
||||||
.filter(~UmeInventoryNE.ne_id.in_(list(seen_ne_ids)))
|
.filter(~UmeInventoryNE.ne_id.in_(list(seen_ne_ids)))
|
||||||
.delete(synchronize_session=False)
|
.delete(synchronize_session=False)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
deleted_holders = int(db.query(UmeInventoryEquipmentHolder).delete(synchronize_session=False))
|
|
||||||
deleted_ne = int(db.query(UmeInventoryNE).delete(synchronize_session=False))
|
deleted_ne = int(db.query(UmeInventoryNE).delete(synchronize_session=False))
|
||||||
|
|
||||||
job.details_json = json.dumps(
|
job.details_json = json.dumps(
|
||||||
{
|
{
|
||||||
"inventory_reconcile": _snapshot_reconcile_ok(inv_meta),
|
"inventory_reconcile": _snapshot_reconcile_ok(inv_meta),
|
||||||
"deleted_inventory_holders": deleted_holders,
|
|
||||||
"deleted_inventory_ne": deleted_ne,
|
"deleted_inventory_ne": deleted_ne,
|
||||||
"paging": {
|
"paging": {
|
||||||
"is_end_of_reply": bool(inv_meta.get("is_end_of_reply")),
|
"is_end_of_reply": bool(inv_meta.get("is_end_of_reply")),
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,6 @@ export function UmePage() {
|
||||||
<th>inserted</th>
|
<th>inserted</th>
|
||||||
<th>updated</th>
|
<th>updated</th>
|
||||||
<th title="对账删除的网元行(仅 inventory 全量成功时)">删网元</th>
|
<th title="对账删除的网元行(仅 inventory 全量成功时)">删网元</th>
|
||||||
<th title="对账删除的机框行">删机框</th>
|
|
||||||
<th title="对账删除的当前告警行(仅 alarms_current 全量成功时)">删当前告警</th>
|
<th title="对账删除的当前告警行(仅 alarms_current 全量成功时)">删当前告警</th>
|
||||||
<th>started_at</th>
|
<th>started_at</th>
|
||||||
<th>ended_at</th>
|
<th>ended_at</th>
|
||||||
|
|
@ -259,7 +258,6 @@ export function UmePage() {
|
||||||
<td>{x.inserted_count}</td>
|
<td>{x.inserted_count}</td>
|
||||||
<td>{x.updated_count}</td>
|
<td>{x.updated_count}</td>
|
||||||
<td>{Number(x.deleted_inventory_ne ?? 0)}</td>
|
<td>{Number(x.deleted_inventory_ne ?? 0)}</td>
|
||||||
<td>{Number(x.deleted_inventory_holders ?? 0)}</td>
|
|
||||||
<td>{Number(x.deleted_current_alarms ?? 0)}</td>
|
<td>{Number(x.deleted_current_alarms ?? 0)}</td>
|
||||||
<td>{formatSystemTime(x.started_at)}</td>
|
<td>{formatSystemTime(x.started_at)}</td>
|
||||||
<td>{x.ended_at ? formatSystemTime(x.ended_at) : "-"}</td>
|
<td>{x.ended_at ? formatSystemTime(x.ended_at) : "-"}</td>
|
||||||
|
|
@ -268,7 +266,7 @@ export function UmePage() {
|
||||||
))}
|
))}
|
||||||
{!syncStatusQuery.isLoading && (syncStatusQuery.data?.items || []).length === 0 && (
|
{!syncStatusQuery.isLoading && (syncStatusQuery.data?.items || []).length === 0 && (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={12}>暂无同步记录</td>
|
<td colSpan={11}>暂无同步记录</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,6 @@ export type UmeSyncJobItem = {
|
||||||
updated_count: number;
|
updated_count: number;
|
||||||
/** Reconcile deletes after full inventory snapshot (netx ume_sync_service). */
|
/** Reconcile deletes after full inventory snapshot (netx ume_sync_service). */
|
||||||
deleted_inventory_ne?: number;
|
deleted_inventory_ne?: number;
|
||||||
deleted_inventory_holders?: number;
|
|
||||||
/** Reconcile deletes for current alarms after full snapshot. */
|
/** Reconcile deletes for current alarms after full snapshot. */
|
||||||
deleted_current_alarms?: number;
|
deleted_current_alarms?: number;
|
||||||
error_message?: string;
|
error_message?: string;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue