Architecture
This page shows, in one diagram, how QemuRun-pve's layers relate to the Proxmox cluster.
System Overview
graph TB
Client -->|HTTP / SSE| Gin[Gin Router + CORS]
Gin --> Handler[Handler Layer<br/>ALLOW_IPS / state checks]
Handler --> Util[Util<br/>VM / node lookup]
Handler --> Service[Service Layer]
Util -->|pvesh| PVE[(Proxmox Cluster API)]
Util --> Disabled[.go_qemu_disabled]
Service -->|qm / pvesh / pvesm| Main[Main Node]
Service -->|SSH root@NODE_x + qm| Remote[Remote Node]
Service -->|HTTP| Mirror[Official Cloud Image Mirrors]
Service -->|SSH| VM[New VM]
VM -->|curl /sh/os_version.sh| Gin
Layers
| Layer | Location | Responsibility |
|---|---|---|
| Entry | cmd/api/main.go |
Loads .env, checks PORT / GATEWAY, mounts the /sh static dir, starts Gin |
| Config | internal/config |
CORS middleware and /api route registration |
| Handler | internal/handler |
Parses params, runs ALLOW_IPS and VM state pre-checks, picks a plain text / JSON / SSE response |
| Service | internal/service |
Every qm / pvesh / pvesm / ssh call, the install pipeline, resource allocation, SSE push |
| Util | internal/util |
Cluster VM / node lookups, the disabled list, ALLOW_IPS matching |
| Model | internal/model |
Request, response, and SSE structures |
Cross-Cutting Principles
- Proxmox CLI as the API: no Proxmox HTTP API calls and no stored tokens; every operation is
qm/pvesh/pvesmon the main node, orqmover SSH on another node - No database: cluster state is read live from
pvesh get /cluster/resourcesand/etc/pve/nodes; the only local data are three State Files - Long operations always stream: install, start, reboot, and migration report each step over SSE; short operations reply
ok - The VMID decides the network: the last IP octet equals the VMID, so there is no DHCP or IP table; see VMID and IP Allocation
Further Reading
Module internals, sequence diagrams, and the VM state machine live in doc/architecture.md.