Skip to main content

fakepve

Buy me a coffee at ko-fi.com

A lightweight fake of the Proxmox VE API, for testing code that drives Proxmox without needing a cluster, and for putting that code through the things a real cluster does to it: slow shutdowns, locked VMs, lost quorum, flaky networks, Ceph trouble.

It is for people writing Ansible modules, Terraform providers, proxmoxer scripts, and Go, Python or JavaScript clients for Proxmox, and for anyone who wants their tests and pipelines to run without a PVE host. It is one Python process on aiohttp: no PVE, QEMU, Ceph or corosync.

Test tool: bind it to loopback. fakepve has no real security. Its default login, root@pam / secret, is public, so anyone who can reach the port can do anything to the fake. Run it on a loopback address (the default), publish container ports as 127.0.0.1:8006:8006, and set PVE_PASS when anyone but you can reach the port. See the security policy.

Why

A real cluster is slow to build, hard to break on purpose and impossible to share between pipelines. The failures that matter to a client (a shutdown that outlasts its timeout, a VM locked by a backup, a node that disappears, a task that ends in TASK ERROR) are exactly the ones that are hard to produce. fakepve answers like PVE 8/9 does, with PVE's status codes and its own wording, and lets a test cause each of those failures with one line.

Quick start

pip install 'fakepve[crypto]'
fakepve examples/guests.json --time-scale 0
fakepve listening on https://127.0.0.2:8006

In another terminal (the login is root@pam / secret; -k because the certificate is self-signed):

$ curl -sk -d username=root@pam -d password=secret https://127.0.0.2:8006/api2/json/access/ticket
{"data": {"ticket": "PVE:root@pam:...", "CSRFPreventionToken": "...", "username": "root@pam", "cap": {}}}

From pytest, with the plugin (pip install 'fakepve[pytest]'; see pytest): the fakepve fixture is a started fake with a certificate your client can verify, and works with xdist.

import requests

def test_vms(fakepve, fakepve_url, fakepve_cafile):
    fakepve.add_vm(100, 'vm1', status='running')
    ticket = requests.post(fakepve_url + '/api2/json/access/ticket', verify=fakepve_cafile,
                           data={'username': 'root@pam', 'password': 'secret'}).json()['data']['ticket']
    vms = requests.get(fakepve_url + '/api2/json/cluster/resources?type=vm', verify=fakepve_cafile,
                       cookies={'PVEAuthCookie': ticket}).json()['data']
    assert [vm['name'] for vm in vms] == ['vm1']

Or in the same process, by hand:

from fakepve import FakePve
from fakepve.certs import make_cert

async def test_shutdown(tmp_path):
    certfile, keyfile, _ = make_cert(str(tmp_path))
    pve = FakePve(user='root@pam', password='secret')
    vm = pve.add_vm(100, 'vm1', status='running', config={'scsi0': 'local-lvm:vm-100-disk-0'})
    vm.shutdown_secs = 90           # slower than PVE's default shutdown timeout
    await pve.start(certfile, keyfile)
    try:
        ...  # drive https://{pve.host}:{pve.port} with your client
    finally:
        await pve.stop()

What it does

  • Logins as PVE has them: tickets with CSRF tokens and expiry, API tokens, optional per-path permissions, two-factor logins (the NeedTFA answer).
  • Every endpoint of the PVE 9 API schema answers: 680 methods on 449 paths. Parameters, including property strings such as net0=virtio,bridge=vmbr0, are validated with PVE's wording (HTTP 400 with per-field errors), under /api2/json and /api2/extjs; permissions are checked as the schema states them, and answers have the shape PVE's returns declares.
  • Stateful where a client reads back what it did: VM power, config and pending changes, tasks with real UPIDs that run, hold the VM config lock and keep a log, storage content, guest agent, consoles over websocket.
  • Real errors, by name: 2314 errors PVE can return, catalogued per method from the PVE sources, each raised with pve.fail(..., error='name'). Errors raised in a PVE worker end a task with TASK ERROR as they do on a node.
  • Faults on demand: slow or hanging guests, config and backup locks, migrations, HA, lost quorum, offline nodes, slow and flaky networks, Ceph slow or down, full storage, expired tickets, 403s, arbitrary failures.
  • Time you control: time_scale turns PVE seconds into real ones, from "every task finishes at once" to real time.
  • Several fakes at once: each instance takes its own loopback address, so all can use port 8006.
  • Easy to run in CI: a command line, a pytest-friendly class, a Dockerfile, and recipes for GitHub, Forgejo and Gitea, and GitLab.

It is a fake, not a copy of PVE: outside the hand-written areas a write succeeds and changes nothing. The details and the known gaps are in How it works.

Documentation

  • Getting started: install, first requests with curl, from Python, the guests file.
  • Command line: every option and environment variable.
  • pytest: the fixtures.
  • Python API: every attribute and method of FakePve and FakeVm.
  • Scenarios: a recipe for each fault, with the exact response the client sees.
  • Errors: the catalogue, listing, triggering, placeholders, limits.
  • CI: pytest, background processes, containers, GitHub, Forgejo, GitLab, certificates.
  • How it works: architecture and refreshing the data for a new PVE release.
  • Endpoint reference: every path and method, generated.
  • Security policy: what the fake is and is not, and how to report a vulnerability.
  • Contributing: checks, and building and publishing the documentation site.
  • examples/: runnable examples for aiohttp, requests, proxmoxer, curl and CI.

Support

fakepve is free and always will be. If it saves you time, you can buy me a coffee at ko-fi.com/qisback.

Buy me a coffee at ko-fi.com

Licence

Copyright Laurence Horrocks-Barlow. Licensed under the GNU Affero General Public License, version 3 or later; see LICENSE.

The files in src/fakepve/data/ are derived from Proxmox VE: the API schema from its API viewer (apidoc.js), and the error messages from its sources at https://git.proxmox.com. Proxmox VE is also AGPL-3.0, so they are distributed under the same terms.

Not affiliated with or endorsed by Proxmox Server Solutions GmbH. Proxmox is a registered trademark of Proxmox Server Solutions GmbH.

Metadata

Release files for fakepve 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fakepve 0.2.0
File Size Uploaded Provenance
fakepve-0.2.0.tar.gz 316.7 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for fakepve 0.2.0
File Interpreter ABI Platform
fakepve-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 476.6 kB

Release files / fakepve-0.2.0.tar.gz

Download URL fakepve-0.2.0.tar.gz
Size 316.7 kB
Tags Source
SHA-256 checksum
How to use checksums
0ff197f3eb3070ac57790a8d9ffe7b4af403b1bc2717a1ffc96afb2b5be78a08
BLAKE2b-256 checksum
How to use checksums
f8720188ae53795e261ee36d52c48653ba94ecbc789393345a4d06f4c6614d7b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Release files / fakepve-0.2.0-py3-none-any.whl

Download URL fakepve-0.2.0-py3-none-any.whl
Size 159.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b01973924e1337eaf14ac7e0e42c05b37621f025f9c233f12c0592eb39c3b9a8
BLAKE2b-256 checksum
How to use checksums
4a3dcee1f80e8aee386e12659566b7bcfe97387b4565a4723b43a7225da50653
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Security for fakepve 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for fakepve-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page