feat: introduce Nest workspace for local Firecracker management

- Added a new server module for the Nest workspace, integrating with UVM's API.
- Updated project description to reflect the new Nest functionality.
- Created tests for the Nest server and CLI, ensuring proper functionality and error handling.
- Refactored existing UVM server code to separate Nest and UVM functionalities.
- Removed the old UVM dashboard assets package as it is now part of the Nest workspace.
- Enhanced error messages for clarity regarding server shutdown commands.
This commit is contained in:
2026-09-25 13:45:57 +05:30
parent 660ba9efee
commit dca7f78dae
22 changed files with 456 additions and 138 deletions
+10 -13
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
from collections.abc import Callable
from ipaddress import ip_address
from pathlib import Path
import ssl
@@ -27,8 +28,7 @@ def create_api(application: Application | None = None, *, host: str | None = Non
try:
from fastapi import FastAPI
from fastapi.responses import JSONResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.responses import JSONResponse
except ModuleNotFoundError as error:
raise UvmError(
"FastAPI server support is not installed. Install this project with its dependencies."
@@ -39,7 +39,6 @@ def create_api(application: Application | None = None, *, host: str | None = Non
from .routers.installation import router as installation_router
from .routers.vms import router as vms_router
from .routers.diagnostics import router as diagnostics_router
from .routers.dashboard import router as dashboard_router
api = FastAPI(
title="uvm",
@@ -61,18 +60,16 @@ def create_api(application: Application | None = None, *, host: str | None = Non
api.include_router(vms_router)
api.include_router(diagnostics_router)
static_dir = Path(__file__).parent / "dashboard" / "static"
api.mount("/dashboard/static", StaticFiles(directory=static_dir), name="dashboard_static")
api.include_router(dashboard_router, prefix="/dashboard")
@api.get("/")
async def root() -> Any:
return RedirectResponse(url="/dashboard")
return api
def run_server(application: Application, *, host: str, port: int) -> None:
def run_server(
application: Application,
*,
host: str,
port: int,
api_factory: Callable[..., Any] | None = None,
) -> None:
"""Run Uvicorn after enforcing the local-management security boundary."""
settings = application.settings
@@ -93,7 +90,7 @@ def run_server(application: Application, *, host: str, port: int) -> None:
if settings.api_tls_cert is not None:
options["ssl_certfile"] = str(settings.api_tls_cert)
options["ssl_keyfile"] = str(settings.api_tls_key)
api = create_api(application, host=host)
api = (api_factory or create_api)(application, host=host)
server = uvicorn.Server(uvicorn.Config(api, **options))
api.state.uvicorn_server = server
server.run()