Architecture¶
This page describes the internal architecture of proxmox-sdk — covering the package layers, the dual-mode FastAPI server, the standalone SDK, and the key design decisions behind each component.
Package Layers¶
The project is organized into five distinct layers, each independently usable:
flowchart TD
CLI["proxmox_cli/\nTyper CLI + Textual TUI\n(interactive use)"]
SERVER["proxmox_sdk/main.py\nDual-mode FastAPI server\n(mock OR real API proxy)"]
CODEGEN["proxmox_codegen/\nPlaywright crawler → OpenAPI + Pydantic\n(schema generation pipeline)"]
SDK["sdk/\nStandalone async Python SDK\n(production integrations)"]
MOCK["mock/\nIn-memory CRUD state store\n(test infrastructure)"]
GEN["generated/proxmox/\nPre-built OpenAPI schemas\n+ Pydantic models"]
CLI -->|uses| SDK
CLI -->|may use| SERVER
SERVER -->|mock mode uses| MOCK
SERVER -->|real mode uses| SDK
CODEGEN -->|produces| GEN
MOCK -->|loaded from| GEN
SDK -->|mock backend loads| GEN
| Layer | Entry point | Standalone? | Description |
|---|---|---|---|
sdk/ |
proxmox_sdk.ProxmoxSDK |
Yes | Async + sync Python SDK with 5 backends |
mock/ |
proxmox_sdk.mock_main |
Yes | FastAPI mock server only |
proxmox_sdk/main.py |
proxmox_sdk.main |
Yes | Dual-mode FastAPI server |
proxmox_codegen/ |
proxmox-sdk-codegen CLI |
Yes | Schema generation pipeline |
proxmox_cli/ |
proxmox / pbx CLI |
Yes | Typer CLI and Textual TUI |
Dual-Mode FastAPI Server¶
The FastAPI server can run in two modes, selected via PROXMOX_API_MODE:
Mock mode loads pre-generated OpenAPI schemas plus route metadata and creates CRUD endpoints backed by configurable mock-state stores. SQLite/WAL is the default. No real Proxmox server required.
flowchart TD
REQ["HTTP Request"]
ROUTER["FastAPI Router"]
MOCK_EP["Generated Mock Dispatcher\n(from route metadata)"]
MODELS["Lazy Pydantic Shards\nmodels/<group>.py"]
STATE["SQLiteMockStore\nWAL row store"]
RESP["JSON Response"]
REQ --> ROUTER
ROUTER --> MOCK_EP
MOCK_EP -->|"load model when needed"| MODELS
MOCK_EP -->|"GET: read"| STATE
MOCK_EP -->|"POST/PUT: write"| STATE
MOCK_EP -->|"DELETE: remove"| STATE
STATE --> RESP
Startup flow:
- Load
generated/proxmox/latest/openapi.json - Load
generated/proxmox/latest/route_metadata.json register_generated_proxmox_mock_routes()iterates 675 metadata operations across 449 paths- For each operation, create a lightweight FastAPI dispatcher with precomputed path, parameter, and mock-topology metadata
- Load request/response model classes lazily from
models/<group>.pythroughmodel_index.json - Routes perform CRUD on
SQLiteMockStoreby default, with shared-memory and dict backends available by env var - State is scoped by namespace and schema fingerprint; the default tempdir SQLite database is not a production persistence layer
Performance: ~2.1 s full app import in local smoke tests, ~0.75 s generated route registration, ~4 ms warm SQLite/WAL mock request latency via local TestClient smoke tests.
Real mode proxies requests to an actual Proxmox VE API, validating both the incoming request and the Proxmox response against the OpenAPI schema.
flowchart TD
REQ["HTTP Request"]
ROUTER["FastAPI Router"]
REAL_EP["Real API Endpoint\n(validates request)"]
CLIENT["ProxmoxClient\n(HttpsBackend)"]
PVE["Real Proxmox VE\n:8006"]
VALID["Response Validation\n(Pydantic)"]
RESP["JSON Response"]
REQ --> ROUTER
ROUTER --> REAL_EP
REAL_EP --> CLIENT
CLIENT -->|"aiohttp HTTPS"| PVE
PVE -->|"JSON data"| CLIENT
CLIENT --> VALID
VALID --> RESP
Startup flow:
- Load
ProxmoxConfigfrom environment variables register_proxmox_routes()creates endpoints mirroring the mock structure- Each request: validate → call
ProxmoxClient.request()→ validate response → return
Performance: ~500 ms startup, Proxmox latency + ~20–100 ms validation overhead.
SDK Architecture¶
The standalone SDK (sdk/) is the primary way for Python applications to query Proxmox programmatically without running the FastAPI server.
flowchart TD
USER["Application code\n(proxbox-api, CLI, tests)"]
SDK_CLASS["ProxmoxSDK\nsdk/api.py"]
ROOT["ProxmoxResource('_/api2/json')\nsdk/resource.py"]
NAV["Navigation chain\n.nodes('pve1').qemu(100).config"]
LEAF["ProxmoxResource\npath=/api2/json/nodes/pve1/qemu/100/config"]
BACKEND["AbstractBackend\nsdk/backends/base.py"]
HTTPS["HttpsBackend\naiohttp + auth"]
MOCK_B["MockBackend\nin-memory"]
SSH["SshParamikoBackend\nor OpenSshBackend"]
LOCAL["LocalBackend\npvesh subprocess"]
PROXMOX["Proxmox VE"]
USER -->|"ProxmoxSDK(host=..., user=..., ...)"| SDK_CLASS
SDK_CLASS -->|"creates"| ROOT
ROOT -->|"__getattr__ / __call__"| NAV
NAV -->|"each step creates new resource"| LEAF
LEAF -->|".get() / .post() / ..."| BACKEND
BACKEND -->|"https"| HTTPS
BACKEND -->|"mock"| MOCK_B
BACKEND -->|"ssh_paramiko / openssh"| SSH
BACKEND -->|"local"| LOCAL
HTTPS -->|"aiohttp HTTPS"| PROXMOX
MOCK_B -->|"in-memory"| PROXMOX
SSH -->|"pvesh via SSH"| PROXMOX
LOCAL -->|"pvesh subprocess"| PROXMOX
Code Generation Pipeline¶
The codegen pipeline converts the Proxmox VE API Viewer into reusable artifacts:
flowchart LR
PVE["Proxmox VE\nAPI Viewer"]
CRAWL["ProxmoxCrawler\nPlaywright"]
PARSE["apidoc_parser.py"]
NORM["normalize.py"]
OA["OpenAPIBuilder\n→ openapi.json\n5.2 MB · 675 ops"]
PYD["PydanticBuilder\n→ pydantic_models.py\n+ model shards"]
META["RouteMetadataBuilder\n→ route_metadata.json\n+ model_index.json"]
USE1["proxmox-sdk\nMock routes"]
USE2["proxbox-api\nResponse validation"]
PVE --> CRAWL
CRAWL --> PARSE
PARSE --> NORM
NORM --> OA
OA --> PYD
OA --> META
OA --> USE1
META --> USE1
PYD --> USE2
See Code Generation Pipeline for the full stage-by-stage breakdown.
Key Design Decisions¶
1. Dual-Mode Architecture¶
A single codebase serves both development (mock) and production (real proxy) use cases. The same API surface — same paths, same schemas, same validation — is available in both modes. Switching from mock to real is a single environment variable change.
| Mock | Real | |
|---|---|---|
| Proxmox server required | No | Yes |
| Data persistence | SQLite/WAL mock state by default | Real Proxmox state |
| Request validation | Yes (Pydantic) | Yes (Pydantic) |
| Response validation | Yes (Pydantic) | Yes (Pydantic) |
| Startup time | ~2.1 s full app import, ~0.75 s generated route registration | ~500 ms + route registration |
2. Metadata-Driven Route Registration¶
Rather than hardcoding 675 routes or rebuilding all route topology at runtime,
the codegen pipeline emits route_metadata.json, model_index.json, and
route-group model shards under each generated/proxmox/<version>/ directory.
The server registers lightweight FastAPI dispatchers from this metadata and
lazy-loads the matching Pydantic shard on the first request that needs
request/response validation. The generated OpenAPI document is merged into the
app docs directly, so Swagger/ReDoc stay complete without importing every model
at startup.
3. Pre-Generated Schemas¶
The OpenAPI schema, aggregate Pydantic models, lazy model shards, model index,
and route metadata are committed to the repository so mock mode works
completely offline without a Proxmox server. Each version (e.g., 9.1.11) is
stored independently under generated/proxmox/; CI ships both 9.1.11/ and a
latest mirror.
4. Full Request/Response Validation¶
Every request body and response passes through Pydantic v2 validation against the OpenAPI-derived models. This enforces type correctness, produces accurate Swagger UI documentation, and catches schema drift between the SDK and Proxmox API.
5. SQLite Mock State¶
Mock state uses SQLiteMockStore by default. It stores objects, collection
members, metadata, and tombstones as separate rows in a tempdir-scoped SQLite
database using WAL mode, which avoids whole-state JSON serialization on every
request. SharedMemoryMockStore and DictMockStore remain available through
PROXMOX_MOCK_STORE=shared-memory|dict for compatibility and specialized test
cases. Value blobs use orjson when installed, with a stdlib JSON fallback.
6. aiohttp for HTTPS Transport¶
The HTTPS backend uses aiohttp for its native async/await support, mature session pooling, and robust SSL/TLS handling. The session is created lazily on first request and reused across all subsequent calls.
Security Model¶
Mock Mode¶
- No authentication by default — safe for development environments
- Rate limiting is applied only on codegen endpoints via SlowAPI (hardcoded in
rate_limit.py) - Codegen endpoints require
CODEGEN_API_KEYBearer token
Real Mode¶
- All outbound Proxmox calls use API token auth (recommended) or password/ticket auth
- SSL/TLS verification configurable via
PROXMOX_API_VERIFY_SSL - No credentials stored in memory after session initialization
SensitiveDataFilterredacts passwords and tokens from all log output
See Security for the full reference.
Performance Characteristics¶
| Metric | Mock Mode | Real Mode |
|---|---|---|
| Startup time | ~2.1 s full app import | Proxmox latency + route registration |
| Request latency | ~4 ms local mock GET smoke | Proxmox latency + ~10–20 ms validation overhead |
| Memory footprint | ~100 MB | ~80 MB |
| Max throughput | 10,000+ req/s (FastAPI-bound) | Proxmox server capacity |
Key optimizations:
- Lazy package imports —
import proxmox_sdkdoes not construct any FastAPI app - Generated route metadata — startup loads route metadata instead of rebuilding topology and signatures
- Lazy model shards — Pydantic route-group shards load only when a request needs validation
- SQLite/WAL mock state — mock CRUD stores rows per object/member instead of serializing one whole-state blob
- Cached URL components —
HttpsBackendcaches(scheme, netloc, base_path)to skip per-request URL parsing - Schema fingerprint caching —
ProxmoxSchemaValue.fingerprintis a@cached_property
See Performance for the complete optimization reference.
Extension Points¶
- Custom mock data — Point
PROXMOX_MOCK_DATA_PATHat a JSON/YAML file with initial mock state - New Proxmox version — Run the codegen pipeline, store artifacts under
generated/proxmox/<version>/ - Custom middleware — Add FastAPI middleware for auth, logging, or rate limiting in
main.py - New SDK backend — Implement
AbstractBackend.request()andAbstractBackend.close(), register in_create_backend()
Testing Strategy¶
| Test type | Scope | File |
|---|---|---|
| Unit | Schema loading and validation | test_schema.py |
| Unit | Individual CRUD operations | test_mock_routes.py |
| Unit | Client auth and request logic | test_proxmox_client.py (mocked) |
| Integration | Full app startup in both modes | test_main_app.py |
| Integration | Custom mock data loading | test_custom_mock_data.py |
| E2E | Manual via Swagger UI | — |
| E2E | Real Proxmox environment | Requires live cluster |