Skip to content

Mock API Mode

Complete guide to using proxmox-sdk in mock mode for development and testing.


Overview

Mock mode provides a fully functional Proxmox API simulation with:

  • 675 generated operations across 449 Proxmox API paths
  • Metadata-driven route registration from bundled route_metadata.json
  • Lazy Pydantic model loading from route-group model shards
  • CRUD operations - Create, read, update, delete
  • Automatic data seeding - Sample data generated on first access
  • SQLite/WAL state by default - Changes persist across requests in the active mock namespace
  • Custom mock data - Load your own test data from JSON/YAML

Starting Mock Mode

Method 1: Dedicated Mock Server

proxmox-sdk-mock

This runs a standalone mock-only server.

Method 2: Main App in Mock Mode (Default)

# Mock mode is the default
uvicorn proxmox_sdk.main:app

# Or explicitly set mock mode
export PROXMOX_API_MODE=mock
uvicorn proxmox_sdk.main:app

Both methods provide the same functionality.


How Mock Data Works

Automatic Seeding

When you make your first GET request to an endpoint, mock data is automatically generated:

import httpx

# First GET request - data doesn't exist yet
response = httpx.get("http://localhost:8000/api2/json/nodes")

# Mock data automatically created and returned:
# [{"node": "pve", "status": "online", ...}]

State Persistence

Changes persist during the server lifetime through the configured mock-state backend. The default is SQLite/WAL, which stores objects, collection members, and tombstones as rows in a tempdir-scoped database:

# Create a VM
httpx.post(
    "http://localhost:8000/api2/json/nodes/pve/qemu",
    json={"vmid": 100, "name": "test-vm"}
)

# Later requests return the same VM
response = httpx.get("http://localhost:8000/api2/json/nodes/pve/qemu/100")
print(response.json())  # Returns the VM we created

Development state, not production persistence

The default SQLite database is scoped by mock namespace and schema fingerprint. It is designed for development and tests, not as a durable database. Set PROXMOX_MOCK_STATE_PATH if you need an explicit database path while debugging.

Mock State Backends

Backend Configure with Use case
SQLite/WAL PROXMOX_MOCK_STORE=sqlite or unset Default; best balance for local dev, tests, and concurrent reads
Shared memory PROXMOX_MOCK_STORE=shared-memory Legacy compatibility; uses a shared-memory JSON blob and file locks
Dict PROXMOX_MOCK_STORE=dict Process-local tests where isolation matters more than cross-process state

SQLite avoids serializing the entire mock state for every read/write. Payload blobs use orjson when it is installed and fall back to the standard json module otherwise.


Custom Mock Data

Load your own test data to simulate specific scenarios.

JSON Format

Create mock-data.json:

{
  "/api2/json/nodes": [
    {
      "node": "pve1",
      "status": "online",
      "cpu": 0.25,
      "maxcpu": 16,
      "mem": 8589934592,
      "maxmem": 68719476736
    },
    {
      "node": "pve2",
      "status": "online",
      "cpu": 0.50,
      "maxcpu": 32,
      "mem": 17179869184,
      "maxmem": 137438953472
    }
  ],
  "/api2/json/cluster/resources": [
    {"type": "node", "node": "pve1", "status": "online"},
    {"type": "node", "node": "pve2", "status": "online"},
    {"type": "qemu", "vmid": 100, "name": "prod-web-01", "node": "pve1"},
    {"type": "qemu", "vmid": 101, "name": "prod-db-01", "node": "pve2"}
  ]
}

YAML Format

Create mock-data.yaml:

/api2/json/nodes:
  - node: pve1
    status: online
    cpu: 0.25
    maxcpu: 16
  - node: pve2
    status: online
    cpu: 0.50
    maxcpu: 32

/api2/json/cluster/resources:
  - type: node
    node: pve1
    status: online
  - type: qemu
    vmid: 100
    name: prod-web-01
    node: pve1

Load Custom Data

export PROXMOX_MOCK_DATA_PATH=./mock-data.json
proxmox-sdk-mock

Place your file at the default path:

sudo mkdir -p /etc/proxmox-sdk
sudo cp mock-data.json /etc/proxmox-sdk/
proxmox-sdk-mock
docker run -p 8000:8000 \
  -v $(pwd)/mock-data.json:/data/mock.json \
  -e PROXMOX_MOCK_DATA_PATH=/data/mock.json \
  ghcr.io/emersonfelipesp/proxmox-sdk:latest

CRUD Operations in Detail

GET Requests

Collections (arrays):

# Returns array of items
response = httpx.get("http://localhost:8000/api2/json/nodes")
# [{"node": "pve", ...}]

Single Resources (objects):

# Returns single object
response = httpx.get("http://localhost:8000/api2/json/nodes/pve/status")
# {"uptime": 12345, "cpu": 0.5, ...}

POST Requests

Create new items in collections:

response = httpx.post(
    "http://localhost:8000/api2/json/nodes/pve/qemu",
    json={
        "vmid": 100,
        "name": "test-vm",
        "memory": 2048,
        "cores": 2,
    }
)

# Item added to collection AND created as individual resource
# Now accessible at:
# - /api2/json/nodes/pve/qemu (in the collection)
# - /api2/json/nodes/pve/qemu/100 (individual resource)

PUT Requests

Replace entire resource:

response = httpx.put(
    "http://localhost:8000/api2/json/nodes/pve/qemu/100",
    json={
        "vmid": 100,
        "name": "test-vm-renamed",
        "memory": 4096,  # Changed
        "cores": 4,      # Changed
    }
)

# Entire object replaced with new values

PATCH Requests

Partial update (merge):

response = httpx.patch(
    "http://localhost:8000/api2/json/nodes/pve/qemu/100",
    json={"memory": 8192}
)

# Only 'memory' field updated, other fields unchanged

DELETE Requests

Remove resources:

response = httpx.delete("http://localhost:8000/api2/json/nodes/pve/qemu/100")

# Resource removed from:
# - Individual endpoint (/api2/json/nodes/pve/qemu/100)
# - Parent collection (/api2/json/nodes/pve/qemu)

Query Parameters

Mock endpoints support query parameter filtering:

# Get all VMs
all_vms = httpx.get("http://localhost:8000/api2/json/cluster/resources?type=qemu")

# Filter by status
running = httpx.get("http://localhost:8000/api2/json/cluster/resources?type=qemu&status=running")

Environment Variables

Configure mock mode behavior:

Variable Default Description
PROXMOX_API_MODE mock Set to mock for mock mode
PROXMOX_MOCK_SCHEMA_VERSION latest OpenAPI schema version to use
PROXMOX_MOCK_DATA_PATH /etc/proxmox-sdk/mock-data.json Custom mock data file path
PROXMOX_MOCK_STORE sqlite Mock state backend: sqlite, shared-memory, or dict
PROXMOX_MOCK_STATE_PATH tempdir scoped by namespace Optional SQLite mock-state DB path
HOST 0.0.0.0 Server host to bind
PORT 8000 Server port

Use Cases

Integration Testing

import httpx
import pytest

@pytest.fixture
def proxmox_client():
    return httpx.Client(base_url="http://localhost:8000/api2/json")

def test_create_vm(proxmox_client):
    response = proxmox_client.post(
        "/nodes/pve/qemu",
        json={"vmid": 100, "name": "test", "memory": 2048}
    )
    assert response.status_code == 200

    # Verify VM was created
    vm = proxmox_client.get("/nodes/pve/qemu/100")
    assert vm.json()["vmid"] == 100

CI/CD Pipelines

# .github/workflows/test.yml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Start Mock Proxmox API
        run: |
          pip install proxmox-sdk
          proxmox-sdk-mock &
          sleep 2

      - name: Run Integration Tests
        run: pytest tests/integration/

Local Development

# Start mock API
proxmox-sdk-mock

# In another terminal, develop your application
python my_proxmox_app.py

Your application can make Proxmox API calls without needing a real cluster!


Limitations

Mock Limitations

  • No real Proxmox logic - Doesn't validate Proxmox-specific business rules
  • Memory-only storage - Data lost on restart
  • Simplified state - Doesn't track complex resource relationships
  • No async operations - Real Proxmox tasks are immediate in mock mode

For production use or testing against real Proxmox behavior, use Real API Mode.


Next Steps