Compare commits
33 Commits
main
...
4deadcba3f
| Author | SHA1 | Date | |
|---|---|---|---|
| 4deadcba3f | |||
| 71d6b89062 | |||
| c78e5a334d | |||
| 7ea63d670c | |||
| 6be309f183 | |||
| e278d6a093 | |||
| caf681fdc2 | |||
| 7214fce178 | |||
| b6136d0b68 | |||
| 46d62cc4a1 | |||
| 76faa10d06 | |||
| 7c7d0262dd | |||
| 1e8164ddf5 | |||
| 12da51e351 | |||
| 43ebb80be6 | |||
| a705789658 | |||
| 711b394afd | |||
| 67b3fac30f | |||
| a2144687b1 | |||
| 015a9d7ed8 | |||
| c07e448d40 | |||
| 59bb0f24db | |||
| ad328efa3c | |||
| 33d2f6e42a | |||
| 2ab78012ba | |||
| 607844f184 | |||
| e79221642b | |||
| f27bc3e4eb | |||
| 77b067ea35 | |||
| 6b61c3240a | |||
| 51753269ca | |||
| 47f10cc2c2 | |||
| 783400884a |
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
PROXMOX_API_URL=http://proxmox.lan:8006/api2/json
|
PROXMOX_API_URL=http://proxmox.lan:8006/api2/json
|
||||||
PROXMOX_WEB_URL=http://proxmox.lan:8006
|
PROXMOX_WEB_URL=http://proxmox.lan:8006
|
||||||
|
PROXMOX_CONSOLE_TOKEN=root@pam!monitorapp
|
||||||
PROXMOX_TOKEN_ID=root@pam!monitorapp
|
PROXMOX_TOKEN_ID=root@pam!monitorapp
|
||||||
PROXMOX_TOKEN_SECRET=<your-token-secret>
|
PROXMOX_TOKEN_SECRET=103d622c-05a3-4002-9356-f67691e10d40
|
||||||
API_POLL_INTERVAL=30000
|
API_POLL_INTERVAL=30000
|
||||||
|
|||||||
15
CLAUDE.md
15
CLAUDE.md
@@ -27,23 +27,22 @@ src/
|
|||||||
│ ├── layout.js # Root layout (Inter font, metadata)
|
│ ├── layout.js # Root layout (Inter font, metadata)
|
||||||
│ └── page.js # Entry — renders <Dashboard />
|
│ └── page.js # Entry — renders <Dashboard />
|
||||||
├── components/
|
├── components/
|
||||||
│ ├── Dashboard.js # Main UI: tabs, summary cards, polling, power action handler
|
│ ├── Dashboard.js # Main UI: tabs, summary cards, power action handler
|
||||||
│ ├── NodeList.js / NodeCard.js # Node overview (collapsible cards with subtotals)
|
│ ├── NodeList.js / NodeCard.js # Node overview
|
||||||
│ ├── VMList.js / LXCList.js # VM/LXC lists grouped by node with search, power actions, console links, IPs
|
│ ├── VMList.js / LXCList.js # VM/LXC list views (each row has Console/Start/Stop buttons)
|
||||||
│ └── StatusBadge.js # Status indicator
|
│ └── StatusBadge.js # Status indicator
|
||||||
└── lib/
|
└── lib/
|
||||||
└── proxmox.js # Proxmox API client — getNodes, getVMs, getLXC, getSummary, powerControl, getConfigIPs
|
└── proxmox.js # Proxmox API client — getNodes, getVMs, getLXC, getSummary, powerControl
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Patterns
|
## Key Patterns
|
||||||
|
|
||||||
- **Dual API endpoints**: Queries use `/api2/json`, power operations use `/api2/extjs`. Power actions send empty body `{}`.
|
- **Dual API endpoints**: Queries use `/api2/json`, power operations use `/api2/extjs`. Power actions send empty body `{}`.
|
||||||
- **API routes** aggregate data across all Proxmox nodes before returning to the client. They are thin wrappers around `lib/proxmox.js`.
|
- **API routes** aggregate data across all Proxmox nodes before returning to the client. They are thin wrappers around `lib/proxmox.js`.
|
||||||
- **Dashboard** uses direct React state + manual `setInterval` polling (not SWR) for periodic data fetching. Power actions use direct `axios.get()` calls for instant UI sync.
|
- **Dashboard** uses direct React state + manual `axios.get()` calls for power actions (instant UI sync), and SWR with `refreshInterval` for periodic polling of the same endpoints.
|
||||||
- **Power action flow**: `handlePowerAction` in Dashboard.js fires `POST /api/power`, then immediately re-fetches all four caches (`/api/nodes`, `/api/vms`, `/api/lxc`, `/api/status`) and sets state directly. Use `requestAnimationFrame` flush before the API call so status messages paint.
|
- **Power action flow**: `handlePowerAction` in Dashboard.js fires `POST /api/power`, then immediately re-fetches all four caches (`/api/nodes`, `/api/vms`, `/api/lxc`, `/api/status`) and sets state directly. Use `requestAnimationFrame` flush before the API call so status messages paint.
|
||||||
- **Auth**: PVEAPIToken header: `Authorization: PVEAPIToken=${TOKEN_ID}=${TOKEN_SECRET}`.
|
- **Auth**: PVEAPIToken header: `Authorization: PVEAPIToken=${TOKEN_ID}=${TOKEN_SECRET}`.
|
||||||
- **Console**: VMList/LXCList build `consoleUrl` from `PROXMOX_WEB_URL` with `?console={qemu|lxc}&vmid={id}&node={node}&resize=scale` params. Dashboard opens it via `window.open()` in a new tab so browser session cookies handle Proxmox auth. LXC console uses `xtermjs=1`, QEMU uses `novnc=1`.
|
- **Console**: VMList/LXCList build `consoleUrl` from `PROXMOX_WEB_URL` with `?console={qemu|lxc}&vmid={id}&node={node}` params. Dashboard opens it via `window.open()` in a new tab so browser session cookies handle Proxmox auth.
|
||||||
- **Per-VM/LXC IPs**: `getConfigIPs()` in proxmox.js fetches QEMU IPs from `/agent/network-get-interfaces`, LXC IPs from `/interfaces` endpoint (fallback to `/config` `net0`-`net7` parsing). IPv4 only.
|
|
||||||
- **TLS**: `NODE_TLS_REJECT_UNAUTHORIZED=0` in `.env.local` for self-signed certs. Shows a console warning — acceptable for internal lab use.
|
- **TLS**: `NODE_TLS_REJECT_UNAUTHORIZED=0` in `.env.local` for self-signed certs. Shows a console warning — acceptable for internal lab use.
|
||||||
- **Tailwind CSS 4**: Uses `@tailwindcss/postcss` config. CSS vars in `globals.css` for theming.
|
- **Tailwind CSS 4**: Uses `@tailwindcss/postcss` config. CSS vars in `globals.css` for theming.
|
||||||
- **All API routes return 502 on Proxmox failures** with `{ error, data: null }`.
|
- **All API routes return 502 on Proxmox failures** with `{ error, data: null }`.
|
||||||
@@ -56,7 +55,7 @@ src/
|
|||||||
| `PROXMOX_TOKEN_ID` | Yes | API token ID |
|
| `PROXMOX_TOKEN_ID` | Yes | API token ID |
|
||||||
| `PROXMOX_TOKEN_SECRET` | Yes | API token secret |
|
| `PROXMOX_TOKEN_SECRET` | Yes | API token secret |
|
||||||
| `PROXMOX_WEB_URL` | No | Web UI URL (defaults from PROXMOX_API_URL) |
|
| `PROXMOX_WEB_URL` | No | Web UI URL (defaults from PROXMOX_API_URL) |
|
||||||
| `API_POLL_INTERVAL` | No | Poll interval ms (default 30000) |
|
| `NEXT_PUBLIC_API_POLL_INTERVAL` | No | Poll interval ms (default 30000) |
|
||||||
| `NODE_TLS_REJECT_UNAUTHORIZED` | No | `0` for self-signed certs |
|
| `NODE_TLS_REJECT_UNAUTHORIZED` | No | `0` for self-signed certs |
|
||||||
|
|
||||||
## Git Workflow
|
## Git Workflow
|
||||||
|
|||||||
50
README.md
50
README.md
@@ -4,24 +4,17 @@ A real-time dashboard for monitoring Proxmox VE nodes, VMs, and LXC containers.
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Node overview** — CPU, memory, uptime, and load for each Proxmox node, grouped into collapsible cards
|
- **Node overview** — CPU, memory, uptime, and load for each Proxmox node
|
||||||
- **VM & LXC tracking** — status, resource usage across all nodes
|
- **VM & LXC tracking** — status, resource usage across all nodes
|
||||||
- **Summary cards** — total nodes, running/stopped VMs, aggregate memory
|
- **Summary cards** — total nodes, running/stopped VMs, aggregate memory
|
||||||
- **Per-VM/LXC IP addresses** — IPv4 from guest agent (QEMU) or network config (LXC), displayed below VM/LXC name
|
- **Auto-refresh** — polling every 30s (configurable)
|
||||||
- **Power control** — Start/stop/restart buttons per row
|
- **Tabbed navigation** — switch between Nodes, VMs, and LXCs
|
||||||
- **Console links** — Opens Proxmox web UI console in a new tab
|
|
||||||
- **Search / filter** — Client-side filtering by name, node, or status with auto-expand
|
|
||||||
- **Group by node** — Collapsible node cards with running/stopped subtotals
|
|
||||||
- **Manual refresh** — Button in header to refresh all data
|
|
||||||
- **Custom poll interval** — Adjustable polling interval (default 30s) via header input
|
|
||||||
- **Uptime display** — Formatted as "Xd Yh Zm"
|
|
||||||
- **Auto-refresh** — Manual `setInterval` polling every 30s (configurable)
|
|
||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
- **Framework** — Next.js 15 (App Router)
|
- **Framework** — Next.js 15 (App Router)
|
||||||
- **UI** — React 19, Tailwind CSS 4
|
- **UI** — React 19, Tailwind CSS 4
|
||||||
- **Data fetching** — Axios with manual `setInterval` polling
|
- **Data fetching** — SWR (auto-refresh), Axios
|
||||||
- **Proxmox** — API2 Token-based auth
|
- **Proxmox** — API2 Token-based auth
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
@@ -39,7 +32,7 @@ cp .env.example .env.local
|
|||||||
```
|
```
|
||||||
PROXMOX_API_URL=https://your-proxmox-host:8006/api2/json
|
PROXMOX_API_URL=https://your-proxmox-host:8006/api2/json
|
||||||
PROXMOX_TOKEN_ID=root@pam!token-name
|
PROXMOX_TOKEN_ID=root@pam!token-name
|
||||||
PROXMOX_TOKEN_SECRET=<your-token-secret>
|
PROXMOX_TOKEN_SECRET=your-secret-uuid
|
||||||
API_POLL_INTERVAL=30000
|
API_POLL_INTERVAL=30000
|
||||||
NODE_TLS_REJECT_UNAUTHORIZED=0
|
NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||||
```
|
```
|
||||||
@@ -76,30 +69,27 @@ src/
|
|||||||
│ │ ├── nodes/route.js # Proxmox node stats
|
│ │ ├── nodes/route.js # Proxmox node stats
|
||||||
│ │ ├── vms/route.js # QEMU VMs across all nodes
|
│ │ ├── vms/route.js # QEMU VMs across all nodes
|
||||||
│ │ ├── lxc/route.js # LXC containers across all nodes
|
│ │ ├── lxc/route.js # LXC containers across all nodes
|
||||||
│ │ ├── status/route.js # Aggregated summary
|
│ │ └── status/route.js # Aggregated summary
|
||||||
│ │ ├── power/route.js # Power control endpoint
|
|
||||||
│ │ └── proxy/[...]/ # Reverse proxy to Proxmox web UI
|
|
||||||
│ ├── layout.js
|
│ ├── layout.js
|
||||||
│ └── page.js
|
│ └── page.js
|
||||||
├── components/
|
├── components/
|
||||||
│ ├── Dashboard.js # Main dashboard with tabs, summary, polling
|
│ ├── Dashboard.js # Main dashboard with tabs & summary
|
||||||
│ ├── NodeList.js # Node overview
|
│ ├── NodeList.js # Node cards
|
||||||
│ ├── NodeCard.js # Single node card
|
│ ├── NodeCard.js # Single node display
|
||||||
│ ├── VMList.js # VM list with group by node, filter, power actions
|
│ ├── VMList.js # VM list view
|
||||||
│ ├── LXCList.js # LXC list with group by node, filter, power actions
|
│ ├── LXCList.js # LXC list view
|
||||||
│ └── StatusBadge.js # Status indicator
|
│ └── StatusBadge.js # Online/good/warn/error/dead
|
||||||
└── lib/
|
└── lib/
|
||||||
└── proxmox.js # Proxmox API client — nodes, VMs, LXC, IPs, power control
|
└── proxmox.js # Proxmox API client & data mappers
|
||||||
```
|
```
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
| Variable | Required | Description |
|
| Variable | Required | Description |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `PROXMOX_API_URL` | Yes | Base URL of the Proxmox API (e.g. `https://host:8006/api2/json`) |
|
| `PROXMOX_API_URL` | Yes | Base URL of the Proxmox API |
|
||||||
| `PROXMOX_TOKEN_ID` | Yes | API token ID (e.g. `root@pam!monitorapp`) |
|
| `PROXMOX_TOKEN_ID` | Yes | API token ID (e.g. `root@pam!monitorapp`) |
|
||||||
| `PROXMOX_TOKEN_SECRET` | Yes | API token secret |
|
| `PROXMOX_TOKEN_SECRET` | Yes | API token secret |
|
||||||
| `PROXMOX_WEB_URL` | No | Web UI URL (defaults from `PROXMOX_API_URL`). Used for console links. |
|
|
||||||
| `API_POLL_INTERVAL` | No | Refresh interval in ms (default: `30000`) |
|
| `API_POLL_INTERVAL` | No | Refresh interval in ms (default: `30000`) |
|
||||||
| `NODE_TLS_REJECT_UNAUTHORIZED` | No | Set to `0` for self-signed certs |
|
| `NODE_TLS_REJECT_UNAUTHORIZED` | No | Set to `0` for self-signed certs |
|
||||||
|
|
||||||
@@ -108,14 +98,6 @@ src/
|
|||||||
| Route | Method | Description |
|
| Route | Method | Description |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `/api/nodes` | GET | All Proxmox nodes |
|
| `/api/nodes` | GET | All Proxmox nodes |
|
||||||
| `/api/vms` | GET | All QEMU VMs (with IPv4 from guest agent) |
|
| `/api/vms` | GET | All QEMU VMs |
|
||||||
| `/api/lxc` | GET | All LXC containers (with IPv4 from interfaces/config) |
|
| `/api/lxc` | GET | All LXC containers |
|
||||||
| `/api/status` | GET | Aggregated summary stats |
|
| `/api/status` | GET | Aggregated summary stats |
|
||||||
| `/api/power` | POST | Power control (start/stop/restart) |
|
|
||||||
| `/api/proxy/*` | GET | Reverse proxy to Proxmox web UI |
|
|
||||||
|
|
||||||
## Per-VM/LXC IP Addresses
|
|
||||||
|
|
||||||
- **QEMU VMs**: fetched from `/nodes/<node>/qemu/<id>/agent/network-get-interfaces` (requires QEMU guest agent installed)
|
|
||||||
- **LXC**: fetched from `/nodes/<node>/lxc/<id>/interfaces` (preferred) or parsed from `/config` `net0`-`net7` fields (fallback)
|
|
||||||
- IPv4 only — IPv6 addresses are excluded
|
|
||||||
|
|||||||
11
backlog.md
11
backlog.md
@@ -28,15 +28,15 @@
|
|||||||
## Quick Wins (low effort, high value)
|
## Quick Wins (low effort, high value)
|
||||||
|
|
||||||
### Per-VM/LXC IP Addresses
|
### Per-VM/LXC IP Addresses
|
||||||
- LXCs: fetches from `/interfaces` endpoint; falls back to `ip=` parsing from `net0`-`net7` in `/config`.
|
- LXCs: parses `ip=` and `ip6=` from `net0`, `net1`, etc. fields in `/nodes/<node>/lxc/<id>/config`.
|
||||||
- VMs: fetches from `/agent/network-get-interfaces` (requires QEMU guest agent).
|
- VMs: fetches from `/nodes/<node>/qemu/<id>/agent/network-get-interfaces` and reads `ipaddresses`.
|
||||||
- IPv4 only. Displays IPs below the name in the table.
|
- Displays IPs below the name in the table.
|
||||||
- **Status: done**
|
- **Status: done**
|
||||||
|
|
||||||
### Search / Filter
|
### Search / Filter
|
||||||
- Client-side text input filtering table rows by name/node/status
|
- Client-side text input filtering table rows by name/node/status
|
||||||
- Uses `useMemo` for performant filtering, auto-expands single node and filter-matched nodes
|
- Uses `useMemo` for performant filtering, auto-expands single node and filter-matched nodes
|
||||||
- **Status: done**
|
- **Status: done (merged to main)**
|
||||||
|
|
||||||
## Medium Effort
|
## Medium Effort
|
||||||
|
|
||||||
@@ -51,6 +51,9 @@
|
|||||||
- Show vCPU count, total disk size alongside usage stats
|
- Show vCPU count, total disk size alongside usage stats
|
||||||
- Note: disk.total is not populated by Proxmox API — only disk.used is available
|
- Note: disk.total is not populated by Proxmox API — only disk.used is available
|
||||||
|
|
||||||
|
### Per-VM IP Addresses
|
||||||
|
- Done — uses `/nodes/<node>/qemu/<id>/agent/network-get-interfaces` for VMs and config `net0`/`net1` parsing for LXCs.
|
||||||
|
|
||||||
### Per-VM CPU/Memory Trend
|
### Per-VM CPU/Memory Trend
|
||||||
- Periodic polling to build a small trend chart
|
- Periodic polling to build a small trend chart
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user