Skip to content

Using the Proxmox SDK with Mock Data

The proxmox-sdk SDK provides built-in mock support for zero-setup testing and development — no real Proxmox server required!


Quick Start

Async Usage

from proxmox_sdk.sdk import ProxmoxSDK

# Create a mock SDK instance
async with ProxmoxSDK.mock() as proxmox:
    # Query mock data
    nodes = await proxmox.nodes.get()
    print(f"Nodes: {nodes}")

    # Create mock resources
    vm = await proxmox.nodes("pve").qemu.post(vmid=100, name="test-vm")
    print(f"Created VM: {vm}")

    # Retrieve created resource
    retrieved = await proxmox.nodes("pve").qemu(100).get()
    print(f"Retrieved VM: {retrieved}")

Sync Usage (No async/await)

from proxmox_sdk.sdk import ProxmoxSDK

# Create a mock SDK instance (blocking)
with ProxmoxSDK.sync_mock() as proxmox:
    # All API calls block until complete
    nodes = proxmox.nodes.get()
    print(f"Nodes: {nodes}")

    # Create mock resources
    vm = proxmox.nodes("pve").qemu.post(vmid=100, name="test-vm")
    print(f"Created VM: {vm}")

Features

Zero Setup — No real Proxmox server needed ✅ In-Memory CRUD — Create, read, update, delete mock resources ✅ Deterministic Data — Same seed produces same data (testable) ✅ Schema-Driven — Mock data respects Proxmox OpenAPI schema ✅ Multi-Service Support — PVE, PMG, PBS ✅ State Persistence — Changes persist during runtime


Detailed Guide

from proxmox_sdk.sdk import ProxmoxSDK

async with ProxmoxSDK.mock() as proxmox:
    # proxmox is the root ProxmoxResource
    nodes = await proxmox.nodes.get()

    # Automatic cleanup when exiting context

Async Manual Lifecycle

from proxmox_sdk.sdk import ProxmoxSDK

proxmox_sdk = ProxmoxSDK.mock()
proxmox = proxmox_sdk._root  # Access the root resource

try:
    nodes = await proxmox.nodes.get()
finally:
    await proxmox_sdk.close()
from proxmox_sdk.sdk import ProxmoxSDK

with ProxmoxSDK.sync_mock() as proxmox:
    nodes = proxmox.nodes.get()
    print(nodes)

    # Automatic cleanup when exiting context

Sync Manual Lifecycle

from proxmox_sdk.sdk import ProxmoxSDK

proxmox = ProxmoxSDK.sync_mock()

try:
    nodes = proxmox.nodes.get()
    print(nodes)
finally:
    proxmox.close()

Common Workflows

Listing Resources

from proxmox_sdk.sdk import ProxmoxSDK

with ProxmoxSDK.sync_mock() as proxmox:
    # List nodes
    nodes = proxmox.nodes.get()
    print(f"Nodes: {nodes}")

    # List VMs on a node
    vms = proxmox.nodes("pve").qemu.get()
    print(f"VMs: {vms}")

    # List containers (LXC)
    containers = proxmox.nodes("pve").lxc.get()
    print(f"Containers: {containers}")

Creating Resources

with ProxmoxSDK.sync_mock() as proxmox:
    # Create a VM
    vm = proxmox.nodes("pve").qemu.post(
        vmid=100,
        name="my-vm",
        memory=2048,
        cores=2
    )
    print(f"Created: {vm}")

Retrieving Specific Resources

with ProxmoxSDK.sync_mock() as proxmox:
    # Get a specific VM
    vm = proxmox.nodes("pve").qemu(100).get()
    print(f"VM 100: {vm}")

    # Get node status
    node_status = proxmox.nodes("pve").status.get()
    print(f"Node status: {node_status}")

Updating Resources

with ProxmoxSDK.sync_mock() as proxmox:
    # Update a VM (PUT replaces all fields)
    updated = proxmox.nodes("pve").qemu(100).put(
        name="updated-vm",
        memory=4096
    )
    print(f"Updated: {updated}")

    # Patch a VM (PATCH updates specific fields)
    patched = proxmox.nodes("pve").qemu(100).patch(
        name="patched-vm"
    )
    print(f"Patched: {patched}")

Deleting Resources

with ProxmoxSDK.sync_mock() as proxmox:
    # Delete a VM
    result = proxmox.nodes("pve").qemu(100).delete()
    print(f"Deleted: {result}")

Specifying Schema Versions

Control which Proxmox OpenAPI schema to use:

from proxmox_sdk.sdk import ProxmoxSDK

# Use latest version (default)
async with ProxmoxSDK.mock() as proxmox:
    nodes = await proxmox.nodes.get()

# Use a specific version
async with ProxmoxSDK.mock(schema_version="9.2") as proxmox:  # or '9.1.11' for previous version
    nodes = await proxmox.nodes.get()

# Sync version
with ProxmoxSDK.sync_mock(schema_version="9.2") as proxmox:  # or '9.1.11' for previous version
    nodes = proxmox.nodes.get()

Available versions depend on your installation. See Mock API documentation for a list of supported versions.


Multi-Service Support

Create mock instances for different Proxmox services:

from proxmox_sdk.sdk import ProxmoxSDK

# Proxmox VE (default)
async with ProxmoxSDK.mock(service="PVE") as proxmox:
    nodes = await proxmox.nodes.get()

# Proxmox Mail Gateway
async with ProxmoxSDK.mock(service="PMG") as proxmox:
    # PMG-specific endpoints
    pass

# Proxmox Backup Server
async with ProxmoxSDK.mock(service="PBS") as proxmox:
    # PBS-specific endpoints
    pass

# Proxmox Datacenter Manager
async with ProxmoxSDK.mock(service="PDM") as proxmox:
    # PDM-specific endpoints, backed by the real generated PDM schema
    pass

PDM mock mode is schema-backed

ProxmoxSDK.mock(service="PDM") (and PDMClient.mock(), see PDM HOW-TO) load the real generated PDM OpenAPI schema via load_pdm_generated_openapi() (246 paths / 318 operations) instead of falling back to the PVE schema or returning empty responses. See the PDM Codegen Path for how that schema is produced.


Testing

Unit Tests

import pytest
from proxmox_sdk.sdk import ProxmoxSDK

@pytest.mark.asyncio
async def test_node_listing():
    """Test listing nodes from mock API."""
    async with ProxmoxSDK.mock() as proxmox:
        nodes = await proxmox.nodes.get()
        assert isinstance(nodes, list)
        assert len(nodes) > 0
        assert nodes[0].get("node") is not None

@pytest.mark.asyncio
async def test_vm_creation():
    """Test creating a VM in mock API."""
    async with ProxmoxSDK.mock() as proxmox:
        vm = await proxmox.nodes("pve").qemu.post(
            vmid=100,
            name="test-vm"
        )
        assert vm.get("vmid") == 100
        assert vm.get("name") == "test-vm"

@pytest.mark.asyncio
async def test_vm_retrieval():
    """Test retrieving a created VM."""
    async with ProxmoxSDK.mock() as proxmox:
        # Create
        created = await proxmox.nodes("pve").qemu.post(
            vmid=101,
            name="test-vm-2"
        )

        # Retrieve
        retrieved = await proxmox.nodes("pve").qemu(101).get()
        assert retrieved.get("vmid") == created.get("vmid")
        assert retrieved.get("name") == created.get("name")

Integration Tests

def test_vm_lifecycle_sync():
    """Test full VM lifecycle using sync API."""
    with ProxmoxSDK.sync_mock() as proxmox:
        # Create
        vm = proxmox.nodes("pve").qemu.post(
            vmid=200,
            name="lifecycle-test"
        )
        assert vm["vmid"] == 200

        # Retrieve
        retrieved = proxmox.nodes("pve").qemu(200).get()
        assert retrieved["vmid"] == 200

        # Update
        updated = proxmox.nodes("pve").qemu(200).put(
            name="lifecycle-updated"
        )
        assert updated["name"] == "lifecycle-updated"

        # Delete
        proxmox.nodes("pve").qemu(200).delete()

        # Verify deletion (should raise or be empty, depending on mock behavior)

State Persistence

Mock state persists in memory during a single session but resets on restart:

with ProxmoxSDK.sync_mock() as proxmox:
    # Session 1: Create data
    vm = proxmox.nodes("pve").qemu.post(vmid=300, name="test")
    retrieved = proxmox.nodes("pve").qemu(300).get()
    print(retrieved)  # ✅ Works

# Context exits, state is lost

with ProxmoxSDK.sync_mock() as proxmox:
    # Session 2: Data is gone
    try:
        vm = proxmox.nodes("pve").qemu(300).get()
    except Exception:
        print("VM not found (state was reset)")  # ✅ Expected

For persistent mock data across sessions, see Custom Mock Data (FastAPI Mode).


Error Handling

The SDK raises ResourceException for API errors:

from proxmox_sdk.sdk import ProxmoxSDK
from proxmox_sdk.sdk.exceptions import ResourceException

with ProxmoxSDK.sync_mock() as proxmox:
    try:
        # Attempt invalid operation
        proxmox.nodes("nonexistent").qemu.get()
    except ResourceException as e:
        print(f"API Error: {e.status_code} - {e.status_message}")

Differences from Real Proxmox

Similarities

  • ✅ Same endpoint structure /api2/json/...
  • ✅ Same request/response format (JSON)
  • ✅ Same attribute-based navigation
  • ✅ Same method names (GET, POST, PUT, PATCH, DELETE)

Differences

  • ⚠️ No actual VM/container creation (mock only)
  • ⚠️ No permission validation (all operations allowed)
  • ⚠️ No task tracking (UPIDs not returned)
  • ⚠️ Limited data validation (basic schema compliance)
  • ⚠️ State resets on server restart (in-memory only)

Next Steps