""" 멀티클라우드 통합 관제 — NCloud + AWS + 기타 엔드포인트: GET /api/multicloud/providers — 등록된 프로바이더 목록 POST /api/multicloud/providers — 프로바이더 등록 DELETE /api/multicloud/providers/{id}— 프로바이더 삭제 GET /api/multicloud/resources — 전체 클라우드 리소스 통합 GET /api/multicloud/costs — 전체 비용 통합 GET /api/multicloud/summary — 멀티클라우드 현황 요약 """ from __future__ import annotations import json, logging from datetime import datetime from typing import Optional import httpx from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from core.auth import get_current_user, require_admin_role from database import get_db from models import User, MultiCloudConfig logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/multicloud", tags=["멀티클라우드"]) SUPPORTED_PROVIDERS = ["ncloud", "aws", "gcp", "azure", "kt_cloud", "naver_cloud"] class ProviderCreate(BaseModel): name: str provider_type: str = Field(..., description="ncloud|aws|gcp|azure|kt_cloud") region: str = "kr-1" access_key: str secret_key: str extra_config: Optional[dict] = None @router.post("/providers") async def add_provider(req: ProviderCreate, db: AsyncSession = Depends(get_db), user: User = Depends(require_admin_role)): if req.provider_type not in SUPPORTED_PROVIDERS: raise HTTPException(400, f"미지원 프로바이더: {req.provider_type}") cfg = MultiCloudConfig( tenant_id=user.tenant_id, name=req.name, provider_type=req.provider_type, region=req.region, access_key=req.access_key, secret_key_enc=req.secret_key, # TODO: AES-256-GCM extra_config=json.dumps(req.extra_config or {}), is_active=True, created_at=datetime.utcnow(), ) db.add(cfg); await db.commit(); await db.refresh(cfg) return {"ok": True, "id": cfg.id} @router.get("/providers") async def list_providers(db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)): rows = await db.execute(select(MultiCloudConfig).where(MultiCloudConfig.tenant_id == user.tenant_id, MultiCloudConfig.is_active == True)) return [{"id": c.id, "name": c.name, "type": c.provider_type, "region": c.region} for c in rows.scalars().all()] @router.delete("/providers/{config_id}") async def delete_provider(config_id: int, db: AsyncSession = Depends(get_db), user: User = Depends(require_admin_role)): row = await db.execute(select(MultiCloudConfig).where(MultiCloudConfig.id == config_id, MultiCloudConfig.tenant_id == user.tenant_id)) cfg = row.scalar_one_or_none() if not cfg: raise HTTPException(404) cfg.is_active = False; await db.commit() return {"ok": True} @router.get("/resources") async def list_all_resources(db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)): rows = await db.execute(select(MultiCloudConfig).where(MultiCloudConfig.tenant_id == user.tenant_id, MultiCloudConfig.is_active == True)) cfgs = rows.scalars().all() all_resources = [] for cfg in cfgs: # NCloud 경유 실제 조회 (다른 프로바이더는 설정 완료 후 활성화) if cfg.provider_type in ("ncloud", "naver_cloud"): try: from routers.ncloud import list_servers as ncloud_list # 기존 ncloud.py 재활용 resources = await _get_ncloud_resources(cfg) for r in resources: r["provider"] = cfg.name r["provider_type"] = cfg.provider_type all_resources.extend(resources) except Exception as e: logger.warning(f"NCloud 조회 실패: {e}") else: all_resources.append({"provider": cfg.name, "provider_type": cfg.provider_type, "note": "설정 후 활성화"}) return {"resources": all_resources, "total": len(all_resources)} async def _get_ncloud_resources(cfg: MultiCloudConfig) -> list[dict]: try: from routers.ncloud import _ncloud_request data = await _ncloud_request(cfg, "GET", "/vserver/v2/getServerInstanceList") if data: return [{"id": s.get("serverInstanceNo"), "name": s.get("serverName"), "status": s.get("serverInstanceStatus", {}).get("codeName"), "ip": s.get("publicIp")} for s in data.get("getServerInstanceListResponse", {}).get("serverInstanceList", [])] except Exception: pass return [] @router.get("/summary") async def multicloud_summary(db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)): rows = await db.execute(select(MultiCloudConfig).where(MultiCloudConfig.tenant_id == user.tenant_id, MultiCloudConfig.is_active == True)) cfgs = rows.scalars().all() return { "provider_count": len(cfgs), "providers": [{"name": c.name, "type": c.provider_type} for c in cfgs], "last_checked": datetime.utcnow(), }