115 lines
3.7 KiB
Python
115 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""同步 dev DB — 補齊 prod 有但 dev 沒有的表"""
|
|
import asyncio
|
|
import os
|
|
import sys
|
|
from sqlalchemy.ext.asyncio import create_async_engine
|
|
from sqlalchemy import text
|
|
|
|
DEV_URL = os.environ.get("DEV_DATABASE_URL")
|
|
if not DEV_URL:
|
|
print("ERROR: DEV_DATABASE_URL not set", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
MIGRATIONS = [
|
|
("auto_repair_executions", """
|
|
CREATE TABLE IF NOT EXISTS auto_repair_executions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
incident_id UUID,
|
|
playbook_name TEXT,
|
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
started_at TIMESTAMPTZ,
|
|
finished_at TIMESTAMPTZ,
|
|
result JSONB,
|
|
error_message TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
)
|
|
"""),
|
|
("alert_operation_log", """
|
|
CREATE TABLE IF NOT EXISTS alert_operation_log (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
event_type TEXT NOT NULL,
|
|
incident_id UUID,
|
|
approval_id UUID,
|
|
actor TEXT,
|
|
action_detail TEXT,
|
|
success BOOLEAN DEFAULT true,
|
|
context JSONB DEFAULT '{}',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
)
|
|
"""),
|
|
("playbooks", """
|
|
CREATE TABLE IF NOT EXISTS playbooks (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name TEXT NOT NULL,
|
|
description TEXT,
|
|
steps JSONB NOT NULL DEFAULT '[]',
|
|
tags TEXT[] DEFAULT '{}',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
)
|
|
"""),
|
|
("drift_reports", """
|
|
CREATE TABLE IF NOT EXISTS drift_reports (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
host TEXT NOT NULL,
|
|
report_type TEXT NOT NULL DEFAULT 'config',
|
|
items JSONB NOT NULL DEFAULT '[]',
|
|
summary TEXT,
|
|
severity TEXT DEFAULT 'low',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
)
|
|
"""),
|
|
("pr_reviews", """
|
|
CREATE TABLE IF NOT EXISTS pr_reviews (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
repo TEXT NOT NULL,
|
|
pr_id TEXT NOT NULL,
|
|
review_text TEXT,
|
|
model TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
)
|
|
"""),
|
|
("vector_extension", "CREATE EXTENSION IF NOT EXISTS vector"),
|
|
("rag_chunks", """
|
|
CREATE TABLE IF NOT EXISTS rag_chunks (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
source TEXT NOT NULL,
|
|
source_id TEXT NOT NULL,
|
|
title TEXT,
|
|
chunk_text TEXT NOT NULL,
|
|
embedding vector(768),
|
|
metadata JSONB DEFAULT '{}',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
)
|
|
"""),
|
|
]
|
|
|
|
|
|
async def main():
|
|
engine = create_async_engine(DEV_URL, echo=False)
|
|
async with engine.begin() as conn:
|
|
r = await conn.execute(text(
|
|
"SELECT table_name FROM information_schema.tables WHERE table_schema='public' ORDER BY table_name"
|
|
))
|
|
existing = {row[0] for row in r}
|
|
print(f"dev 現有: {sorted(existing)}")
|
|
|
|
for name, sql in MIGRATIONS:
|
|
try:
|
|
await conn.execute(text(sql))
|
|
print(f" ✓ {name}")
|
|
except Exception as e:
|
|
print(f" ⚠ {name}: {e}")
|
|
|
|
r2 = await conn.execute(text(
|
|
"SELECT table_name FROM information_schema.tables WHERE table_schema='public' ORDER BY table_name"
|
|
))
|
|
final = [row[0] for row in r2]
|
|
print(f"\ndev 最終: {final}")
|
|
|
|
await engine.dispose()
|
|
|
|
|
|
asyncio.run(main())
|