Files
news_all_spo/api/route/admin_system.py
2026-05-19 17:48:35 +05:00

116 lines
3.9 KiB
Python

import os
import time
import asyncio
from urllib.parse import urlparse
from fastapi import APIRouter, Depends
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession
from bd.database import get_db, get_redis, DATABASE_URL, REDIS_URL
from route.deps import require_admin
router = APIRouter()
MINIO_ENDPOINT = os.getenv("MINIO_ENDPOINT", "minio:9000")
MINIO_ACCESS_KEY = os.getenv("MINIO_ACCESS_KEY", "minioadmin")
MINIO_SECRET_KEY = os.getenv("MINIO_SECRET_KEY", "minioadmin")
MINIO_BUCKET = os.getenv("MINIO_BUCKET", "news-media")
MINIO_PUBLIC_URL = os.getenv("MINIO_PUBLIC_URL", "http://localhost:9000")
def _parse_db_url(url: str) -> dict:
"""Вытащить host/port/db/user из DATABASE_URL без пароля."""
try:
# postgresql+asyncpg://user:pass@host:port/db
p = urlparse(url.replace("+asyncpg", ""))
return {
"host": p.hostname or "?",
"port": p.port or 5432,
"database": (p.path or "/").lstrip("/") or "?",
"user": p.username or "?",
}
except Exception:
return {"host": "?", "port": 5432, "database": "?", "user": "?"}
def _parse_redis_url(url: str) -> dict:
"""Вытащить host/port из REDIS_URL без пароля."""
try:
p = urlparse(url)
return {
"host": p.hostname or "?",
"port": p.port or 6379,
"db": (p.path or "/0").lstrip("/") or "0",
}
except Exception:
return {"host": "?", "port": 6379, "db": "0"}
async def _check_postgres(db: AsyncSession) -> dict:
info = _parse_db_url(DATABASE_URL)
t0 = time.monotonic()
try:
result = await db.execute(text("SELECT version()"))
version = result.scalar() or ""
latency_ms = round((time.monotonic() - t0) * 1000, 1)
# Извлекаем короткую версию: "PostgreSQL 15.3 ..."
short_ver = version.split(",")[0] if version else "?"
return {"ok": True, "latency_ms": latency_ms, "version": short_ver, **info}
except Exception as e:
return {"ok": False, "error": str(e), "latency_ms": None, **info}
async def _check_redis() -> dict:
info = _parse_redis_url(REDIS_URL)
t0 = time.monotonic()
try:
redis = await get_redis()
pong = await redis.ping()
latency_ms = round((time.monotonic() - t0) * 1000, 1)
server_info = await redis.info("server")
version = server_info.get("redis_version", "?")
return {"ok": bool(pong), "latency_ms": latency_ms, "version": f"Redis {version}", **info}
except Exception as e:
return {"ok": False, "error": str(e), "latency_ms": None, **info}
async def _check_minio() -> dict:
t0 = time.monotonic()
try:
from minio import Minio
loop = asyncio.get_event_loop()
client = Minio(MINIO_ENDPOINT, access_key=MINIO_ACCESS_KEY, secret_key=MINIO_SECRET_KEY, secure=False)
exists = await loop.run_in_executor(None, client.bucket_exists, MINIO_BUCKET)
latency_ms = round((time.monotonic() - t0) * 1000, 1)
return {
"ok": True,
"latency_ms": latency_ms,
"endpoint": MINIO_ENDPOINT,
"bucket": MINIO_BUCKET,
"public_url": MINIO_PUBLIC_URL,
"bucket_exists": exists,
}
except Exception as e:
return {
"ok": False,
"error": str(e),
"latency_ms": None,
"endpoint": MINIO_ENDPOINT,
"bucket": MINIO_BUCKET,
"public_url": MINIO_PUBLIC_URL,
}
@router.get("/status")
async def system_status(db: AsyncSession = Depends(get_db), _: str = Depends(require_admin)):
pg, redis, minio = await asyncio.gather(
_check_postgres(db),
_check_redis(),
_check_minio(),
)
return {
"postgres": pg,
"redis": redis,
"minio": minio,
}