guardia-itsm/.claude/skills/dr-automation/SKILL.md

5.4 KiB

name description
dr-automation GUARDiA DR(재해복구) 자동화 구현 스킬. DR 시나리오 관리, Failover 실행, 백업 무결성 검증, 복구 테스트, RTO/RPO 추적 기능을 FastAPI + paramiko 패턴으로 구현한다. 다음 상황에서 반드시 사용: (1) 'DR 구현', '재해복구', 'Failover', 'RTO/RPO' 관련 요청; (2) dr.py 라우터 또는 core/dr_engine.py 작업; (3) 백업 무결성 검증, 복구 테스트 구현; (4) DR 대시보드 구현; (5) 다시 실행, 업데이트, 보완 요청. paramiko SSH 패턴과 SQLAlchemy async 패턴을 따른다.

DR 자동화 구현 스킬

구현 대상 파일

  • itsm/core/dr_engine.py — DR 비즈니스 로직
  • itsm/routers/dr.py — FastAPI 라우터

핵심 구현 원칙

  1. Fail-Safe 시퀀스: 스냅샷 → 대기서버 활성화 → 서비스 전환 → 헬스체크 → 롤백(실패 시)
  2. 자격증명 보호: paramiko 접속 시 IP/계정 노출 금지, AES 복호화 후 메모리만 사용
  3. 비동기: asyncio.create_subprocess_exec + paramiko를 run_in_executor로 래핑
  4. 감사 기록: 모든 DR 작업은 tb_audit_log에 기록

DB 모델 (models.py에 추가)

class DRScenario(Base):
    __tablename__ = "tb_dr_scenario"
    id               = Column(Integer, primary_key=True)
    name             = Column(String(100), nullable=False)
    scenario_type    = Column(String(30))   # SITE_FAILURE | SERVER_FAILURE | DATA_CORRUPTION
    primary_server_id = Column(Integer, ForeignKey("tb_server_info.id"))
    standby_server_id = Column(Integer, ForeignKey("tb_server_info.id"))
    rto_minutes      = Column(Integer)      # 목표 RTO (분)
    rpo_minutes      = Column(Integer)      # 목표 RPO (분)
    failover_steps   = Column(JSON)         # 페일오버 실행 단계 목록
    healthcheck_url  = Column(String(255))
    last_test_at     = Column(DateTime)
    last_test_result = Column(String(20))   # PASS | FAIL | PARTIAL
    is_active        = Column(Boolean, default=True)
    created_at       = Column(DateTime, default=func.now())

class DRTest(Base):
    __tablename__ = "tb_dr_test"
    id              = Column(Integer, primary_key=True)
    scenario_id     = Column(Integer, ForeignKey("tb_dr_scenario.id"))
    test_type       = Column(String(20))    # BACKUP_VERIFY | FAILOVER_SIM | RECOVERY
    status          = Column(String(20))    # RUNNING | PASS | FAIL | PARTIAL
    rto_actual      = Column(Integer)       # 실제 RTO (분)
    rpo_actual      = Column(Integer)       # 실제 RPO (분)
    result_detail   = Column(JSON)          # 단계별 결과
    started_at      = Column(DateTime, default=func.now())
    completed_at    = Column(DateTime)
    triggered_by    = Column(String(100))

core/dr_engine.py 구현 패턴

import asyncio, hashlib, time
from datetime import datetime
from typing import Optional
import paramiko
from sqlalchemy.ext.asyncio import AsyncSession

from core.ssh_exec import _get_server_credentials  # 기존 AES 복호화 함수 재사용
from models import DRScenario, DRTest, Server

class DREngine:
    async def verify_backup(self, db: AsyncSession, server_name: str) -> dict:
        """백업 파일 무결성 검증 (SHA-256 체크)."""
        # 1. 서버 정보 조회 (ip_addr, ssh_user, os_pw_enc)
        # 2. AES 복호화로 자격증명 획득
        # 3. paramiko SSH 접속
        # 4. backup_path 하위 최신 파일 SHA-256 계산
        # 5. 결과 반환 (파일명, 크기, 해시, 경로 미노출)
        ...

    async def run_recovery_test(self, db: AsyncSession, scenario_id: int,
                                 triggered_by: str) -> DRTest:
        """복구 테스트 실행."""
        # 1. 시나리오 조회
        # 2. DRTest 레코드 생성 (status=RUNNING)
        # 3. failover_steps 순서대로 SSH 명령 실행
        # 4. 각 단계 결과 result_detail에 누적
        # 5. healthcheck_url 응답 확인
        # 6. RTO 계산 (started_at ~ 헬스체크 성공)
        # 7. DRTest status 업데이트 (PASS/FAIL/PARTIAL)
        ...

    def calculate_rto_rpo(self, tests: list[DRTest]) -> dict:
        """최근 5회 테스트 기반 RTO/RPO 통계."""
        ...

routers/dr.py 엔드포인트 구조

GET  /api/dr/scenarios              목록 (ENGINEER 이상)
POST /api/dr/scenarios              등록 (ADMIN 전용)
GET  /api/dr/scenarios/{id}         상세
PUT  /api/dr/scenarios/{id}         수정 (ADMIN 전용)
POST /api/dr/test                   복구 테스트 실행 (ENGINEER 이상)
GET  /api/dr/test/{id}              테스트 결과 조회
GET  /api/dr/tests                  테스트 이력 목록
POST /api/dr/backup-verify          백업 무결성 검증 (ENGINEER 이상)
POST /api/dr/failover/{scenario_id} Failover 실행 (ADMIN 전용, 승인 필요)
GET  /api/dr/rto-rpo                RTO/RPO 현황 대시보드
GET  /api/dr/dashboard              DR 전체 현황

보안 규칙

  • Failover 실행은 require_admin_role 의존성 필수
  • 백업 검증은 ENGINEER 이상 허용
  • 서버 IP/경로를 API 응답 body에 포함하지 않는다
  • SSH 자격증명은 core/ssh_exec.py의 기존 AES 복호화 함수 재사용

헬스체크 URL 검증 방법

import httpx
async with httpx.AsyncClient(verify=False, timeout=10) as client:
    resp = await client.get(scenario.healthcheck_url)
    return resp.status_code == 200