Files
homelab-optimized/dashboard/api/routers/olares.py
Gitea Mirror Bot 24b249b290
Some checks failed
Documentation / Deploy to GitHub Pages (push) Has been cancelled
Documentation / Build Docusaurus (push) Has started running
Sanitized mirror from private repository - 2026-04-19 09:32:43 UTC
2026-04-19 09:32:43 +00:00

94 lines
2.9 KiB
Python

"""Olares K3s pod listing and GPU status."""
import subprocess
from fastapi import APIRouter, Query
router = APIRouter(tags=["olares"])
def _ssh_olares(cmd: str, timeout: int = 10) -> str:
"""Run a command on olares via SSH."""
result = subprocess.run(
["ssh", "-o", "ConnectTimeout=3", "olares", cmd],
capture_output=True, text=True, timeout=timeout,
)
return result.stdout if result.returncode == 0 else ""
@router.get("/olares/pods")
def olares_pods(namespace: str | None = Query(None)):
"""List K3s pods on olares."""
if namespace:
cmd = f"kubectl get pods -n {namespace} -o wide --no-headers"
else:
cmd = "kubectl get pods -A -o wide --no-headers"
output = _ssh_olares(cmd, timeout=15)
if not output:
return []
pods = []
for line in output.strip().split("\n"):
parts = line.split()
if not parts:
continue
if namespace:
# No namespace column when -n is used
if len(parts) >= 7:
pods.append({
"namespace": namespace,
"name": parts[0],
"ready": parts[1],
"status": parts[2],
"restarts": parts[3],
"age": parts[4],
"ip": parts[5] if len(parts) > 5 else "",
"node": parts[6] if len(parts) > 6 else "",
})
else:
# Has namespace column
if len(parts) >= 8:
pods.append({
"namespace": parts[0],
"name": parts[1],
"ready": parts[2],
"status": parts[3],
"restarts": parts[4],
"age": parts[5],
"ip": parts[6] if len(parts) > 6 else "",
"node": parts[7] if len(parts) > 7 else "",
})
return pods
@router.get("/olares/gpu")
def olares_gpu():
"""GPU status from olares."""
output = _ssh_olares(
"nvidia-smi --query-gpu=name,temperature.gpu,power.draw,power.limit,"
"memory.used,memory.total,utilization.gpu --format=csv,noheader,nounits"
)
if not output:
return {"available": False}
parts = [p.strip() for p in output.strip().split(",")]
def _float(val: str) -> float | None:
try:
return float(val)
except (ValueError, TypeError):
return None
if len(parts) >= 7:
return {
"available": True,
"name": parts[0],
"temp_c": _float(parts[1]),
"power_draw_w": _float(parts[2]),
"power_limit_w": _float(parts[3]),
"memory_used_mb": _float(parts[4]),
"memory_total_mb": _float(parts[5]),
"utilization_pct": _float(parts[6]),
}
return {"available": False}