feat: Implement UVM Dashboard with frontend and backend integration

- Added dashboard.js for frontend functionality, including VM management and system health monitoring.
- Created dashboard route to serve the dashboard HTML.
- Introduced diagnostics route for token-protected host diagnostics.
- Enhanced VMs router with bulk actions, VM log retrieval, and port management.
- Updated lifecycle service to read VM log tails with truncation handling.
- Integrated static file serving for dashboard assets in the FastAPI server.
- Redirect root URL to the dashboard for improved user experience.
This commit is contained in:
2026-09-19 10:50:29 +05:30
parent 3d7af4adb8
commit b3b1b527e1
17 changed files with 2285 additions and 69 deletions
+32 -11
View File
@@ -217,35 +217,53 @@ sudo env UVM_API_TOKEN="$UVM_API_TOKEN" \
```
The default bind address is `127.0.0.1` and the default port is `8000`.
OpenAPI documentation is available at `/docs` once the server is running.
OpenAPI documentation is available at `/docs` once the server is running. The
root URL redirects to the local dashboard at `/dashboard`; enter the API token
there for the current browser session.
The server exposes these routes:
| Method | Route | Purpose |
|---|---|---|
| `GET` | `/` | Redirect to the local dashboard |
| `GET` | `/dashboard` | Serve the local management dashboard |
| `GET` | `/health` | Unauthenticated liveness response |
| `GET` | `/diagnostics` | Run host readiness checks for the dashboard/system view |
| `POST` | `/install` | Install or refresh host assets; body: `{ "force": false }` |
| `GET` | `/vms` | List VM records and observed status |
| `POST` | `/vms` | Create; supports `cpu`, `ram`, `guest_ip`, `username`, `password`, `name`, `ports`, `no_default_ports` |
| `POST` | `/vms/actions` | Run a fixed snapshot of selected or all VM lifecycle actions |
| `GET` | `/vms/{identifier}` | Inspect by exact ID, name, or guest IP |
| `POST` | `/vms/{identifier}/stop` | Stop a VM while retaining its private disk |
| `DELETE` | `/vms/{identifier}` | Delete a VM and release its resources |
| `POST` | `/vms/{identifier}/start` | Boot a retained private disk |
| `POST` | `/vms/{identifier}/restart` | Stop then boot a VM; optional `timeout` query parameter |
| `POST` | `/vms/{identifier}/stop` | Stop a VM while retaining its private disk; optional `timeout` query parameter |
| `DELETE` | `/vms/{identifier}` | Delete a VM and release its resources; optional `timeout` query parameter |
| `POST` | `/vms/{vm_id}/ports` | Set, open, or close private port rules for an exact VM ID |
| `POST` | `/vms/{vm_id}/ports/sync` | Reapply a managed private port policy for an exact VM ID |
| `GET` | `/vms/{identifier}/logs` | Read a bounded, non-following tail of a VM log |
API port rules are objects such as `{"port": 80, "protocol": "HTTP"}`;
`no_default_ports` is a boolean, default `false`. Responses include `name`,
`no_default_ports` is a boolean, default `false`. Port changes use
`{"mode":"set"|"open"|"close", "ports":[...]}`. A legacy VM must be
stopped and use `set` to establish a managed policy. Responses include `name`,
`ports`, `policy_status`, and `operation`, but never passwords. See
[USAGE.md](USAGE.md) for request examples and strict schema details.
Log reads use an optional `tail` query parameter from `0` to `1000`, default
`100`, and are capped at the final 256 KiB of the log.
The endpoint set is unchanged: there are **no start/restart, port-management,
or bulk HTTP endpoints**. SSH, logs, and doctor are also CLI-only. Use the
local CLI for those operations; the API is not a background reconciler.
Bulk requests use an action (`start`, `stop`, `restart`, `delete`, or
`ports-sync`) plus either `identifiers` or `all_vms: true`; they return a result
for each fixed target and do not prompt for confirmation. Interactive SSH
remains CLI-only. The API and dashboard are not background reconcilers.
### API Security
The server controls privileged host operations. `UVM_API_TOKEN` is required
for every API server, including loopback-only deployments. All management
routes require it in the `X-UVM-Token` header. FastAPI's informational `/docs`,
`/redoc`, and `/openapi.json` endpoints do not require a token.
routes require it in the `X-UVM-Token` header. The dashboard shell, liveness
route, and FastAPI's informational `/docs`, `/redoc`, and `/openapi.json`
endpoints do not require a token; the dashboard stores the entered token only
for its current browser session and applies it to management requests.
A non-loopback bind additionally requires TLS certificate and key paths:
@@ -406,6 +424,8 @@ Selected files:
│ ├── lifecycle.py # Lifecycle, bulk operations, recovery, port-policy intent
│ ├── network.py # IP/MAC/TAP/bridge/NAT management
│ ├── firewall.py # Owned nftables bridge policies and offline conntrack cleanup
│ ├── dashboard/ # Local dashboard HTML, CSS, and JavaScript
│ ├── routers/ # FastAPI routes, including the dashboard document
│ └── firecracker/ # Firecracker config, API, and process adapters
└── tests/ # Unit tests and opt-in isolated namespace packet tests
```
@@ -424,8 +444,9 @@ python3 -B -m unittest discover -s tests -v
The unit tests do not need root, KVM, Firecracker, or host network changes.
They cover validation, state migration and locking, integrity manifests,
network/firewall rendering, Firecracker request ordering, process safety,
retained-disk resume, bulk operations, and lifecycle rollback. API route tests
run when the FastAPI and `httpx` test dependencies are installed.
retained-disk resume, bulk operations, lifecycle rollback, dashboard delivery,
and API routes. API route tests run when the FastAPI and `httpx` test
dependencies are installed.
Opt-in packet checks run **only in disposable isolated user/network
namespaces**, which may require privileges and the installed network tools: