guardia-itsm/database.py
DESKTOP-TKLFCPRython 64c27c3509 feat(itsm): G-1~G-12 확장 기능 + 하네스/봇/설치스크립트 구현
G-1: 메신저 Webhook Relay + _send_to_room 실제 httpx 호출 구현
G-2: POST /api/tasks/bulk SR 대량작업 엔드포인트 (최대 100건)
G-3: 라이선스 만료 알림 스케줄러 (매일 09:00 KST)
G-4: 체험판 upgrade_banner 필드 + license.py 배너 로직
G-5: core/auto_rca.py + incidents/problem auto-rca 엔드포인트
G-6: core/deploy_impact.py + vibe impact-analysis 엔드포인트
G-7: core/ticket_classifier.py + SR 생성 시 AI 분류 + ai-suggestion API
G-8: VulnPatchRecord 모델 + vuln_scan 패치추적 4개 엔드포인트
G-9: core/jira_sync.py + gateway Jira/Confluence 연동 엔드포인트
G-10: core/push_notify.py + routers/push.py + PushSubscription 모델
G-11: approvals 다중승인 (위임/서명/기한초과/마감연장)
G-12: alembic.ini + migrations/ + cicd/migrate_to_postgres.sh

하네스: guardia-orchestrator 확장기능 Phase 반영
봇명령어: /sr /status /license /bulk 슬래시 명령어 추가
설치스크립트: setup/ (Ubuntu, CentOS, RHEL, Windows) --test 옵션 포함

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:18:52 +09:00

93 lines
3.5 KiB
Python

"""
GUARDiA ITSM — 데이터베이스 엔진 설정.
환경변수 DATABASE_URL 로 DB를 자동 선택한다:
- 미설정(기본): SQLite + aiosqlite (개발/단독 실행)
- postgresql+asyncpg://user:pass@host:5432/db: PostgreSQL (운영)
PostgreSQL 사용 시 asyncpg, alembic 패키지가 필요하다:
pip install asyncpg alembic
마이그레이션:
alembic init migrations
alembic revision --autogenerate -m "initial_schema"
alembic upgrade head
"""
from __future__ import annotations
import logging
import os
from sqlalchemy.ext.asyncio import (
AsyncSession,
async_sessionmaker,
create_async_engine,
)
from sqlalchemy.orm import DeclarativeBase
logger = logging.getLogger(__name__)
# ── 환경변수 기반 DB URL 자동 선택 ───────────────────────────────────────────
DATABASE_URL: str = os.getenv(
"DATABASE_URL",
"sqlite+aiosqlite:///./guardia_itsm.db", # 기본: SQLite (개발)
)
# URL 정규화: postgres:// → postgresql+asyncpg:// (Heroku/Gitpod 호환)
if DATABASE_URL.startswith("postgres://"):
DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql+asyncpg://", 1)
_is_postgres = DATABASE_URL.startswith("postgresql")
# ── 엔진 생성 ────────────────────────────────────────────────────────────────
_engine_kwargs: dict = {
"echo": os.getenv("DB_ECHO", "false").lower() == "true",
"pool_pre_ping": True,
}
if _is_postgres:
# PostgreSQL: MVCC 기반 연결 풀링
_engine_kwargs["pool_size"] = int(os.getenv("DB_POOL_SIZE", "10"))
_engine_kwargs["max_overflow"] = int(os.getenv("DB_MAX_OVERFLOW", "20"))
logger.info("GUARDiA DB: PostgreSQL 모드 (pool_size=%s)", _engine_kwargs["pool_size"])
else:
# SQLite: 파일 잠금 방식, 오버플로 불가
_engine_kwargs["connect_args"] = {"check_same_thread": False}
logger.info("GUARDiA DB: SQLite 모드")
engine = create_async_engine(DATABASE_URL, **_engine_kwargs)
SessionLocal = async_sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False,
)
# ── Base ─────────────────────────────────────────────────────────────────────
class Base(DeclarativeBase):
pass
# ── 의존성 주입 ───────────────────────────────────────────────────────────────
async def get_db():
"""FastAPI Depends용 — DB 세션 제공 후 자동 정리."""
async with SessionLocal() as session:
yield session
# ── 테이블 초기화 ─────────────────────────────────────────────────────────────
async def init_db() -> None:
"""
개발 환경에서 테이블 자동 생성.
운영(PostgreSQL)에서는 Alembic migration을 사용하므로
create_all은 이미 존재하는 테이블을 건드리지 않는다.
"""
from models import Base as ModelBase # noqa: F401 — 모델 등록용 임포트
async with engine.begin() as conn:
await conn.run_sync(ModelBase.metadata.create_all)
logger.info("DB 테이블 초기화 완료")