fakepve
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 as127.0.0.1:8006:8006, and setPVE_PASSwhen 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
NeedTFAanswer). - 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-fielderrors), under/api2/jsonand/api2/extjs; permissions are checked as the schema states them, and answers have the shape PVE'sreturnsdeclares. - 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 config and content, pools, the firewall, 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 withTASK ERRORas 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_scaleturns 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
FakePveandFakeVm. - 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.
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.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| fakepve-0.3.0.tar.gz | 381.8 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fakepve-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 580.8 kB
Release files / fakepve-0.3.0.tar.gz
| Download URL | fakepve-0.3.0.tar.gz |
|---|---|
| Size | 381.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
58b35955684ef0b067ec54b25f69b37ba6dff7e4ed424808aed8989754c8cc62
|
|
BLAKE2b-256 checksum How to use checksums |
24933bf44bc6217f871880e75f9de54f3631921ad97a72cd1efb79295105107d
|
| 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 logRelease files / fakepve-0.3.0-py3-none-any.whl
| Download URL | fakepve-0.3.0-py3-none-any.whl |
|---|---|
| Size | 199.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d79ed0f982618f7902b56f22dea4032a66f9bf321f26e8498a162d6422d59a1a
|
|
BLAKE2b-256 checksum How to use checksums |
63d3b0df1af3671d523fa6256edf47d05a15f0a4f716d5e980a3df47bc9268ff
|
| 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 logSecurity for fakepve 0.3.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.
Attestation for fakepve-0.3.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 logA 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.