OrbStack 라이선스 만료로 Mac mini Docker 서비스를 GPU 서버로 통합. nginx → Caddy 전환, 12개 서브도메인 자동 HTTPS, fail2ban Caddy JSON 연동. 주요 변경: - home-caddy: Caddy 리버스 프록시 (Let's Encrypt 자동 HTTPS) - home-fail2ban: Caddy JSON 로그 기반 보안 모니터링 - home-ddns: Cloudflare DDNS (API 키 .env 분리) - gpu-hub-api/web: AI 백엔드 라우터 + 웹 UI (gpu-services에서 이전) - AI 런타임(Ollama) 내부망 전용, 외부는 gpu-hub 인증 게이트웨이 경유 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
42 lines
1.2 KiB
Python
42 lines
1.2 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import logging
|
|
|
|
from config import settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def get_gpu_info() -> dict | None:
|
|
"""Run nvidia-smi and parse GPU info."""
|
|
try:
|
|
proc = await asyncio.create_subprocess_exec(
|
|
settings.nvidia_smi_path,
|
|
"--query-gpu=utilization.gpu,temperature.gpu,memory.used,memory.total,power.draw,name",
|
|
"--format=csv,noheader,nounits",
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.PIPE,
|
|
)
|
|
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=5.0)
|
|
|
|
if proc.returncode != 0:
|
|
logger.debug("nvidia-smi failed: %s", stderr.decode())
|
|
return None
|
|
|
|
line = stdout.decode().strip().split("\n")[0]
|
|
parts = [p.strip() for p in line.split(",")]
|
|
if len(parts) < 6:
|
|
return None
|
|
|
|
return {
|
|
"utilization": int(parts[0]),
|
|
"temperature": int(parts[1]),
|
|
"vram_used": int(parts[2]),
|
|
"vram_total": int(parts[3]),
|
|
"power_draw": float(parts[4]),
|
|
"name": parts[5],
|
|
}
|
|
except (FileNotFoundError, asyncio.TimeoutError):
|
|
return None
|