f8d3cbdd59
Add the FastAPI app, PostgreSQL migrations, Docker/Helm packaging, API contracts, docs, client examples, and the unit/integration/compatibility test suite for local client and tooling labs without a real vCenter.
124 lines
4.1 KiB
Python
124 lines
4.1 KiB
Python
"""Appliance health / networking / timesync — mutable lab state."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from fastapi import APIRouter, Depends
|
|
|
|
from app.db.pool import Database
|
|
from app.dependencies import get_database
|
|
from app.vsphere.domain import appliance
|
|
from app.vsphere.errors import invalid_argument
|
|
from app.vsphere.security.authz import require_admin, require_read
|
|
from app.vsphere.security.session import SessionInfo
|
|
|
|
router = APIRouter(tags=["vSphere Appliance"])
|
|
|
|
|
|
@router.get("/api/appliance/health/system")
|
|
async def health_system(
|
|
database: Database = Depends(get_database),
|
|
_: SessionInfo = Depends(require_read),
|
|
) -> dict[str, Any]:
|
|
from app.vsphere.domain import api_state
|
|
|
|
payload = await api_state.get_payload(database, "GET", "/api/appliance/health/system")
|
|
return payload if isinstance(payload, dict) else {"status": "unknown", "messages": []}
|
|
|
|
|
|
@router.get("/api/appliance/networking")
|
|
async def networking(
|
|
database: Database = Depends(get_database),
|
|
_: SessionInfo = Depends(require_read),
|
|
) -> dict[str, Any]:
|
|
return await appliance.get_networking(database)
|
|
|
|
|
|
@router.get("/api/appliance/networking/dns/hostname")
|
|
async def get_dns_hostname(
|
|
database: Database = Depends(get_database),
|
|
_: SessionInfo = Depends(require_read),
|
|
) -> dict[str, str]:
|
|
return {"name": await appliance.get_hostname(database)}
|
|
|
|
|
|
@router.put("/api/appliance/networking/dns/hostname")
|
|
@router.post("/api/appliance/networking/dns/hostname")
|
|
async def set_dns_hostname(
|
|
body: dict[str, Any],
|
|
database: Database = Depends(get_database),
|
|
_: SessionInfo = Depends(require_admin),
|
|
) -> dict[str, str]:
|
|
name = str(body.get("name") or body.get("hostname") or "").strip()
|
|
if not name:
|
|
raise invalid_argument("name is required")
|
|
hostname = await appliance.set_hostname(database, name)
|
|
return {"name": hostname}
|
|
|
|
|
|
@router.get("/api/appliance/networking/dns/servers")
|
|
async def get_dns_servers(
|
|
database: Database = Depends(get_database),
|
|
_: SessionInfo = Depends(require_read),
|
|
) -> dict[str, Any]:
|
|
networking_state = await appliance.get_networking(database)
|
|
dns = networking_state.get("dns") or {}
|
|
return {"mode": dns.get("mode"), "servers": list(dns.get("servers") or [])}
|
|
|
|
|
|
@router.put("/api/appliance/networking/dns/servers")
|
|
@router.post("/api/appliance/networking/dns/servers")
|
|
async def set_dns_servers(
|
|
body: dict[str, Any],
|
|
database: Database = Depends(get_database),
|
|
_: SessionInfo = Depends(require_admin),
|
|
) -> dict[str, Any]:
|
|
mode = body.get("mode")
|
|
servers = body.get("servers")
|
|
if servers is None and body.get("server"):
|
|
servers = [body["server"]]
|
|
return await appliance.set_dns_servers(
|
|
database,
|
|
mode=str(mode) if mode is not None else None,
|
|
servers=[str(s) for s in servers] if isinstance(servers, list) else None,
|
|
)
|
|
|
|
|
|
@router.get("/api/appliance/networking/dns/domains")
|
|
async def get_dns_domains(
|
|
database: Database = Depends(get_database),
|
|
_: SessionInfo = Depends(require_read),
|
|
) -> list[str]:
|
|
networking_state = await appliance.get_networking(database)
|
|
dns = networking_state.get("dns") or {}
|
|
return list(dns.get("domains") or [])
|
|
|
|
|
|
@router.put("/api/appliance/networking/dns/domains")
|
|
@router.post("/api/appliance/networking/dns/domains")
|
|
async def set_dns_domains(
|
|
body: dict[str, Any] | list[Any],
|
|
database: Database = Depends(get_database),
|
|
_: SessionInfo = Depends(require_admin),
|
|
) -> list[str]:
|
|
if isinstance(body, list):
|
|
domains = [str(d) for d in body]
|
|
else:
|
|
domains = [str(d) for d in (body.get("domains") or body.get("domain") or [])]
|
|
if isinstance(body.get("domain"), str):
|
|
domains = [str(body["domain"])]
|
|
if not domains:
|
|
from app.vsphere.errors import invalid_argument
|
|
|
|
raise invalid_argument("domains is required")
|
|
return await appliance.set_dns_domains(database, domains)
|
|
|
|
|
|
@router.get("/api/appliance/timesync")
|
|
async def timesync(
|
|
database: Database = Depends(get_database),
|
|
_: SessionInfo = Depends(require_read),
|
|
) -> dict[str, Any]:
|
|
return await appliance.get_timesync(database)
|