"""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)