Language / Язык: English | Русский
Stateful asynchronous VMware vSphere API simulator for testing API clients and infrastructure tooling without a real ESXi/vCenter cluster.
The simulator is backed by PostgreSQL and exposes native vCenter surfaces:
REST Automation API (/api, legacy /rest) and SOAP VIM/PBM (/sdk).
Semantic handlers persist inventory, sessions, tasks, tags, content libraries,
and permissions; power/clone/relocate/snapshot operations run as durable CIS
tasks with real task ids.
Coverage is tracked against the public vSphere Automation API operations index (~1037 unique verb+path routes in the simulator registry).
Two layers (read this before the table):
| Layer | Share (major 9) | Meaning |
|---|---|---|
| Core deep handlers | ~104 routes (~10%) | Inventory, VM lifecycle, tasks, tagging, content library, appliance, authz — real PostgreSQL semantics |
| DB-backed stub surface | remaining registry (~90%) | Seeded non-empty JSON for the rest of the Broadcom route table (lab stand-ins, not production parity) |
| Catalog major | vSphere label | Catalog floor / universe | Floor coverage |
|---|---|---|---|
| 6 | 7.0 | 31 / 1077 | 2.9% |
| 7 | 7.0 U3 | 77 / 1077 | 7.2% |
| 8 | 8.0 | 103 / 1077 | 9.6% |
| 9 | 8.0 U2 (Automation 9.1 surface) | 1077 / 1077 | 100% route registry |
At major 9 the full route registry is served (no known path 501s): deep
handlers plus stubs. Hot-swap (POST /ui/api/contract/apply?major=N) only
changes the catalog major used by the Web UI / evidence reports. See
Compatibility, compatibility 0.1.0,
and API coverage.
This is measurable route-registry and handler coverage for a laboratory simulator — not a claim that every vSphere edge case or ESXi-hardware behavior is reproduced identically to production vCenter.
Image: inecs/vmware-api-simulator
Requires a git checkout of this repository (Compose mounts
docker/gateway/ and docker/tls/ next to the compose file).
docker compose -f docker-compose.release.yml up -d --wait
# seed runs automatically; re-run manually if you wiped the DB:
# docker compose -f docker-compose.release.yml run --rm --entrypoint python \
# simulator -m app.simulation.seed_cli
curl -sk https://localhost/health/ready
SID=$(curl -sk -u 'administrator@vsphere.local:VMware1!' -X POST \
https://localhost/api/session | tr -d '"')
curl -sk -H "vmware-api-session-id: $SID" https://localhost/api/vcenter/vmOr: make release-up (seed is part of the release stack)
helm upgrade --install vmware-sim ./helm/vmware-api-simulator \
-n vmware-sim --create-namespace \
-f ./helm/vmware-api-simulator/values-ingress-example.yaml \
--set certManager.email=you@example.com \
--set ingress.hosts[0].host=vmware-sim.example.com \
--set ingress.tls[0].hosts[0]=vmware-sim.example.com \
--set secret.ticketSigningKey="$(openssl rand -hex 32)"Requires an Ingress controller and cert-manager. Details: Kubernetes / Helm.
- Lab UI + REST (Compose gateway): https://localhost/
- FastAPI schema docs: https://localhost/docs
- Default seeded admin:
administrator@vsphere.local/VMware1!
Build and run the bind-mounted development stack from this repository:
make install
make up
make seed PROFILE=small
curl -sk https://localhost/health/ready
curl -sk https://localhost/api/appliance/system/version- HTTPS gateway (primary vCenter entry):
https://localhost - HTTP lab face:
http://localhost - PostgreSQL (localhost only):
5434 - Internal FastAPI process (not published to the host):
8080 - The checked-in
docker/tls/server.keyis a lab-only localhost cert; do not reuse it outside local Compose. - FastAPI schema docs: https://localhost/docs
Interactive console with light/dark themes, endpoint catalog for vSphere majors 6–9, request/response editing, and runtime contract hot-swap.
Full walkthrough and more screenshots: Web UI.
Password VMware1! for all seeded principals:
| User | Role |
|---|---|
administrator@vsphere.local |
Administrator |
readonly@vsphere.local |
ReadOnly |
operator@vsphere.local |
VirtualMachinePowerUser |
vmadmin@vsphere.local |
VirtualMachineAdministrator |
Documentation is bilingual. Use the Language / Язык switcher at the top of each page, or open the Russian root README.ru.md. Index: docs/README.md · docs/ru/README.md.
| Guide | Description |
|---|---|
| Getting started | First successful lab session |
| Configuration | Environment variables and Compose |
| Authentication | Sessions, vmware-api-session-id, privileges |
| API versions | Catalog majors 6–9 and hot-swap |
| API surface | REST/SOAP routing, coverage registry, stubs |
| API coverage | Broadcom universe vs implemented surface |
| Clients & examples | Python, Go, Java, Perl, Ansible, Terraform, Pulumi |
| Seed profiles | Deterministic inventory fixtures |
| Domains | Session, inventory, VM, storage, networking, tagging, SOAP, tasks, … |
| Web UI | Interactive console and catalogs |
| Operations | Reseed, migrate, release, upgrade |
| Kubernetes / Helm | Hub image + Ingress + Let's Encrypt |
| Security | Lab threat model and credentials |
| Observability | Health endpoints and logging |
| Ports | Published host ports and internal services |
| Troubleshooting | Common failure modes |
| FAQ | Short answers |
| Architecture | Component boundaries |
| Compatibility | Evidence model and release matrix |
Runnable cookbooks live under examples/. The
pulumi-vsphere lab suite
(nonempty output checks, HTML report) lives under
pulumi-tests/ — run with make pulumi-tests.
Latest lab run (2026-07-18): offline 161 passed; test-vsphere probes
green; full pulumi-tests 7/7 with REST matrix 1987/1987 (critical=0).
See pulumi-tests/README.md.
import requests
requests.packages.urllib3.disable_warnings()
session = requests.post(
"https://localhost/api/session",
auth=("administrator@vsphere.local", "VMware1!"),
verify=False, # local self-signed development certificate only
)
headers = {"vmware-api-session-id": session.json()}
vms = requests.get("https://localhost/api/vcenter/vm", headers=headers, verify=False)
print(vms.json())SOAP / VIM clients (pyvmomi, govmomi, hashicorp/vsphere Terraform provider,
Pulumi) point at https://localhost/sdk with the same credentials.
make up / make down / make logs / make dev
make seed # large vSphere seed (10 hosts / 1000 VMs)
VSPHERE_PROFILE=small make seed # compact inventory (3 hosts / 5 VMs)
make test # unit + contract (offline)
make test-vsphere # native vSphere unit + integration + surface + matrix
make vsphere-surface # probe REST coverage registry against the running gateway
make vsphere-matrix # full REST matrix: all verbs × majors 6-9 (no 5xx)
make evidence # regenerate evidence/vsphere-*.json ledgers
make db-migrate
make shell
make ci # ruff + mypy + offline pytest + surface probe
make release # build + push runtime image to Docker Hub
make release-up # pull/start docker-compose.release.yml
make release-seed PROFILE=smallDocker Hub release (requires docker login as the Hub owner; see
Operations):
make release # inecs/vmware-api-simulator:<pyproject version> + :latest
make release VERSION=0.2.0 # override tag
make release-build # build/tag only, no push
make release-up && make release-seed # run the published stack locally- Not a hypervisor: no ESXi/KVM execution on bare metal or nested hosts.
- Not a drop-in multi-tenant production vCenter replacement.
- No Supervisor/Tanzu control plane, no NSX Manager, no deep vSAN, no
SAML/OIDC federation, no VECS certificate store — lab-shaped stand-ins
exist for some of these (seeded, non-binary-compatible data). HttpNfcLease
/ content-library transfer handshakes are implemented on
/nfcand related REST/SOAP paths, but not production-binary-compatible NFC uploads; see docs/api-coverage.md. - Remote IdP / LDAP / live NSX / live ACME directories are simulated locally; they do not call real external systems.
- An optional legacy Proxmox VE stub plane exists behind
ENABLE_PVE_STUB(off by default) from a shared platform lineage; it is not the primary surface of this project.
Apache-2.0 — see LICENSE.
Web UI console guide: docs/web-ui.md.
