"""P2 배포 마무리: DB 테이블 + 서비스 재시작 + 검증""" import paramiko, sys, time sys.stdout.reconfigure(encoding='utf-8', errors='replace') c = paramiko.SSHClient(); c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=15) sftp = c.open_sftp() def run(label, cmd, timeout=30): print(f'\n[{label}]') _, o, _ = c.exec_command(cmd, timeout=timeout) print(o.read().decode('utf-8','replace').strip()[:500]) # DB 테이블 생성 (서버에서 스크립트 실행) db_script = """ import asyncio import sys sys.path.insert(0, '/opt/guardia/app') from database import engine, Base from models import K8sCluster, SSOConfig, SSOSession, SlackConfig, TenantBranding async def create_tables(): async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) print('테이블 생성 완료') asyncio.run(create_tables()) """ with sftp.open('/tmp/create_tables.py', 'w') as f: f.write(db_script) run('DB 테이블 생성', 'cd /opt/guardia/app && /opt/guardia/venv/bin/python3 /tmp/create_tables.py 2>&1; rm /tmp/create_tables.py') # 포트 정리 + 서비스 재시작 run('포트 정리 + 재시작', 'fuser -k 9001/tcp 2>/dev/null || true; sleep 1; systemctl restart guardia && sleep 6 && systemctl is-active guardia') time.sleep(4) # 검증 스크립트 verify_script = """ import asyncio, sys, json, urllib.request sys.path.insert(0, '/opt/guardia/app') # API 엔드포인트 확인 try: d = json.loads(urllib.request.urlopen("http://localhost:9001/openapi.json", timeout=10).read()) paths = sorted(d["paths"].keys()) keywords = ["/api/k8s", "/api/sso", "/api/predict", "/api/slack", "/api/brand"] new_paths = [p for p in paths if any(k in p for k in keywords)] print(f"P2 신규 엔드포인트: {len(new_paths)}개 / 전체: {len(paths)}개") for p in new_paths: print(" ", p) except Exception as e: print(f"API 확인 실패: {e}") # DB 테이블 확인 from database import engine from sqlalchemy import text async def check(): tables = ['tb_k8s_cluster', 'tb_sso_config', 'tb_slack_config', 'tb_tenant_branding'] async with engine.connect() as conn: for t in tables: try: await conn.execute(text(f"SELECT COUNT(*) FROM {t}")) print(f" {t}: OK") except Exception as e: print(f" {t}: {str(e)[:50]}") asyncio.run(check()) """ with sftp.open('/tmp/verify_p2.py', 'w') as f: f.write(verify_script) run('최종 검증', 'cd /opt/guardia/app && /opt/guardia/venv/bin/python3 /tmp/verify_p2.py 2>&1; rm /tmp/verify_p2.py') sftp.close(); c.close() print('\n=== P2 배포 완료 ===')