"""FastAPI 진입점: 정적 자산 마운트, 라우터 등록, 헬스체크. 화면용 라우트는 JSON 이 아니라 HTML(전체 페이지 또는 조각)을 반환한다(스펙 §7). """ from __future__ import annotations from pathlib import Path import httpx from fastapi import Depends, FastAPI, Request from fastapi.responses import HTMLResponse, JSONResponse from fastapi.staticfiles import StaticFiles # 테스트 호환을 위해 re-export (tests 가 app.main.get_pulp_client 를 override 함) from .deps import get_pulp_client, templates from .pulp_client import PulpClient from .routes import dashboard, deploy, sync, versions BASE_DIR = Path(__file__).resolve().parent app = FastAPI(title="Pulp 패치 관리 콘솔") app.mount("/static", StaticFiles(directory=str(BASE_DIR / "static")), name="static") app.include_router(dashboard.router) app.include_router(sync.router) app.include_router(versions.router) app.include_router(deploy.router) __all__ = ["app", "get_pulp_client"] @app.get("/healthz") def healthz() -> JSONResponse: """앱 라이브니스(컨테이너 헬스체크용). Pulp 상태와 무관하게 항상 200. Pulp 미연결이라도 앱 자체는 살아있으므로, Coolify 가 컨테이너를 unhealthy 로 오판하지 않도록 여기서는 Pulp 를 확인하지 않는다. 연결 확인은 /pulp-status. """ return JSONResponse({"ok": True}) @app.get("/pulp-status", response_class=HTMLResponse) def pulp_status( request: Request, pulp: PulpClient = Depends(get_pulp_client) ) -> HTMLResponse: """Pulp status 프록시 → 연결 상태 배지 조각 (대시보드 폴링 대상).""" try: pulp.status() online, detail = True, "Pulp 연결됨" except httpx.HTTPError as exc: online, detail = False, f"Pulp 연결 실패: {exc}" return templates.TemplateResponse( request, "partials/health.html", {"online": online, "detail": detail}, status_code=200 if online else 503, )