mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 23:20:51 +08:00
Add cutover migration monitor and day-based batch retention.
Protect baselines and compare/migration-referenced batches from purge or delete, and let operators mark baselines and clean high-freq data manually. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
c7539e379d
commit
8631f58113
23 changed files with 3837 additions and 91 deletions
|
|
@ -42,6 +42,13 @@ from .biz_state import (
|
|||
BizStateTaskItem,
|
||||
BizStateTaskItemBinding,
|
||||
)
|
||||
from .biz_migration import (
|
||||
BizMigrationBatch,
|
||||
BizMigrationDiff,
|
||||
BizMigrationProject,
|
||||
BizMigrationRedTicket,
|
||||
BizMigrationRun,
|
||||
)
|
||||
from .port_traffic import (
|
||||
PortTrafficBoard,
|
||||
PortTrafficDevice,
|
||||
|
|
@ -146,4 +153,9 @@ __all__ = [
|
|||
"BizCompareJob",
|
||||
"BizCompareRun",
|
||||
"BizCompareDiff",
|
||||
"BizMigrationProject",
|
||||
"BizMigrationBatch",
|
||||
"BizMigrationRun",
|
||||
"BizMigrationDiff",
|
||||
"BizMigrationRedTicket",
|
||||
]
|
||||
|
|
|
|||
129
netx_api/models/biz_migration.py
Normal file
129
netx_api/models/biz_migration.py
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
"""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 collect tasks + baselines."""
|
||||
|
||||
__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)
|
||||
old_task_id: Mapped[str] = mapped_column(String(64), default="", index=True)
|
||||
new_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)
|
||||
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","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"),
|
||||
)
|
||||
|
||||
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="")
|
||||
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)
|
||||
|
|
@ -14,10 +14,13 @@ from ._types import JsonType as _JsonType
|
|||
|
||||
|
||||
class BizStateTask(Base):
|
||||
"""Per-NE business state monitoring config."""
|
||||
"""Per-NE business state monitoring config.
|
||||
|
||||
Multiple tasks per ``(source, ne_id)`` are allowed (e.g. hourly full +
|
||||
cutover high-freq port-only).
|
||||
"""
|
||||
|
||||
__tablename__ = "biz_state_task"
|
||||
__table_args__ = (UniqueConstraint("source", "ne_id", name="uq_biz_state_task_ne"),)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(64), primary_key=True, default=lambda: uuid4().hex)
|
||||
source: Mapped[str] = mapped_column(String(32), default="managed", index=True)
|
||||
|
|
@ -29,6 +32,12 @@ class BizStateTask(Base):
|
|||
note: Mapped[str] = mapped_column(String(256), default="")
|
||||
status: Mapped[str] = mapped_column(String(32), default="draft", index=True) # draft|running|paused|stopped
|
||||
interval_sec: Mapped[int] = mapped_column(Integer, default=300)
|
||||
# Keep snapshots for N calendar days (protected baselines/refs never auto-deleted)
|
||||
retention_days: Mapped[int] = mapped_column(Integer, default=30)
|
||||
# Optional: keep only N batches per past calendar day (purge extras next day). Default off.
|
||||
daily_keep_enabled: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
daily_keep_count: Mapped[int] = mapped_column(Integer, default=10)
|
||||
# Legacy column kept for brownfield reads; unused by new purge path
|
||||
retention_batches: Mapped[int] = mapped_column(Integer, default=30)
|
||||
collect_running: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
last_collect_started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
|
|
@ -83,6 +92,9 @@ class BizStateBatch(Base):
|
|||
message: Mapped[str] = mapped_column(String(1024), default="")
|
||||
started_at: Mapped[datetime] = mapped_column(DateTime, default=utcnow_naive, index=True)
|
||||
ended_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
# Manual pin: excluded from auto-purge until revoked
|
||||
is_baseline: Mapped[bool] = mapped_column(Boolean, default=False, index=True)
|
||||
baseline_marked_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
|
||||
|
||||
class BizStateBatchCommand(Base):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue