mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 04:20:45 +08:00
Decouple heavy CLI parse via ParsePool, keep ECMP/multi-RD keys, and expose per-command CLI lines vs DB rows with raw.txt export. Co-authored-by: Cursor <cursoragent@cursor.com>
160 lines
8.7 KiB
Python
160 lines
8.7 KiB
Python
"""Cutover / migration monitor ORM (separate from biz_state CompareJob)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from uuid import uuid4
|
|
|
|
from sqlalchemy import Boolean, DateTime, Index, Integer, String, Text
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from ..db import Base
|
|
from ..timeutil import utcnow_naive
|
|
from ._types import JsonType as _JsonType
|
|
|
|
|
|
class BizMigrationProject(Base):
|
|
"""Cutover project linking old/new portrait + HF collect tasks + baselines.
|
|
|
|
``old_task_id`` / ``new_task_id`` = portrait (biz-monitor) tasks — baseline source.
|
|
``old_hf_task_id`` / ``new_hf_task_id`` = cutover high-freq tasks — current source.
|
|
"""
|
|
|
|
__tablename__ = "biz_migration_project"
|
|
|
|
id: Mapped[str] = mapped_column(String(64), primary_key=True, default=lambda: uuid4().hex)
|
|
name: Mapped[str] = mapped_column(String(256), default="", index=True)
|
|
# Portrait / biz-monitor tasks (baseline batches come from these)
|
|
old_task_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
new_task_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
# Cutover high-freq tasks (current batches for evaluate)
|
|
old_hf_task_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
new_hf_task_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
old_baseline_batch_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
new_baseline_batch_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
# Reuse biz_port_mapping (before_if=old, after_if=new)
|
|
mapping_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
# BizMonitorTemplate — HOW (via compare template) + dual/status rules
|
|
monitor_template_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
# Project-level collect override (empty = use monitor template)
|
|
collect_metric_ids_json: Mapped[list] = mapped_column(_JsonType, default=list)
|
|
# Per-metric interval overrides: {"interface_brief": 60, "bgp_peer": 300}
|
|
metric_interval_sec_json: Mapped[dict] = mapped_column(_JsonType, default=dict)
|
|
# HF bindings (may be multiple tasks when intervals differ):
|
|
# [{"task_id":"...","metric_ids":["interface_brief"],"interval_sec":60}, ...]
|
|
old_hf_bindings_json: Mapped[list] = mapped_column(_JsonType, default=list)
|
|
new_hf_bindings_json: Mapped[list] = mapped_column(_JsonType, default=list)
|
|
# HF schedule window (project-level)
|
|
hf_interval_sec: Mapped[int] = mapped_column(Integer, default=60)
|
|
hf_start_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
hf_end_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
status: Mapped[str] = mapped_column(String(32), default="draft", index=True) # draft|active|done
|
|
note: Mapped[str] = mapped_column(String(512), default="")
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=utcnow_naive, index=True)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=utcnow_naive)
|
|
|
|
|
|
class BizMigrationBatch(Base):
|
|
"""One cutover night / wave with an expect set."""
|
|
|
|
__tablename__ = "biz_migration_batch"
|
|
|
|
id: Mapped[str] = mapped_column(String(64), primary_key=True, default=lambda: uuid4().hex)
|
|
project_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
batch_label: Mapped[str] = mapped_column(String(128), default="")
|
|
# pending | active | review | done
|
|
status: Mapped[str] = mapped_column(String(32), default="pending", index=True)
|
|
# {"ports": ["gei-..."], "items": [{"metric_id":"bgp_peer","sheet_id":"bgp_peer.vpnv4","key":"..."}]}
|
|
expect_set_json: Mapped[dict] = mapped_column(_JsonType, default=dict)
|
|
started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
ended_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
# Acceptance (set by finish_batch): none | passed | failed
|
|
accept_status: Mapped[str] = mapped_column(String(32), default="none", index=True)
|
|
accept_run_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
accept_summary_json: Mapped[dict] = mapped_column(_JsonType, default=dict)
|
|
note: Mapped[str] = mapped_column(String(512), default="")
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=utcnow_naive)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=utcnow_naive)
|
|
|
|
|
|
class BizMigrationRun(Base):
|
|
"""One user-triggered evaluation against baselines + current batches."""
|
|
|
|
__tablename__ = "biz_migration_run"
|
|
__table_args__ = (Index("ix_biz_migration_run_batch_created", "batch_id", "created_at"),)
|
|
|
|
id: Mapped[str] = mapped_column(String(64), primary_key=True, default=lambda: uuid4().hex)
|
|
project_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
batch_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
old_batch_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
new_batch_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
# manual | acceptance
|
|
purpose: Mapped[str] = mapped_column(String(32), default="manual", index=True)
|
|
status: Mapped[str] = mapped_column(String(32), default="success", index=True)
|
|
summary_json: Mapped[dict] = mapped_column(_JsonType, default=dict)
|
|
message: Mapped[str] = mapped_column(String(1024), default="")
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=utcnow_naive, index=True)
|
|
|
|
|
|
class BizMigrationDiff(Base):
|
|
"""Per-row / dual verdict row for a migration run (paged board detail)."""
|
|
|
|
__tablename__ = "biz_migration_diff"
|
|
__table_args__ = (
|
|
Index("ix_biz_migration_diff_run_metric", "run_id", "metric_id"),
|
|
Index("ix_biz_migration_diff_run_verdict", "run_id", "verdict"),
|
|
)
|
|
|
|
id: Mapped[str] = mapped_column(String(64), primary_key=True, default=lambda: uuid4().hex)
|
|
run_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
metric_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
seq: Mapped[int] = mapped_column(Integer, default=0)
|
|
# ok | expected | anomaly | migrating | migrated | lost | not_involved | unfinished
|
|
verdict: Mapped[str] = mapped_column(String(32), default="", index=True)
|
|
# green | yellow | red | gray
|
|
color: Mapped[str] = mapped_column(String(16), default="")
|
|
key_json: Mapped[dict] = mapped_column(_JsonType, default=dict)
|
|
old_kind: Mapped[str] = mapped_column(String(16), default="")
|
|
new_kind: Mapped[str] = mapped_column(String(16), default="")
|
|
old_json: Mapped[dict] = mapped_column(_JsonType, default=dict)
|
|
new_json: Mapped[dict] = mapped_column(_JsonType, default=dict)
|
|
in_expect: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
search_text: Mapped[str] = mapped_column(Text, default="")
|
|
|
|
|
|
class BizMigrationRedTicket(Base):
|
|
"""Persisted anomaly / unfinished expect items — survive across batches (带红继续)."""
|
|
|
|
__tablename__ = "biz_migration_red_ticket"
|
|
__table_args__ = (
|
|
Index("ix_biz_migration_red_project_status", "project_id", "status"),
|
|
Index("ix_biz_migration_red_batch", "batch_id"),
|
|
Index(
|
|
"ix_biz_migration_red_upsert",
|
|
"project_id",
|
|
"metric_id",
|
|
"match_key_str",
|
|
"status",
|
|
),
|
|
)
|
|
|
|
id: Mapped[str] = mapped_column(String(64), primary_key=True, default=lambda: uuid4().hex)
|
|
project_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
batch_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
run_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
metric_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
|
key_str: Mapped[str] = mapped_column(String(256), default="")
|
|
new_key_str: Mapped[str] = mapped_column(String(256), default="")
|
|
# Stable identity for upsert (match_old_key / normalized expect key)
|
|
match_key_str: Mapped[str] = mapped_column(String(256), default="", index=True)
|
|
verdict: Mapped[str] = mapped_column(String(32), default="")
|
|
color: Mapped[str] = mapped_column(String(16), default="red")
|
|
old_status: Mapped[str] = mapped_column(String(64), default="")
|
|
new_status: Mapped[str] = mapped_column(String(64), default="")
|
|
detail_json: Mapped[dict] = mapped_column(_JsonType, default=dict)
|
|
# open | carried | resolved
|
|
status: Mapped[str] = mapped_column(String(32), default="open", index=True)
|
|
carried_to_batch_id: Mapped[str] = mapped_column(String(64), default="")
|
|
note: Mapped[str] = mapped_column(String(512), default="")
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=utcnow_naive, index=True)
|
|
resolved_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|