Initial commit: VMware vSphere API simulator scaffold.
Add the FastAPI app, PostgreSQL migrations, Docker/Helm packaging, API contracts, docs, client examples, and the unit/integration/compatibility test suite for local client and tooling labs without a real vCenter.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
**Language / Язык:** [English](README.md) | [Русский](ru/README.md)
|
||||
|
||||
# Documentation
|
||||
|
||||
Guides for the VMware vSphere API simulator. Switch language with the header on each
|
||||
page. Russian mirrors live under [`ru/`](ru/README.md).
|
||||
|
||||
| Guide | Description |
|
||||
|---|---|
|
||||
| [Getting started](getting-started.md) | First successful lab session |
|
||||
| [Configuration](configuration.md) | Environment variables and Compose |
|
||||
| [Authentication](authentication.md) | Sessions, `vmware-api-session-id`, privileges |
|
||||
| [API versions](api-versions.md) | Catalog majors 6–9 and hot-swap |
|
||||
| [API surface](api-surface.md) | REST/SOAP routing, coverage registry, stubs |
|
||||
| [API coverage](api-coverage.md) | Broadcom universe vs implemented surface |
|
||||
| [Clients & examples](clients.md) | Python, Go, Java, Perl, Ansible, Terraform, Pulumi |
|
||||
| [Seed profiles](seed-profiles.md) | Deterministic inventory fixtures |
|
||||
| [Domains](domains/README.md) | Session, inventory, VM, storage, networking, tagging, SOAP, tasks, … |
|
||||
| [Web UI](web-ui.md) | Interactive console and catalogs |
|
||||
| [Operations](operations.md) | Reseed, migrate, release, upgrade |
|
||||
| [Kubernetes / Helm](kubernetes.md) | Hub image + Ingress + Let's Encrypt |
|
||||
| [Security](security.md) | Lab threat model and credentials |
|
||||
| [Observability](observability.md) | Health endpoints and logging |
|
||||
| [Ports](ports.md) | Published host ports and internal services |
|
||||
| [Troubleshooting](troubleshooting.md) | Common failure modes |
|
||||
| [FAQ](faq.md) | Short answers |
|
||||
| [Architecture](architecture.md) | Component boundaries |
|
||||
| [Compatibility](compatibility.md) | Evidence model and release matrix |
|
||||
|
||||
Runnable cookbooks: [`examples/`](../examples/README.md).
|
||||
Integration suites: [`pulumi-tests/`](../pulumi-tests/README.md) (`make pulumi-tests`).
|
||||
@@ -0,0 +1,135 @@
|
||||
**Language / Язык:** [English](api-coverage.md) | [Русский](ru/api-coverage.md)
|
||||
|
||||
# vSphere API coverage matrix
|
||||
|
||||
Auto-oriented registry: [`app/vsphere/rest/coverage.py`](../app/vsphere/rest/coverage.py).
|
||||
Broadcom universe stubs: [`app/vsphere/rest/universe.json`](../app/vsphere/rest/universe.json) (from the public operations index).
|
||||
Per-major floors + stub OpenAPI bundles: [`app/vsphere/contracts/matrix.py`](../app/vsphere/contracts/matrix.py) → `contracts/vsphere/<version>/manifest.json`.
|
||||
|
||||
## Broadcom vs this simulator
|
||||
|
||||
Public source (scraped): [vSphere Automation API Operations Index (9.1 Latest)](https://developer.broadcom.com/xapis/vsphere-automation-api/latest/operation-index/)
|
||||
|
||||
| Surface | Count | Notes |
|
||||
|---|---:|---|
|
||||
| Broadcom Operations Index | **1348** | GET 628 / POST 422 / DELETE 114 / PUT 93 / PATCH 91 |
|
||||
| Generated unique `verb + path` routes | **~1037** | Same HTTP path can back several named ops (`?action=…`, `$Task`) |
|
||||
| Simulator registry (core + stubs + `/rest`) | **1077** | Core deep handlers overwrite stub entries on the same path |
|
||||
| Core deep handlers | **104** | Seeded inventory / lifecycle / authz behaviour |
|
||||
| DB-backed surface rows (`vsphere_api_state`) | **~540+** | Seeded for every GET `/api` route + lab extras |
|
||||
|
||||
Regenerate universe after refreshing the index dump:
|
||||
|
||||
```bash
|
||||
python scripts/generate_vsphere_universe.py
|
||||
make vsphere-bundles
|
||||
```
|
||||
|
||||
Refresh live stats / regenerate artifacts:
|
||||
|
||||
```bash
|
||||
curl -sk https://localhost/ui/api/compatibility?major=9
|
||||
make vsphere-surface
|
||||
python scripts/write_vsphere_bundles.py
|
||||
python scripts/write_vsphere_evidence.py
|
||||
```
|
||||
|
||||
| Major | Label | Implemented / universe | Coverage | Notes |
|
||||
|---|---|---:|---:|---|
|
||||
| 6 | vSphere 7.0 | 31 / 1077 | 2.9% | Catalog/evidence floor only |
|
||||
| 7 | vSphere 7.0 U3 | 77 / 1077 | 7.2% | Catalog/evidence floor only |
|
||||
| 8 | vSphere 8.0 | 103 / 1077 | 9.6% | Catalog/evidence floor only |
|
||||
| 9 | vSphere 8.0 U2 / Automation 9.1 surface | **1077 / 1077** | **100%** | Deep handlers + DB-backed Broadcom surface |
|
||||
|
||||
Numbers come from `GET /ui/api/compatibility?major=N` and `evidence/vsphere-*.json` (`make vsphere-bundles`).
|
||||
|
||||
Hot-swap (`POST /ui/api/contract/apply?major=N`) changes the **catalog** major used by the Web UI / evidence reports. **Runtime always serves the full registered surface** — known paths are never HTTP 501’d by version floor.
|
||||
|
||||
## Planes
|
||||
|
||||
| Plane | Default | Notes |
|
||||
|---|---|---|
|
||||
| Native REST `/api`, `/rest` | on | Primary lab surface |
|
||||
| Native SOAP `/sdk` | on | PropertyCollector subset + VM tasks |
|
||||
| Proxmox `/api2/*` stub | **off** (`ENABLE_PVE_STUB=false`) | Optional legacy |
|
||||
|
||||
## Auth & synthetic data
|
||||
|
||||
| Item | Detail |
|
||||
|---|---|
|
||||
| Users | `administrator`, `readonly`, `operator`, `vmadmin` `@vsphere.local` / `VMware1!` |
|
||||
| AuthZ | Role → privilege gate on mutate endpoints (403 `unauthorized`) |
|
||||
| Seed `large` | 10 hosts, **1000 VMs**, 4 datastores, DVS, folders, permissions |
|
||||
| Seed `demo-cluster` | 20 hosts, 1000 VMs (UI demo load) |
|
||||
| Seed `small` | 3 hosts, 5 named VMs (tests) |
|
||||
|
||||
## REST domains
|
||||
|
||||
### Deep (core) at major 9
|
||||
|
||||
- Session / CIS tasks / AuthZ roles+permissions / identity providers / TLS cert stub
|
||||
- VM list/get/create/delete/power, hardware, snapshots, clone, relocate, tools, guest identity/networking/power/customization, console tickets, template/unregister
|
||||
- Host list/get + maintenance + storage-device + networking
|
||||
- Datastore list/get + file metadata
|
||||
- Network list + DVS/DVPG create
|
||||
- Datacenter / cluster / folder (+children) / resource-pool CRUD
|
||||
- Tagging, content library + OVF, storage policies (+ VM associations), privileges
|
||||
- Appliance version/health/networking/timesync
|
||||
- `vapi` metamodel service list stub
|
||||
|
||||
### DB-backed Automation surface (Broadcom universe catch-all)
|
||||
|
||||
Remaining Automation API routes from the 9.1 operations index are registered and answered by [`app/vsphere/rest/stub_surface.py`](../app/vsphere/rest/stub_surface.py) against PostgreSQL:
|
||||
|
||||
- table `vsphere_api_state` (migration `011_vsphere_api_state.sql`)
|
||||
- seeded by `seed_api_surface()` on every profile including **`demo-cluster`** / UI `POST /ui/api/demo/load`
|
||||
- inventory overlay for VM hardware (cdrom/scsi/boot/…), host networking/storage, tagging, content libraries
|
||||
- PUT/PATCH persist into `vsphere_api_state`; POST appends collection rows; DELETE removes them
|
||||
|
||||
No `"stub": true` markers — probes require real seeded payloads on major 9.
|
||||
|
||||
## SOAP domains (govmomi / Terraform / Pulumi / pyvmomi)
|
||||
|
||||
- RetrieveServiceContent (+ TaskManager / SearchIndex / GuestOperationsManager / FileManager / OvfManager)
|
||||
- RetrieveProperties / RetrievePropertiesEx / **ContinueRetrievePropertiesEx** (pagination tokens; `<objects>` plural)
|
||||
- PropertyCollector: parent-chain Ancestors, one-hop `childEntity` ListFolder, ContainerView `view` traversal
|
||||
- Folder.childType as `ArrayOfString`; string props carry `xsi:type="xsd:string"` (govmomi decode)
|
||||
- Datastore.host as `ArrayOfDatastoreHostMount`; Cluster/Host **environmentBrowser**
|
||||
- **QueryConfigOption** / QueryConfigOptionEx / QueryConfigOptionDescriptor / QueryConfigTarget
|
||||
- CreateFilter / WaitForUpdatesEx (version tokens; empty polls)
|
||||
- FindByInventoryPath (govmomi paths omit root `Datacenters`), FindByUuid/Dns/Ip, FindChild
|
||||
- **CreateVM_Task** / CreateChildVM_Task, CreateFolder, Power/Clone/Snapshot/Rename/Reconfig/Relocate/Destroy/Unregister/MarkAsTemplate/CustomizeVM_Task + CancelTask
|
||||
- Guest file ops: ListFilesInGuest, InitiateFileTransferTo/FromGuest, DeleteFileInGuest, MakeDirectoryInGuest
|
||||
- Real task IDs from `vsphere_tasks` (including `info.result` MoRef on create/clone)
|
||||
- `/sdk/vimService.wsdl`, `/sdk/about.do`, `/pbm` stub
|
||||
- Type-strict MOR lookup: `VirtualApp:resgroup-*` does not resolve a plain ResourcePool (Terraform CreateVM path)
|
||||
|
||||
## REST extras for Ansible / Python apps
|
||||
|
||||
- VM power returns `{ "task": "task-…" }` for CIS task polling
|
||||
- Guest virtual filesystem: `/api/vcenter/vm/{vm}/guest/filesystem` (+ local-filesystem listing)
|
||||
- Content library update/download sessions for OVF push/pull lab flows
|
||||
|
||||
## Legacy `/rest`
|
||||
|
||||
`{ "value": … }` wrappers for vm/host/datastore/network/datacenter/cluster/power/appliance.
|
||||
|
||||
## Contract majors (browse vs runtime)
|
||||
|
||||
Hot-swap (`POST /ui/api/contract/apply?major=N`) still switches the **catalog** major for UI browse/evidence. **Runtime always serves the full registered surface** with deep handlers or DB-backed stubs — known paths are never HTTP 501’d by version floor. Catalog floors remain historical for documentation only.
|
||||
|
||||
## Platform surfaces (lab-available)
|
||||
|
||||
These were historically “deferred”; they now return **non-empty seeded lab data** and accept basic mutate:
|
||||
|
||||
| Area | REST | SOAP |
|
||||
|---|---|---|
|
||||
| NSX (tier0 / projects / edges / VPC / subnets) | Seeded Automation paths under `namespace-management` / `namespaces` | — |
|
||||
| Supervisor / WCP | namespaces, VM classes, supervisor summary/identity, infra policies | — |
|
||||
| vSAN | Storage policies with `policy_type: VSAN` (+ RAID1 lab policy) | — |
|
||||
| SAML / OIDC | `GET/POST/PATCH/DELETE /api/vcenter/identity/providers` (LocalOS + OIDC + SAML) | — |
|
||||
| VECS / certs | TLS, TLS CSR, trusted-root-chains, supervisor certs/signing-requests | — |
|
||||
| HttpNfcLease | `PUT/GET /nfc/{lease}/files/...` | `ImportVApp_Task`, `CreateImportSpec`, lease progress/complete |
|
||||
| Guest customization | GET+POST `/api/vcenter/vm/{vm}/guest/customization` | `CustomizeVM_Task` |
|
||||
|
||||
This is still a **lab-grade** stand-in (not a binary-compatible NSX Manager / real VECS store / full Broadcom device XML matrix). Perf/Event/Alarm remain answered but not deeply simulated.
|
||||
@@ -0,0 +1,87 @@
|
||||
**Language / Язык:** [English](api-surface.md) | [Русский](ru/api-surface.md)
|
||||
|
||||
# API surface
|
||||
|
||||
## Request path
|
||||
|
||||
1. Middleware assigns or forwards a request ID (`REQUEST_ID_HEADER`).
|
||||
2. FastAPI routes the request to the vSphere REST router (`/api`, `/rest`),
|
||||
the SOAP router (`/sdk`), or (if `ENABLE_PVE_STUB=true`) the optional
|
||||
legacy stub.
|
||||
3. `/api/session` (or `/rest/com/vmware/cis/session`, or SOAP `Login`)
|
||||
resolves a principal and issues a `vmware-api-session-id`.
|
||||
4. `require_read` / `require_privilege(...)` dependencies check the session's
|
||||
roles before revealing or mutating resources.
|
||||
5. A deep handler (core inventory/lifecycle/tagging/content/appliance logic)
|
||||
or the DB-backed stub surface executes against PostgreSQL-backed state.
|
||||
6. Long operations (power, clone, relocate, snapshot, OVF deploy) create a
|
||||
durable CIS task and return `{ "task": "task-…" }`.
|
||||
|
||||
## Two REST surfaces on one registry
|
||||
|
||||
- **Core (deep) handlers** — ~104 verb+path combinations across
|
||||
[`app/vsphere/rest/router.py`](../app/vsphere/rest/router.py),
|
||||
`vm_ext.py`, `inventory_ext.py`, `platform_rest.py`, `tagging_rest.py`,
|
||||
`content_rest.py`, `appliance_ext.py`, `nfc_rest.py`, `tasks.py`. These read
|
||||
and mutate the seeded inventory/tagging/content/appliance tables directly.
|
||||
- **DB-backed stub surface** —
|
||||
[`app/vsphere/rest/stub_surface.py`](../app/vsphere/rest/stub_surface.py)
|
||||
answers the remaining Broadcom Automation API operations index routes
|
||||
(registered from `universe.json`) against `vsphere_api_state`. GET returns
|
||||
live inventory-derived payloads when possible, otherwise seeded rows;
|
||||
PUT/PATCH persist into `vsphere_api_state`; POST appends collection rows;
|
||||
DELETE removes them. No `"stub": true` marker is returned — probes see real
|
||||
seeded payloads.
|
||||
|
||||
Both surfaces share one route table; core handlers take priority over stub
|
||||
entries registered for the same verb+path.
|
||||
|
||||
## Legacy `/rest`
|
||||
|
||||
[`app/vsphere/rest/legacy.py`](../app/vsphere/rest/legacy.py) wraps
|
||||
vm/host/datastore/network/datacenter/cluster/power/appliance reads (and VM
|
||||
power) in `{ "value": … }` envelopes for older `com.vmware.vcenter.*` clients.
|
||||
|
||||
## Errors ([`app/vsphere/errors.py`](../app/vsphere/errors.py))
|
||||
|
||||
| Status | `error_type` | Typical cause |
|
||||
|---|---|---|
|
||||
| 400 | `invalid_argument` / `already_exists` | Malformed body, duplicate name |
|
||||
| 401 | `unauthenticated` | Missing/invalid/expired session |
|
||||
| 403 | `unauthorized` | Session lacks the required privilege |
|
||||
| 404 | `not_found` | Unknown MOID/path parameter |
|
||||
| 409 | (handler-specific) | Illegal power-state transition, lock conflict |
|
||||
| 501 | `error` | Only reachable via the optional legacy stub's undeclared-method fallback |
|
||||
|
||||
All error bodies follow the vSphere Automation shape:
|
||||
`{ "error_type": "...", "messages": [{ "default_message": "...", "id": "...", "args": [] }] }`.
|
||||
|
||||
## Tasks
|
||||
|
||||
Async work (power, clone, snapshot, relocate, OVF deploy, guest customize)
|
||||
returns a task id. Poll:
|
||||
|
||||
```text
|
||||
GET /api/cis/tasks/{task}
|
||||
```
|
||||
|
||||
Task rows commit in `vsphere_tasks`; `progress` is `100` once `status` is
|
||||
`SUCCEEDED`/`FAILED`. HTTP 200/201 on the mutation request means "accepted",
|
||||
not "VM already in final state". See [Tasks](domains/tasks.md).
|
||||
|
||||
## Exploration
|
||||
|
||||
- Interactive FastAPI docs: `/docs`
|
||||
- Web UI method inspector: `/` → catalog → method
|
||||
- UI helper APIs: `/ui/api/catalog`, `/ui/api/method`, `/ui/api/compatibility`
|
||||
- Coverage registry: [`app/vsphere/rest/coverage.py`](../app/vsphere/rest/coverage.py)
|
||||
- Path-floor / catalog matrix: [`app/vsphere/contracts/matrix.py`](../app/vsphere/contracts/matrix.py)
|
||||
|
||||
## Compatibility endpoints
|
||||
|
||||
| Path | Format |
|
||||
|---|---|
|
||||
| `/ui/api/compatibility?major=N` | JSON |
|
||||
|
||||
See [Compatibility](compatibility.md) and [API coverage](api-coverage.md) for
|
||||
the full Broadcom-universe-vs-implemented breakdown.
|
||||
@@ -0,0 +1,77 @@
|
||||
**Language / Язык:** [English](api-versions.md) | [Русский](ru/api-versions.md)
|
||||
|
||||
# API versions (vSphere catalog majors 6–9)
|
||||
|
||||
The Web UI and evidence/compatibility reports browse four integer **catalog
|
||||
majors** that map onto vSphere Automation API label floors:
|
||||
|
||||
| Major | vSphere label | Contract version string |
|
||||
|---|---|---|
|
||||
| 6 | 7.0 | `7.0.0` |
|
||||
| 7 | 7.0 U3 | `7.0.3` |
|
||||
| 8 | 8.0 | `8.0.0` |
|
||||
| 9 | 8.0 U2 (Automation 9.1 surface) | `8.0.2` |
|
||||
|
||||
Definitions live in [`app/vsphere/contracts/matrix.py`](../app/vsphere/contracts/matrix.py)
|
||||
(`VERSIONS`, `PATH_FLOOR`). Each registered REST path has a **floor** — the
|
||||
lowest major at which it appears in the catalog — sourced from the same
|
||||
module. Undated paths default to the highest major (9) until catalogued.
|
||||
|
||||
## Runtime vs catalog
|
||||
|
||||
This is the most important distinction in the project:
|
||||
|
||||
- **Catalog major** — controls what the Web UI endpoint tree, `/ui/api/catalog`,
|
||||
and compatibility/evidence reports show for a given major.
|
||||
- **Runtime surface** — the simulator always serves the **full registered
|
||||
route table** with deep handlers or DB-backed stubs, independent of the
|
||||
active catalog major. A known path is never returned as HTTP 501 because of
|
||||
a version floor.
|
||||
|
||||
Hot-swapping the catalog major is therefore a **documentation/browse**
|
||||
switch, not a compatibility gate on live traffic. See
|
||||
[`available_for_request()`](../app/vsphere/contracts/matrix.py) for the exact
|
||||
policy.
|
||||
|
||||
## Cold start
|
||||
|
||||
`GET /api/appliance/system/version` reports the version string of the
|
||||
currently selected runtime source (defaults to `8.0.2` / major 9 unless the
|
||||
process overrides `app.state.runtime_source_version`).
|
||||
|
||||
## Hot-swap (catalog browse)
|
||||
|
||||
Browse any major in the Web UI catalog, or call:
|
||||
|
||||
```http
|
||||
POST /ui/api/contract/apply?major=7
|
||||
```
|
||||
|
||||
Effects:
|
||||
|
||||
- The Web UI catalog, `/ui/api/compatibility`, and evidence reports switch to
|
||||
major 7's floor and ledger (`evidence/vsphere-7.0.3.json`).
|
||||
- The change is **process-local** and **not persisted**; a restart returns to
|
||||
the default (major 9).
|
||||
- REST/SOAP routes already registered continue to answer with their real
|
||||
handlers regardless of the applied major.
|
||||
|
||||
### Client guidance
|
||||
|
||||
- Most clients (pyvmomi, govmomi, Terraform, Pulumi, Ansible `uri`) do not
|
||||
need to pin a catalog major — the runtime surface does not change shape
|
||||
based on it.
|
||||
- Use catalog majors when you specifically want the Web UI / evidence view to
|
||||
reflect an older vSphere label for documentation or screenshots.
|
||||
- After apply, re-check `/ui/api/compatibility?major=N` for the active
|
||||
catalog state.
|
||||
|
||||
## Regenerating catalog artifacts
|
||||
|
||||
```bash
|
||||
make vsphere-bundles # stub OpenAPI matrices + evidence ledgers
|
||||
make vsphere-universe # regenerate universe.json from the Broadcom operations index
|
||||
make evidence # regenerate per-major verified surface evidence ledgers
|
||||
```
|
||||
|
||||
See [API surface](api-surface.md) and [Compatibility](compatibility.md).
|
||||
@@ -0,0 +1,76 @@
|
||||
**Language / Язык:** [English](architecture.md) | [Русский](ru/architecture.md)
|
||||
|
||||
# Architecture
|
||||
|
||||
## Goals
|
||||
|
||||
`vmware-api-simulator` is a stateful vSphere lab emulator (Automation REST + VIM SOAP).
|
||||
The primary design goal is **practical client compatibility**: sessions, inventory,
|
||||
VM lifecycle, PropertyCollector walks, tasks, tagging/content library stubs, and
|
||||
AuthZ roles are implemented against a large synthetic datastore so tools like curl,
|
||||
govc-style flows, pyvmomi, and Terraform can exercise common paths without a real
|
||||
vCenter.
|
||||
|
||||
Catalog majors **6–9** map to vSphere 7.0 / 7.0U3 / 8.0 / 8.0U2 floors. Hot-swap
|
||||
changes the catalog used for Web UI browse/evidence only — it does **not** gate
|
||||
live routes. Optional Proxmox `/api2/*` stub remains behind `ENABLE_PVE_STUB`
|
||||
(off by default).
|
||||
|
||||
## System context
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Client["API clients<br/>pyvmomi / Terraform / govc / REST SDKs"]
|
||||
Admin["Lab operator"]
|
||||
UI["Web lab UI"]
|
||||
API["FastAPI application"]
|
||||
Gateway["HTTPS gateway :443"]
|
||||
Contract["vSphere contract matrix"]
|
||||
Domain["vsphere domain + inventory"]
|
||||
DB[(PostgreSQL)]
|
||||
Obs["Logs / Prometheus / OpenTelemetry"]
|
||||
|
||||
Client -->|"/api /rest /sdk"| Gateway
|
||||
Gateway --> API
|
||||
UI --> Gateway
|
||||
Admin -->|"seed / migrate"| API
|
||||
API --> Contract
|
||||
API --> Domain
|
||||
Domain --> DB
|
||||
API --> Obs
|
||||
```
|
||||
|
||||
## Planes
|
||||
|
||||
| Plane | Path | Notes |
|
||||
|---|---|---|
|
||||
| Automation REST | `/api`, `/rest` | Session header `vmware-api-session-id` |
|
||||
| VIM SOAP | `/sdk` | PropertyCollector subset + VM tasks |
|
||||
| Lab UI helpers | `/ui/api/*` | Catalog, demo seed, compatibility |
|
||||
| Optional PVE stub | `/api2/*` | Off unless `ENABLE_PVE_STUB=true` |
|
||||
|
||||
## Data model
|
||||
|
||||
Inventory lives in `vsphere_objects` (MOIDs, types, props JSON, parent links).
|
||||
Sessions, credentials, tasks, tags, libraries, snapshots, and permissions are
|
||||
sibling tables (migrations `009_vsphere.sql`, `010_vsphere_platform.sql`).
|
||||
DB-backed Automation stubs use `vsphere_api_state` (`011`); content-library
|
||||
transfer sessions and HttpNfcLease rows live in `vsphere_transfer_sessions` /
|
||||
`vsphere_nfc_leases` (`012`); PropertyCollector views/tokens and console
|
||||
tickets persist in `vsphere_pc_state` / `vsphere_console_tickets` (`013`).
|
||||
|
||||
Seed profiles (`small` / `large` / `demo-cluster`) build a deterministic cluster —
|
||||
default **large** is ~10 hosts / **1000 VMs**.
|
||||
|
||||
## AuthZ
|
||||
|
||||
Credentials map to roles → privilege sets. Mutate handlers use
|
||||
`require_privilege(...)`; read paths use `require_read`. SOAP Login issues a cookie
|
||||
compatible with VIM sessions.
|
||||
|
||||
## Related docs
|
||||
|
||||
- [API coverage](api-coverage.md)
|
||||
- [Authentication](authentication.md)
|
||||
- [Web UI](web-ui.md)
|
||||
- [Clients](clients.md)
|
||||
@@ -0,0 +1,102 @@
|
||||
**Language / Язык:** [English](authentication.md) | [Русский](ru/authentication.md)
|
||||
|
||||
# Authentication
|
||||
|
||||
Primary plane: **vSphere Automation REST** sessions (`vmware-api-session-id`).
|
||||
SOAP `/sdk` uses its own `Login`/`Logout` on the VIM `SessionManager`. An
|
||||
optional legacy Proxmox stub plane (`ENABLE_PVE_STUB=true`) keeps historic
|
||||
`/api2/json/access/ticket` behavior from a shared platform lineage — it is not
|
||||
the default lab path and is not covered further here.
|
||||
|
||||
## Session login (REST)
|
||||
|
||||
```http
|
||||
POST /api/session
|
||||
Authorization: Basic base64(user:password)
|
||||
```
|
||||
|
||||
Successful response:
|
||||
|
||||
- Body: JSON string session id (e.g. `"a1b2c3…"`)
|
||||
- Header: `vmware-api-session-id: <id>`
|
||||
- Cookie: `vmware-api-session-id=<id>` (`SameSite=Strict`, 2 hour TTL)
|
||||
|
||||
Legacy wrapper (same credentials, `{ "value": "<session-id>" }` shape):
|
||||
|
||||
```http
|
||||
POST /rest/com/vmware/cis/session
|
||||
Authorization: Basic base64(user:password)
|
||||
```
|
||||
|
||||
### Calling APIs
|
||||
|
||||
```bash
|
||||
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/vm'
|
||||
```
|
||||
|
||||
Cookie-only clients also work after login (`credentials: include` in the
|
||||
browser Web UI).
|
||||
|
||||
### Session inspect / logout
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| GET | `/api/session` | HTTP 200 with `x-vmware-session-user` / `x-vmware-session-roles` headers |
|
||||
| DELETE | `/api/session` | Invalidates the session and clears the cookie |
|
||||
| GET / DELETE | `/rest/com/vmware/cis/session` | Legacy `{ "value": … }` equivalents |
|
||||
|
||||
Sessions live in PostgreSQL (`vsphere_sessions`) with a 2-hour sliding
|
||||
expiry — every authenticated request extends `expires_at`. Expired sessions
|
||||
return HTTP 401 on the next lookup and are lazily deleted.
|
||||
|
||||
## Seeded lab principals
|
||||
|
||||
Password for all: `VMware1!`
|
||||
|
||||
| Principal | Role |
|
||||
|---|---|
|
||||
| `administrator@vsphere.local` | Administrator |
|
||||
| `readonly@vsphere.local` | ReadOnly |
|
||||
| `operator@vsphere.local` | VirtualMachinePowerUser |
|
||||
| `vmadmin@vsphere.local` | VirtualMachineAdministrator |
|
||||
|
||||
Credentials are stored in `vsphere_credentials` (scrypt-hashed passwords,
|
||||
`roles` array) and are re-inserted idempotently on first `/api/session` call
|
||||
and by every seed profile. See [Authorization](domains/authz.md) for the
|
||||
privilege model and [Seed profiles](seed-profiles.md) for how the four
|
||||
principals map to inventory-scoped permissions.
|
||||
|
||||
Mutating endpoints check privileges via `require_privilege(...)`; calling a
|
||||
mutate path as `readonly@vsphere.local` returns **403**.
|
||||
|
||||
## SOAP `/sdk`
|
||||
|
||||
```xml
|
||||
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:vim25">
|
||||
<soapenv:Body>
|
||||
<urn:Login>
|
||||
<urn:_this type="SessionManager">SessionManager</urn:_this>
|
||||
<urn:userName>administrator@vsphere.local</urn:userName>
|
||||
<urn:password>VMware1!</urn:password>
|
||||
</urn:Login>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
||||
```
|
||||
|
||||
`Login` issues the same underlying session id, returned as
|
||||
`vmware-api-session-id` and as a `vmware_soap_session` cookie; subsequent SOAP
|
||||
calls (pyvmomi, govmomi, the `hashicorp/vsphere` Terraform provider, Pulumi)
|
||||
carry that cookie automatically. `Logout` deletes the session. See
|
||||
[SOAP / VIM](domains/soap.md).
|
||||
|
||||
## Optional legacy Proxmox stub
|
||||
|
||||
Only when `ENABLE_PVE_STUB=true`: ticket login at `/api2/json/access/ticket`
|
||||
with `PVEAuthCookie` + CSRF, inherited from the shared simulator platform this
|
||||
project forked from. It is disabled by default (`ENABLE_PVE_STUB=false`) and
|
||||
is not exercised by the vSphere docs, examples, or test suites in this
|
||||
repository.
|
||||
@@ -0,0 +1,83 @@
|
||||
**Language / Язык:** [English](clients.md) | [Русский](ru/clients.md)
|
||||
|
||||
# Clients
|
||||
|
||||
Use the simulator from common VMware automation stacks: Python, Ansible, Terraform, Pulumi.
|
||||
|
||||
## Connection matrix
|
||||
|
||||
| Stack | Transport | Notes | Code |
|
||||
|---|---|---|---|
|
||||
| REST (curl / SDK) | HTTPS `:443` | `vmware-api-session-id` after Basic session | `examples/python/vsphere_rest_smoke.py`, `vsphere_lifecycle.py` |
|
||||
| SOAP / VIM | HTTPS `:443/sdk` | pyvmomi / govmomi / Terraform / Pulumi providers | `examples/python/vsphere_soap_smoke.py` |
|
||||
| Legacy `/rest` | HTTPS `:443` | `{ "value": … }` wrappers | `/rest/vcenter/vm` |
|
||||
| Terraform | HTTPS `:443` | `hashicorp/vsphere` data sources + optional VM resource | `examples/terraform/vsphere/` |
|
||||
| Ansible | HTTPS `:443` | REST lifecycle playbook (`uri` module) | `examples/ansible/vsphere_playbook.yml` |
|
||||
| Pulumi | HTTPS `:443` | REST ComponentResource cookbook | `examples/pulumi/` |
|
||||
| govc | HTTPS `:443` | `GOVC_URL=https://…` insecure | see below |
|
||||
| Go / Java / Perl | HTTPS `:443` | Minimal REST cookbooks (Basic-auth session) | `examples/go/`, `examples/java/`, `examples/perl/` |
|
||||
|
||||
## Credentials (seed)
|
||||
|
||||
| User | Password | Role |
|
||||
|---|---|---|
|
||||
| `administrator@vsphere.local` | `VMware1!` | Administrator |
|
||||
| `readonly@vsphere.local` | `VMware1!` | ReadOnly |
|
||||
| `operator@vsphere.local` | `VMware1!` | VirtualMachinePowerUser |
|
||||
| `vmadmin@vsphere.local` | `VMware1!` | VirtualMachineAdministrator |
|
||||
|
||||
## Inventory seed
|
||||
|
||||
```bash
|
||||
make seed # large: 10 hosts / 1000 VMs
|
||||
VSPHERE_PROFILE=demo-cluster make seed
|
||||
VSPHERE_PROFILE=small make seed
|
||||
```
|
||||
|
||||
## Quick cookbooks
|
||||
|
||||
```bash
|
||||
# All four stacks (Python/Ansible/Terraform/Pulumi-style) inside Compose
|
||||
make client-cookbooks
|
||||
|
||||
# Python REST + SOAP CreateVM / NFC
|
||||
VSPHERE_BASE=https://localhost python examples/python/vsphere_lifecycle.py
|
||||
|
||||
# Ansible
|
||||
ansible-playbook -i examples/ansible/inventory.ini examples/ansible/vsphere_playbook.yml
|
||||
|
||||
# Terraform — hashicorp/vsphere data sources (plan) + optional CreateVM resource
|
||||
cd examples/terraform/vsphere
|
||||
terraform init
|
||||
TF_VAR_vsphere_server=localhost TF_VAR_create_lab_vm=false terraform plan
|
||||
TF_VAR_vsphere_server=localhost TF_VAR_create_lab_vm=true terraform apply
|
||||
|
||||
# Pulumi REST
|
||||
cd examples/pulumi && pulumi up
|
||||
```
|
||||
|
||||
Verified against the gateway (`:443`): Python lifecycle, Ansible playbook, Pulumi-style REST, and `terraform plan` (datacenter/cluster/datastore/network/VM data sources) are green. SOAP `CreateVM_Task` is available for the resource path; use a fresh seed if folder names were renamed by probes (`make seed`).
|
||||
|
||||
## govc (optional host tool)
|
||||
|
||||
```bash
|
||||
export GOVC_URL=https://localhost
|
||||
export GOVC_USERNAME=administrator@vsphere.local
|
||||
export GOVC_PASSWORD='VMware1!'
|
||||
export GOVC_INSECURE=1
|
||||
govc about
|
||||
govc ls /
|
||||
govc find / -type m | head
|
||||
govc vm.info web-01
|
||||
```
|
||||
|
||||
## pyvmomi smoke
|
||||
|
||||
```bash
|
||||
docker compose run --rm --no-deps -e VSPHERE_BASE=http://simulator:8080 \
|
||||
-e TEST_DATABASE_URL=postgresql://vmware:vmware@postgres:5432/vmware_simulator \
|
||||
dev pytest tests/compatibility/test_vsphere_pyvmomi.py -q
|
||||
```
|
||||
|
||||
Per-language guides: [examples/overview.md](examples/overview.md). Coverage:
|
||||
[api-coverage.md](api-coverage.md).
|
||||
@@ -0,0 +1,86 @@
|
||||
**Language / Язык:** [English](compatibility-0.1.0.md) | [Русский](ru/compatibility-0.1.0.md)
|
||||
|
||||
# Compatibility report — 0.1.0
|
||||
|
||||
This report records evidence for simulator release 0.1.0 against the vSphere
|
||||
Automation API route registry (catalog majors 6–9, primary contract major 9 /
|
||||
8.0 U2). It is a limitation matrix for *quality / external integration*
|
||||
dimensions, not a claim of general vCenter/ESXi hardware compatibility.
|
||||
|
||||
For the user-facing overview see [compatibility.md](compatibility.md). Live
|
||||
machine-readable counts are always available from
|
||||
`/ui/api/compatibility?major=N` when the simulator is running.
|
||||
|
||||
## Summary (major 9 / vSphere 8.0 U2 primary contract)
|
||||
|
||||
| Level | Methods | Universe share | Evidence |
|
||||
|---|---:|---:|---|
|
||||
| Declared in universe (Broadcom operations index → route table) | 1077 | 100% | `app/vsphere/rest/universe.json` |
|
||||
| Implemented at major 9 (catalog floor) | **1077** | **100%** | `app/vsphere/contracts/matrix.py` |
|
||||
| Core deep handlers (inventory/lifecycle/tagging/content/appliance) | 104 | 9.7% | `app/vsphere/rest/coverage.py` (`CORE_IMPLEMENTED`) |
|
||||
| DB-backed stub surface (remaining registry) | ~973 | 90.3% | `app/vsphere/rest/stub_surface.py` against `vsphere_api_state` |
|
||||
| Verified / observed surface ledger | **1077** | **100%** | `evidence/vsphere-8.0.2.json` |
|
||||
|
||||
## Coverage by catalog major
|
||||
|
||||
| Major | vSphere label | Implemented | Universe | Coverage |
|
||||
|---|---|---:|---:|---:|
|
||||
| 6 | 7.0 | 31 | 1077 | 2.88% |
|
||||
| 7 | 7.0 U3 | 77 | 1077 | 7.15% |
|
||||
| 8 | 8.0 | 103 | 1077 | 9.56% |
|
||||
| 9 | 8.0 U2 | 1077 | 1077 | 100.00% |
|
||||
|
||||
**Implemented** here is a catalog-floor score for Web UI browse and evidence
|
||||
reports, regenerated with `make evidence` / `make vsphere-bundles` and
|
||||
guarded by `tests/compatibility/test_verified_surface.py`. It does **not**
|
||||
gate live traffic — see [API surface](api-surface.md) for why runtime always
|
||||
serves the registered route regardless of the applied major.
|
||||
|
||||
## Implemented surface (high level)
|
||||
|
||||
- **Session**: `/api/session`, `/rest/com/vmware/cis/session`, SOAP
|
||||
`Login`/`Logout` — all durable in PostgreSQL (`vsphere_sessions`,
|
||||
`vsphere_credentials`).
|
||||
- **Inventory**: VM/host/datastore/network/datacenter/cluster/folder/resource-pool
|
||||
list+get, plus create/delete for datacenter/cluster/folder/resource-pool.
|
||||
- **VM lifecycle**: create, delete, power, hardware (CPU/memory/disk/NIC/boot),
|
||||
snapshots, clone, relocate, guest identity/networking/power/customization,
|
||||
console tickets, tools.
|
||||
- **Tasks**: `/api/cis/tasks`, real ids from `vsphere_tasks`, SOAP task MoRefs.
|
||||
- **Tagging / content library**: categories, tags, associations, libraries,
|
||||
library items, update/download sessions, OVF deploy.
|
||||
- **Authorization**: privileges, roles, permissions CRUD, identity providers.
|
||||
- **Appliance**: version, health, networking (hostname/DNS), timesync.
|
||||
- **SOAP / VIM**: RetrieveServiceContent, PropertyCollector
|
||||
(RetrieveProperties/Ex, ContinueRetrievePropertiesEx, CreateFilter,
|
||||
WaitForUpdatesEx), FindBy* / FindChild, CreateVM_Task and friends, guest
|
||||
file operations, HttpNfcLease import flow, WSDL stub.
|
||||
- **Platform lab surfaces**: seeded (non-binary-compatible) NSX/Supervisor/vSAN/
|
||||
SAML-OIDC/VECS-cert stand-ins — see [API coverage](api-coverage.md) for the
|
||||
exact list and caveats.
|
||||
|
||||
## Persistence principle
|
||||
|
||||
Every create/update/delete path writes to PostgreSQL (tables and/or the
|
||||
`vsphere_api_state` catch-all). Secrets may be stored but must not be echoed
|
||||
on GET. User-facing "not supported in the emulator" errors are forbidden for
|
||||
registered paths — see `.cursor/rules/durable-simulator.mdc`.
|
||||
|
||||
## Known limitations
|
||||
|
||||
| Area | Current behavior |
|
||||
|---|---|
|
||||
| External systems | NSX/LDAP/SAML/OIDC/ACME do not contact real remotes; state is simulated locally |
|
||||
| TLS | Local nginx gateway with a checked-in self-signed development key only |
|
||||
| Client certification | pyvmomi/govmomi-style SOAP smoke + Ansible/Terraform/Pulumi cookbooks; not a formal certification suite for every provider version |
|
||||
| Provider smoke | The `pulumi-vsphere` suite under `pulumi-tests/` (`make pulumi-tests`) exercises SOAP-backed inventory/VM/tag resources with nonempty export checks; semantic depth still varies (deep handlers vs DB-backed stubs) |
|
||||
|
||||
Full registry coverage at major 9 means HTTP 501 "handler pending" should not
|
||||
appear for any route in the simulator's registry. Compatibility *quality*
|
||||
(exact vSphere edge-case parity) still deepens with tests and observation.
|
||||
|
||||
When importing a refreshed Broadcom operations index dump: regenerate
|
||||
`universe.json` (`make vsphere-universe`), regenerate bundles/evidence
|
||||
(`make vsphere-bundles`, `make evidence`), run
|
||||
`pytest tests/compatibility/test_verified_surface.py`, and commit the updated
|
||||
`evidence/vsphere-*.json` ledgers.
|
||||
@@ -0,0 +1,74 @@
|
||||
**Language / Язык:** [English](compatibility.md) | [Русский](ru/compatibility.md)
|
||||
|
||||
# Compatibility
|
||||
|
||||
This document explains how the simulator claims compatibility with the
|
||||
vSphere Automation API across catalog majors **6–9**. Prefer live reports
|
||||
when the process is running.
|
||||
|
||||
## Live reports
|
||||
|
||||
| URL | Format |
|
||||
|---|---|
|
||||
| `/ui/api/compatibility?major=N` | JSON |
|
||||
|
||||
The Web UI also exposes a compatibility panel driven by this endpoint.
|
||||
|
||||
## Registry vs verified surface coverage
|
||||
|
||||
| Major | vSphere label | Implemented / universe | 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%** |
|
||||
|
||||
- **Universe** — unique verb+path routes derived from the public
|
||||
[vSphere Automation API operations index](https://developer.broadcom.com/xapis/vsphere-automation-api/latest/operation-index/)
|
||||
(1348 documented operations → ~1037 unique routes → 1077 registered in this
|
||||
simulator's route table, since some paths back multiple named operations).
|
||||
- **Implemented (per major)** — routes whose catalog floor
|
||||
(`app/vsphere/contracts/matrix.py`) is at or below that major. This is a
|
||||
**catalog/documentation** score, not a live-traffic gate.
|
||||
- **Runtime** — regardless of the applied catalog major, every registered
|
||||
route is always served by its real handler (104 deep handlers) or the
|
||||
DB-backed stub surface. See [API surface](api-surface.md).
|
||||
|
||||
After **Apply as runtime** (`POST /ui/api/contract/apply?major=N`), the live
|
||||
report loads that major's ledger (`evidence/vsphere-{version}.json`) so the
|
||||
Web UI compatibility panel reflects the selected major.
|
||||
|
||||
## Evidence dimensions
|
||||
|
||||
Per-major ledgers in `evidence/vsphere-{version}.json` record `declared`,
|
||||
`implemented`, `observed`, and `verified` counts plus per-HTTP-verb and
|
||||
per-domain (`auth_session`, `inventory`, …) breakdowns. Regenerate with:
|
||||
|
||||
```bash
|
||||
make evidence # app/evidence_gen.py
|
||||
make vsphere-bundles # stub OpenAPI matrices + evidence ledgers together
|
||||
```
|
||||
|
||||
Executable backing for those claims:
|
||||
|
||||
| Suite | Role |
|
||||
|---|---|
|
||||
| `tests/compatibility/test_verified_surface.py` | hot-swap + ledger drift + score gates |
|
||||
| `tests/compatibility/test_group_smoke.py` | representative REST group mutations with PostgreSQL |
|
||||
| `tests/compatibility/test_vsphere_pyvmomi.py` | external pyvmomi SOAP smoke |
|
||||
| `tests/integration/test_vsphere_full_api.py` | broad REST/SOAP integration coverage |
|
||||
|
||||
Additional cookbooks under [`examples/`](../examples/README.md) and the
|
||||
`pulumi-vsphere` lab suite under [`pulumi-tests/`](../pulumi-tests/README.md)
|
||||
(`make pulumi-tests`) are manual or CI-optional depending on the stack.
|
||||
|
||||
## Known behavioural limits
|
||||
|
||||
| Area | Behaviour |
|
||||
|---|---|
|
||||
| External systems | NSX Manager, live LDAP/SAML/OIDC IdPs, and ACME directories do not contact real remotes; seeded/local state only |
|
||||
| TLS | Local self-signed development gateway only (Compose); use your own certs / cert-manager for real deployments |
|
||||
| Hypervisor | No real ESXi/KVM execution; no binary NFC uploads |
|
||||
| Observation corpus | Sanitized real-vCenter observation data remains limited; deep semantic parity is verified path-by-path via the suites above, not by exhaustive production diffing |
|
||||
|
||||
Historical release notes: [compatibility-0.1.0.md](compatibility-0.1.0.md).
|
||||
@@ -0,0 +1,96 @@
|
||||
**Language / Язык:** [English](configuration.md) | [Русский](ru/configuration.md)
|
||||
|
||||
# Configuration
|
||||
|
||||
Application settings are loaded from the environment (see `.env.example`).
|
||||
Docker Compose injects many of these for the `simulator` service; values
|
||||
declared under `environment:` in `docker-compose.yml` override `.env` for that
|
||||
service. The typed settings model lives in [`app/config.py`](../app/config.py).
|
||||
|
||||
## Core
|
||||
|
||||
| Variable | Default / example | Meaning |
|
||||
|---|---|---|
|
||||
| `APP_HOST` | `0.0.0.0` | Bind address |
|
||||
| `APP_PORT` | `8080` | Internal uvicorn listen port (not published; the gateway publishes vCenter HTTPS) |
|
||||
| `DATABASE_URL` | `postgresql://vmware:vmware@postgres:5432/vmware_simulator` | asyncpg DSN |
|
||||
| `DB_POOL_MIN_SIZE` | `1` | Pool minimum |
|
||||
| `DB_POOL_MAX_SIZE` | `10` | Pool maximum |
|
||||
| `DB_CONNECT_TIMEOUT_SECONDS` | `10` | Connect timeout |
|
||||
| `DB_COMMAND_TIMEOUT_SECONDS` | `30` | Command timeout |
|
||||
| `LOG_LEVEL` | `INFO` | Logging level |
|
||||
| `REQUEST_ID_HEADER` | `X-Request-ID` | Request correlation header |
|
||||
|
||||
## vSphere seed inventory
|
||||
|
||||
| Variable | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `SEED_VSPHERE_PROFILE` | `large` | `small` \| `large` \| `demo-cluster` — see [Seed profiles](seed-profiles.md) |
|
||||
| `SEED_VSPHERE_LARGE_HOSTS` | `10` | Host count for the `large` profile |
|
||||
| `SEED_VSPHERE_LARGE_VMS` | `1000` | VM count for the `large` profile |
|
||||
|
||||
## Optional legacy plane
|
||||
|
||||
| Variable | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `ENABLE_PVE_STUB` | `false` | Enables the legacy Proxmox VE `/api2/*` stub plane inherited from a shared platform lineage. Native vSphere `/api` + `/rest` + `/sdk` is the default and primary plane regardless of this flag. |
|
||||
|
||||
## Contract and catalog
|
||||
|
||||
| Variable | Meaning |
|
||||
|---|---|
|
||||
| `CONTRACT_SNAPSHOT` | Optional path to a normalized PVE-style snapshot (only relevant with `ENABLE_PVE_STUB=true`) |
|
||||
| `CONTRACT_FALLBACK` | `error` (default), `schema-default`, or `fixture` — fallback behaviour for the optional stub plane |
|
||||
| `COMPATIBILITY_EVIDENCE` | Optional evidence JSON path used by compatibility reports |
|
||||
| `CATALOG_ARTIFACT_URL_6` … `_9` | Labels backing the vSphere catalog majors (6→7.0, 7→7.0 U3, 8→8.0, 9→8.0 U2); stub URLs, not live downloads |
|
||||
|
||||
Runtime hot-swap (Web UI / `POST /ui/api/contract/apply?major=N`) switches the
|
||||
active **catalog** major used by the Web UI and compatibility/evidence
|
||||
reports. It does not gate the registered REST/SOAP surface — every known
|
||||
route is always served with its real handler or DB-backed stub. See
|
||||
[API versions](api-versions.md).
|
||||
|
||||
## Security and tasks
|
||||
|
||||
| Variable | Meaning |
|
||||
|---|---|
|
||||
| `TICKET_SIGNING_KEY` | HMAC signing key for sessions (**change outside toy labs**) |
|
||||
| `TASK_WORKER_CONCURRENCY` | Number of leased asyncio workers (1–32) |
|
||||
| `TASK_LEASE_SECONDS` | PostgreSQL task lease duration |
|
||||
| `SIMULATION_TIME_SCALE` | Accelerates simulated task durations (higher = faster) |
|
||||
|
||||
## Client test hooks
|
||||
|
||||
| Variable | Meaning |
|
||||
|---|---|
|
||||
| `TEST_DATABASE_URL` | Integration-test DSN |
|
||||
| `VSPHERE_BASE` | Target base URL used by cookbooks/probes (`https://localhost` from the host, `http://simulator:8080` from inside Compose) |
|
||||
|
||||
## Ports and TLS
|
||||
|
||||
| Endpoint | Use |
|
||||
|---|---|
|
||||
| `https://localhost` | Primary vCenter HTTPS entry (curl, browsers, pyvmomi, govmomi, Terraform, most examples) |
|
||||
| `http://localhost` | HTTP lab face |
|
||||
| `localhost:5434` | PostgreSQL (localhost only) |
|
||||
| Internal `simulator:8080` | Direct FastAPI process; only reachable inside the Compose network |
|
||||
|
||||
The checked-in certificate under `docker/tls/` is disposable development
|
||||
material. Never reuse it outside local labs. See [Security](security.md) and
|
||||
[Ports](ports.md).
|
||||
|
||||
## Compose notes
|
||||
|
||||
- `migrate` runs once; `simulator` waits for a successful migrate.
|
||||
- Development Compose bind-mounts the repository and enables Uvicorn reload.
|
||||
- The `api-gateway` (nginx) service publishes `443`/`80` and proxies to the
|
||||
internal `simulator:8080` process; it sets `X-VMware-Service` /
|
||||
`X-Forwarded-Port` so future routers can tell which listener was used.
|
||||
|
||||
## Open and unused example keys
|
||||
|
||||
`.env.example` still lists a few keys from the shared platform lineage that
|
||||
are **not** consumed by the current vSphere-first settings model, notably
|
||||
`SIMULATION_SEED`, `SIMULATOR_ADMIN_ENABLED`, and `SIMULATOR_ADMIN_TOKEN`. Do
|
||||
not assume an authenticated `/_simulator` admin API exists today — see
|
||||
[Security](security.md).
|
||||
@@ -0,0 +1,42 @@
|
||||
**Language / Язык:** [English](README.md) | [Русский](../ru/domains/README.md)
|
||||
|
||||
# Domain guides
|
||||
|
||||
These pages summarize durable semantics by area. For exhaustive method lists,
|
||||
use the Web UI catalog or OpenAPI (`/docs`), or browse
|
||||
[`app/vsphere/rest/coverage.py`](../../app/vsphere/rest/coverage.py) directly
|
||||
— the runtime always serves the full registered surface regardless of the
|
||||
active catalog major.
|
||||
|
||||
| Guide | Topics |
|
||||
|---|---|
|
||||
| [Session](session.md) | `/api/session`, legacy `/rest` session, SOAP `Login`/`Logout` |
|
||||
| [Inventory](inventory.md) | Datacenter, cluster, folder, resource pool, host, datastore, network CRUD |
|
||||
| [Virtual machines](vm.md) | Create/delete, power, hardware, snapshots, clone, relocate, guest ops |
|
||||
| [Storage](storage.md) | Datastores, files, host storage devices, storage policies |
|
||||
| [Networking](networking.md) | Standard/distributed portgroups, DVS, host networking |
|
||||
| [Tagging](tagging.md) | Categories, tags, associations |
|
||||
| [Content library](content-library.md) | Libraries, items, update/download sessions, OVF deploy |
|
||||
| [SOAP / VIM](soap.md) | RetrieveServiceContent, PropertyCollector, task-returning operations |
|
||||
| [Tasks](tasks.md) | CIS task ids, polling, workers |
|
||||
| [Appliance](appliance.md) | Version, health, networking, timesync |
|
||||
| [Authorization](authz.md) | Roles, privileges, permissions |
|
||||
|
||||
## Persistence map
|
||||
|
||||
- Inventory objects (hosts, VMs, datastores, networks, folders, …) →
|
||||
`vsphere_objects` (MOID, type, name, parent, `props` JSONB).
|
||||
- Sessions / credentials → `vsphere_sessions`, `vsphere_credentials`.
|
||||
- Tasks → `vsphere_tasks`.
|
||||
- Tags / categories / associations → `vsphere_tag_categories`,
|
||||
`vsphere_tags`, `vsphere_tag_associations`.
|
||||
- Content libraries / items → `vsphere_libraries`, `vsphere_library_items`.
|
||||
- Datastore file metadata → `vsphere_datastore_files`.
|
||||
- Remaining Broadcom Automation API routes (the DB-backed stub surface) →
|
||||
`vsphere_api_state` (migration `011`).
|
||||
- Content-library update/download sessions → `vsphere_transfer_sessions`
|
||||
(migration `012`).
|
||||
- HttpNfcLease transfer state → `vsphere_nfc_leases` (migration `012`).
|
||||
- PropertyCollector views / WaitForUpdates tokens → `vsphere_pc_state`
|
||||
(migration `013`).
|
||||
- Console tickets → `vsphere_console_tickets` (migration `013`).
|
||||
@@ -0,0 +1,35 @@
|
||||
**Language / Язык:** [English](appliance.md) | [Русский](../ru/domains/appliance.md)
|
||||
|
||||
# Appliance
|
||||
|
||||
vCenter Server Appliance (VCSA) surfaces — version, health, networking,
|
||||
timesync:
|
||||
[`app/vsphere/rest/appliance_ext.py`](../../app/vsphere/rest/appliance_ext.py),
|
||||
[`app/vsphere/domain/appliance.py`](../../app/vsphere/domain/appliance.py).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| GET | `/api/appliance/system/version` | Readable without a session; reflects the active catalog major's label |
|
||||
| GET | `/api/appliance/health/system` | Overall health summary |
|
||||
| GET/PUT/POST | `/api/appliance/networking` | Hostname, DNS, default gateway, interfaces, proxy |
|
||||
| GET/PUT/POST | `/api/appliance/networking/dns/hostname` \| `/dns/servers` \| `/dns/domains` | Focused mirrors kept in sync with `/networking` |
|
||||
| GET | `/api/appliance/timesync` | NTP mode + servers |
|
||||
| GET | `/api/vcenter/certificate-management/vcenter/tls[-csr]` \| `/trusted-root-chains` | Machine-cert / CSR / trust-chain stand-ins |
|
||||
|
||||
## Highlights
|
||||
|
||||
- Defaults model a realistic single-nic VCSA (`vcenter.lab.local`,
|
||||
`192.168.1.50/24`, gateway `192.168.1.1`, `8.8.8.8`/`1.1.1.1` DNS).
|
||||
- `save_networking` keeps the focused DNS mirrors
|
||||
(`/dns/hostname`, `/dns/servers`, `/dns/domains`) consistent with the full
|
||||
`/networking` document so both shapes of Automation API client work.
|
||||
- State is idempotently seeded once per fresh database
|
||||
(`seed_appliance_state`) and persists in `vsphere_api_state`.
|
||||
- The TLS/certificate-management endpoints are seeded stand-ins, not a real
|
||||
VECS certificate store — see [API coverage](../api-coverage.md).
|
||||
|
||||
`/api/appliance/system/version` intentionally does not require a session in
|
||||
this lab build (real vCenter behavior varies by version) so smoke scripts can
|
||||
check availability before authenticating.
|
||||
@@ -0,0 +1,52 @@
|
||||
**Language / Язык:** [English](authz.md) | [Русский](../ru/domains/authz.md)
|
||||
|
||||
# Authorization
|
||||
|
||||
Role → privilege gate for REST mutate endpoints (and a decorator-style hook
|
||||
for SOAP): [`app/vsphere/security/authz.py`](../../app/vsphere/security/authz.py),
|
||||
[`platform_rest.py`](../../app/vsphere/rest/platform_rest.py).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| GET | `/api/vcenter/privilege` | Privilege catalog |
|
||||
| GET | `/api/vcenter/authorization/roles` | Role → privilege set |
|
||||
| GET/POST/DELETE | `/api/vcenter/authorization/permissions[/{permission_id}]` | Principal ↔ role ↔ entity bindings |
|
||||
| GET/POST/PATCH/DELETE | `/api/vcenter/identity/providers[/{provider}]` | LocalOS + OIDC + SAML identity-provider stand-ins |
|
||||
|
||||
## Roles (seed)
|
||||
|
||||
| Role | Scope |
|
||||
|---|---|
|
||||
| `Administrator` | Every privilege in the catalog |
|
||||
| `ReadOnly` | `System.Anonymous`, `System.Read`, `System.View`, `Datastore.Browse` |
|
||||
| `VirtualMachinePowerUser` | Read + power/snapshot/clone interactions |
|
||||
| `VirtualMachineAdministrator` | Power-user set + create/delete/reconfigure/tag/content-library privileges |
|
||||
|
||||
`ROLE_PRIVILEGES` in `authz.py` defines the exact privilege sets; a
|
||||
non-exhaustive sample of gated privileges: `VirtualMachine.Inventory.Create`,
|
||||
`VirtualMachine.Inventory.Delete`, `VirtualMachine.Interact.PowerOn`,
|
||||
`VirtualMachine.Config.CPUCount`, `VirtualMachine.Provisioning.Clone`,
|
||||
`Datastore.FileManagement`, `Network.Assign`,
|
||||
`InventoryService.Tagging.CreateTag`, `ContentLibrary.AddLibraryItem`,
|
||||
`Authorization.ModifyPermissions`.
|
||||
|
||||
## How gating works
|
||||
|
||||
- `require_privilege(*needed)` is a FastAPI dependency factory: it resolves
|
||||
the session, loads roles (from the session or `vsphere_credentials` if
|
||||
absent), and raises HTTP 403 (`unauthorized`) if any listed privilege is
|
||||
missing.
|
||||
- `require_read` is shorthand for `require_privilege("System.Read")`.
|
||||
- Permissions can also scope a role to a specific entity MOID
|
||||
(`PermissionSpec(principal, role, entity_moid, propagate)`); the seed
|
||||
scopes `readonly@vsphere.local` to the datacenter and the two VM-admin
|
||||
principals to the VM folder.
|
||||
|
||||
## Seeded principals
|
||||
|
||||
See [Authentication](../authentication.md) for the four
|
||||
`@vsphere.local` principals and their roles, and
|
||||
[Seed profiles](../seed-profiles.md) for how permissions are scoped per
|
||||
profile.
|
||||
@@ -0,0 +1,38 @@
|
||||
**Language / Язык:** [English](content-library.md) | [Русский](../ru/domains/content-library.md)
|
||||
|
||||
# Content library
|
||||
|
||||
Local content libraries, library items, upload/download sessions, and OVF
|
||||
deploy:
|
||||
[`app/vsphere/rest/content_rest.py`](../../app/vsphere/rest/content_rest.py),
|
||||
[`nfc_rest.py`](../../app/vsphere/rest/nfc_rest.py),
|
||||
[`app/vsphere/domain/content.py`](../../app/vsphere/domain/content.py).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| GET | `/api/content/library` | List library ids |
|
||||
| POST | `/api/content/local-library` | Create a local library |
|
||||
| GET/POST | `/api/content/library/item` | List / create items (`?library_id=`) |
|
||||
| POST | `/api/vcenter/ovf/library-item/{item_id}` | Deploy OVF item → new `VirtualMachine` + task |
|
||||
| POST | `/api/content/library/item/update-session[/{session_id}[/file]]` | Push-upload flow (Ansible/Terraform-style) |
|
||||
| GET/POST | `/api/content/library/item/download-session[/{session_id}[/file]]` | Pull-download flow |
|
||||
| GET/PUT/POST | `/nfc/{lease}` \| `/nfc/{lease}/files/{filename}` \| `/nfc/{lease}/complete` | HttpNfcLease-style transfer endpoints for the SOAP import path |
|
||||
|
||||
## Highlights
|
||||
|
||||
- Libraries/items persist in `vsphere_libraries` / `vsphere_library_items`;
|
||||
the seed creates two libraries ("Local Content", "Published Templates")
|
||||
with OVF-typed items (`ubuntu-22.04`, `centos-stream-9`, `golden-image`).
|
||||
- Update/download sessions persist in PostgreSQL (`vsphere_transfer_sessions`,
|
||||
migration `012`) and model the file-transfer handshake — not a real
|
||||
byte-for-byte OVF/VMDK store. HttpNfcLease rows live in `vsphere_nfc_leases`.
|
||||
- `deploy_ovf_from_library` creates a real `VirtualMachine` row and returns a
|
||||
task id, mirroring the SOAP `ImportVApp_Task` / `CreateImportSpec` +
|
||||
`HttpNfcLease*` flow used by govc-style `ovf.import`.
|
||||
- Requires `ContentLibrary.CreateLocalLibrary` / `.AddLibraryItem` to create,
|
||||
and `VirtualMachine.Provisioning.DeployTemplate` to deploy.
|
||||
|
||||
See [SOAP / VIM](soap.md) for the HttpNfcLease progress/complete/abort
|
||||
operations used by upload-heavy clients.
|
||||
@@ -0,0 +1,46 @@
|
||||
**Language / Язык:** [English](inventory.md) | [Русский](../ru/domains/inventory.md)
|
||||
|
||||
# Inventory
|
||||
|
||||
Datacenter, cluster, folder, resource pool, host, and datastore/network
|
||||
listing + CRUD:
|
||||
[`app/vsphere/rest/router.py`](../../app/vsphere/rest/router.py),
|
||||
[`app/vsphere/domain/inventory_ops.py`](../../app/vsphere/domain/inventory_ops.py).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| GET | `/api/vcenter/datacenter` | List |
|
||||
| POST/DELETE | `/api/vcenter/datacenter[/{datacenter}]` | Create seeds host/vm/datastore/network sub-folders |
|
||||
| GET | `/api/vcenter/cluster` | List |
|
||||
| POST/DELETE | `/api/vcenter/cluster[/{cluster}]` | Create seeds a `ResourcePool` |
|
||||
| GET | `/api/vcenter/folder` | List; `GET /api/vcenter/folder/{folder}/children` |
|
||||
| POST/DELETE | `/api/vcenter/folder[/{folder}]` | |
|
||||
| GET | `/api/vcenter/resource-pool` | List |
|
||||
| POST/DELETE | `/api/vcenter/resource-pool[/{resource_pool}]` | |
|
||||
| GET | `/api/vcenter/host[/{host}]` | Connection state, CPU/memory, IP, storage devices, networking |
|
||||
| POST | `/api/vcenter/host/{host}/maintenance` | Toggle maintenance mode |
|
||||
| GET | `/api/vcenter/datastore[/{datastore}]` | Type, capacity, free space, accessibility |
|
||||
| GET | `/api/vcenter/network` | Standard networks + distributed portgroups |
|
||||
|
||||
Legacy `/rest/vcenter/*` mirrors most GET paths with a `{ "value": … }`
|
||||
envelope — see [API surface](../api-surface.md).
|
||||
|
||||
## Highlights
|
||||
|
||||
- Every inventory object is a row in `vsphere_objects` (MOID, type, name,
|
||||
`parent_moid`, `props` JSONB) — see
|
||||
[`app/vsphere/inventory.py`](../../app/vsphere/inventory.py).
|
||||
- MOID conventions follow real vCenter shapes: `datacenter-NN`,
|
||||
`domain-cNN` (cluster), `resgroup-NN` (resource pool), `group-vNN`/`group-hNN`/
|
||||
`group-sNN`/`group-nNN` (VM/host/datastore/network folders), `host-NN`,
|
||||
`datastore-NN`, `network-NN` / `dvportgroup-NN`.
|
||||
- `list_hosts`/`list_clusters`/etc. filter live PostgreSQL state; there is no
|
||||
separate cache to invalidate after a mutation.
|
||||
- VM listing (`GET /api/vcenter/vm`) supports filters: `names`,
|
||||
`power_states`, `hosts`, `folders`, `datacenters`, `clusters`,
|
||||
`resource_pools`, plus `limit`/`cursor` pagination.
|
||||
|
||||
See [Seed profiles](../seed-profiles.md) for the default topology shape and
|
||||
[Virtual machines](vm.md) for VM-specific operations.
|
||||
@@ -0,0 +1,35 @@
|
||||
**Language / Язык:** [English](networking.md) | [Русский](../ru/domains/networking.md)
|
||||
|
||||
# Networking
|
||||
|
||||
Standard networks, distributed portgroups/switches, and host networking:
|
||||
[`app/vsphere/rest/router.py`](../../app/vsphere/rest/router.py),
|
||||
[`platform_rest.py`](../../app/vsphere/rest/platform_rest.py).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| GET | `/api/vcenter/network` | Standard `Network` objects + `DistributedVirtualPortgroup` |
|
||||
| GET/POST | `/api/vcenter/network/dvs` | Distributed virtual switches |
|
||||
| POST | `/api/vcenter/network/dvpg` | Create a distributed portgroup |
|
||||
| GET | `/api/vcenter/host/{host}/networking` | DNS, default gateway, `vmk0` interface, routing |
|
||||
| GET/PUT/POST | `/api/appliance/networking` \| `/networking/dns/{hostname,servers,domains}` | vCenter appliance-level networking (see [Appliance](appliance.md)) |
|
||||
|
||||
Legacy `GET /rest/vcenter/network` mirrors the list.
|
||||
|
||||
## Highlights
|
||||
|
||||
- Every VM's `nics[].value.backing` points at either a `STANDARD_PORTGROUP`
|
||||
(`network-41`, "VM Network") or a `DISTRIBUTED_PORTGROUP`
|
||||
(`dvportgroup-4N`, tagged with a `vlan_id`).
|
||||
- The default topology seeds one `VmwareDistributedVirtualSwitch`
|
||||
(`dvs-51`, `mtu: 9000`) and 1–3 extra distributed portgroups depending on
|
||||
profile size.
|
||||
- Host networking (`GET /api/vcenter/host/{host}/networking`) returns DNS
|
||||
servers/domains, a default gateway, and a single `vmk0` management
|
||||
interface with a deterministic IPv4 address per host index.
|
||||
- NSX-labelled Automation API paths (tier-0 gateway, projects, edges,
|
||||
VPC/subnets) are seeded lab stand-ins under `namespace-management` — see
|
||||
the "Platform surfaces" table in [API coverage](../api-coverage.md); they
|
||||
are not a real NSX Manager.
|
||||
@@ -0,0 +1,31 @@
|
||||
**Language / Язык:** [English](session.md) | [Русский](../ru/domains/session.md)
|
||||
|
||||
# Session
|
||||
|
||||
Durable session identity shared by REST and SOAP:
|
||||
[`app/vsphere/security/session.py`](../../app/vsphere/security/session.py).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| POST | `/api/session` | Basic auth → JSON string session id + `vmware-api-session-id` header/cookie |
|
||||
| GET | `/api/session` | HTTP 200; `x-vmware-session-user` / `x-vmware-session-roles` headers |
|
||||
| DELETE | `/api/session` | Invalidates the session, clears cookie |
|
||||
| POST/GET/DELETE | `/rest/com/vmware/cis/session` | Legacy `{ "value": … }` equivalents |
|
||||
| POST | SOAP `SessionManager.Login` | Returns the same session id; sets `vmware_soap_session` cookie |
|
||||
| POST | SOAP `SessionManager.Logout` | Deletes the session |
|
||||
|
||||
## Highlights
|
||||
|
||||
- Sessions are opaque 32-char hex tokens stored in `vsphere_sessions` with a
|
||||
**2-hour sliding TTL** — every authenticated call extends `expires_at`.
|
||||
- The four lab credentials (`vsphere_credentials`, scrypt-hashed) are
|
||||
idempotently ensured on first login and by every seed profile
|
||||
(`ensure_default_credentials`).
|
||||
- `require_session` resolves the session from either the
|
||||
`vmware-api-session-id` header or cookie; missing/expired → HTTP 401.
|
||||
- Roles are attached to the session at lookup time
|
||||
(`vsphere_credentials.roles`) and drive [Authorization](authz.md).
|
||||
|
||||
See [Authentication](../authentication.md) for full request examples.
|
||||
@@ -0,0 +1,68 @@
|
||||
**Language / Язык:** [English](soap.md) | [Русский](../ru/domains/soap.md)
|
||||
|
||||
# SOAP / VIM
|
||||
|
||||
Minimal VIM SDK for pyvmomi / govmomi-style clients (Terraform's
|
||||
`hashicorp/vsphere` provider, Pulumi, govc):
|
||||
[`app/vsphere/soap/router.py`](../../app/vsphere/soap/router.py),
|
||||
[`property_collector.py`](../../app/vsphere/soap/property_collector.py),
|
||||
[`pbm.py`](../../app/vsphere/soap/pbm.py).
|
||||
|
||||
## Endpoint
|
||||
|
||||
All operations POST a SOAP envelope to `/sdk` (also `/sdk/`). Auxiliary
|
||||
routes:
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| GET | `/sdk/vimService.wsdl` (alias `/sdk/vim.wsdl`) | WSDL stub advertising the implemented operation list |
|
||||
| GET | `/sdk/about.do` (alias `/about.do`) | Human-readable "VMware vCenter Server" page |
|
||||
| POST | `/sdk/vim25/{version}/SessionManager/SessionManager/Login` | JSON-body login variant used by some SDKs |
|
||||
|
||||
## Implemented operations
|
||||
|
||||
- `RetrieveServiceContent`, `Login`, `Logout`
|
||||
- `RetrieveProperties`, `RetrievePropertiesEx`, **ContinueRetrievePropertiesEx**
|
||||
(pagination tokens; `<objects>` plural), `CreateFilter`,
|
||||
`WaitForUpdatesEx` (version tokens; empty polls), `CreateContainerView`,
|
||||
`DestroyPropertyFilter`
|
||||
- `FindByInventoryPath` (paths omit the root `Datacenters` folder, matching
|
||||
govmomi conventions), `FindByUuid`, `FindByDnsName`, `FindByIp`, `FindChild`
|
||||
- `CreateVM_Task`, `CreateChildVM_Task`, `CreateFolder`, `PowerOnVM_Task`,
|
||||
`PowerOffVM_Task`, `CloneVM_Task`, `CreateSnapshot_Task`, `Rename_Task`,
|
||||
`ReconfigVM_Task`, `RelocateVM_Task`, `Destroy_Task`, `CustomizeVM_Task`,
|
||||
`CancelTask`, `CurrentTime`
|
||||
- Guest file ops: `InitiateFileTransferToGuest`,
|
||||
`InitiateFileTransferFromGuest`, `ListFilesInGuest`, `DeleteFileInGuest`,
|
||||
`MakeDirectoryInGuest`
|
||||
- Import/upload: `ImportVApp_Task`, `CreateImportSpec`,
|
||||
`HttpNfcLeaseComplete`, `HttpNfcLeaseProgress`, `HttpNfcLeaseAbort`,
|
||||
`HttpNfcLeaseGetManifest` (paired with the REST `/nfc/{lease}` endpoints —
|
||||
see [Content library](content-library.md))
|
||||
- `QueryConfigOption`, `QueryConfigOptionEx`, `QueryConfigOptionDescriptor`,
|
||||
`QueryConfigTarget`
|
||||
- PBM (`/pbm`) stub for storage-policy-aware clients
|
||||
|
||||
## Highlights
|
||||
|
||||
- `Login` issues the same underlying session as REST (`vmware-api-session-id`
|
||||
cookie/header, plus a `vmware_soap_session` cookie) — see
|
||||
[Session](session.md).
|
||||
- `VIM_VERSION` is pinned to `8.0.2` with ≤3 dotted components, since
|
||||
`hashicorp/vsphere` parses `AboutInfo.version` strictly.
|
||||
- Type-strict MOR lookup rejects a `VirtualApp:resgroup-*` reference from
|
||||
resolving as a plain `ResourcePool` — matters for the Terraform
|
||||
`CreateVM_Task` resource path.
|
||||
- Task-returning operations create a real row in `vsphere_tasks` (shared with
|
||||
REST — see [Tasks](tasks.md)), including `info.result` MoRefs on
|
||||
create/clone.
|
||||
- PropertyCollector filters, ContainerViews, and WaitForUpdatesEx version
|
||||
tokens persist in `vsphere_pc_state` (migration `013`) across process
|
||||
restarts within a lab.
|
||||
- `Folder.childType` is emitted as `ArrayOfString`; string properties carry
|
||||
`xsi:type="xsd:string"` so govmomi's decoder accepts them; `Datastore.host`
|
||||
is `ArrayOfDatastoreHostMount`; `Cluster`/`Host` expose `environmentBrowser`.
|
||||
|
||||
See [Clients](../clients.md) for pyvmomi/govmomi/Terraform/Pulumi connection
|
||||
examples and [examples/python/vsphere_soap_smoke.py](../../examples/python/vsphere_soap_smoke.py)
|
||||
for a minimal raw-XML smoke.
|
||||
@@ -0,0 +1,37 @@
|
||||
**Language / Язык:** [English](storage.md) | [Русский](../ru/domains/storage.md)
|
||||
|
||||
# Storage
|
||||
|
||||
Datastores, datastore file metadata, host storage devices, and storage
|
||||
policies:
|
||||
[`app/vsphere/rest/router.py`](../../app/vsphere/rest/router.py),
|
||||
[`content_rest.py`](../../app/vsphere/rest/content_rest.py),
|
||||
[`platform_rest.py`](../../app/vsphere/rest/platform_rest.py),
|
||||
[`app/vsphere/domain/content.py`](../../app/vsphere/domain/content.py).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| GET | `/api/vcenter/datastore[/{datastore}]` | Type (`VMFS`/`NFS`), capacity, free space, `multiple_host_access` |
|
||||
| GET/POST | `/api/vcenter/datastore/{datastore}/files` | List / register file metadata (ISOs, VMX, VMDK paths) |
|
||||
| GET | `/api/vcenter/host/{host}/storage/storage-device` | Seeded local disk devices (`naa.*`, capacity, SSD flag) |
|
||||
| GET | `/api/vcenter/storage/policies[/{policy}/vm]` | Storage-based policy management, incl. `policy_type: VSAN` lab policies |
|
||||
|
||||
Legacy `GET /rest/vcenter/datastore` mirrors the list in a
|
||||
`{ "value": … }` envelope.
|
||||
|
||||
## Highlights
|
||||
|
||||
- Datastore rows are seeded with realistic capacity/free-space pairs
|
||||
(`type`, `capacity`, `free_space`, `accessible`,
|
||||
`multiple_host_access`) — see
|
||||
[`app/vsphere/profiles.py`](../../app/vsphere/profiles.py).
|
||||
- File metadata lives in `vsphere_datastore_files` (`path`, `size`, `type`);
|
||||
the seed pre-populates ISOs and a VM's `.vmx`/`.vmdk` entries
|
||||
(`seed_platform_extras`).
|
||||
- Storage policies include a lab `RAID1` vSAN-labelled policy — see the
|
||||
"Platform surfaces" table in [API coverage](../api-coverage.md) for the
|
||||
vSAN caveat (seeded lab data, not a real vSAN cluster).
|
||||
- Host storage devices are per-host synthetic disks, not real ESXi VMFS
|
||||
extents — capacity/SSD flags vary deterministically by host index.
|
||||
@@ -0,0 +1,31 @@
|
||||
**Language / Язык:** [English](tagging.md) | [Русский](../ru/domains/tagging.md)
|
||||
|
||||
# Tagging
|
||||
|
||||
CIS tagging service (categories, tags, object associations):
|
||||
[`app/vsphere/rest/tagging_rest.py`](../../app/vsphere/rest/tagging_rest.py),
|
||||
[`app/vsphere/domain/tagging.py`](../../app/vsphere/domain/tagging.py).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| GET/POST | `/api/cis/tagging/category` | List / create (`cardinality`, `associable_types`) |
|
||||
| GET/DELETE | `/api/cis/tagging/category/{category_id}` | |
|
||||
| GET/POST | `/api/cis/tagging/tag` | List / create under a category |
|
||||
| GET/DELETE | `/api/cis/tagging/tag/{tag_id}` | |
|
||||
| POST | `/api/cis/tagging/tag-association` | Attach/detach a tag to/from an object |
|
||||
|
||||
## Highlights
|
||||
|
||||
- Category and tag ids follow the real `urn:vmomi:InventoryServiceCategory:…`
|
||||
/ `urn:vmomi:InventoryServiceTag:…:GLOBAL` shape.
|
||||
- Rows persist in `vsphere_tag_categories`, `vsphere_tags`,
|
||||
`vsphere_tag_associations` — durable across restarts, replaced on reseed.
|
||||
- The seed creates two categories (`Environment`, `Owner`) with `prod`/
|
||||
`staging`/`platform` tags and attaches `prod` to two seeded VMs
|
||||
(`seed_platform_extras` in
|
||||
[`app/vsphere/domain/content.py`](../../app/vsphere/domain/content.py)).
|
||||
- Attaching/creating a tag requires
|
||||
`InventoryService.Tagging.CreateCategory` / `.CreateTag` / `.AttachTag`
|
||||
privileges — see [Authorization](authz.md).
|
||||
@@ -0,0 +1,37 @@
|
||||
**Language / Язык:** [English](tasks.md) | [Русский](../ru/domains/tasks.md)
|
||||
|
||||
# Tasks
|
||||
|
||||
Long-running operations (power, clone, relocate, snapshot, OVF deploy, guest
|
||||
customize) return a CIS-style task id:
|
||||
[`app/vsphere/domain/tasks.py`](../../app/vsphere/domain/tasks.py),
|
||||
[`app/vsphere/rest/tasks.py`](../../app/vsphere/rest/tasks.py).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| GET | `/api/cis/tasks` | List recent tasks (most recent 200) |
|
||||
| GET | `/api/cis/tasks/{task}` | Status, progress, `service`/`operation`, `result`/`error` |
|
||||
|
||||
## Client pattern
|
||||
|
||||
1. `POST`/`DELETE` mutation → read the task id from `{ "task": "task-…" }`
|
||||
(REST) or the SOAP `*_Task` MoRef.
|
||||
2. Poll `GET /api/cis/tasks/{task}` until `status` is `SUCCEEDED` or `FAILED`.
|
||||
3. `result` holds operation-specific output (for example `{"vm": "vm-104"}`
|
||||
on create/clone/deploy).
|
||||
|
||||
## Highlights
|
||||
|
||||
- Task rows commit to `vsphere_tasks` (`id`, `description`, `status`,
|
||||
`service`, `operation`, `result`, `error`, `completed_at`).
|
||||
- `progress` is synthesized as `50` while running and `100` once terminal —
|
||||
this simulator does not model fractional progress.
|
||||
- The same task store backs both REST `/api/cis/tasks` and SOAP task MoRefs,
|
||||
so a Terraform apply (SOAP `CreateVM_Task`) and a REST poll of the same id
|
||||
see consistent state.
|
||||
- Simulation durations honour `SIMULATION_TIME_SCALE`
|
||||
(higher = faster simulated completion).
|
||||
|
||||
See [API surface](../api-surface.md) and [Operations](../operations.md).
|
||||
@@ -0,0 +1,50 @@
|
||||
**Language / Язык:** [English](vm.md) | [Русский](../ru/domains/vm.md)
|
||||
|
||||
# Virtual machines
|
||||
|
||||
Full REST lifecycle for `VirtualMachine` objects:
|
||||
[`app/vsphere/rest/router.py`](../../app/vsphere/rest/router.py),
|
||||
[`vm_ext.py`](../../app/vsphere/rest/vm_ext.py),
|
||||
[`app/vsphere/domain/vm_ops.py`](../../app/vsphere/domain/vm_ops.py).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Notes |
|
||||
|---|---|---|
|
||||
| GET | `/api/vcenter/vm` | List with `names`/`power_states`/`hosts`/`folders`/`datacenters`/`clusters`/`resource_pools`/`limit`/`cursor` filters |
|
||||
| GET/DELETE | `/api/vcenter/vm/{vm}` | Get / delete (must be powered off) |
|
||||
| POST | `/api/vcenter/vm` | Create — `placement.{folder,host,datastore,resource_pool}`, `cpu.count`, `memory.size_MiB`, `disks`, `nics` |
|
||||
| GET/POST | `/api/vcenter/vm/{vm}/power` | Get power state / `?action=start\|stop\|suspend\|reset` — returns `{ "task": "task-…" }` |
|
||||
| GET | `/api/vcenter/vm/{vm}/hardware` | Summary |
|
||||
| GET/PATCH | `/api/vcenter/vm/{vm}/hardware/cpu` \| `/memory` | Change CPU count / memory (privilege-gated) |
|
||||
| GET/POST | `/api/vcenter/vm/{vm}/hardware/disk` \| `/ethernet` | Add disk / NIC |
|
||||
| GET | `/api/vcenter/vm/{vm}/hardware/boot` | Boot type/order |
|
||||
| GET/POST/DELETE | `/api/vcenter/vm/{vm}/snapshots[/{snapshot}]` | Create, revert (`?action=revert`), delete |
|
||||
| POST | `/api/vcenter/vm/{vm}/clone` \| `/relocate` | Task-returning |
|
||||
| GET/POST | `/api/vcenter/vm/{vm}/tools` | Guest tools status / upgrade |
|
||||
| GET | `/api/vcenter/vm/{vm}/guest/identity` \| `/networking` | Guest OS name, synthetic IP |
|
||||
| GET/POST | `/api/vcenter/vm/{vm}/guest/power` | Guest-level power ops |
|
||||
| POST | `/api/vcenter/vm/{vm}/guest/customization` | Sysprep/cloud-init-style customization spec |
|
||||
| POST | `/api/vcenter/vm/{vm}/console/tickets` | Console (VNC/WebMKS-style) ticket |
|
||||
| GET/PUT/DELETE | `/api/vcenter/vm/{vm}/guest/filesystem` | Lab virtual guest filesystem (Ansible/Terraform write-a-file flows) |
|
||||
| GET | `/api/vcenter/vm/{vm}/guest/filesystem/files` \| `/guest/local-filesystem` | Listing |
|
||||
|
||||
## Highlights
|
||||
|
||||
- Every VM row carries a realistic device shape: `nics`, `disks`, `cdroms`,
|
||||
`floppies`, `serials`, `scsi_adapters`, `boot`/`boot_devices`, `identity`
|
||||
(`instance_uuid`, `bios_uuid`), and a synthetic `guest_ip` /
|
||||
`guest_filesystems` map — the same fields power both the REST hardware
|
||||
endpoints and SOAP `VirtualMachineConfigInfo`.
|
||||
- Create requires `VirtualMachine.Inventory.Create`; delete requires
|
||||
`VirtualMachine.Inventory.Delete` **and** the VM must be `POWERED_OFF`.
|
||||
- Power/clone/snapshot/relocate/customize all create a durable CIS task (see
|
||||
[Tasks](tasks.md)) rather than mutating synchronously in the response body.
|
||||
- Console tickets from `/api/vcenter/vm/{vm}/console/tickets` persist in
|
||||
`vsphere_console_tickets` (migration `013`).
|
||||
- MOIDs follow the `vm-{100+n}` convention seeded by
|
||||
[`app/vsphere/profiles.py`](../../app/vsphere/profiles.py).
|
||||
|
||||
See [Storage](storage.md) for datastore/disk-file semantics and
|
||||
[SOAP / VIM](soap.md) for the equivalent `CreateVM_Task`/`PowerOnVM_Task`/…
|
||||
operations used by pyvmomi, govmomi, Terraform, and Pulumi.
|
||||
@@ -0,0 +1,23 @@
|
||||
**Language / Язык:** [English](ansible.md) | [Русский](../ru/examples/ansible.md)
|
||||
|
||||
# Ansible
|
||||
|
||||
The playbook uses the `uri` module against the HTTPS gateway
|
||||
(`https://localhost`), with Basic-auth session login followed by
|
||||
`vmware-api-session-id`-header calls for the rest of the lifecycle.
|
||||
|
||||
```bash
|
||||
cd examples/ansible
|
||||
ansible-playbook -i inventory.ini vsphere_playbook.yml
|
||||
```
|
||||
|
||||
[`vsphere_playbook.yml`](../../examples/ansible/vsphere_playbook.yml) covers:
|
||||
session login, list VMs, create, power on, poll the CIS task
|
||||
(`/api/cis/tasks/{task}`), write a file to the lab guest virtual filesystem,
|
||||
power off, delete, and session logout.
|
||||
|
||||
Reseed the simulator (`make seed`) before relying on fixed VM names/MOIDs
|
||||
from a previous run.
|
||||
|
||||
For the official `pulumi-vsphere` lab suite (nonempty exports, HTML report),
|
||||
see [`pulumi-tests/`](../../pulumi-tests/README.md) or `make pulumi-tests`.
|
||||
@@ -0,0 +1,21 @@
|
||||
**Language / Язык:** [English](go.md) | [Русский](../ru/examples/go.md)
|
||||
|
||||
# Go
|
||||
|
||||
Uses the Go standard library (`net/http`) against
|
||||
`https://localhost` with a Basic-auth session
|
||||
(`vmware-api-session-id`).
|
||||
|
||||
```bash
|
||||
cd examples/go
|
||||
go run .
|
||||
```
|
||||
|
||||
Override defaults with `VSPHERE_BASE`, `VSPHERE_USER`, `VSPHERE_PASSWORD`,
|
||||
`VSPHERE_VM_NAME`. See [`main.go`](../../examples/go/main.go) for the
|
||||
session → list → create → power → wait-task → delete flow and the
|
||||
`waitTask` helper that polls `GET /api/cis/tasks/{task}`.
|
||||
|
||||
TLS verification is disabled in the HTTP client for the local self-signed
|
||||
development gateway certificate only — do not reuse that transport against a
|
||||
real vCenter.
|
||||
@@ -0,0 +1,22 @@
|
||||
**Language / Язык:** [English](java.md) | [Русский](../ru/examples/java.md)
|
||||
|
||||
# Java
|
||||
|
||||
Java 11+ `HttpClient` cookbook using a Basic-auth session
|
||||
(`vmware-api-session-id`) against `https://localhost`. No third-party
|
||||
JSON library — responses are inspected with a small string-based field
|
||||
extractor suitable for a lab smoke.
|
||||
|
||||
```bash
|
||||
cd examples/java
|
||||
javac Cookbook.java && java Cookbook
|
||||
```
|
||||
|
||||
Override defaults with `VSPHERE_BASE`, `VSPHERE_USER`, `VSPHERE_PASSWORD`,
|
||||
`VSPHERE_VM_NAME` environment variables. See
|
||||
[`Cookbook.java`](../../examples/java/Cookbook.java) for the session →
|
||||
create → power → wait-task → delete flow.
|
||||
|
||||
The client installs a trust-all `SSLContext` for the local self-signed
|
||||
development gateway certificate only — do not reuse it against a real
|
||||
vCenter.
|
||||
@@ -0,0 +1,53 @@
|
||||
**Language / Язык:** [English](overview.md) | [Русский](../ru/examples/overview.md)
|
||||
|
||||
# Client examples overview
|
||||
|
||||
## Bring-up checklist
|
||||
|
||||
```bash
|
||||
make up
|
||||
curl -skf https://localhost/health/ready
|
||||
make seed
|
||||
curl -sk https://localhost/api/appliance/system/version
|
||||
```
|
||||
|
||||
## Endpoints
|
||||
|
||||
| URL | When |
|
||||
|---|---|
|
||||
| `https://localhost` | curl, pyvmomi, govmomi, Terraform, Pulumi, Ansible, Go, Java, Perl — everything in `examples/` |
|
||||
| `http://localhost` | Plain-HTTP lab face (no TLS handshake needed) |
|
||||
|
||||
## Auth quick reference
|
||||
|
||||
**Session (REST)**
|
||||
|
||||
```bash
|
||||
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/vm
|
||||
```
|
||||
|
||||
**SOAP Login**
|
||||
|
||||
```bash
|
||||
python examples/python/vsphere_soap_smoke.py https://localhost
|
||||
```
|
||||
|
||||
## Task waiting
|
||||
|
||||
Never treat the mutation HTTP response alone as "VM running". Power, clone,
|
||||
relocate, snapshot, and OVF-deploy calls return `{ "task": "task-…" }`; poll
|
||||
`GET /api/cis/tasks/{task}` until `status` is `SUCCEEDED` or `FAILED`. See
|
||||
[Tasks](../domains/tasks.md).
|
||||
|
||||
## Reseed warning
|
||||
|
||||
`make seed` replaces the PostgreSQL inventory. Refresh Terraform/Pulumi/Ansible
|
||||
state afterwards — see [Seed profiles](../seed-profiles.md).
|
||||
|
||||
## Runnable tree
|
||||
|
||||
See [`examples/README.md`](../../examples/README.md). The official
|
||||
`pulumi-vsphere` lab suite lives under
|
||||
[`pulumi-tests/`](../../pulumi-tests/README.md) (`make pulumi-tests`).
|
||||
@@ -0,0 +1,20 @@
|
||||
**Language / Язык:** [English](perl.md) | [Русский](../ru/examples/perl.md)
|
||||
|
||||
# Perl
|
||||
|
||||
`HTTP::Tiny` + `JSON` cookbook using a Basic-auth session
|
||||
(`vmware-api-session-id`) against `https://localhost`.
|
||||
|
||||
```bash
|
||||
cd examples/perl
|
||||
cpanm --installdeps . # or install HTTP::Tiny, JSON, IO::Socket::SSL manually
|
||||
perl cookbook.pl
|
||||
```
|
||||
|
||||
Override defaults with `VSPHERE_BASE`, `VSPHERE_USER`, `VSPHERE_PASSWORD`,
|
||||
`VSPHERE_VM_NAME` environment variables. See
|
||||
[`cookbook.pl`](../../examples/perl/cookbook.pl) for the session → list →
|
||||
create → power → wait-task → delete flow.
|
||||
|
||||
`HTTP::Tiny` is constructed with `verify_SSL => 0` for the local self-signed
|
||||
development gateway certificate only.
|
||||
@@ -0,0 +1,31 @@
|
||||
**Language / Язык:** [English](pulumi.md) | [Русский](../ru/examples/pulumi.md)
|
||||
|
||||
# Pulumi
|
||||
|
||||
[`examples/pulumi/`](../../examples/pulumi/) is a Python Pulumi program that uses
|
||||
the official [`pulumi-vsphere`](https://www.pulumi.com/registry/packages/vsphere/)
|
||||
provider (SOAP/VIM) against the simulator — the same provider path as Terraform
|
||||
`hashicorp/vsphere`.
|
||||
|
||||
```bash
|
||||
cd examples/pulumi
|
||||
pip install -r requirements.txt
|
||||
pulumi plugin install resource vsphere 4.17.0
|
||||
pulumi stack init dev # once
|
||||
pulumi config set server localhost # or your gateway host
|
||||
pulumi config set --secret password 'VMware1!'
|
||||
pulumi up
|
||||
```
|
||||
|
||||
Configuration (`pulumi config set`): `server` (default `localhost`), `user`
|
||||
(default `administrator@vsphere.local`), `password` (secret), `datacenter`,
|
||||
`datastore`, `cluster`, `network`, `vm_name` (default `pulumi-lab-01`).
|
||||
|
||||
Same reseed caution as Terraform: simulator PostgreSQL state and Pulumi state
|
||||
are independent. Pin the catalog major for reproducible CI if your workflow
|
||||
depends on Web UI/evidence output (see [API versions](../api-versions.md)) —
|
||||
runtime routes themselves are always available regardless of the major.
|
||||
|
||||
For the lab suite (inventory + folder + VM + tags, nonempty output checks, HTML
|
||||
report), see [`pulumi-tests/`](../../pulumi-tests/README.md) or run
|
||||
`make pulumi-tests` from the repo root.
|
||||
@@ -0,0 +1,33 @@
|
||||
**Language / Язык:** [English](python-requests.md) | [Русский](../ru/examples/python-requests.md)
|
||||
|
||||
# Python — REST (requests / stdlib)
|
||||
|
||||
Raw HTTP against the vSphere REST gateway, no vendor SDK required.
|
||||
|
||||
```bash
|
||||
pip install -r examples/python/requirements.txt
|
||||
python examples/python/requests_cookbook.py
|
||||
```
|
||||
|
||||
[`requests_cookbook.py`](../../examples/python/requests_cookbook.py)
|
||||
demonstrates the shared session → create → wait-for-task → power on → wait →
|
||||
power off → delete flow using `requests`, with the session id carried as the
|
||||
`vmware-api-session-id` header.
|
||||
|
||||
For a dependency-free variant using only the standard library (`urllib`),
|
||||
see [`vsphere_rest_smoke.py`](../../examples/python/vsphere_rest_smoke.py):
|
||||
|
||||
```bash
|
||||
python examples/python/vsphere_rest_smoke.py https://localhost
|
||||
```
|
||||
|
||||
For a combined REST-create + SOAP-`CreateVM_Task` + guest-filesystem smoke,
|
||||
see [`vsphere_lifecycle.py`](../../examples/python/vsphere_lifecycle.py):
|
||||
|
||||
```bash
|
||||
VSPHERE_BASE=https://localhost python examples/python/vsphere_lifecycle.py
|
||||
```
|
||||
|
||||
All three scripts default to `administrator@vsphere.local` / `VMware1!` and
|
||||
disable TLS verification for the local self-signed development gateway
|
||||
certificate only.
|
||||
@@ -0,0 +1,32 @@
|
||||
**Language / Язык:** [English](terraform.md) | [Русский](../ru/examples/terraform.md)
|
||||
|
||||
# Terraform
|
||||
|
||||
[`examples/terraform/vsphere/`](../../examples/terraform/vsphere/) uses the
|
||||
official `hashicorp/vsphere` provider (SOAP `/sdk` under the hood) pointed at
|
||||
the local HTTPS gateway (`https://localhost`) with
|
||||
`allow_unverified_ssl = true` for the development certificate.
|
||||
|
||||
```bash
|
||||
cd examples/terraform/vsphere
|
||||
terraform init
|
||||
TF_VAR_create_lab_vm=false terraform plan # data sources only (datacenter/cluster/datastore/network/VM)
|
||||
TF_VAR_create_lab_vm=true terraform apply # also creates a lab VM (SOAP CreateVM_Task)
|
||||
```
|
||||
|
||||
Defaults (`variables.tf`): `vsphere_server = "localhost"`,
|
||||
`vsphere_user = "administrator@vsphere.local"`,
|
||||
`vsphere_password = "VMware1!"`, `datacenter = "Datacenter"`,
|
||||
`cluster = "Cluster"`, `datastore = "datastore1"`,
|
||||
`network = "VM Network"`, `vm_name = "web-01"` (a `small`/`large` seeded VM).
|
||||
|
||||
Provider plugin versions move quickly — pin versions in a `required_providers`
|
||||
block to what you have tested. After `make seed`, refresh or recreate state
|
||||
so VM name/MOID assumptions stay aligned.
|
||||
|
||||
This cookbook is a starting point for lab CI, not a certification of every
|
||||
`hashicorp/vsphere` resource/data source against the full route registry. See
|
||||
[SOAP / VIM](../domains/soap.md) for the exact operations backing the
|
||||
provider's create/read paths, and
|
||||
[`pulumi-tests/`](../../pulumi-tests/README.md) for the `pulumi-vsphere` lab
|
||||
suite (`make pulumi-tests`).
|
||||
@@ -0,0 +1,15 @@
|
||||
**Language / Язык:** [English](troubleshooting-clients.md) | [Русский](../ru/examples/troubleshooting-clients.md)
|
||||
|
||||
# Troubleshooting clients
|
||||
|
||||
| Symptom | Fix |
|
||||
|---|---|
|
||||
| TLS certificate errors | Use `:443` with `verify=False` / `insecure`/`allow_unverified_ssl=true` **only** locally, or use plain HTTP `:80` |
|
||||
| 401 on first call | Send `Authorization: Basic …` only to `/api/session` (or SOAP `Login`); every other call needs `vmware-api-session-id` |
|
||||
| 403 on power/create | You may be using `readonly@vsphere.local` — switch to `administrator@vsphere.local` or `operator@vsphere.local` |
|
||||
| VM not found | `small` seed VM names are `web-01`, `web-02`, `db-01`, `app-01`, `jumpbox` — not Proxmox-style numeric VMIDs |
|
||||
| Create returns a MOID, not a task | REST `POST /api/vcenter/vm` returns the new VM's MOID synchronously; only **power/clone/relocate/snapshot/OVF-deploy** return `{ "task": "…" }` |
|
||||
| Provider create vs task | Poll `/api/cis/tasks/{task}`; many providers (Terraform, Pulumi) already wait internally — raw HTTP/Go/Java/Perl clients often forget to |
|
||||
| Drift after reseed | Refresh/recreate Terraform/Pulumi/Ansible state after `make seed` |
|
||||
| Session expired mid-run | Sessions have a 2-hour sliding TTL; re-login if a long-running script idles past that |
|
||||
| SOAP `Login` fails | Confirm the envelope targets `/sdk` with `SOAPAction` set (empty string is fine) and `Content-Type: text/xml` |
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
**Language / Язык:** [English](faq.md) | [Русский](ru/faq.md)
|
||||
|
||||
# FAQ
|
||||
|
||||
## Is this a real vCenter / ESXi?
|
||||
|
||||
No. It is an API and state simulator. Hosts, VMs, datastores, and networks
|
||||
are durable PostgreSQL models, not ESXi hosts or KVM/vmkernel processes.
|
||||
|
||||
## Do you really cover the vSphere Automation API?
|
||||
|
||||
The **runtime** always serves the full registered route table (1077 routes:
|
||||
104 deep handlers + a DB-backed stub surface for the rest) — see
|
||||
[API surface](api-surface.md). The **catalog** majors 6–8 are intentionally
|
||||
low-coverage historical floors (2.9%–9.6%); only major 9 (8.0 U2 / Automation
|
||||
9.1 surface) is declared 100% in the catalog. See
|
||||
[API versions](api-versions.md) and [Compatibility](compatibility.md).
|
||||
|
||||
## Can I use this in CI for Terraform / Ansible / pyvmomi / custom clients?
|
||||
|
||||
Yes. That is a primary use case. Seed a profile and point clients at the
|
||||
HTTPS gateway `:443` (REST `/api`/`/rest` or SOAP `/sdk`). See
|
||||
[Clients](clients.md).
|
||||
|
||||
## Why do some NSX / Supervisor / vSAN / SAML calls "succeed" without remotes?
|
||||
|
||||
Those areas persist **local, seeded** simulator state (see the "Platform
|
||||
surfaces" table in [API coverage](api-coverage.md)). They intentionally do
|
||||
not call a real NSX Manager, Tanzu Supervisor, or IdP.
|
||||
|
||||
## Does registry coverage mean perfect vSphere parity?
|
||||
|
||||
It means every registered route has a durable handler or DB-backed stub and
|
||||
is subject to the project's verification suites. Exact edge-case parity with
|
||||
a physical ESXi cluster can still differ; use `/ui/api/compatibility` and
|
||||
your own client tests for certification claims.
|
||||
|
||||
## Where is the Web UI?
|
||||
|
||||
[https://localhost/](https://localhost/) after `make up` (gateway).
|
||||
|
||||
## Can I deploy on Kubernetes?
|
||||
|
||||
Yes. Use the Helm chart under `helm/vmware-api-simulator` with the published
|
||||
Hub image. Ingress + cert-manager Let's Encrypt is supported — see
|
||||
[Kubernetes / Helm](kubernetes.md).
|
||||
|
||||
## What is `ENABLE_PVE_STUB`?
|
||||
|
||||
An optional, off-by-default legacy Proxmox VE `/api2/*` stub plane inherited
|
||||
from a shared platform lineage. Native vSphere REST/SOAP is always on and is
|
||||
the primary surface of this project regardless of this flag.
|
||||
|
||||
## Which VMs does the `small` seed use?
|
||||
|
||||
`web-01`, `web-02`, `db-01`, `app-01`, `jumpbox` — see
|
||||
[Seed profiles](seed-profiles.md).
|
||||
@@ -0,0 +1,175 @@
|
||||
**Language / Язык:** [English](getting-started.md) | [Русский](ru/getting-started.md)
|
||||
|
||||
# Getting started
|
||||
|
||||
Bring up a local vSphere laboratory, authenticate, and exercise a first
|
||||
read/mutation cycle against the simulator.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker and Docker Compose
|
||||
- `make` (optional but used by the documented commands)
|
||||
|
||||
Python, linters, and tests run **inside** containers. You do not need a local
|
||||
Python toolchain for day-to-day use.
|
||||
|
||||
## Choose a path
|
||||
|
||||
| Path | When to use |
|
||||
|---|---|
|
||||
| [Published image](#1a-published-image-docker-hub) | Fastest lab using `inecs/vmware-api-simulator` |
|
||||
| [Helm / Kubernetes](kubernetes.md) | Cluster install with Ingress + Let's Encrypt |
|
||||
| [Development checkout](#1b-development-checkout) | Contribute / bind-mount source |
|
||||
|
||||
## 1a. Published image (Docker Hub)
|
||||
|
||||
Uses [`docker-compose.release.yml`](../docker-compose.release.yml) — PostgreSQL +
|
||||
runtime simulator + HTTPS gateway from Hub. No source build required, but you
|
||||
**must** run Compose from a checkout of this repository so `docker/gateway/` and
|
||||
`docker/tls/` bind-mounts resolve. Seed runs automatically after the simulator
|
||||
is healthy.
|
||||
|
||||
```bash
|
||||
# from a git checkout of this repository (needs docker/gateway + docker/tls)
|
||||
docker compose -f docker-compose.release.yml pull
|
||||
docker compose -f docker-compose.release.yml up -d --wait
|
||||
```
|
||||
|
||||
Pin a version:
|
||||
|
||||
```bash
|
||||
IMAGE_TAG=0.1.0 docker compose -f docker-compose.release.yml up -d --wait
|
||||
```
|
||||
|
||||
Make helpers (git checkout):
|
||||
|
||||
```bash
|
||||
make release-up
|
||||
# optional re-seed: make release-seed PROFILE=small
|
||||
```
|
||||
|
||||
| Host port | Service |
|
||||
|---|---|
|
||||
| `443` | HTTPS gateway (primary vCenter entry) |
|
||||
| `80` | HTTP lab face |
|
||||
| `5434` | PostgreSQL (localhost only) |
|
||||
|
||||
Migrations run automatically via the `migrate` one-shot service.
|
||||
|
||||
Then continue from [Wait until ready](#2-wait-until-ready).
|
||||
|
||||
## 1b. Development checkout
|
||||
|
||||
```bash
|
||||
make install
|
||||
make up
|
||||
```
|
||||
|
||||
Services (see [Ports](ports.md) for the full picture):
|
||||
|
||||
| Host port | Service |
|
||||
|---|---|
|
||||
| `443` | HTTPS gateway (nginx) → simulator |
|
||||
| `80` | HTTP lab face |
|
||||
| `5434` | PostgreSQL (localhost only) |
|
||||
|
||||
Migrations apply automatically before the simulator becomes ready. The
|
||||
internal FastAPI process listens on `8080` and is not published to the host.
|
||||
|
||||
## 2. Wait until ready
|
||||
|
||||
```bash
|
||||
curl -sk https://localhost/health/live
|
||||
curl -sk https://localhost/health/ready
|
||||
```
|
||||
|
||||
`/health/ready` returns HTTP 503 until PostgreSQL is reachable **and** the
|
||||
latest packaged migration is applied.
|
||||
|
||||
## 3. Seed a profile
|
||||
|
||||
```bash
|
||||
make seed # default: large — 10 hosts / 1000 VMs
|
||||
VSPHERE_PROFILE=small make seed
|
||||
```
|
||||
|
||||
`small` creates a 3-host cluster with five named VMs (`web-01`, `web-02`,
|
||||
`db-01`, `app-01`, `jumpbox`), datastores, a standard portgroup, and the four
|
||||
lab principals. See [Seed profiles](seed-profiles.md) for other sizes.
|
||||
|
||||
## 4. Check the API version
|
||||
|
||||
```bash
|
||||
curl -sk https://localhost/api/appliance/system/version | jq .
|
||||
```
|
||||
|
||||
The cold-start catalog major defaults to **9** (vSphere 8.0 U2 / Automation
|
||||
9.1 surface) in Docker Compose. Browse or hot-swap majors 6–9 from the Web UI
|
||||
or [API versions](api-versions.md).
|
||||
|
||||
## 5. Authenticate
|
||||
|
||||
```bash
|
||||
SID=$(curl -sk -u 'administrator@vsphere.local:VMware1!' \
|
||||
-X POST https://localhost/api/session | tr -d '"')
|
||||
echo "$SID"
|
||||
```
|
||||
|
||||
`SID` is the `vmware-api-session-id`. Send it on every subsequent call as a
|
||||
header (or rely on the cookie the login response also sets):
|
||||
|
||||
```bash
|
||||
curl -sk -H "vmware-api-session-id: $SID" https://localhost/api/vcenter/vm
|
||||
```
|
||||
|
||||
Details: [Authentication](authentication.md).
|
||||
|
||||
## 6. List VMs and power one on
|
||||
|
||||
```bash
|
||||
curl -sk -H "vmware-api-session-id: $SID" \
|
||||
https://localhost/api/vcenter/vm | jq .
|
||||
|
||||
curl -sk -X POST -H "vmware-api-session-id: $SID" \
|
||||
"https://localhost/api/vcenter/vm/vm-104/power?action=start" | jq .
|
||||
```
|
||||
|
||||
Power actions and other long-running operations return a CIS task id.
|
||||
Poll until the task finishes:
|
||||
|
||||
```bash
|
||||
curl -sk -H "vmware-api-session-id: $SID" \
|
||||
"https://localhost/api/cis/tasks/${TASK_ID}" | jq .
|
||||
```
|
||||
|
||||
## 7. Open the Web UI
|
||||
|
||||
Visit [https://localhost/](https://localhost/) for the interactive
|
||||
console, endpoint catalog (vSphere majors 6–9), compatibility view, runtime
|
||||
contract apply, and demo-cluster controls. See [Web UI](web-ui.md) for
|
||||
light/dark theme screenshots and the full feature list.
|
||||
|
||||
## 8. Try a client library
|
||||
|
||||
```bash
|
||||
# from the repository root after make up + seed
|
||||
python examples/python/vsphere_rest_smoke.py https://localhost
|
||||
python examples/python/vsphere_soap_smoke.py https://localhost
|
||||
```
|
||||
|
||||
More stacks: [Clients](clients.md) and [`examples/`](../examples/README.md).
|
||||
|
||||
## You're done when…
|
||||
|
||||
- `/health/ready` returns `{"status": "ok"}` (or equivalent OK body)
|
||||
- `/api/appliance/system/version` reports the active catalog major's version
|
||||
- Session login succeeds for `administrator@vsphere.local`
|
||||
- `/api/vcenter/vm` lists the seeded VMs
|
||||
- A power action returns a task id that reaches `SUCCEEDED`
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Configuration](configuration.md) — env vars, workers, seed sizing
|
||||
- [API versions](api-versions.md) — hot-swap catalog majors 6–9
|
||||
- [Clients](clients.md) — Python, Ansible, Terraform, Pulumi
|
||||
- [Operations](operations.md) — reseed, migrate, upgrades
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,162 @@
|
||||
**Language / Язык:** [English](kubernetes.md) | [Русский](ru/kubernetes.md)
|
||||
|
||||
# Kubernetes / Helm
|
||||
|
||||
Deploy the published Docker Hub runtime image with the chart in
|
||||
[`helm/vmware-api-simulator`](../helm/vmware-api-simulator).
|
||||
|
||||
Image: [`inecs/vmware-api-simulator`](https://hub.docker.com/r/inecs/vmware-api-simulator)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.27+ (or comparable)
|
||||
- Helm 3.14+
|
||||
- [Ingress NGINX](https://kubernetes.github.io/ingress-nginx/) (or another
|
||||
IngressClass that supports HTTP-01)
|
||||
- [cert-manager](https://cert-manager.io/) installed cluster-wide
|
||||
|
||||
Example cert-manager install:
|
||||
|
||||
```bash
|
||||
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.yaml
|
||||
```
|
||||
|
||||
## Quick install (Hub release + Ingress + Let's Encrypt)
|
||||
|
||||
From a git checkout of this repository:
|
||||
|
||||
```bash
|
||||
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)" \
|
||||
--set postgresql.auth.password="$(openssl rand -hex 16)"
|
||||
```
|
||||
|
||||
What this does:
|
||||
|
||||
1. Pulls `inecs/vmware-api-simulator:0.1.0` (see `image.tag` in the example file).
|
||||
2. Installs bundled PostgreSQL 17 (`postgres:17.5-bookworm`, same as Compose).
|
||||
3. Runs schema migrations in an init container (idempotent).
|
||||
4. Seeds the `small` lab profile (`seed.enabled=true`).
|
||||
5. Creates `ClusterIssuer` resources:
|
||||
- `letsencrypt-prod`
|
||||
- `letsencrypt-staging`
|
||||
6. Creates an Ingress with
|
||||
`cert-manager.io/cluster-issuer: letsencrypt-prod` and a TLS secret
|
||||
`vmware-api-simulator-tls`.
|
||||
|
||||
DNS for `vmware-sim.example.com` must point at your Ingress controller. Then:
|
||||
|
||||
```bash
|
||||
kubectl -n vmware-sim get certificate,ingress,pods
|
||||
# wait until Certificate READY=True
|
||||
curl -sS https://vmware-sim.example.com/health/ready
|
||||
open https://vmware-sim.example.com/
|
||||
```
|
||||
|
||||
Default seeded login: `administrator@vsphere.local` / `VMware1!`.
|
||||
|
||||
### Staging first (recommended)
|
||||
|
||||
Validate HTTP-01 without hitting production rate limits:
|
||||
|
||||
```bash
|
||||
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 certManager.useStaging=true \
|
||||
--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)"
|
||||
```
|
||||
|
||||
Browsers will not trust the staging CA — use `curl -k` while testing. Flip
|
||||
`certManager.useStaging=false` and recreate the Certificate/TLS secret for
|
||||
production.
|
||||
|
||||
## Minimal install (ClusterIP + port-forward)
|
||||
|
||||
```bash
|
||||
helm upgrade --install vmware-sim ./helm/vmware-api-simulator \
|
||||
-n vmware-sim --create-namespace \
|
||||
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
|
||||
--set seed.enabled=true
|
||||
|
||||
kubectl -n vmware-sim port-forward svc/vmware-sim-vmware-api-simulator 8080:8080
|
||||
```
|
||||
|
||||
Open http://127.0.0.1:8080/. The Service exposes the internal application
|
||||
port (`8080`, see [Ports](ports.md)) — the chart does not run the nginx
|
||||
TLS gateway used by Compose; put TLS in front of it via Ingress in
|
||||
production, or talk to the plain-HTTP Service for local testing.
|
||||
|
||||
## External PostgreSQL
|
||||
|
||||
```bash
|
||||
helm upgrade --install vmware-sim ./helm/vmware-api-simulator \
|
||||
-n vmware-sim --create-namespace \
|
||||
--set postgresql.enabled=false \
|
||||
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
|
||||
--set secret.databaseUrl='postgresql://user:pass@pg.example.com:5432/vmware_simulator'
|
||||
```
|
||||
|
||||
Or use `secret.existingSecret` with keys `DATABASE_URL` and `TICKET_SIGNING_KEY`.
|
||||
|
||||
## How TLS issuance works
|
||||
|
||||
When `certManager.enabled=true` and `certManager.createClusterIssuer=true`, the
|
||||
chart creates ACME `ClusterIssuer` objects that solve HTTP-01 through your
|
||||
Ingress class. The Ingress template adds:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
tls:
|
||||
- secretName: vmware-api-simulator-tls
|
||||
hosts: [vmware-sim.example.com]
|
||||
```
|
||||
|
||||
cert-manager then creates a `Certificate`, completes HTTP-01, and stores the
|
||||
Let's Encrypt key pair in that TLS secret. The chart does **not** install
|
||||
cert-manager or the Ingress controller — only the issuers + Ingress wiring.
|
||||
|
||||
If ClusterIssuers already exist cluster-wide, set:
|
||||
|
||||
```yaml
|
||||
certManager:
|
||||
enabled: true
|
||||
createClusterIssuer: false
|
||||
issuerName: your-existing-issuer
|
||||
```
|
||||
|
||||
## Operations
|
||||
|
||||
```bash
|
||||
# logs
|
||||
kubectl -n vmware-sim logs -l app.kubernetes.io/instance=vmware-sim -c simulator -f
|
||||
|
||||
# reseed
|
||||
kubectl -n vmware-sim exec deploy/vmware-sim-vmware-api-simulator -- \
|
||||
python -m app.simulation.seed_cli
|
||||
# SEED_VSPHERE_PROFILE via: kubectl set env ... or --set seed.profile=demo-cluster and upgrade
|
||||
|
||||
# uninstall
|
||||
helm -n vmware-sim uninstall vmware-sim
|
||||
```
|
||||
|
||||
## Values reference
|
||||
|
||||
See [`helm/vmware-api-simulator/values.yaml`](../helm/vmware-api-simulator/values.yaml)
|
||||
and the [chart README](../helm/vmware-api-simulator/README.md). Related docs:
|
||||
|
||||
- [Getting started](getting-started.md) — Compose paths
|
||||
- [Operations](operations.md) — Docker Hub publish / release compose
|
||||
- [Security](security.md) — lab credentials and trust boundary
|
||||
- [Ports](ports.md) — internal `8080` vs published gateway ports
|
||||
@@ -0,0 +1,45 @@
|
||||
**Language / Язык:** [English](observability.md) | [Русский](ru/observability.md)
|
||||
|
||||
# Observability
|
||||
|
||||
## Health
|
||||
|
||||
| Path | Meaning |
|
||||
|---|---|
|
||||
| `GET /health/live` | Process liveness — no dependency checks |
|
||||
| `GET /health/ready` | Database reachable via `database.is_ready()`; HTTP 503 when not |
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
curl -sk https://localhost/health/live
|
||||
curl -sk https://localhost/health/ready
|
||||
```
|
||||
|
||||
Implementation: [`app/observability/health.py`](../app/observability/health.py).
|
||||
|
||||
## Request correlation
|
||||
|
||||
Incoming requests accept or generate an ID via `REQUEST_ID_HEADER`
|
||||
(default `X-Request-ID`). Structured logs include correlation fields and
|
||||
redact known secret patterns (session ids, passwords, ticket-like tokens).
|
||||
|
||||
## Metrics / tracing
|
||||
|
||||
There is **no** Prometheus `/metrics` scrape endpoint and **no** bundled
|
||||
OpenTelemetry exporter in the current application. Architecture notes that
|
||||
mention them describe target design, not shipping telemetry.
|
||||
|
||||
Do not confuse vSphere REST paths under `/api/vcenter/activity-history` or
|
||||
the seeded appliance health/timesync endpoints with simulator process
|
||||
telemetry — those handlers simulate vCenter appliance state inside
|
||||
PostgreSQL, not this process's own metrics.
|
||||
|
||||
## Compatibility evidence
|
||||
|
||||
Operational compatibility reports:
|
||||
|
||||
- `/ui/api/compatibility?major=N`
|
||||
|
||||
Also available through the Web UI compatibility panel. See
|
||||
[Compatibility](compatibility.md).
|
||||
@@ -0,0 +1,148 @@
|
||||
**Language / Язык:** [English](operations.md) | [Русский](ru/operations.md)
|
||||
|
||||
# Operations
|
||||
|
||||
## Day-2 commands
|
||||
|
||||
```bash
|
||||
make up # start stack
|
||||
make down # stop stack
|
||||
make restart
|
||||
make logs
|
||||
make dev # foreground reload-oriented workflow
|
||||
make db-migrate # idempotent migrations
|
||||
make seed # atomic reseed (SEED_VSPHERE_PROFILE=large by default)
|
||||
make shell # interactive tools container
|
||||
```
|
||||
|
||||
## Migrations
|
||||
|
||||
Ordered SQL files apply transactionally and record SHA-256 checksums.
|
||||
Re-running `make db-migrate` is safe. Altering an already-applied migration
|
||||
is rejected. `/health/ready` stays unavailable until the latest packaged
|
||||
migration is present.
|
||||
|
||||
## Reseed
|
||||
|
||||
```bash
|
||||
make seed # large (default)
|
||||
VSPHERE_PROFILE=small make seed
|
||||
VSPHERE_PROFILE=demo-cluster make seed
|
||||
```
|
||||
|
||||
Reseed replaces the PostgreSQL inventory atomically. External automation
|
||||
state (Terraform state files, Pulumi stacks, Ansible inventories that encode
|
||||
VM MOIDs/names) may then drift — refresh or recreate those side channels.
|
||||
See [Seed profiles](seed-profiles.md).
|
||||
|
||||
## Worker recovery
|
||||
|
||||
CIS task workers use PostgreSQL leases (`FOR UPDATE SKIP LOCKED`). After a
|
||||
crash or restart, expired leases are reclaimed and incomplete work can resume
|
||||
safely. Tunables: `TASK_WORKER_CONCURRENCY`, `TASK_LEASE_SECONDS`,
|
||||
`SIMULATION_TIME_SCALE`.
|
||||
|
||||
## Changing the default catalog major
|
||||
|
||||
1. The default catalog major is **9** (8.0 U2 / Automation 9.1 surface) at
|
||||
cold start; this does not gate the runtime route table (see
|
||||
[API versions](api-versions.md)).
|
||||
2. Use the Web UI "Apply as runtime" or
|
||||
`POST /ui/api/contract/apply?major=N` to switch the catalog major
|
||||
process-locally for browse/evidence purposes.
|
||||
|
||||
## Backing up lab state
|
||||
|
||||
PostgreSQL is the system of record. Use normal Postgres backup/restore
|
||||
(`pg_dump` / volume snapshots) if you need to preserve a seeded laboratory.
|
||||
Application containers are disposable when the database volume remains.
|
||||
|
||||
## Publishing to Docker Hub
|
||||
|
||||
`make release` builds the **runtime** image (the `runtime` build target — not
|
||||
the local bind-mounted `dev` image) and pushes it to Docker Hub:
|
||||
|
||||
```bash
|
||||
docker login # once; account must own or can push to DOCKERHUB_USER
|
||||
make release
|
||||
```
|
||||
|
||||
Defaults:
|
||||
|
||||
| Variable | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `DOCKERHUB_USER` | `inecs` | Docker Hub namespace/org |
|
||||
| `IMAGE_NAME` | `vmware-api-simulator` | Repository name |
|
||||
| `VERSION` | from `pyproject.toml` | Image tag |
|
||||
| `PUSH_LATEST` | `1` | Also tag/push `:latest` |
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
make release
|
||||
make release VERSION=0.2.0
|
||||
make release DOCKERHUB_USER=myorg PUSH_LATEST=0
|
||||
make release-build # build/tag locally without pushing
|
||||
```
|
||||
|
||||
Published tags:
|
||||
|
||||
- `inecs/vmware-api-simulator:<version>`
|
||||
- `inecs/vmware-api-simulator:latest` (unless `PUSH_LATEST=0`)
|
||||
|
||||
## Quick start with the published compose file
|
||||
|
||||
[`docker-compose.release.yml`](../docker-compose.release.yml) pulls the Hub
|
||||
runtime image and starts PostgreSQL + migrate + simulator + the HTTPS
|
||||
gateway:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.release.yml up -d
|
||||
docker compose -f docker-compose.release.yml run --rm --entrypoint python \
|
||||
simulator -m app.simulation.seed_cli
|
||||
|
||||
curl -sk https://localhost/health/ready
|
||||
open https://localhost/
|
||||
```
|
||||
|
||||
Helpers from a git checkout:
|
||||
|
||||
```bash
|
||||
make release-up
|
||||
make release-seed PROFILE=small
|
||||
make release-down
|
||||
```
|
||||
|
||||
Useful overrides:
|
||||
|
||||
| Variable | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `DOCKER_IMAGE` | `inecs/vmware-api-simulator` | Image repository |
|
||||
| `IMAGE_TAG` | `latest` | Tag to pull |
|
||||
| `HTTP_PORT` | `80` | Host HTTP port |
|
||||
| `HTTPS_PORT` | `443` | Host HTTPS port |
|
||||
| `POSTGRES_PORT` | `127.0.0.1:5434` | Host Postgres bind |
|
||||
| `TICKET_SIGNING_KEY` | lab default | Change outside toy labs |
|
||||
| `POSTGRES_PASSWORD` | `vmware` | DB password |
|
||||
|
||||
For Kubernetes with public TLS (cert-manager / Let's Encrypt), use the Helm
|
||||
chart — see [Kubernetes / Helm](kubernetes.md).
|
||||
|
||||
## Upgrades
|
||||
|
||||
1. Pull / rebuild images (`make install` / `make docker-build` as appropriate).
|
||||
2. Run migrations (`make db-migrate`).
|
||||
3. Confirm `/health/ready`.
|
||||
4. Re-check `/ui/api/compatibility?major=9` and `/api/appliance/system/version`.
|
||||
5. Re-run `make test-vsphere` / `make vsphere-matrix` if you validate the
|
||||
surface after upgrading.
|
||||
|
||||
## Resetting a lab
|
||||
|
||||
```bash
|
||||
make seed PROFILE=small
|
||||
# or via UI: unload demo → small, then seed again
|
||||
```
|
||||
|
||||
For a hard database reset use `make db-reset` (destructive — see Makefile
|
||||
help).
|
||||
@@ -0,0 +1,49 @@
|
||||
**Language / Язык:** [English](ports.md) | [Русский](ru/ports.md)
|
||||
|
||||
# vCenter ports in this simulator
|
||||
|
||||
Reference: [vSphere Networking Ports](https://ports.esp.vmware.com/) (vCenter Server).
|
||||
|
||||
The `api-gateway` (nginx) publishes the **primary vCenter HTTPS listener**
|
||||
plus an HTTP lab face. Every published port proxies to the same FastAPI
|
||||
process, which already path-routes REST (`/api`, `/rest`) and SOAP (`/sdk`)
|
||||
internally — there is no separate port per protocol. The gateway also sets
|
||||
`X-VMware-Service` / `X-Forwarded-Port` so clients and future routers can tell
|
||||
which port was used.
|
||||
|
||||
## Published by Compose (`api-gateway`)
|
||||
|
||||
| Service | Container port | Host port (dev compose) |
|
||||
|---|---:|---:|
|
||||
| HTTP lab face | 80 | 80 |
|
||||
| vCenter HTTPS (primary UI/API entry) | 443 | 443 |
|
||||
|
||||
Host ports match real vCenter defaults so remote clients can use
|
||||
`https://<host>/` and `http://<host>/` without a non-standard port.
|
||||
Override on release compose with `HTTP_PORT` / `HTTPS_PORT` if needed.
|
||||
|
||||
Also published by Compose (not via the gateway):
|
||||
|
||||
| Service | Host port (dev compose) |
|
||||
|---|---:|
|
||||
| PostgreSQL | `5434` (localhost only) |
|
||||
|
||||
Internal simulator process (not published to the host): `8080`.
|
||||
|
||||
## Path layout on HTTPS
|
||||
|
||||
| Surface | Path prefix | Status |
|
||||
|---|---|---|
|
||||
| vSphere REST | `/api/…`, `/rest/…` | implemented (core inventory + session) |
|
||||
| SOAP / VIM SDK | `/sdk` | implemented (RetrieveServiceContent / Login / RetrieveProperties subset) |
|
||||
| HttpNfcLease / NFC | `/nfc/…` | lab transfer handshake on the same HTTPS listener |
|
||||
| Lab console | `/` | yes |
|
||||
| Health | `/health/live`, `/health/ready` | yes |
|
||||
|
||||
## Documented but not published yet
|
||||
|
||||
| Service | Ports |
|
||||
|---|---|
|
||||
| VAMI / appliance management | 5480 |
|
||||
| ESXi host management (if simulated later) | 443 (separate host) |
|
||||
| Syslog / etc. | various |
|
||||
@@ -0,0 +1,32 @@
|
||||
**Language / Язык:** [English](../README.md) | [Русский](README.md)
|
||||
|
||||
# Документация
|
||||
|
||||
Руководства по симулятору VMware vSphere API. Переключайте язык с помощью заголовка на
|
||||
каждой странице. Русские версии находятся в каталоге [`ru/`](README.md).
|
||||
|
||||
| Руководство | Описание |
|
||||
|---|---|
|
||||
| [Быстрый старт](getting-started.md) | Первая успешная лабораторная сессия |
|
||||
| [Конфигурация](configuration.md) | Переменные окружения и Compose |
|
||||
| [Аутентификация](authentication.md) | Сессии, `vmware-api-session-id`, привилегии |
|
||||
| [Версии API](api-versions.md) | Catalog majors 6–9 и hot-swap |
|
||||
| [Поверхность API](api-surface.md) | Маршрутизация REST/SOAP, coverage registry, stubs |
|
||||
| [Покрытие API](api-coverage.md) | Broadcom universe vs реализованная поверхность |
|
||||
| [Клиенты и примеры](clients.md) | Python, Go, Java, Perl, Ansible, Terraform, Pulumi |
|
||||
| [Профили seed](seed-profiles.md) | Детерминированные фикстуры инвентаря |
|
||||
| [Домены](domains/README.md) | Session, inventory, VM, storage, networking, tagging, SOAP, tasks, … |
|
||||
| [Web UI](web-ui.md) | Интерактивная консоль и каталоги |
|
||||
| [Эксплуатация](operations.md) | Reseed, migrate, release, upgrade |
|
||||
| [Kubernetes / Helm](kubernetes.md) | Образ Hub + Ingress + Let's Encrypt |
|
||||
| [Безопасность](security.md) | Модель угроз лаборатории и учётные данные |
|
||||
| [Наблюдаемость](observability.md) | Эндпоинты health и логирование |
|
||||
| [Порты](ports.md) | Опубликованные порты хоста и внутренние сервисы |
|
||||
| [Устранение неполадок](troubleshooting.md) | Типичные сбои |
|
||||
| [FAQ](faq.md) | Краткие ответы |
|
||||
| [Архитектура](architecture.md) | Границы компонентов |
|
||||
| [Совместимость](compatibility.md) | Модель evidence и матрица релизов |
|
||||
|
||||
Исполняемые cookbook'и: [`examples/`](../../examples/README.ru.md).
|
||||
Интеграционные наборы: [`pulumi-tests/`](../../pulumi-tests/README.ru.md)
|
||||
(`make pulumi-tests`).
|
||||
@@ -0,0 +1,167 @@
|
||||
**Language / Язык:** [English](../api-coverage.md) | [Русский](api-coverage.md)
|
||||
|
||||
# Матрица покрытия vSphere API
|
||||
|
||||
Реестр, ориентированный на автоматизацию: [`app/vsphere/rest/coverage.py`](../../app/vsphere/rest/coverage.py).
|
||||
Стабы universe от Broadcom: [`app/vsphere/rest/universe.json`](../../app/vsphere/rest/universe.json) (из публичного индекса операций).
|
||||
Уровни по мажорам + бандлы стаб-OpenAPI: [`app/vsphere/contracts/matrix.py`](../../app/vsphere/contracts/matrix.py) → `contracts/vsphere/<version>/manifest.json`.
|
||||
|
||||
## Broadcom в сравнении с этим симулятором
|
||||
|
||||
Публичный источник (собран скрапингом): [Индекс операций vSphere Automation API (9.1 Latest)](https://developer.broadcom.com/xapis/vsphere-automation-api/latest/operation-index/)
|
||||
|
||||
| Поверхность | Количество | Примечания |
|
||||
|---|---:|---|
|
||||
| Индекс операций Broadcom | **1348** | GET 628 / POST 422 / DELETE 114 / PUT 93 / PATCH 91 |
|
||||
| Сгенерированные уникальные маршруты `verb + path` | **~1037** | Один и тот же HTTP-путь может обслуживать несколько именованных операций (`?action=…`, `$Task`) |
|
||||
| Реестр симулятора (core + стабы + `/rest`) | **1077** | Глубокие core-обработчики перезаписывают записи стабов на том же пути |
|
||||
| Глубокие core-обработчики | **104** | Поведение seeded-инвентаря / жизненного цикла / authz |
|
||||
| Строки поверхности, поддерживаемые БД (`vsphere_api_state`) | **~540+** | Загружаются seed для каждого GET-маршрута `/api` + лабораторные дополнения |
|
||||
|
||||
Регенерируйте universe после обновления дампа индекса:
|
||||
|
||||
```bash
|
||||
python scripts/generate_vsphere_universe.py
|
||||
make vsphere-bundles
|
||||
```
|
||||
|
||||
Обновление живой статистики / регенерация артефактов:
|
||||
|
||||
```bash
|
||||
curl -sk https://localhost/ui/api/compatibility?major=9
|
||||
make vsphere-surface
|
||||
python scripts/write_vsphere_bundles.py
|
||||
python scripts/write_vsphere_evidence.py
|
||||
```
|
||||
|
||||
| Мажор | Метка | Реализовано / universe | Покрытие | Примечания |
|
||||
|---|---|---:|---:|---|
|
||||
| 6 | vSphere 7.0 | 31 / 1077 | 2.9% | Только floor каталога/evidence |
|
||||
| 7 | vSphere 7.0 U3 | 77 / 1077 | 7.2% | Только floor каталога/evidence |
|
||||
| 8 | vSphere 8.0 | 103 / 1077 | 9.6% | Только floor каталога/evidence |
|
||||
| 9 | vSphere 8.0 U2 / поверхность Automation 9.1 | **1077 / 1077** | **100%** | Глубокие обработчики + DB-backed поверхность Broadcom |
|
||||
|
||||
Числа берутся из `GET /ui/api/compatibility?major=N` и
|
||||
`evidence/vsphere-*.json` (`make vsphere-bundles`).
|
||||
|
||||
Hot-swap (`POST /ui/api/contract/apply?major=N`) меняет **catalog** major для
|
||||
Web UI / evidence-отчётов. **Runtime всегда обслуживает полную
|
||||
зарегистрированную поверхность** — известные пути не получают HTTP 501 из-за
|
||||
version floor.
|
||||
|
||||
## Плоскости
|
||||
|
||||
| Плоскость | По умолчанию | Примечания |
|
||||
|---|---|---|
|
||||
| Native REST `/api`, `/rest` | включена | Основная лабораторная поверхность |
|
||||
| Native SOAP `/sdk` | включена | Подмножество PropertyCollector + задачи ВМ |
|
||||
| Стаб Proxmox `/api2/*` | **выключена** (`ENABLE_PVE_STUB=false`) | Опциональный legacy |
|
||||
|
||||
## Auth и синтетические данные
|
||||
|
||||
| Пункт | Детали |
|
||||
|---|---|
|
||||
| Пользователи | `administrator`, `readonly`, `operator`, `vmadmin` `@vsphere.local` / `VMware1!` |
|
||||
| AuthZ | Проверка привилегий по роли на мутирующих эндпоинтах (403 `unauthorized`) |
|
||||
| Seed `large` | 10 хостов, **1000 ВМ**, 4 datastore, DVS, папки, права |
|
||||
| Seed `demo-cluster` | 20 хостов, 1000 ВМ (загрузка demo в UI) |
|
||||
| Seed `small` | 3 хоста, 5 именованных ВМ (тесты) |
|
||||
|
||||
## Домены REST
|
||||
|
||||
### Глубокие (core) на мажоре 9
|
||||
|
||||
- Сессия / задачи CIS / роли+права AuthZ / провайдеры идентичности / стаб TLS-сертификата
|
||||
- Список/получение/создание/удаление/power ВМ, оборудование, снапшоты,
|
||||
клонирование, relocate, tools, идентичность/сети/питание/customization
|
||||
гостя, консольные тикеты, template/unregister
|
||||
- Список/получение хостов + maintenance + storage-device + сети
|
||||
- Список/получение datastore + метаданные файлов
|
||||
- Список сетей + создание DVS/DVPG
|
||||
- CRUD для datacenter / cluster / folder (+ дети) / resource-pool
|
||||
- Тегирование, content library + OVF, политики хранения (+ привязки к ВМ), привилегии
|
||||
- Версия/health/сети/timesync appliance
|
||||
- Стаб списка сервисов метамодели `vapi`
|
||||
|
||||
### DB-backed поверхность Automation (catch-all universe Broadcom)
|
||||
|
||||
Оставшиеся маршруты Automation API из индекса операций 9.1 зарегистрированы
|
||||
и обслуживаются [`app/vsphere/rest/stub_surface.py`](../../app/vsphere/rest/stub_surface.py) против PostgreSQL:
|
||||
|
||||
- таблица `vsphere_api_state` (миграция `011_vsphere_api_state.sql`)
|
||||
- seed через `seed_api_surface()` при каждом профиле, включая
|
||||
**`demo-cluster`** / UI `POST /ui/api/demo/load`
|
||||
- overlay инвентаря для оборудования ВМ (cdrom/scsi/boot/…), сетей/хранения
|
||||
хоста, тегирования, content library
|
||||
- PUT/PATCH сохраняются в `vsphere_api_state`; POST добавляет строки
|
||||
коллекции; DELETE их удаляет
|
||||
|
||||
Нет маркеров `"stub": true` — зондам нужны реальные seeded-payload'ы на
|
||||
мажоре 9.
|
||||
|
||||
## Домены SOAP (govmomi / Terraform / Pulumi / pyvmomi)
|
||||
|
||||
- RetrieveServiceContent (+ TaskManager / SearchIndex / GuestOperationsManager / FileManager / OvfManager)
|
||||
- RetrieveProperties / RetrievePropertiesEx / **ContinueRetrievePropertiesEx** (токены пагинации; `<objects>` во множественном числе)
|
||||
- PropertyCollector: цепочка предков Ancestors, однохоповый `childEntity`
|
||||
ListFolder, обход ContainerView `view`
|
||||
- `Folder.childType` как `ArrayOfString`; строковые свойства несут
|
||||
`xsi:type="xsd:string"` (декодирование govmomi)
|
||||
- `Datastore.host` как `ArrayOfDatastoreHostMount`; **environmentBrowser** у
|
||||
Cluster/Host
|
||||
- **QueryConfigOption** / QueryConfigOptionEx / QueryConfigOptionDescriptor / QueryConfigTarget
|
||||
- CreateFilter / WaitForUpdatesEx (токены версий; пустые опросы)
|
||||
- FindByInventoryPath (пути govmomi не включают корневую `Datacenters`),
|
||||
FindByUuid/Dns/Ip, FindChild
|
||||
- **CreateVM_Task** / CreateChildVM_Task, CreateFolder,
|
||||
Power/Clone/Snapshot/Rename/Reconfig/Relocate/Destroy/Unregister/MarkAsTemplate/CustomizeVM_Task + CancelTask
|
||||
- Файловые операции гостя: ListFilesInGuest,
|
||||
InitiateFileTransferTo/FromGuest, DeleteFileInGuest, MakeDirectoryInGuest
|
||||
- Реальные ID задач из `vsphere_tasks` (включая MoRef в `info.result` при
|
||||
create/clone)
|
||||
- `/sdk/vimService.wsdl`, `/sdk/about.do`, стаб `/pbm`
|
||||
- Строгий по типам поиск MOR: `VirtualApp:resgroup-*` не резолвится как
|
||||
обычный ResourcePool (путь CreateVM в Terraform)
|
||||
|
||||
## Дополнения REST для Ansible / Python-приложений
|
||||
|
||||
- Power ВМ возвращает `{ "task": "task-…" }` для опроса задач CIS
|
||||
- Виртуальная файловая система гостя:
|
||||
`/api/vcenter/vm/{vm}/guest/filesystem` (+ листинг локальной файловой
|
||||
системы)
|
||||
- Сессии обновления/загрузки content library для лабораторных потоков
|
||||
push/pull OVF
|
||||
|
||||
## Legacy `/rest`
|
||||
|
||||
Обёртки `{ "value": … }` для
|
||||
vm/host/datastore/network/datacenter/cluster/power/appliance.
|
||||
|
||||
## Мажоры контракта (browse в сравнении с runtime)
|
||||
|
||||
Hot-swap (`POST /ui/api/contract/apply?major=N`) всё ещё переключает мажор
|
||||
**каталога** для просмотра/evidence в UI. **Runtime всегда обслуживает
|
||||
полную зарегистрированную поверхность** глубокими обработчиками или
|
||||
DB-backed стабами — известные пути никогда не получают HTTP 501 из-за
|
||||
уровня версии. Уровни каталога остаются историческими только для
|
||||
документации.
|
||||
|
||||
## Поверхности платформы (доступны в лаборатории)
|
||||
|
||||
Исторически они считались «отложенными»; теперь они возвращают
|
||||
**непустые seeded лабораторные данные** и принимают базовые мутации:
|
||||
|
||||
| Область | REST | SOAP |
|
||||
|---|---|---|
|
||||
| NSX (tier0 / проекты / edges / VPC / подсети) | Seeded-пути Automation под `namespace-management` / `namespaces` | — |
|
||||
| Supervisor / WCP | namespace, классы ВМ, сводка/идентичность supervisor, политики инфраструктуры | — |
|
||||
| vSAN | Политики хранения с `policy_type: VSAN` (+ лабораторная политика RAID1) | — |
|
||||
| SAML / OIDC | `GET/POST/PATCH/DELETE /api/vcenter/identity/providers` (LocalOS + OIDC + SAML) | — |
|
||||
| VECS / сертификаты | TLS, CSR TLS, доверенные цепочки корней, сертификаты/запросы подписи supervisor | — |
|
||||
| HttpNfcLease | `PUT/GET /nfc/{lease}/files/...` | `ImportVApp_Task`, `CreateImportSpec`, ход/завершение lease |
|
||||
| Customization гостя | GET+POST `/api/vcenter/vm/{vm}/guest/customization` | `CustomizeVM_Task` |
|
||||
|
||||
Это всё ещё **лабораторный** заменитель (не бинарно совместимый с NSX
|
||||
Manager / не настоящее хранилище VECS / не полная матрица XML устройств
|
||||
Broadcom). Perf/Event/Alarm по-прежнему отвечают, но не симулируются
|
||||
глубоко.
|
||||
@@ -0,0 +1,91 @@
|
||||
**Language / Язык:** [English](../api-surface.md) | [Русский](api-surface.md)
|
||||
|
||||
# Поверхность API
|
||||
|
||||
## Путь запроса
|
||||
|
||||
1. Middleware назначает или пересылает ID запроса (`REQUEST_ID_HEADER`).
|
||||
2. FastAPI направляет запрос в роутер vSphere REST (`/api`, `/rest`), роутер
|
||||
SOAP (`/sdk`) или (если `ENABLE_PVE_STUB=true`) в опциональный legacy-стаб.
|
||||
3. `/api/session` (либо `/rest/com/vmware/cis/session`, либо SOAP `Login`)
|
||||
определяет принципала и выдаёт `vmware-api-session-id`.
|
||||
4. Зависимости `require_read` / `require_privilege(...)` проверяют роли
|
||||
сессии перед раскрытием или мутацией ресурсов.
|
||||
5. Глубокий обработчик (базовая логика инвентаря/жизненного цикла/тегов/
|
||||
контента/appliance) или DB-backed поверхность стабов выполняется против
|
||||
состояния, хранимого в PostgreSQL.
|
||||
6. Долгие операции (power, clone, relocate, snapshot, деплой OVF) создают
|
||||
долговечную CIS-задачу и возвращают `{ "task": "task-…" }`.
|
||||
|
||||
## Две REST-поверхности в одном реестре
|
||||
|
||||
- **Core (глубокие) обработчики** — ~104 комбинации verb+path в
|
||||
[`app/vsphere/rest/router.py`](../../app/vsphere/rest/router.py),
|
||||
`vm_ext.py`, `inventory_ext.py`, `platform_rest.py`, `tagging_rest.py`,
|
||||
`content_rest.py`, `appliance_ext.py`, `nfc_rest.py`, `tasks.py`. Они
|
||||
читают и мутируют напрямую seeded-таблицы инвентаря/тегов/контента/
|
||||
appliance.
|
||||
- **DB-backed поверхность стабов** —
|
||||
[`app/vsphere/rest/stub_surface.py`](../../app/vsphere/rest/stub_surface.py)
|
||||
отвечает на оставшиеся маршруты индекса операций Broadcom Automation API
|
||||
(зарегистрированные из `universe.json`) против `vsphere_api_state`. GET
|
||||
возвращает живые payload'ы, производные от инвентаря, когда это возможно,
|
||||
иначе — seeded-строки; PUT/PATCH сохраняются в `vsphere_api_state`; POST
|
||||
добавляет строки коллекции; DELETE их удаляет. Маркер `"stub": true` не
|
||||
возвращается — зонды видят реальные seeded-payload'ы.
|
||||
|
||||
Обе поверхности используют одну таблицу маршрутов; core-обработчики имеют
|
||||
приоритет над записями стабов, зарегистрированными для того же verb+path.
|
||||
|
||||
## Legacy `/rest`
|
||||
|
||||
[`app/vsphere/rest/legacy.py`](../../app/vsphere/rest/legacy.py) оборачивает
|
||||
чтения vm/host/datastore/network/datacenter/cluster/power/appliance (и
|
||||
power ВМ) в конверты `{ "value": … }` для более старых клиентов
|
||||
`com.vmware.vcenter.*`.
|
||||
|
||||
## Ошибки ([`app/vsphere/errors.py`](../../app/vsphere/errors.py))
|
||||
|
||||
| Статус | `error_type` | Типичная причина |
|
||||
|---|---|---|
|
||||
| 400 | `invalid_argument` / `already_exists` | Некорректное тело, дублирующееся имя |
|
||||
| 401 | `unauthenticated` | Отсутствующая/недействительная/истёкшая сессия |
|
||||
| 403 | `unauthorized` | У сессии нет требуемой привилегии |
|
||||
| 404 | `not_found` | Неизвестный параметр MOID/path |
|
||||
| 409 | (зависит от обработчика) | Недопустимый переход состояния питания, конфликт блокировки |
|
||||
| 501 | `error` | Достижимо только через fallback опционального legacy-стаба для необъявленных методов |
|
||||
|
||||
Все тела ошибок следуют форме vSphere Automation:
|
||||
`{ "error_type": "...", "messages": [{ "default_message": "...", "id": "...", "args": [] }] }`.
|
||||
|
||||
## Задачи
|
||||
|
||||
Асинхронная работа (power, clone, snapshot, relocate, деплой OVF, guest
|
||||
customize) возвращает id задачи. Опрашивайте:
|
||||
|
||||
```text
|
||||
GET /api/cis/tasks/{task}
|
||||
```
|
||||
|
||||
Строки задач фиксируются в `vsphere_tasks`; `progress` равен `100`, как
|
||||
только `status` становится `SUCCEEDED`/`FAILED`. HTTP 200/201 на запросе
|
||||
мутации означает «принято», а не «ВМ уже в конечном состоянии». См.
|
||||
[Задачи](domains/tasks.md).
|
||||
|
||||
## Исследование
|
||||
|
||||
- Интерактивная документация FastAPI: `/docs`
|
||||
- Инспектор методов в Web UI: `/` → каталог → метод
|
||||
- Вспомогательные API UI: `/ui/api/catalog`, `/ui/api/method`,
|
||||
`/ui/api/compatibility`
|
||||
- Реестр покрытия: [`app/vsphere/rest/coverage.py`](../../app/vsphere/rest/coverage.py)
|
||||
- Матрица уровней пути / каталога: [`app/vsphere/contracts/matrix.py`](../../app/vsphere/contracts/matrix.py)
|
||||
|
||||
## Эндпоинты совместимости
|
||||
|
||||
| Path | Формат |
|
||||
|---|---|
|
||||
| `/ui/api/compatibility?major=N` | JSON |
|
||||
|
||||
См. [Совместимость](compatibility.md) и [Покрытие API](api-coverage.md) для
|
||||
полной разбивки Broadcom-universe в сравнении с реализованным.
|
||||
@@ -0,0 +1,77 @@
|
||||
**Language / Язык:** [English](../api-versions.md) | [Русский](api-versions.md)
|
||||
|
||||
# Версии API (vSphere catalog majors 6–9)
|
||||
|
||||
Web UI и evidence/compatibility отчёты просматривают четыре целочисленных **catalog
|
||||
majors**, которые сопоставляются с label floors vSphere Automation API:
|
||||
|
||||
| Major | Метка vSphere | Строка версии contract |
|
||||
|---|---|---|
|
||||
| 6 | 7.0 | `7.0.0` |
|
||||
| 7 | 7.0 U3 | `7.0.3` |
|
||||
| 8 | 8.0 | `8.0.0` |
|
||||
| 9 | 8.0 U2 (Automation 9.1 surface) | `8.0.2` |
|
||||
|
||||
Определения находятся в [`app/vsphere/contracts/matrix.py`](../../app/vsphere/contracts/matrix.py)
|
||||
(`VERSIONS`, `PATH_FLOOR`). Каждый зарегистрированный REST path имеет **floor** —
|
||||
наименьший major, при котором он появляется в catalog — из того же
|
||||
модуля. Undated paths по умолчанию получают наивысший major (9), пока не catalogued.
|
||||
|
||||
## Runtime vs catalog
|
||||
|
||||
Это самое важное различие в проекте:
|
||||
|
||||
- **Catalog major** — управляет тем, что показывает Web UI endpoint tree, `/ui/api/catalog`,
|
||||
и compatibility/evidence отчёты для данного major.
|
||||
- **Runtime surface** — симулятор всегда обслуживает **полную зарегистрированную
|
||||
route table** с deep handlers или DB-backed stubs, независимо от
|
||||
активного catalog major. Известный path никогда не возвращается как HTTP 501 из-за
|
||||
version floor.
|
||||
|
||||
Hot-swap catalog major — это **documentation/browse**
|
||||
переключатель, а не compatibility gate для live traffic. См.
|
||||
[`available_for_request()`](../../app/vsphere/contracts/matrix.py) для точной
|
||||
политики.
|
||||
|
||||
## Cold start
|
||||
|
||||
`GET /api/appliance/system/version` сообщает version string текущего
|
||||
выбранного runtime source (по умолчанию `8.0.2` / major 9, если процесс не
|
||||
переопределяет `app.state.runtime_source_version`).
|
||||
|
||||
## Hot-swap (catalog browse)
|
||||
|
||||
Просматривайте любой major в Web UI catalog или вызывайте:
|
||||
|
||||
```http
|
||||
POST /ui/api/contract/apply?major=7
|
||||
```
|
||||
|
||||
Эффекты:
|
||||
|
||||
- Web UI catalog, `/ui/api/compatibility` и evidence отчёты переключаются на
|
||||
floor major 7 и ledger (`evidence/vsphere-7.0.3.json`).
|
||||
- Изменение **process-local** и **не сохраняется**; restart возвращает
|
||||
default (major 9).
|
||||
- Зарегистрированные REST/SOAP routes продолжают отвечать своими реальными
|
||||
handlers независимо от применённого major.
|
||||
|
||||
### Рекомендации для клиентов
|
||||
|
||||
- Большинству клиентов (pyvmomi, govmomi, Terraform, Pulumi, Ansible `uri`) не
|
||||
нужно pin'ить catalog major — runtime surface не меняет форму
|
||||
на его основе.
|
||||
- Используйте catalog majors, когда нужно, чтобы Web UI / evidence view
|
||||
отражали более старую метку vSphere для документации или скриншотов.
|
||||
- После apply перепроверьте `/ui/api/compatibility?major=N` для активного
|
||||
catalog state.
|
||||
|
||||
## Регенерация catalog artifacts
|
||||
|
||||
```bash
|
||||
make vsphere-bundles # stub OpenAPI matrices + evidence ledgers
|
||||
make vsphere-universe # regenerate universe.json from the Broadcom operations index
|
||||
make evidence # regenerate per-major verified surface evidence ledgers
|
||||
```
|
||||
|
||||
См. [Поверхность API](api-surface.md) и [Совместимость](compatibility.md).
|
||||
@@ -0,0 +1,77 @@
|
||||
**Language / Язык:** [English](../architecture.md) | [Русский](architecture.md)
|
||||
|
||||
# Архитектура
|
||||
|
||||
## Цели
|
||||
|
||||
`vmware-api-simulator` — stateful лабораторный эмулятор vSphere (Automation REST +
|
||||
VIM SOAP). Главная цель дизайна — **практическая совместимость клиентов**:
|
||||
сессии, inventory, жизненный цикл VM, обходы PropertyCollector, задачи,
|
||||
stubs tagging/content library и роли AuthZ реализованы поверх большого
|
||||
синтетического datastore, чтобы инструменты вроде curl, govc-подобных
|
||||
потоков, pyvmomi и Terraform могли прогонять типовые пути без реального
|
||||
vCenter.
|
||||
|
||||
Catalog majors **6–9** соответствуют floors vSphere 7.0 / 7.0U3 / 8.0 / 8.0U2.
|
||||
Hot-swap меняет каталог только для browse/evidence в Web UI — он **не**
|
||||
гейтит живые маршруты. Опциональный stub Proxmox `/api2/*` остаётся за
|
||||
`ENABLE_PVE_STUB` (по умолчанию выключен).
|
||||
|
||||
## Контекст системы
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Client["API clients<br/>pyvmomi / Terraform / govc / REST SDKs"]
|
||||
Admin["Lab operator"]
|
||||
UI["Web lab UI"]
|
||||
API["FastAPI application"]
|
||||
Gateway["HTTPS gateway :443"]
|
||||
Contract["vSphere contract matrix"]
|
||||
Domain["vsphere domain + inventory"]
|
||||
DB[(PostgreSQL)]
|
||||
Obs["Logs / Prometheus / OpenTelemetry"]
|
||||
|
||||
Client -->|"/api /rest /sdk"| Gateway
|
||||
Gateway --> API
|
||||
UI --> Gateway
|
||||
Admin -->|"seed / migrate"| API
|
||||
API --> Contract
|
||||
API --> Domain
|
||||
Domain --> DB
|
||||
API --> Obs
|
||||
```
|
||||
|
||||
## Плоскости
|
||||
|
||||
| Плоскость | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| Automation REST | `/api`, `/rest` | Заголовок сессии `vmware-api-session-id` |
|
||||
| VIM SOAP | `/sdk` | Подмножество PropertyCollector + VM tasks |
|
||||
| Lab UI helpers | `/ui/api/*` | Каталог, demo seed, совместимость |
|
||||
| Опциональный PVE stub | `/api2/*` | Выкл., пока `ENABLE_PVE_STUB=true` |
|
||||
|
||||
## Модель данных
|
||||
|
||||
Inventory живёт в `vsphere_objects` (MOID, типы, props JSON, parent-ссылки).
|
||||
Sessions, credentials, tasks, tags, libraries, snapshots и permissions —
|
||||
соседние таблицы (миграции `009_vsphere.sql`, `010_vsphere_platform.sql`).
|
||||
DB-backed Automation stubs используют `vsphere_api_state` (`011`); сессии
|
||||
transfer content library и строки HttpNfcLease — в `vsphere_transfer_sessions` /
|
||||
`vsphere_nfc_leases` (`012`); views/tokens PropertyCollector и console tickets —
|
||||
в `vsphere_pc_state` / `vsphere_console_tickets` (`013`).
|
||||
|
||||
Профили seed (`small` / `large` / `demo-cluster`) строят детерминированный
|
||||
кластер — по умолчанию **large** это ~10 hosts / **1000 VMs**.
|
||||
|
||||
## AuthZ
|
||||
|
||||
Credentials отображаются в roles → privilege sets. Мутирующие обработчики
|
||||
используют `require_privilege(...)`; пути чтения — `require_read`. SOAP Login
|
||||
выдаёт cookie, совместимый с VIM-сессиями.
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- [Покрытие API](api-coverage.md)
|
||||
- [Аутентификация](authentication.md)
|
||||
- [Web UI](web-ui.md)
|
||||
- [Клиенты](clients.md)
|
||||
@@ -0,0 +1,101 @@
|
||||
**Language / Язык:** [English](../authentication.md) | [Русский](authentication.md)
|
||||
|
||||
# Аутентификация
|
||||
|
||||
Основная плоскость: **vSphere Automation REST** sessions (`vmware-api-session-id`).
|
||||
SOAP `/sdk` использует собственные `Login`/`Logout` на VIM `SessionManager`. Опциональная
|
||||
legacy Proxmox stub-плоскость (`ENABLE_PVE_STUB=true`) сохраняет историческое поведение
|
||||
`/api2/json/access/ticket` из общей platform lineage — это не default lab path и далее
|
||||
не рассматривается.
|
||||
|
||||
## Session login (REST)
|
||||
|
||||
```http
|
||||
POST /api/session
|
||||
Authorization: Basic base64(user:password)
|
||||
```
|
||||
|
||||
Успешный ответ:
|
||||
|
||||
- Body: JSON string session id (например, `"a1b2c3…"`)
|
||||
- Header: `vmware-api-session-id: <id>`
|
||||
- Cookie: `vmware-api-session-id=<id>` (`SameSite=Strict`, TTL 2 часа)
|
||||
|
||||
Legacy wrapper (те же credentials, форма `{ "value": "<session-id>" }`):
|
||||
|
||||
```http
|
||||
POST /rest/com/vmware/cis/session
|
||||
Authorization: Basic base64(user:password)
|
||||
```
|
||||
|
||||
### Вызов API
|
||||
|
||||
```bash
|
||||
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/vm'
|
||||
```
|
||||
|
||||
Cookie-only клиенты также работают после login (`credentials: include` в
|
||||
браузерном Web UI).
|
||||
|
||||
### Inspect / logout сессии
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| GET | `/api/session` | HTTP 200 с заголовками `x-vmware-session-user` / `x-vmware-session-roles` |
|
||||
| DELETE | `/api/session` | Инвалидирует сессию и очищает cookie |
|
||||
| GET / DELETE | `/rest/com/vmware/cis/session` | Legacy эквиваленты `{ "value": … }` |
|
||||
|
||||
Сессии хранятся в PostgreSQL (`vsphere_sessions`) с 2-часовым sliding
|
||||
expiry — каждый аутентифицированный запрос продлевает `expires_at`. Истёкшие сессии
|
||||
возвращают HTTP 401 при следующем lookup и лениво удаляются.
|
||||
|
||||
## Засеянные lab principals
|
||||
|
||||
Пароль для всех: `VMware1!`
|
||||
|
||||
| Principal | Роль |
|
||||
|---|---|
|
||||
| `administrator@vsphere.local` | Administrator |
|
||||
| `readonly@vsphere.local` | ReadOnly |
|
||||
| `operator@vsphere.local` | VirtualMachinePowerUser |
|
||||
| `vmadmin@vsphere.local` | VirtualMachineAdministrator |
|
||||
|
||||
Credentials хранятся в `vsphere_credentials` (scrypt-hashed passwords,
|
||||
массив `roles`) и идемпотентно re-insert'ятся при первом вызове `/api/session`
|
||||
и каждым seed profile. См. [Authorization](domains/authz.md) для модели
|
||||
привилегий и [Профили seed](seed-profiles.md) для соответствия четырёх
|
||||
principals inventory-scoped permissions.
|
||||
|
||||
Mutating endpoints проверяют привилегии через `require_privilege(...)`; вызов
|
||||
mutate path как `readonly@vsphere.local` возвращает **403**.
|
||||
|
||||
## SOAP `/sdk`
|
||||
|
||||
```xml
|
||||
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:vim25">
|
||||
<soapenv:Body>
|
||||
<urn:Login>
|
||||
<urn:_this type="SessionManager">SessionManager</urn:_this>
|
||||
<urn:userName>administrator@vsphere.local</urn:userName>
|
||||
<urn:password>VMware1!</urn:password>
|
||||
</urn:Login>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
||||
```
|
||||
|
||||
`Login` выдаёт тот же underlying session id, возвращаемый как
|
||||
`vmware-api-session-id` и как cookie `vmware_soap_session`; последующие SOAP
|
||||
вызовы (pyvmomi, govmomi, Terraform provider `hashicorp/vsphere`, Pulumi)
|
||||
передают этот cookie автоматически. `Logout` удаляет сессию. См.
|
||||
[SOAP / VIM](domains/soap.md).
|
||||
|
||||
## Опциональная legacy Proxmox stub
|
||||
|
||||
Только при `ENABLE_PVE_STUB=true`: ticket login на `/api2/json/access/ticket`
|
||||
с `PVEAuthCookie` + CSRF, унаследованный от общей simulator platform, от которой
|
||||
этот проект fork'нулся. По умолчанию выключен (`ENABLE_PVE_STUB=false`) и
|
||||
не используется vSphere docs, examples или test suites в этом репозитории.
|
||||
@@ -0,0 +1,88 @@
|
||||
**Language / Язык:** [English](../clients.md) | [Русский](clients.md)
|
||||
|
||||
# Клиенты
|
||||
|
||||
Используйте симулятор из распространённых стеков автоматизации VMware:
|
||||
Python, Ansible, Terraform, Pulumi.
|
||||
|
||||
## Матрица подключений
|
||||
|
||||
| Стек | Транспорт | Примечания | Код |
|
||||
|---|---|---|---|
|
||||
| REST (curl / SDK) | HTTPS `:443` | `vmware-api-session-id` после Basic-сессии | `examples/python/vsphere_rest_smoke.py`, `vsphere_lifecycle.py` |
|
||||
| SOAP / VIM | HTTPS `:443/sdk` | провайдеры pyvmomi / govmomi / Terraform / Pulumi | `examples/python/vsphere_soap_smoke.py` |
|
||||
| Legacy `/rest` | HTTPS `:443` | обёртки `{ "value": … }` | `/rest/vcenter/vm` |
|
||||
| Terraform | HTTPS `:443` | источники данных `hashicorp/vsphere` + опциональный ресурс ВМ | `examples/terraform/vsphere/` |
|
||||
| Ansible | HTTPS `:443` | playbook жизненного цикла REST (модуль `uri`) | `examples/ansible/vsphere_playbook.yml` |
|
||||
| Pulumi | HTTPS `:443` | кулинарная книга REST ComponentResource | `examples/pulumi/` |
|
||||
| govc | HTTPS `:443` | `GOVC_URL=https://…` insecure | см. ниже |
|
||||
| Go / Java / Perl | HTTPS `:443` | минимальные кулинарные книги REST (сессия по Basic-auth) | `examples/go/`, `examples/java/`, `examples/perl/` |
|
||||
|
||||
## Учётные данные (seed)
|
||||
|
||||
| Пользователь | Пароль | Роль |
|
||||
|---|---|---|
|
||||
| `administrator@vsphere.local` | `VMware1!` | Administrator |
|
||||
| `readonly@vsphere.local` | `VMware1!` | ReadOnly |
|
||||
| `operator@vsphere.local` | `VMware1!` | VirtualMachinePowerUser |
|
||||
| `vmadmin@vsphere.local` | `VMware1!` | VirtualMachineAdministrator |
|
||||
|
||||
## Seed инвентаря
|
||||
|
||||
```bash
|
||||
make seed # large: 10 хостов / 1000 ВМ
|
||||
VSPHERE_PROFILE=demo-cluster make seed
|
||||
VSPHERE_PROFILE=small make seed
|
||||
```
|
||||
|
||||
## Быстрые кулинарные книги
|
||||
|
||||
```bash
|
||||
# Все четыре стека (в стиле Python/Ansible/Terraform/Pulumi) внутри Compose
|
||||
make client-cookbooks
|
||||
|
||||
# Python REST + SOAP CreateVM / NFC
|
||||
VSPHERE_BASE=https://localhost python examples/python/vsphere_lifecycle.py
|
||||
|
||||
# Ansible
|
||||
ansible-playbook -i examples/ansible/inventory.ini examples/ansible/vsphere_playbook.yml
|
||||
|
||||
# Terraform — источники данных hashicorp/vsphere (plan) + опциональный ресурс CreateVM
|
||||
cd examples/terraform/vsphere
|
||||
terraform init
|
||||
TF_VAR_vsphere_server=localhost TF_VAR_create_lab_vm=false terraform plan
|
||||
TF_VAR_vsphere_server=localhost TF_VAR_create_lab_vm=true terraform apply
|
||||
|
||||
# Pulumi REST
|
||||
cd examples/pulumi && pulumi up
|
||||
```
|
||||
|
||||
Проверено против gateway (`:443`): жизненный цикл Python, playbook Ansible,
|
||||
REST в стиле Pulumi и `terraform plan` (источники данных
|
||||
datacenter/cluster/datastore/network/VM) — всё зелёное. SOAP
|
||||
`CreateVM_Task` доступен для пути ресурса; используйте свежий seed, если
|
||||
имена папок были переименованы зондами (`make seed`).
|
||||
|
||||
## govc (опциональный инструмент на хосте)
|
||||
|
||||
```bash
|
||||
export GOVC_URL=https://localhost
|
||||
export GOVC_USERNAME=administrator@vsphere.local
|
||||
export GOVC_PASSWORD='VMware1!'
|
||||
export GOVC_INSECURE=1
|
||||
govc about
|
||||
govc ls /
|
||||
govc find / -type m | head
|
||||
govc vm.info web-01
|
||||
```
|
||||
|
||||
## Smoke-тест pyvmomi
|
||||
|
||||
```bash
|
||||
docker compose run --rm --no-deps -e VSPHERE_BASE=http://simulator:8080 \
|
||||
-e TEST_DATABASE_URL=postgresql://vmware:vmware@postgres:5432/vmware_simulator \
|
||||
dev pytest tests/compatibility/test_vsphere_pyvmomi.py -q
|
||||
```
|
||||
|
||||
Руководства по языкам: [examples/overview.md](examples/overview.md). Покрытие:
|
||||
[api-coverage.md](api-coverage.md).
|
||||
@@ -0,0 +1,87 @@
|
||||
**Language / Язык:** [English](../compatibility-0.1.0.md) | [Русский](compatibility-0.1.0.md)
|
||||
|
||||
# Отчёт совместимости — 0.1.0
|
||||
|
||||
Этот отчёт фиксирует evidence для релиза симулятора 0.1.0 относительно реестра
|
||||
маршрутов vSphere Automation API (catalog majors 6–9, основной contract major 9 /
|
||||
8.0 U2). Это матрица ограничений по измерениям *качества / внешней интеграции*,
|
||||
а не утверждение общей аппаратной совместимости с vCenter/ESXi.
|
||||
|
||||
Пользовательский обзор — [compatibility.md](compatibility.md). Живые
|
||||
машиночитаемые счётчики всегда доступны из
|
||||
`/ui/api/compatibility?major=N`, когда симулятор запущен.
|
||||
|
||||
## Сводка (major 9 / основной контракт vSphere 8.0 U2)
|
||||
|
||||
| Уровень | Methods | Доля universe | Evidence |
|
||||
|---|---:|---:|---|
|
||||
| Declared in universe (Broadcom operations index → route table) | 1077 | 100% | `app/vsphere/rest/universe.json` |
|
||||
| Implemented at major 9 (catalog floor) | **1077** | **100%** | `app/vsphere/contracts/matrix.py` |
|
||||
| Core deep handlers (inventory/lifecycle/tagging/content/appliance) | 104 | 9.7% | `app/vsphere/rest/coverage.py` (`CORE_IMPLEMENTED`) |
|
||||
| DB-backed stub surface (остальной реестр) | ~973 | 90.3% | `app/vsphere/rest/stub_surface.py` против `vsphere_api_state` |
|
||||
| Verified / observed surface ledger | **1077** | **100%** | `evidence/vsphere-8.0.2.json` |
|
||||
|
||||
## Покрытие по catalog major
|
||||
|
||||
| Major | Метка vSphere | Implemented | Universe | Coverage |
|
||||
|---|---|---:|---:|---:|
|
||||
| 6 | 7.0 | 31 | 1077 | 2.88% |
|
||||
| 7 | 7.0 U3 | 77 | 1077 | 7.15% |
|
||||
| 8 | 8.0 | 103 | 1077 | 9.56% |
|
||||
| 9 | 8.0 U2 | 1077 | 1077 | 100.00% |
|
||||
|
||||
**Implemented** здесь — оценка catalog-floor для browse в Web UI и
|
||||
evidence-отчётов, перегенерируется через `make evidence` / `make vsphere-bundles`
|
||||
и защищена `tests/compatibility/test_verified_surface.py`. Она **не**
|
||||
гейтит живой трафик — почему runtime всегда обслуживает зарегистрированный
|
||||
маршрут независимо от применённого major, см. [Поверхность API](api-surface.md).
|
||||
|
||||
## Реализованная поверхность (верхний уровень)
|
||||
|
||||
- **Session**: `/api/session`, `/rest/com/vmware/cis/session`, SOAP
|
||||
`Login`/`Logout` — всё устойчиво в PostgreSQL (`vsphere_sessions`,
|
||||
`vsphere_credentials`).
|
||||
- **Inventory**: list+get для VM/host/datastore/network/datacenter/cluster/folder/resource-pool,
|
||||
плюс create/delete для datacenter/cluster/folder/resource-pool.
|
||||
- **VM lifecycle**: create, delete, power, hardware (CPU/memory/disk/NIC/boot),
|
||||
snapshots, clone, relocate, guest identity/networking/power/customization,
|
||||
console tickets, tools.
|
||||
- **Tasks**: `/api/cis/tasks`, реальные ids из `vsphere_tasks`, SOAP task MoRefs.
|
||||
- **Tagging / content library**: categories, tags, associations, libraries,
|
||||
library items, update/download sessions, OVF deploy.
|
||||
- **Authorization**: privileges, roles, permissions CRUD, identity providers.
|
||||
- **Appliance**: version, health, networking (hostname/DNS), timesync.
|
||||
- **SOAP / VIM**: RetrieveServiceContent, PropertyCollector
|
||||
(RetrieveProperties/Ex, ContinueRetrievePropertiesEx, CreateFilter,
|
||||
WaitForUpdatesEx), FindBy* / FindChild, CreateVM_Task и связанные, guest
|
||||
file operations, HttpNfcLease import flow, WSDL stub.
|
||||
- **Platform lab surfaces**: seeded (не бинарно совместимые) stand-in'ы
|
||||
NSX/Supervisor/vSAN/SAML-OIDC/VECS-cert — точный список и оговорки в
|
||||
[Покрытие API](api-coverage.md).
|
||||
|
||||
## Принцип персистентности
|
||||
|
||||
Каждый путь create/update/delete пишет в PostgreSQL (таблицы и/или catch-all
|
||||
`vsphere_api_state`). Секреты могут храниться, но не должны отдаваться на GET.
|
||||
Пользовательские ошибки «not supported in the emulator» для зарегистрированных
|
||||
путей запрещены — см. `.cursor/rules/durable-simulator.mdc`.
|
||||
|
||||
## Известные ограничения
|
||||
|
||||
| Область | Текущее поведение |
|
||||
|---|---|
|
||||
| Внешние системы | NSX/LDAP/SAML/OIDC/ACME не обращаются к реальным remotes; состояние симулируется локально |
|
||||
| TLS | Локальный nginx gateway только с закоммиченным self-signed development key |
|
||||
| Сертификация клиентов | SOAP smoke в стиле pyvmomi/govmomi + cookbook'и Ansible/Terraform/Pulumi; не формальный certification suite для каждой версии провайдера |
|
||||
| Smoke провайдера | Набор `pulumi-vsphere` в `pulumi-tests/` (`make pulumi-tests`) гоняет SOAP inventory/VM/tag с проверкой непустых export'ов; семантическая глубина по-прежнему разная (deep handlers vs DB-backed stubs) |
|
||||
|
||||
Полное покрытие реестра на major 9 означает, что HTTP 501 «handler pending»
|
||||
не должен появляться ни для одного маршрута в реестре симулятора. *Качество*
|
||||
совместимости (точный паритет крайних случаев vSphere) по-прежнему углубляется
|
||||
тестами и observation.
|
||||
|
||||
При импорте обновлённого дампа Broadcom operations index: перегенерируйте
|
||||
`universe.json` (`make vsphere-universe`), bundles/evidence
|
||||
(`make vsphere-bundles`, `make evidence`), запустите
|
||||
`pytest tests/compatibility/test_verified_surface.py` и закоммитьте обновлённые
|
||||
ledgers `evidence/vsphere-*.json`.
|
||||
@@ -0,0 +1,79 @@
|
||||
**Language / Язык:** [English](../compatibility.md) | [Русский](compatibility.md)
|
||||
|
||||
# Совместимость
|
||||
|
||||
Этот документ объясняет, как симулятор заявляет совместимость с vSphere
|
||||
Automation API по мажорам каталога **6–9**. Когда процесс запущен,
|
||||
предпочитайте живые отчёты.
|
||||
|
||||
## Живые отчёты
|
||||
|
||||
| URL | Формат |
|
||||
|---|---|
|
||||
| `/ui/api/compatibility?major=N` | JSON |
|
||||
|
||||
Web UI также предоставляет панель совместимости, управляемую этим
|
||||
endpoint'ом.
|
||||
|
||||
## Покрытие реестра в сравнении с проверенной поверхностью
|
||||
|
||||
| Мажор | Метка vSphere | Реализовано / universe | Покрытие |
|
||||
|---|---|---:|---:|
|
||||
| 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) | **1077 / 1077** | **100%** |
|
||||
|
||||
- **Universe** — уникальные маршруты verb+path, полученные из публичного
|
||||
[индекса операций vSphere Automation API](https://developer.broadcom.com/xapis/vsphere-automation-api/latest/operation-index/)
|
||||
(1348 документированных операций → ~1037 уникальных маршрутов → 1077
|
||||
зарегистрированных в таблице маршрутов этого симулятора, поскольку
|
||||
некоторые пути обслуживают несколько именованных операций).
|
||||
- **Реализовано (по мажору)** — маршруты, чей уровень каталога
|
||||
(`app/vsphere/contracts/matrix.py`) равен этому мажору или ниже. Это
|
||||
оценка **каталога/документации**, а не ограничение живого трафика.
|
||||
- **Runtime** — независимо от применённого мажора каталога, каждый
|
||||
зарегистрированный маршрут всегда обслуживается своим реальным
|
||||
обработчиком (104 глубоких обработчика) или DB-backed поверхностью
|
||||
стабов. См. [Поверхность API](api-surface.md).
|
||||
|
||||
После **Apply as runtime** (`POST /ui/api/contract/apply?major=N`) живой
|
||||
отчёт загружает журнал этого мажора (`evidence/vsphere-{version}.json`), так
|
||||
что панель совместимости Web UI отражает выбранный мажор.
|
||||
|
||||
## Измерения evidence
|
||||
|
||||
Журналы по мажорам в `evidence/vsphere-{version}.json` записывают счётчики
|
||||
`declared`, `implemented`, `observed` и `verified`, а также разбивки по
|
||||
HTTP-методам и доменам (`auth_session`, `inventory`, …). Регенерируйте с
|
||||
помощью:
|
||||
|
||||
```bash
|
||||
make evidence # app/evidence_gen.py
|
||||
make vsphere-bundles # стаб-бандлы OpenAPI + журналы evidence вместе
|
||||
```
|
||||
|
||||
Исполняемое подтверждение этих заявлений:
|
||||
|
||||
| Набор тестов | Роль |
|
||||
|---|---|
|
||||
| `tests/compatibility/test_verified_surface.py` | hot-swap + дрейф журнала + пороги оценки |
|
||||
| `tests/compatibility/test_group_smoke.py` | представительные мутации групп REST с PostgreSQL |
|
||||
| `tests/compatibility/test_vsphere_pyvmomi.py` | внешний smoke-тест SOAP через pyvmomi |
|
||||
| `tests/integration/test_vsphere_full_api.py` | широкое интеграционное покрытие REST/SOAP |
|
||||
|
||||
Дополнительные cookbook'и под [`examples/`](../../examples/README.ru.md)
|
||||
и lab-набор `pulumi-vsphere` под
|
||||
[`pulumi-tests/`](../../pulumi-tests/README.ru.md) (`make pulumi-tests`)
|
||||
выполняются вручную или опционально в CI.
|
||||
|
||||
## Известные поведенческие ограничения
|
||||
|
||||
| Область | Поведение |
|
||||
|---|---|
|
||||
| Внешние системы | NSX Manager, живые LDAP/SAML/OIDC IdP и ACME-директории не обращаются к реальным удалённым сервисам; только seeded/локальное состояние |
|
||||
| TLS | Только локальный self-signed development-gateway (Compose); используйте свои сертификаты / cert-manager для реальных развёртываний |
|
||||
| Гипервизор | Нет реального выполнения ESXi/KVM; нет бинарных загрузок NFC |
|
||||
| Корпус наблюдений | Санированные данные наблюдений реального vCenter остаются ограниченными; глубокий семантический паритет проверяется путь-за-путём указанными выше наборами тестов, а не исчерпывающим сравнением с production |
|
||||
|
||||
Исторические заметки о релизах: [compatibility-0.1.0.md](compatibility-0.1.0.md).
|
||||
@@ -0,0 +1,96 @@
|
||||
**Language / Язык:** [English](../configuration.md) | [Русский](configuration.md)
|
||||
|
||||
# Конфигурация
|
||||
|
||||
Настройки приложения загружаются из окружения (см. `.env.example`).
|
||||
Docker Compose инжектирует многие из них для сервиса `simulator`; значения,
|
||||
объявленные в `environment:` в `docker-compose.yml`, переопределяют `.env` для этого
|
||||
сервиса. Типизированная модель настроек находится в [`app/config.py`](../../app/config.py).
|
||||
|
||||
## Основное
|
||||
|
||||
| Переменная | По умолчанию / пример | Значение |
|
||||
|---|---|---|
|
||||
| `APP_HOST` | `0.0.0.0` | Адрес bind |
|
||||
| `APP_PORT` | `8080` | Внутренний порт uvicorn (не публикуется; gateway публикует vCenter HTTPS) |
|
||||
| `DATABASE_URL` | `postgresql://vmware:vmware@postgres:5432/vmware_simulator` | asyncpg DSN |
|
||||
| `DB_POOL_MIN_SIZE` | `1` | Минимум пула |
|
||||
| `DB_POOL_MAX_SIZE` | `10` | Максимум пула |
|
||||
| `DB_CONNECT_TIMEOUT_SECONDS` | `10` | Таймаут подключения |
|
||||
| `DB_COMMAND_TIMEOUT_SECONDS` | `30` | Таймаут команды |
|
||||
| `LOG_LEVEL` | `INFO` | Уровень логирования |
|
||||
| `REQUEST_ID_HEADER` | `X-Request-ID` | Заголовок корреляции запросов |
|
||||
|
||||
## vSphere seed inventory
|
||||
|
||||
| Переменная | По умолчанию | Значение |
|
||||
|---|---|---|
|
||||
| `SEED_VSPHERE_PROFILE` | `large` | `small` \| `large` \| `demo-cluster` — см. [Профили seed](seed-profiles.md) |
|
||||
| `SEED_VSPHERE_LARGE_HOSTS` | `10` | Число хостов для профиля `large` |
|
||||
| `SEED_VSPHERE_LARGE_VMS` | `1000` | Число VM для профиля `large` |
|
||||
|
||||
## Опциональная legacy-плоскость
|
||||
|
||||
| Переменная | По умолчанию | Значение |
|
||||
|---|---|---|
|
||||
| `ENABLE_PVE_STUB` | `false` | Включает legacy Proxmox VE `/api2/*` stub-плоскость, унаследованную из общей platform lineage. Нативная vSphere `/api` + `/rest` + `/sdk` — основная плоскость по умолчанию независимо от этого флага. |
|
||||
|
||||
## Contract и catalog
|
||||
|
||||
| Переменная | Значение |
|
||||
|---|---|
|
||||
| `CONTRACT_SNAPSHOT` | Опциональный путь к нормализованному PVE-style snapshot (актуально только при `ENABLE_PVE_STUB=true`) |
|
||||
| `CONTRACT_FALLBACK` | `error` (default), `schema-default`, или `fixture` — fallback-поведение для опциональной stub-плоскости |
|
||||
| `COMPATIBILITY_EVIDENCE` | Опциональный путь к evidence JSON для отчётов совместимости |
|
||||
| `CATALOG_ARTIFACT_URL_6` … `_9` | Метки catalog majors vSphere (6→7.0, 7→7.0 U3, 8→8.0, 9→8.0 U2); stub URLs, не live downloads |
|
||||
|
||||
Runtime hot-swap (Web UI / `POST /ui/api/contract/apply?major=N`) переключает
|
||||
активный **catalog** major, используемый Web UI и compatibility/evidence
|
||||
отчётами. Он не ограничивает зарегистрированную REST/SOAP поверхность — каждый
|
||||
известный маршрут всегда обслуживается реальным обработчиком или DB-backed stub.
|
||||
См. [Версии API](api-versions.md).
|
||||
|
||||
## Безопасность и задачи
|
||||
|
||||
| Переменная | Значение |
|
||||
|---|---|
|
||||
| `TICKET_SIGNING_KEY` | HMAC signing key для сессий (**меняйте вне toy labs**) |
|
||||
| `TASK_WORKER_CONCURRENCY` | Число leased asyncio workers (1–32) |
|
||||
| `TASK_LEASE_SECONDS` | Длительность lease PostgreSQL-задачи |
|
||||
| `SIMULATION_TIME_SCALE` | Ускоряет симулированные длительности задач (выше = быстрее) |
|
||||
|
||||
## Client test hooks
|
||||
|
||||
| Переменная | Значение |
|
||||
|---|---|
|
||||
| `TEST_DATABASE_URL` | DSN для integration-тестов |
|
||||
| `VSPHERE_BASE` | Базовый URL для cookbooks/probes (`https://localhost` с хоста, `http://simulator:8080` изнутри Compose) |
|
||||
|
||||
## Порты и TLS
|
||||
|
||||
| Endpoint | Назначение |
|
||||
|---|---|
|
||||
| `https://localhost` | Основная vCenter HTTPS точка входа (curl, browsers, pyvmomi, govmomi, Terraform, большинство examples) |
|
||||
| `http://localhost` | HTTP-грань для лабораторных нужд |
|
||||
| `localhost:5434` | PostgreSQL (только localhost) |
|
||||
| Internal `simulator:8080` | Прямой процесс FastAPI; доступен только внутри Compose network |
|
||||
|
||||
Вшитый сертификат в `docker/tls/` — одноразовый development material.
|
||||
Никогда не используйте его вне локальных labs. См. [Безопасность](security.md) и
|
||||
[Порты](ports.md).
|
||||
|
||||
## Заметки по Compose
|
||||
|
||||
- `migrate` выполняется один раз; `simulator` ждёт успешного migrate.
|
||||
- Development Compose bind-mount'ит репозиторий и включает Uvicorn reload.
|
||||
- Сервис `api-gateway` (nginx) публикует `443`/`80` и проксирует на
|
||||
внутренний процесс `simulator:8080`; устанавливает `X-VMware-Service` /
|
||||
`X-Forwarded-Port`, чтобы будущие routers могли определить использованный listener.
|
||||
|
||||
## Открытые и неиспользуемые example keys
|
||||
|
||||
`.env.example` всё ещё перечисляет несколько ключей из общей platform lineage, которые
|
||||
**не** потребляются текущей vSphere-first моделью настроек, в частности
|
||||
`SIMULATION_SEED`, `SIMULATOR_ADMIN_ENABLED` и `SIMULATOR_ADMIN_TOKEN`. Не
|
||||
предполагайте, что аутентифицированный admin API `/_simulator` существует сегодня — см.
|
||||
[Безопасность](security.md).
|
||||
@@ -0,0 +1,43 @@
|
||||
**Language / Язык:** [English](../../domains/README.md) | [Русский](README.md)
|
||||
|
||||
# Руководства по доменам
|
||||
|
||||
Эти страницы описывают устойчивую семантику по областям API. Для исчерпывающих
|
||||
списков методов используйте каталог Web UI или OpenAPI (`/docs`), либо
|
||||
непосредственно
|
||||
[`app/vsphere/rest/coverage.py`](../../../app/vsphere/rest/coverage.py) —
|
||||
runtime всегда обслуживает полную зарегистрированную поверхность независимо от
|
||||
активного catalog major.
|
||||
|
||||
| Руководство | Темы |
|
||||
|---|---|
|
||||
| [Session](session.md) | `/api/session`, legacy `/rest` session, SOAP `Login`/`Logout` |
|
||||
| [Inventory](inventory.md) | Datacenter, cluster, folder, resource pool, host, datastore, network CRUD |
|
||||
| [Виртуальные машины](vm.md) | Create/delete, power, hardware, snapshots, clone, relocate, guest ops |
|
||||
| [Storage](storage.md) | Datastores, files, host storage devices, storage policies |
|
||||
| [Networking](networking.md) | Standard/distributed portgroups, DVS, host networking |
|
||||
| [Tagging](tagging.md) | Categories, tags, associations |
|
||||
| [Content library](content-library.md) | Libraries, items, update/download sessions, OVF deploy |
|
||||
| [SOAP / VIM](soap.md) | RetrieveServiceContent, PropertyCollector, task-returning operations |
|
||||
| [Tasks](tasks.md) | CIS task ids, polling, workers |
|
||||
| [Appliance](appliance.md) | Version, health, networking, timesync |
|
||||
| [Авторизация](authz.md) | Roles, privileges, permissions |
|
||||
|
||||
## Карта персистентности
|
||||
|
||||
- Объекты inventory (hosts, VMs, datastores, networks, folders, …) →
|
||||
`vsphere_objects` (MOID, type, name, parent, `props` JSONB).
|
||||
- Sessions / credentials → `vsphere_sessions`, `vsphere_credentials`.
|
||||
- Tasks → `vsphere_tasks`.
|
||||
- Tags / categories / associations → `vsphere_tag_categories`,
|
||||
`vsphere_tags`, `vsphere_tag_associations`.
|
||||
- Content libraries / items → `vsphere_libraries`, `vsphere_library_items`.
|
||||
- Метаданные файлов datastore → `vsphere_datastore_files`.
|
||||
- Оставшиеся маршруты Broadcom Automation API (DB-backed stub surface) →
|
||||
`vsphere_api_state` (миграция `011`).
|
||||
- Update/download sessions content library → `vsphere_transfer_sessions`
|
||||
(миграция `012`).
|
||||
- Состояние transfer HttpNfcLease → `vsphere_nfc_leases` (миграция `012`).
|
||||
- Views PropertyCollector / токены WaitForUpdates → `vsphere_pc_state`
|
||||
(миграция `013`).
|
||||
- Console tickets → `vsphere_console_tickets` (миграция `013`).
|
||||
@@ -0,0 +1,35 @@
|
||||
**Language / Язык:** [English](../../domains/appliance.md) | [Русский](appliance.md)
|
||||
|
||||
# Appliance
|
||||
|
||||
Поверхности vCenter Server Appliance (VCSA) — version, health, networking,
|
||||
timesync:
|
||||
[`app/vsphere/rest/appliance_ext.py`](../../../app/vsphere/rest/appliance_ext.py),
|
||||
[`app/vsphere/domain/appliance.py`](../../../app/vsphere/domain/appliance.py).
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| GET | `/api/appliance/system/version` | Читается без сессии; отражает метку активного catalog major |
|
||||
| GET | `/api/appliance/health/system` | Сводка общего health |
|
||||
| GET/PUT/POST | `/api/appliance/networking` | Hostname, DNS, default gateway, interfaces, proxy |
|
||||
| GET/PUT/POST | `/api/appliance/networking/dns/hostname` \| `/dns/servers` \| `/dns/domains` | Сфокусированные зеркала, синхронизированные с `/networking` |
|
||||
| GET | `/api/appliance/timesync` | Режим NTP + servers |
|
||||
| GET | `/api/vcenter/certificate-management/vcenter/tls[-csr]` \| `/trusted-root-chains` | Stand-in'ы machine-cert / CSR / trust-chain |
|
||||
|
||||
## Основные моменты
|
||||
|
||||
- Defaults моделируют реалистичный single-nic VCSA (`vcenter.lab.local`,
|
||||
`192.168.1.50/24`, gateway `192.168.1.1`, DNS `8.8.8.8`/`1.1.1.1`).
|
||||
- `save_networking` держит сфокусированные DNS-зеркала
|
||||
(`/dns/hostname`, `/dns/servers`, `/dns/domains`) согласованными с полным
|
||||
документом `/networking`, чтобы работали оба стиля клиентов Automation API.
|
||||
- Состояние идемпотентно засевается один раз на свежую БД
|
||||
(`seed_appliance_state`) и хранится в `vsphere_api_state`.
|
||||
- Эндпоинты TLS/certificate-management — seeded stand-in'ы, не настоящее
|
||||
хранилище сертификатов VECS — см. [Покрытие API](../api-coverage.md).
|
||||
|
||||
`/api/appliance/system/version` намеренно не требует сессию в этой lab-сборке
|
||||
(поведение реального vCenter зависит от версии), чтобы smoke-скрипты могли
|
||||
проверить доступность до аутентификации.
|
||||
@@ -0,0 +1,51 @@
|
||||
**Language / Язык:** [English](../../domains/authz.md) | [Русский](authz.md)
|
||||
|
||||
# Авторизация
|
||||
|
||||
Gate роль → privilege для мутирующих REST-эндпоинтов (и decorator-style hook
|
||||
для SOAP): [`app/vsphere/security/authz.py`](../../../app/vsphere/security/authz.py),
|
||||
[`platform_rest.py`](../../../app/vsphere/rest/platform_rest.py).
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| GET | `/api/vcenter/privilege` | Каталог привилегий |
|
||||
| GET | `/api/vcenter/authorization/roles` | Role → набор privilege |
|
||||
| GET/POST/DELETE | `/api/vcenter/authorization/permissions[/{permission_id}]` | Привязки principal ↔ role ↔ entity |
|
||||
| GET/POST/PATCH/DELETE | `/api/vcenter/identity/providers[/{provider}]` | Stand-in'ы identity-provider LocalOS + OIDC + SAML |
|
||||
|
||||
## Роли (seed)
|
||||
|
||||
| Роль | Область |
|
||||
|---|---|
|
||||
| `Administrator` | Каждая привилегия в каталоге |
|
||||
| `ReadOnly` | `System.Anonymous`, `System.Read`, `System.View`, `Datastore.Browse` |
|
||||
| `VirtualMachinePowerUser` | Read + взаимодействия power/snapshot/clone |
|
||||
| `VirtualMachineAdministrator` | Набор power-user + привилегии create/delete/reconfigure/tag/content-library |
|
||||
|
||||
`ROLE_PRIVILEGES` в `authz.py` задаёт точные наборы привилегий; неполный
|
||||
пример gated-привилегий: `VirtualMachine.Inventory.Create`,
|
||||
`VirtualMachine.Inventory.Delete`, `VirtualMachine.Interact.PowerOn`,
|
||||
`VirtualMachine.Config.CPUCount`, `VirtualMachine.Provisioning.Clone`,
|
||||
`Datastore.FileManagement`, `Network.Assign`,
|
||||
`InventoryService.Tagging.CreateTag`, `ContentLibrary.AddLibraryItem`,
|
||||
`Authorization.ModifyPermissions`.
|
||||
|
||||
## Как работает gating
|
||||
|
||||
- `require_privilege(*needed)` — фабрика зависимостей FastAPI: резолвит
|
||||
сессию, загружает роли (из сессии или `vsphere_credentials`, если нет),
|
||||
и поднимает HTTP 403 (`unauthorized`), если отсутствует любая из
|
||||
перечисленных привилегий.
|
||||
- `require_read` — сокращение для `require_privilege("System.Read")`.
|
||||
- Permissions также могут ограничить роль конкретным entity MOID
|
||||
(`PermissionSpec(principal, role, entity_moid, propagate)`); seed
|
||||
ограничивает `readonly@vsphere.local` datacenter'ом, а двух VM-admin
|
||||
принципалов — папкой VM.
|
||||
|
||||
## Seeded-принципалы
|
||||
|
||||
Четыре принципала `@vsphere.local` и их роли — в
|
||||
[Аутентификация](../authentication.md); как permissions скоупятся по
|
||||
профилю — в [Профили seed](../seed-profiles.md).
|
||||
@@ -0,0 +1,38 @@
|
||||
**Language / Язык:** [English](../../domains/content-library.md) | [Русский](content-library.md)
|
||||
|
||||
# Content library
|
||||
|
||||
Локальные content libraries, library items, upload/download sessions и OVF
|
||||
deploy:
|
||||
[`app/vsphere/rest/content_rest.py`](../../../app/vsphere/rest/content_rest.py),
|
||||
[`nfc_rest.py`](../../../app/vsphere/rest/nfc_rest.py),
|
||||
[`app/vsphere/domain/content.py`](../../../app/vsphere/domain/content.py).
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| GET | `/api/content/library` | Список library ids |
|
||||
| POST | `/api/content/local-library` | Создать local library |
|
||||
| GET/POST | `/api/content/library/item` | Список / create items (`?library_id=`) |
|
||||
| POST | `/api/vcenter/ovf/library-item/{item_id}` | Deploy OVF item → новая `VirtualMachine` + task |
|
||||
| POST | `/api/content/library/item/update-session[/{session_id}[/file]]` | Поток push-upload (стиль Ansible/Terraform) |
|
||||
| GET/POST | `/api/content/library/item/download-session[/{session_id}[/file]]` | Поток pull-download |
|
||||
| GET/PUT/POST | `/nfc/{lease}` \| `/nfc/{lease}/files/{filename}` \| `/nfc/{lease}/complete` | Эндпоинты transfer в стиле HttpNfcLease для SOAP import path |
|
||||
|
||||
## Основные моменты
|
||||
|
||||
- Libraries/items живут в `vsphere_libraries` / `vsphere_library_items`;
|
||||
seed создаёт две libraries («Local Content», «Published Templates») с
|
||||
OVF-typed items (`ubuntu-22.04`, `centos-stream-9`, `golden-image`).
|
||||
- Update/download sessions живут в PostgreSQL (`vsphere_transfer_sessions`,
|
||||
миграция `012`) и моделируют handshake передачи файлов — не реальное
|
||||
byte-for-byte хранилище OVF/VMDK. Строки HttpNfcLease — в `vsphere_nfc_leases`.
|
||||
- `deploy_ovf_from_library` создаёт реальную строку `VirtualMachine` и
|
||||
возвращает task id, зеркаля SOAP-поток `ImportVApp_Task` /
|
||||
`CreateImportSpec` + `HttpNfcLease*`, используемый govc-style `ovf.import`.
|
||||
- Для create нужны `ContentLibrary.CreateLocalLibrary` / `.AddLibraryItem`,
|
||||
для deploy — `VirtualMachine.Provisioning.DeployTemplate`.
|
||||
|
||||
Операции HttpNfcLease progress/complete/abort для upload-heavy клиентов —
|
||||
[SOAP / VIM](soap.md).
|
||||
@@ -0,0 +1,46 @@
|
||||
**Language / Язык:** [English](../../domains/inventory.md) | [Русский](inventory.md)
|
||||
|
||||
# Inventory
|
||||
|
||||
Listing + CRUD для datacenter, cluster, folder, resource pool, host и
|
||||
datastore/network:
|
||||
[`app/vsphere/rest/router.py`](../../../app/vsphere/rest/router.py),
|
||||
[`app/vsphere/domain/inventory_ops.py`](../../../app/vsphere/domain/inventory_ops.py).
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| GET | `/api/vcenter/datacenter` | Список |
|
||||
| POST/DELETE | `/api/vcenter/datacenter[/{datacenter}]` | Create засевает подпапки host/vm/datastore/network |
|
||||
| GET | `/api/vcenter/cluster` | Список |
|
||||
| POST/DELETE | `/api/vcenter/cluster[/{cluster}]` | Create засевает `ResourcePool` |
|
||||
| GET | `/api/vcenter/folder` | Список; `GET /api/vcenter/folder/{folder}/children` |
|
||||
| POST/DELETE | `/api/vcenter/folder[/{folder}]` | |
|
||||
| GET | `/api/vcenter/resource-pool` | Список |
|
||||
| POST/DELETE | `/api/vcenter/resource-pool[/{resource_pool}]` | |
|
||||
| GET | `/api/vcenter/host[/{host}]` | Connection state, CPU/memory, IP, storage devices, networking |
|
||||
| POST | `/api/vcenter/host/{host}/maintenance` | Переключение maintenance mode |
|
||||
| GET | `/api/vcenter/datastore[/{datastore}]` | Type, capacity, free space, accessibility |
|
||||
| GET | `/api/vcenter/network` | Standard networks + distributed portgroups |
|
||||
|
||||
Legacy `/rest/vcenter/*` зеркалит большинство GET-путей с конвертом
|
||||
`{ "value": … }` — см. [Поверхность API](../api-surface.md).
|
||||
|
||||
## Основные моменты
|
||||
|
||||
- Каждый объект inventory — строка в `vsphere_objects` (MOID, type, name,
|
||||
`parent_moid`, `props` JSONB) — см.
|
||||
[`app/vsphere/inventory.py`](../../../app/vsphere/inventory.py).
|
||||
- Конвенции MOID следуют формам реального vCenter: `datacenter-NN`,
|
||||
`domain-cNN` (cluster), `resgroup-NN` (resource pool), `group-vNN`/`group-hNN`/
|
||||
`group-sNN`/`group-nNN` (папки VM/host/datastore/network), `host-NN`,
|
||||
`datastore-NN`, `network-NN` / `dvportgroup-NN`.
|
||||
- `list_hosts`/`list_clusters`/и т.п. фильтруют живое состояние PostgreSQL;
|
||||
отдельного кэша для инвалидации после мутации нет.
|
||||
- Список VM (`GET /api/vcenter/vm`) поддерживает фильтры: `names`,
|
||||
`power_states`, `hosts`, `folders`, `datacenters`, `clusters`,
|
||||
`resource_pools`, плюс пагинацию `limit`/`cursor`.
|
||||
|
||||
Форма топологии по умолчанию — [Профили seed](../seed-profiles.md);
|
||||
операции по VM — [Виртуальные машины](vm.md).
|
||||
@@ -0,0 +1,35 @@
|
||||
**Language / Язык:** [English](../../domains/networking.md) | [Русский](networking.md)
|
||||
|
||||
# Networking
|
||||
|
||||
Standard networks, distributed portgroups/switches и host networking:
|
||||
[`app/vsphere/rest/router.py`](../../../app/vsphere/rest/router.py),
|
||||
[`platform_rest.py`](../../../app/vsphere/rest/platform_rest.py).
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| GET | `/api/vcenter/network` | Объекты standard `Network` + `DistributedVirtualPortgroup` |
|
||||
| GET/POST | `/api/vcenter/network/dvs` | Distributed virtual switches |
|
||||
| POST | `/api/vcenter/network/dvpg` | Создать distributed portgroup |
|
||||
| GET | `/api/vcenter/host/{host}/networking` | DNS, default gateway, интерфейс `vmk0`, routing |
|
||||
| GET/PUT/POST | `/api/appliance/networking` \| `/networking/dns/{hostname,servers,domains}` | Networking на уровне appliance vCenter (см. [Appliance](appliance.md)) |
|
||||
|
||||
Legacy `GET /rest/vcenter/network` зеркалит список.
|
||||
|
||||
## Основные моменты
|
||||
|
||||
- `nics[].value.backing` каждой VM указывает либо на `STANDARD_PORTGROUP`
|
||||
(`network-41`, «VM Network»), либо на `DISTRIBUTED_PORTGROUP`
|
||||
(`dvportgroup-4N`, с `vlan_id`).
|
||||
- Топология по умолчанию засевает один `VmwareDistributedVirtualSwitch`
|
||||
(`dvs-51`, `mtu: 9000`) и 1–3 дополнительных distributed portgroup в
|
||||
зависимости от размера профиля.
|
||||
- Host networking (`GET /api/vcenter/host/{host}/networking`) возвращает DNS
|
||||
servers/domains, default gateway и один management-интерфейс `vmk0` с
|
||||
детерминированным IPv4 по индексу host.
|
||||
- Пути Automation API с меткой NSX (tier-0 gateway, projects, edges,
|
||||
VPC/subnets) — seeded lab stand-in'ы под `namespace-management` — см.
|
||||
таблицу «Platform surfaces» в [Покрытие API](../api-coverage.md); это не
|
||||
реальный NSX Manager.
|
||||
@@ -0,0 +1,32 @@
|
||||
**Language / Язык:** [English](../../domains/session.md) | [Русский](session.md)
|
||||
|
||||
# Session
|
||||
|
||||
Устойчивая идентичность сессии, общая для REST и SOAP:
|
||||
[`app/vsphere/security/session.py`](../../../app/vsphere/security/session.py).
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| POST | `/api/session` | Basic auth → JSON-строка session id + заголовок/cookie `vmware-api-session-id` |
|
||||
| GET | `/api/session` | HTTP 200; заголовки `x-vmware-session-user` / `x-vmware-session-roles` |
|
||||
| DELETE | `/api/session` | Инвалидирует сессию, очищает cookie |
|
||||
| POST/GET/DELETE | `/rest/com/vmware/cis/session` | Legacy-эквиваленты `{ "value": … }` |
|
||||
| POST | SOAP `SessionManager.Login` | Возвращает тот же session id; ставит cookie `vmware_soap_session` |
|
||||
| POST | SOAP `SessionManager.Logout` | Удаляет сессию |
|
||||
|
||||
## Основные моменты
|
||||
|
||||
- Сессии — непрозрачные 32-символьные hex-токены в `vsphere_sessions` со
|
||||
**скользящим TTL 2 часа** — каждый аутентифицированный вызов продлевает
|
||||
`expires_at`.
|
||||
- Четыре лабораторные учётки (`vsphere_credentials`, scrypt-хеш) идемпотентно
|
||||
обеспечиваются при первом login и каждым профилем seed
|
||||
(`ensure_default_credentials`).
|
||||
- `require_session` резолвит сессию из заголовка или cookie
|
||||
`vmware-api-session-id`; отсутствует/истекла → HTTP 401.
|
||||
- Роли привязываются к сессии при lookup (`vsphere_credentials.roles`) и
|
||||
управляют [Авторизацией](authz.md).
|
||||
|
||||
Полные примеры запросов — [Аутентификация](../authentication.md).
|
||||
@@ -0,0 +1,68 @@
|
||||
**Language / Язык:** [English](../../domains/soap.md) | [Русский](soap.md)
|
||||
|
||||
# SOAP / VIM
|
||||
|
||||
Минимальный VIM SDK для клиентов в стиле pyvmomi / govmomi (провайдер
|
||||
Terraform `hashicorp/vsphere`, Pulumi, govc):
|
||||
[`app/vsphere/soap/router.py`](../../../app/vsphere/soap/router.py),
|
||||
[`property_collector.py`](../../../app/vsphere/soap/property_collector.py),
|
||||
[`pbm.py`](../../../app/vsphere/soap/pbm.py).
|
||||
|
||||
## Эндпоинт
|
||||
|
||||
Все операции POST'ят SOAP-конверт на `/sdk` (также `/sdk/`). Вспомогательные
|
||||
маршруты:
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| GET | `/sdk/vimService.wsdl` (alias `/sdk/vim.wsdl`) | WSDL stub со списком реализованных операций |
|
||||
| GET | `/sdk/about.do` (alias `/about.do`) | Человекочитаемая страница «VMware vCenter Server» |
|
||||
| POST | `/sdk/vim25/{version}/SessionManager/SessionManager/Login` | Login-вариант с JSON-телом, используемый некоторыми SDK |
|
||||
|
||||
## Реализованные операции
|
||||
|
||||
- `RetrieveServiceContent`, `Login`, `Logout`
|
||||
- `RetrieveProperties`, `RetrievePropertiesEx`, **ContinueRetrievePropertiesEx**
|
||||
(токены пагинации; plural `<objects>`), `CreateFilter`,
|
||||
`WaitForUpdatesEx` (version tokens; пустые polls), `CreateContainerView`,
|
||||
`DestroyPropertyFilter`
|
||||
- `FindByInventoryPath` (пути без корневой папки `Datacenters`, как в
|
||||
конвенциях govmomi), `FindByUuid`, `FindByDnsName`, `FindByIp`, `FindChild`
|
||||
- `CreateVM_Task`, `CreateChildVM_Task`, `CreateFolder`, `PowerOnVM_Task`,
|
||||
`PowerOffVM_Task`, `CloneVM_Task`, `CreateSnapshot_Task`, `Rename_Task`,
|
||||
`ReconfigVM_Task`, `RelocateVM_Task`, `Destroy_Task`, `CustomizeVM_Task`,
|
||||
`CancelTask`, `CurrentTime`
|
||||
- Guest file ops: `InitiateFileTransferToGuest`,
|
||||
`InitiateFileTransferFromGuest`, `ListFilesInGuest`, `DeleteFileInGuest`,
|
||||
`MakeDirectoryInGuest`
|
||||
- Import/upload: `ImportVApp_Task`, `CreateImportSpec`,
|
||||
`HttpNfcLeaseComplete`, `HttpNfcLeaseProgress`, `HttpNfcLeaseAbort`,
|
||||
`HttpNfcLeaseGetManifest` (в паре с REST `/nfc/{lease}` —
|
||||
см. [Content library](content-library.md))
|
||||
- `QueryConfigOption`, `QueryConfigOptionEx`, `QueryConfigOptionDescriptor`,
|
||||
`QueryConfigTarget`
|
||||
- Stub PBM (`/pbm`) для клиентов, учитывающих storage policy
|
||||
|
||||
## Основные моменты
|
||||
|
||||
- `Login` выдаёт ту же underlying-сессию, что и REST (`vmware-api-session-id`
|
||||
cookie/header плюс cookie `vmware_soap_session`) — см.
|
||||
[Session](session.md).
|
||||
- `VIM_VERSION` зафиксирован как `8.0.2` с ≤3 компонентами через точку, так
|
||||
как `hashicorp/vsphere` строго парсит `AboutInfo.version`.
|
||||
- Type-strict MOR lookup отклоняет ссылку `VirtualApp:resgroup-*`,
|
||||
резолвящуюся как plain `ResourcePool` — важно для Terraform resource path
|
||||
`CreateVM_Task`.
|
||||
- Операции, возвращающие задачу, создают реальную строку в `vsphere_tasks`
|
||||
(общую с REST — см. [Tasks](tasks.md)), включая MoRefs `info.result` при
|
||||
create/clone.
|
||||
- Filters PropertyCollector, ContainerViews и version tokens WaitForUpdatesEx
|
||||
живут в `vsphere_pc_state` (миграция `013`) между перезапусками процесса
|
||||
в рамках лаборатории.
|
||||
- `Folder.childType` отдаётся как `ArrayOfString`; строковые свойства несут
|
||||
`xsi:type="xsd:string"`, чтобы их принимал decoder govmomi; `Datastore.host`
|
||||
— `ArrayOfDatastoreHostMount`; у `Cluster`/`Host` есть `environmentBrowser`.
|
||||
|
||||
Примеры подключений pyvmomi/govmomi/Terraform/Pulumi — [Клиенты](../clients.md);
|
||||
минимальный raw-XML smoke —
|
||||
[examples/python/vsphere_soap_smoke.py](../../../examples/python/vsphere_soap_smoke.py).
|
||||
@@ -0,0 +1,37 @@
|
||||
**Language / Язык:** [English](../../domains/storage.md) | [Русский](storage.md)
|
||||
|
||||
# Storage
|
||||
|
||||
Datastores, метаданные файлов datastore, устройства хранения host и storage
|
||||
policies:
|
||||
[`app/vsphere/rest/router.py`](../../../app/vsphere/rest/router.py),
|
||||
[`content_rest.py`](../../../app/vsphere/rest/content_rest.py),
|
||||
[`platform_rest.py`](../../../app/vsphere/rest/platform_rest.py),
|
||||
[`app/vsphere/domain/content.py`](../../../app/vsphere/domain/content.py).
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| GET | `/api/vcenter/datastore[/{datastore}]` | Type (`VMFS`/`NFS`), capacity, free space, `multiple_host_access` |
|
||||
| GET/POST | `/api/vcenter/datastore/{datastore}/files` | Список / регистрация метаданных файлов (пути ISO, VMX, VMDK) |
|
||||
| GET | `/api/vcenter/host/{host}/storage/storage-device` | Seeded local disk devices (`naa.*`, capacity, флаг SSD) |
|
||||
| GET | `/api/vcenter/storage/policies[/{policy}/vm]` | Storage-based policy management, в т.ч. lab-политики `policy_type: VSAN` |
|
||||
|
||||
Legacy `GET /rest/vcenter/datastore` зеркалит список в конверте
|
||||
`{ "value": … }`.
|
||||
|
||||
## Основные моменты
|
||||
|
||||
- Строки datastore засеваются реалистичными парами capacity/free-space
|
||||
(`type`, `capacity`, `free_space`, `accessible`,
|
||||
`multiple_host_access`) — см.
|
||||
[`app/vsphere/profiles.py`](../../../app/vsphere/profiles.py).
|
||||
- Метаданные файлов живут в `vsphere_datastore_files` (`path`, `size`, `type`);
|
||||
seed заранее заполняет ISO и записи `.vmx`/`.vmdk` VM
|
||||
(`seed_platform_extras`).
|
||||
- Среди storage policies есть lab-политика с меткой vSAN `RAID1` — оговорку
|
||||
по vSAN (seeded lab data, не реальный кластер vSAN) см. в таблице
|
||||
«Platform surfaces» в [Покрытие API](../api-coverage.md).
|
||||
- Устройства хранения host — синтетические диски на host, не реальные extents
|
||||
ESXi VMFS; флаги capacity/SSD детерминированно зависят от индекса host.
|
||||
@@ -0,0 +1,33 @@
|
||||
**Language / Язык:** [English](../../domains/tagging.md) | [Русский](tagging.md)
|
||||
|
||||
# Tagging
|
||||
|
||||
Сервис CIS tagging (categories, tags, object associations):
|
||||
[`app/vsphere/rest/tagging_rest.py`](../../../app/vsphere/rest/tagging_rest.py),
|
||||
[`app/vsphere/domain/tagging.py`](../../../app/vsphere/domain/tagging.py).
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| GET/POST | `/api/cis/tagging/category` | Список / create (`cardinality`, `associable_types`) |
|
||||
| GET/DELETE | `/api/cis/tagging/category/{category_id}` | |
|
||||
| GET/POST | `/api/cis/tagging/tag` | Список / create под category |
|
||||
| GET/DELETE | `/api/cis/tagging/tag/{tag_id}` | |
|
||||
| POST | `/api/cis/tagging/tag-association` | Attach/detach тега к/от объекта |
|
||||
|
||||
## Основные моменты
|
||||
|
||||
- Id category и tag следуют реальной форме
|
||||
`urn:vmomi:InventoryServiceCategory:…` /
|
||||
`urn:vmomi:InventoryServiceTag:…:GLOBAL`.
|
||||
- Строки живут в `vsphere_tag_categories`, `vsphere_tags`,
|
||||
`vsphere_tag_associations` — устойчивы между перезапусками, заменяются
|
||||
при reseed.
|
||||
- Seed создаёт две categories (`Environment`, `Owner`) с тегами `prod`/
|
||||
`staging`/`platform` и прикрепляет `prod` к двум seeded VM
|
||||
(`seed_platform_extras` в
|
||||
[`app/vsphere/domain/content.py`](../../../app/vsphere/domain/content.py)).
|
||||
- Attach/create тега требует привилегии
|
||||
`InventoryService.Tagging.CreateCategory` / `.CreateTag` / `.AttachTag` —
|
||||
см. [Авторизация](authz.md).
|
||||
@@ -0,0 +1,38 @@
|
||||
**Language / Язык:** [English](../../domains/tasks.md) | [Русский](tasks.md)
|
||||
|
||||
# Tasks
|
||||
|
||||
Длительные операции (power, clone, relocate, snapshot, OVF deploy, guest
|
||||
customize) возвращают CIS-style task id:
|
||||
[`app/vsphere/domain/tasks.py`](../../../app/vsphere/domain/tasks.py),
|
||||
[`app/vsphere/rest/tasks.py`](../../../app/vsphere/rest/tasks.py).
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| GET | `/api/cis/tasks` | Список недавних задач (до 200 последних) |
|
||||
| GET | `/api/cis/tasks/{task}` | Status, progress, `service`/`operation`, `result`/`error` |
|
||||
|
||||
## Паттерн клиента
|
||||
|
||||
1. Мутация `POST`/`DELETE` → прочитайте task id из `{ "task": "task-…" }`
|
||||
(REST) или SOAP MoRef `*_Task`.
|
||||
2. Опрашивайте `GET /api/cis/tasks/{task}`, пока `status` не станет
|
||||
`SUCCEEDED` или `FAILED`.
|
||||
3. В `result` — результат операции (например `{"vm": "vm-104"}` при
|
||||
create/clone/deploy).
|
||||
|
||||
## Основные моменты
|
||||
|
||||
- Строки задач коммитятся в `vsphere_tasks` (`id`, `description`, `status`,
|
||||
`service`, `operation`, `result`, `error`, `completed_at`).
|
||||
- `progress` синтезируется как `50` во время выполнения и `100` в терминальном
|
||||
состоянии — дробный progress этот симулятор не моделирует.
|
||||
- Одно и то же хранилище задач обслуживает и REST `/api/cis/tasks`, и SOAP
|
||||
task MoRefs, поэтому Terraform apply (SOAP `CreateVM_Task`) и REST-опрос
|
||||
того же id видят согласованное состояние.
|
||||
- Длительности симуляции учитывают `SIMULATION_TIME_SCALE`
|
||||
(больше = быстрее завершение).
|
||||
|
||||
См. [Поверхность API](../api-surface.md) и [Эксплуатация](../operations.md).
|
||||
@@ -0,0 +1,50 @@
|
||||
**Language / Язык:** [English](../../domains/vm.md) | [Русский](vm.md)
|
||||
|
||||
# Виртуальные машины
|
||||
|
||||
Полный REST lifecycle для объектов `VirtualMachine`:
|
||||
[`app/vsphere/rest/router.py`](../../../app/vsphere/rest/router.py),
|
||||
[`vm_ext.py`](../../../app/vsphere/rest/vm_ext.py),
|
||||
[`app/vsphere/domain/vm_ops.py`](../../../app/vsphere/domain/vm_ops.py).
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
| Метод | Путь | Заметки |
|
||||
|---|---|---|
|
||||
| GET | `/api/vcenter/vm` | Список с фильтрами `names`/`power_states`/`hosts`/`folders`/`datacenters`/`clusters`/`resource_pools`/`limit`/`cursor` |
|
||||
| GET/DELETE | `/api/vcenter/vm/{vm}` | Get / delete (должна быть powered off) |
|
||||
| POST | `/api/vcenter/vm` | Create — `placement.{folder,host,datastore,resource_pool}`, `cpu.count`, `memory.size_MiB`, `disks`, `nics` |
|
||||
| GET/POST | `/api/vcenter/vm/{vm}/power` | Get power state / `?action=start\|stop\|suspend\|reset` — возвращает `{ "task": "task-…" }` |
|
||||
| GET | `/api/vcenter/vm/{vm}/hardware` | Сводка |
|
||||
| GET/PATCH | `/api/vcenter/vm/{vm}/hardware/cpu` \| `/memory` | Смена CPU count / memory (privilege-gated) |
|
||||
| GET/POST | `/api/vcenter/vm/{vm}/hardware/disk` \| `/ethernet` | Добавить disk / NIC |
|
||||
| GET | `/api/vcenter/vm/{vm}/hardware/boot` | Boot type/order |
|
||||
| GET/POST/DELETE | `/api/vcenter/vm/{vm}/snapshots[/{snapshot}]` | Create, revert (`?action=revert`), delete |
|
||||
| POST | `/api/vcenter/vm/{vm}/clone` \| `/relocate` | Возвращают задачу |
|
||||
| GET/POST | `/api/vcenter/vm/{vm}/tools` | Статус guest tools / upgrade |
|
||||
| GET | `/api/vcenter/vm/{vm}/guest/identity` \| `/networking` | Имя guest OS, синтетический IP |
|
||||
| GET/POST | `/api/vcenter/vm/{vm}/guest/power` | Guest-level power ops |
|
||||
| POST | `/api/vcenter/vm/{vm}/guest/customization` | Спека customization в стиле sysprep/cloud-init |
|
||||
| POST | `/api/vcenter/vm/{vm}/console/tickets` | Console-тикет (стиль VNC/WebMKS) |
|
||||
| GET/PUT/DELETE | `/api/vcenter/vm/{vm}/guest/filesystem` | Lab virtual guest filesystem (потоки write-a-file Ansible/Terraform) |
|
||||
| GET | `/api/vcenter/vm/{vm}/guest/filesystem/files` \| `/guest/local-filesystem` | Listing |
|
||||
|
||||
## Основные моменты
|
||||
|
||||
- У каждой строки VM реалистичная форма устройств: `nics`, `disks`, `cdroms`,
|
||||
`floppies`, `serials`, `scsi_adapters`, `boot`/`boot_devices`, `identity`
|
||||
(`instance_uuid`, `bios_uuid`) и синтетическая карта `guest_ip` /
|
||||
`guest_filesystems` — те же поля питают и REST hardware-эндпоинты, и SOAP
|
||||
`VirtualMachineConfigInfo`.
|
||||
- Create требует `VirtualMachine.Inventory.Create`; delete требует
|
||||
`VirtualMachine.Inventory.Delete` **и** VM должна быть `POWERED_OFF`.
|
||||
- Power/clone/snapshot/relocate/customize создают устойчивую CIS-задачу (см.
|
||||
[Tasks](tasks.md)), а не мутируют синхронно в теле ответа.
|
||||
- Console tickets из `/api/vcenter/vm/{vm}/console/tickets` живут в
|
||||
`vsphere_console_tickets` (миграция `013`).
|
||||
- MOID следуют конвенции `vm-{100+n}`, засеваемой
|
||||
[`app/vsphere/profiles.py`](../../../app/vsphere/profiles.py).
|
||||
|
||||
Семантика datastore/disk-file — [Storage](storage.md); эквивалентные
|
||||
операции `CreateVM_Task`/`PowerOnVM_Task`/… для pyvmomi, govmomi, Terraform и
|
||||
Pulumi — [SOAP / VIM](soap.md).
|
||||
@@ -0,0 +1,23 @@
|
||||
**Language / Язык:** [English](../../examples/ansible.md) | [Русский](ansible.md)
|
||||
|
||||
# Ansible
|
||||
|
||||
Playbook использует модуль `uri` против HTTPS-шлюза
|
||||
(`https://localhost`): вход по Basic-auth сессии, затем вызовы с
|
||||
заголовком `vmware-api-session-id` для остального жизненного цикла.
|
||||
|
||||
```bash
|
||||
cd examples/ansible
|
||||
ansible-playbook -i inventory.ini vsphere_playbook.yml
|
||||
```
|
||||
|
||||
[`vsphere_playbook.yml`](../../../examples/ansible/vsphere_playbook.yml) охватывает:
|
||||
вход в сессию, список ВМ, создание, power on, опрос CIS-задачи
|
||||
(`/api/cis/tasks/{task}`), запись файла в лабораторную гостевую виртуальную ФС,
|
||||
power off, удаление и выход из сессии.
|
||||
|
||||
Перед опорой на фиксированные имена ВМ/MOID из предыдущего запуска выполните
|
||||
повторный seed симулятора (`make seed`).
|
||||
|
||||
Для lab-набора на официальном `pulumi-vsphere` (непустые export'ы, HTML-отчёт)
|
||||
см. [`pulumi-tests/`](../../../pulumi-tests/README.ru.md) или `make pulumi-tests`.
|
||||
@@ -0,0 +1,21 @@
|
||||
**Language / Язык:** [English](../../examples/go.md) | [Русский](go.md)
|
||||
|
||||
# Go
|
||||
|
||||
Использует стандартную библиотеку Go (`net/http`) против
|
||||
`https://localhost` с Basic-auth сессией
|
||||
(`vmware-api-session-id`).
|
||||
|
||||
```bash
|
||||
cd examples/go
|
||||
go run .
|
||||
```
|
||||
|
||||
Переопределите значения по умолчанию через `VSPHERE_BASE`, `VSPHERE_USER`,
|
||||
`VSPHERE_PASSWORD`, `VSPHERE_VM_NAME`. См. [`main.go`](../../../examples/go/main.go)
|
||||
для потока session → list → create → power → wait-task → delete и вспомогательной
|
||||
функции `waitTask`, которая опрашивает `GET /api/cis/tasks/{task}`.
|
||||
|
||||
Проверка TLS отключена в HTTP-клиенте только для локального самоподписанного
|
||||
сертификата разработческого шлюза — не переиспользуйте такой transport против
|
||||
реального vCenter.
|
||||
@@ -0,0 +1,22 @@
|
||||
**Language / Язык:** [English](../../examples/java.md) | [Русский](java.md)
|
||||
|
||||
# Java
|
||||
|
||||
Cookbook на Java 11+ `HttpClient` с Basic-auth сессией
|
||||
(`vmware-api-session-id`) против `https://localhost`. Без сторонних
|
||||
JSON-библиотек — ответы разбираются простым строковым извлечением полей,
|
||||
достаточным для лабораторного smoke.
|
||||
|
||||
```bash
|
||||
cd examples/java
|
||||
javac Cookbook.java && java Cookbook
|
||||
```
|
||||
|
||||
Переопределите значения по умолчанию переменными окружения `VSPHERE_BASE`,
|
||||
`VSPHERE_USER`, `VSPHERE_PASSWORD`, `VSPHERE_VM_NAME`. См.
|
||||
[`Cookbook.java`](../../../examples/java/Cookbook.java) для потока session →
|
||||
create → power → wait-task → delete.
|
||||
|
||||
Клиент устанавливает trust-all `SSLContext` только для локального
|
||||
самоподписанного сертификата разработческого шлюза — не переиспользуйте его
|
||||
против реального vCenter.
|
||||
@@ -0,0 +1,53 @@
|
||||
**Language / Язык:** [English](../../examples/overview.md) | [Русский](overview.md)
|
||||
|
||||
# Обзор примеров клиентов
|
||||
|
||||
## Чеклист запуска
|
||||
|
||||
```bash
|
||||
make up
|
||||
curl -skf https://localhost/health/ready
|
||||
make seed
|
||||
curl -sk https://localhost/api/appliance/system/version
|
||||
```
|
||||
|
||||
## Конечные точки
|
||||
|
||||
| URL | Когда использовать |
|
||||
|---|---|
|
||||
| `https://localhost` | curl, pyvmomi, govmomi, Terraform, Pulumi, Ansible, Go, Java, Perl — всё из `examples/` |
|
||||
| `http://localhost` | Лабораторный HTTP без TLS (без рукопожатия TLS) |
|
||||
|
||||
## Краткая справка по аутентификации
|
||||
|
||||
**Сессия (REST)**
|
||||
|
||||
```bash
|
||||
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/vm
|
||||
```
|
||||
|
||||
**SOAP Login**
|
||||
|
||||
```bash
|
||||
python examples/python/vsphere_soap_smoke.py https://localhost
|
||||
```
|
||||
|
||||
## Ожидание задач
|
||||
|
||||
Не считайте HTTP-ответ мутации достаточным признаком «ВМ запущена». Вызовы
|
||||
power, clone, relocate, snapshot и OVF-deploy возвращают `{ "task": "task-…" }`;
|
||||
опрашивайте `GET /api/cis/tasks/{task}`, пока `status` не станет `SUCCEEDED` или
|
||||
`FAILED`. См. [Задачи](../domains/tasks.md).
|
||||
|
||||
## Предупреждение о повторном seed
|
||||
|
||||
`make seed` заменяет инвентарь PostgreSQL. После этого обновите состояние
|
||||
Terraform/Pulumi/Ansible — см. [Профили seed](../seed-profiles.md).
|
||||
|
||||
## Дерево исполняемых примеров
|
||||
|
||||
См. [`examples/README.ru.md`](../../../examples/README.ru.md). Lab-набор на
|
||||
официальном `pulumi-vsphere` — в
|
||||
[`pulumi-tests/`](../../../pulumi-tests/README.ru.md) (`make pulumi-tests`).
|
||||
@@ -0,0 +1,20 @@
|
||||
**Language / Язык:** [English](../../examples/perl.md) | [Русский](perl.md)
|
||||
|
||||
# Perl
|
||||
|
||||
Cookbook на `HTTP::Tiny` + `JSON` с Basic-auth сессией
|
||||
(`vmware-api-session-id`) против `https://localhost`.
|
||||
|
||||
```bash
|
||||
cd examples/perl
|
||||
cpanm --installdeps . # или установите HTTP::Tiny, JSON, IO::Socket::SSL вручную
|
||||
perl cookbook.pl
|
||||
```
|
||||
|
||||
Переопределите значения по умолчанию переменными окружения `VSPHERE_BASE`,
|
||||
`VSPHERE_USER`, `VSPHERE_PASSWORD`, `VSPHERE_VM_NAME`. См.
|
||||
[`cookbook.pl`](../../../examples/perl/cookbook.pl) для потока session → list →
|
||||
create → power → wait-task → delete.
|
||||
|
||||
`HTTP::Tiny` создаётся с `verify_SSL => 0` только для локального самоподписанного
|
||||
сертификата разработческого шлюза.
|
||||
@@ -0,0 +1,32 @@
|
||||
**Language / Язык:** [English](../../examples/pulumi.md) | [Русский](pulumi.md)
|
||||
|
||||
# Pulumi
|
||||
|
||||
[`examples/pulumi/`](../../../examples/pulumi/) — Python-программа Pulumi на
|
||||
официальном [`pulumi-vsphere`](https://www.pulumi.com/registry/packages/vsphere/)
|
||||
(SOAP/VIM) против симулятора — тот же путь провайдера, что у Terraform
|
||||
`hashicorp/vsphere`.
|
||||
|
||||
```bash
|
||||
cd examples/pulumi
|
||||
pip install -r requirements.txt
|
||||
pulumi plugin install resource vsphere 4.17.0
|
||||
pulumi stack init dev # один раз
|
||||
pulumi config set server localhost
|
||||
pulumi config set --secret password 'VMware1!'
|
||||
pulumi up
|
||||
```
|
||||
|
||||
Конфигурация (`pulumi config set`): `server` (по умолчанию `localhost`), `user`
|
||||
(по умолчанию `administrator@vsphere.local`), `password` (secret), `datacenter`,
|
||||
`datastore`, `cluster`, `network`, `vm_name` (по умолчанию `pulumi-lab-01`).
|
||||
|
||||
Та же осторожность при reseed, что и для Terraform: состояние PostgreSQL
|
||||
симулятора и state Pulumi независимы. Закрепите major каталога для
|
||||
воспроизводимого CI, если ваш workflow зависит от вывода Web UI/evidence (см.
|
||||
[Версии API](../api-versions.md)) — сами runtime-маршруты доступны всегда
|
||||
независимо от major.
|
||||
|
||||
Для lab-набора (inventory + folder + VM + tags, проверки непустых export'ов,
|
||||
HTML-отчёт) см. [`pulumi-tests/`](../../../pulumi-tests/README.ru.md) или
|
||||
`make pulumi-tests` из корня репозитория.
|
||||
@@ -0,0 +1,33 @@
|
||||
**Language / Язык:** [English](../../examples/python-requests.md) | [Русский](python-requests.md)
|
||||
|
||||
# Python — REST (requests / stdlib)
|
||||
|
||||
Сырой HTTP к REST-шлюзу vSphere без vendor SDK.
|
||||
|
||||
```bash
|
||||
pip install -r examples/python/requirements.txt
|
||||
python examples/python/requests_cookbook.py
|
||||
```
|
||||
|
||||
[`requests_cookbook.py`](../../../examples/python/requests_cookbook.py)
|
||||
демонстрирует общий поток session → create → wait-for-task → power on → wait →
|
||||
power off → delete с помощью `requests`; идентификатор сессии передаётся в
|
||||
заголовке `vmware-api-session-id`.
|
||||
|
||||
Для варианта без внешних зависимостей, только на стандартной библиотеке
|
||||
(`urllib`), см. [`vsphere_rest_smoke.py`](../../../examples/python/vsphere_rest_smoke.py):
|
||||
|
||||
```bash
|
||||
python examples/python/vsphere_rest_smoke.py https://localhost
|
||||
```
|
||||
|
||||
Для комбинированного smoke REST-create + SOAP-`CreateVM_Task` + guest-filesystem
|
||||
см. [`vsphere_lifecycle.py`](../../../examples/python/vsphere_lifecycle.py):
|
||||
|
||||
```bash
|
||||
VSPHERE_BASE=https://localhost python examples/python/vsphere_lifecycle.py
|
||||
```
|
||||
|
||||
Все три скрипта по умолчанию используют `administrator@vsphere.local` / `VMware1!`
|
||||
и отключают проверку TLS только для локального самоподписанного сертификата
|
||||
разработческого шлюза.
|
||||
@@ -0,0 +1,32 @@
|
||||
**Language / Язык:** [English](../../examples/terraform.md) | [Русский](terraform.md)
|
||||
|
||||
# Terraform
|
||||
|
||||
[`examples/terraform/vsphere/`](../../../examples/terraform/vsphere/) использует
|
||||
официальный провайдер `hashicorp/vsphere` (SOAP `/sdk` под капотом), направленный
|
||||
на локальный HTTPS-шлюз (`https://localhost`) с
|
||||
`allow_unverified_ssl = true` для разработческого сертификата.
|
||||
|
||||
```bash
|
||||
cd examples/terraform/vsphere
|
||||
terraform init
|
||||
TF_VAR_create_lab_vm=false terraform plan # только data sources (datacenter/cluster/datastore/network/VM)
|
||||
TF_VAR_create_lab_vm=true terraform apply # также создаёт лабораторную ВМ (SOAP CreateVM_Task)
|
||||
```
|
||||
|
||||
Значения по умолчанию (`variables.tf`): `vsphere_server = "localhost"`,
|
||||
`vsphere_user = "administrator@vsphere.local"`,
|
||||
`vsphere_password = "VMware1!"`, `datacenter = "Datacenter"`,
|
||||
`cluster = "Cluster"`, `datastore = "datastore1"`,
|
||||
`network = "VM Network"`, `vm_name = "web-01"` (ВМ из seed `small`/`large`).
|
||||
|
||||
Версии плагинов провайдера меняются быстро — закрепите версии в блоке
|
||||
`required_providers` под то, что вы протестировали. После `make seed` обновите
|
||||
или пересоздайте state, чтобы допущения об именах ВМ/MOID оставались согласованными.
|
||||
|
||||
Этот cookbook — отправная точка для лабораторного CI, а не сертификация каждого
|
||||
resource/data source `hashicorp/vsphere` против полного реестра маршрутов. См.
|
||||
[SOAP / VIM](../domains/soap.md) для точных операций, лежащих в основе create/read
|
||||
путей провайдера, и
|
||||
[`pulumi-tests/`](../../../pulumi-tests/README.ru.md) для lab-набора
|
||||
`pulumi-vsphere` (`make pulumi-tests`).
|
||||
@@ -0,0 +1,15 @@
|
||||
**Language / Язык:** [English](../../examples/troubleshooting-clients.md) | [Русский](troubleshooting-clients.md)
|
||||
|
||||
# Устранение неполадок клиентов
|
||||
|
||||
| Симптом | Решение |
|
||||
|---|---|
|
||||
| Ошибки TLS-сертификата | Используйте `:443` с `verify=False` / `insecure`/`allow_unverified_ssl=true` **только** локально или plain HTTP `:80` |
|
||||
| 401 на первом вызове | Отправляйте `Authorization: Basic …` только на `/api/session` (или SOAP `Login`); все остальные вызовы требуют `vmware-api-session-id` |
|
||||
| 403 на power/create | Возможно, вы используете `readonly@vsphere.local` — переключитесь на `administrator@vsphere.local` или `operator@vsphere.local` |
|
||||
| ВМ не найдена | Имена ВМ seed `small`: `web-01`, `web-02`, `db-01`, `app-01`, `jumpbox` — не числовые VMID в стиле Proxmox |
|
||||
| Create возвращает MOID, а не task | REST `POST /api/vcenter/vm` синхронно возвращает MOID новой ВМ; только **power/clone/relocate/snapshot/OVF-deploy** возвращают `{ "task": "…" }` |
|
||||
| Create провайдера vs task | Опрашивайте `/api/cis/tasks/{task}`; многие провайдеры (Terraform, Pulumi) уже ждут внутри — сырые HTTP/Go/Java/Perl клиенты часто забывают |
|
||||
| Drift после reseed | Обновите/пересоздайте state Terraform/Pulumi/Ansible после `make seed` |
|
||||
| Сессия истекла во время выполнения | Сессии имеют скользящий TTL 2 часа; выполните повторный login, если длинный скрипт простаивал дольше |
|
||||
| SOAP `Login` не проходит | Убедитесь, что envelope направлен на `/sdk` с `SOAPAction` (пустая строка допустима) и `Content-Type: text/xml` |
|
||||
@@ -0,0 +1,57 @@
|
||||
**Language / Язык:** [English](../faq.md) | [Русский](faq.md)
|
||||
|
||||
# FAQ
|
||||
|
||||
## Это настоящий vCenter / ESXi?
|
||||
|
||||
Нет. Это симулятор API и состояния. Хосты, VM, datastores и сети —
|
||||
устойчивые модели PostgreSQL, а не ESXi-хосты или процессы KVM/vmkernel.
|
||||
|
||||
## Вы действительно покрываете vSphere Automation API?
|
||||
|
||||
**Runtime** всегда обслуживает полную зарегистрированную route table (1077 маршрутов:
|
||||
104 deep handlers + DB-backed stub surface для остальных) — см.
|
||||
[Поверхность API](api-surface.md). **Catalog** majors 6–8 — намеренно
|
||||
низкопокрытые исторические floors (2.9%–9.6%); только major 9 (8.0 U2 / Automation
|
||||
9.1 surface) объявлен как 100% в catalog. См.
|
||||
[Версии API](api-versions.md) и [Совместимость](compatibility.md).
|
||||
|
||||
## Можно ли использовать это в CI для Terraform / Ansible / pyvmomi / custom clients?
|
||||
|
||||
Да. Это основной сценарий использования. Засейте профиль и направьте клиентов на
|
||||
HTTPS gateway `:443` (REST `/api`/`/rest` или SOAP `/sdk`). См.
|
||||
[Клиенты](clients.md).
|
||||
|
||||
## Почему некоторые NSX / Supervisor / vSAN / SAML calls «успешны» без remotes?
|
||||
|
||||
Эти области сохраняют **локальное, засеянное** состояние симулятора (см. таблицу
|
||||
«Platform surfaces» в [Покрытие API](api-coverage.md)). Они намеренно не
|
||||
обращаются к реальному NSX Manager, Tanzu Supervisor или IdP.
|
||||
|
||||
## Означает ли registry coverage perfect vSphere parity?
|
||||
|
||||
Это означает, что каждый зарегистрированный маршрут имеет устойчивый обработчик
|
||||
или DB-backed stub и проходит verification suites проекта. Точное совпадение
|
||||
краевых случаев с физическим ESXi-кластером может отличаться; используйте
|
||||
`/ui/api/compatibility` и собственные client tests для certification claims.
|
||||
|
||||
## Где Web UI?
|
||||
|
||||
[https://localhost/](https://localhost/) после `make up` (gateway).
|
||||
|
||||
## Можно ли развернуть в Kubernetes?
|
||||
|
||||
Да. Используйте Helm chart в `helm/vmware-api-simulator` с опубликованным
|
||||
образом Hub. Поддерживаются Ingress + cert-manager Let's Encrypt — см.
|
||||
[Kubernetes / Helm](kubernetes.md).
|
||||
|
||||
## Что такое `ENABLE_PVE_STUB`?
|
||||
|
||||
Опциональная, выключенная по умолчанию legacy Proxmox VE `/api2/*` stub-плоскость,
|
||||
унаследованная из общей platform lineage. Нативная vSphere REST/SOAP всегда
|
||||
включена и является основной поверхностью проекта независимо от этого флага.
|
||||
|
||||
## Какие VM использует seed `small`?
|
||||
|
||||
`web-01`, `web-02`, `db-01`, `app-01`, `jumpbox` — см.
|
||||
[Профили seed](seed-profiles.md).
|
||||
@@ -0,0 +1,176 @@
|
||||
**Language / Язык:** [English](../getting-started.md) | [Русский](getting-started.md)
|
||||
|
||||
# Быстрый старт
|
||||
|
||||
Поднимите локальную лабораторию vSphere, пройдите аутентификацию и выполните первый
|
||||
цикл чтения/мутации против симулятора.
|
||||
|
||||
## Требования
|
||||
|
||||
- Docker и Docker Compose
|
||||
- `make` (необязательно, но используется в документированных командах)
|
||||
|
||||
Python, линтеры и тесты запускаются **внутри** контейнеров. Для повседневной работы
|
||||
локальный Python-инструментарий не нужен.
|
||||
|
||||
## Выберите путь
|
||||
|
||||
| Путь | Когда использовать |
|
||||
|---|---|
|
||||
| [Опубликованный образ](#1a-опубликованный-образ-docker-hub) | Самая быстрая лаборатория на `inecs/vmware-api-simulator` |
|
||||
| [Helm / Kubernetes](kubernetes.md) | Установка в кластер с Ingress + Let's Encrypt |
|
||||
| [Development checkout](#1b-development-checkout) | Вклад в код / bind-mount исходников |
|
||||
|
||||
## 1a. Опубликованный образ (Docker Hub)
|
||||
|
||||
Использует [`docker-compose.release.yml`](../../docker-compose.release.yml) — PostgreSQL +
|
||||
runtime-симулятор + HTTPS gateway с Hub. Сборка исходников не нужна, но Compose
|
||||
нужно запускать из **checkout этого репозитория**, чтобы смонтировались
|
||||
`docker/gateway/` и `docker/tls/`. Seed выполняется автоматически после готовности
|
||||
симулятора.
|
||||
|
||||
```bash
|
||||
# из git checkout этого репозитория (нужны docker/gateway и docker/tls)
|
||||
docker compose -f docker-compose.release.yml pull
|
||||
docker compose -f docker-compose.release.yml up -d --wait
|
||||
```
|
||||
|
||||
Закрепить версию:
|
||||
|
||||
```bash
|
||||
IMAGE_TAG=0.1.0 docker compose -f docker-compose.release.yml up -d --wait
|
||||
```
|
||||
|
||||
Make-хелперы (git checkout):
|
||||
|
||||
```bash
|
||||
make release-up
|
||||
# опциональный повторный seed: make release-seed PROFILE=small
|
||||
```
|
||||
|
||||
| Порт хоста | Сервис |
|
||||
|---|---|
|
||||
| `443` | HTTPS gateway (основная точка входа vCenter) |
|
||||
| `80` | HTTP lab face |
|
||||
| `5434` | PostgreSQL (только localhost) |
|
||||
|
||||
Миграции выполняются автоматически через one-shot сервис `migrate`.
|
||||
|
||||
Далее — с [Дождитесь готовности](#2-дождитесь-готовности).
|
||||
|
||||
## 1b. Development checkout
|
||||
|
||||
```bash
|
||||
make install
|
||||
make up
|
||||
```
|
||||
|
||||
Сервисы (полная картина — [Порты](ports.md)):
|
||||
|
||||
| Порт хоста | Сервис |
|
||||
|---|---|
|
||||
| `443` | HTTPS gateway (nginx) → simulator |
|
||||
| `80` | HTTP lab face |
|
||||
| `5434` | PostgreSQL (только localhost) |
|
||||
|
||||
Миграции применяются автоматически до готовности симулятора. Внутренний
|
||||
процесс FastAPI слушает `8080` и на хост не публикуется.
|
||||
|
||||
## 2. Дождитесь готовности
|
||||
|
||||
```bash
|
||||
curl -sk https://localhost/health/live
|
||||
curl -sk https://localhost/health/ready
|
||||
```
|
||||
|
||||
`/health/ready` возвращает HTTP 503, пока PostgreSQL недоступен **и** пока
|
||||
не применена последняя упакованная миграция.
|
||||
|
||||
## 3. Засейте профиль
|
||||
|
||||
```bash
|
||||
make seed # default: large — 10 hosts / 1000 VMs
|
||||
VSPHERE_PROFILE=small make seed
|
||||
```
|
||||
|
||||
`small` создаёт 3-хостовый кластер с пятью именованными VM (`web-01`, `web-02`,
|
||||
`db-01`, `app-01`, `jumpbox`), datastores, standard portgroup и четырьмя
|
||||
лабораторными принципалами. Другие размеры — [Профили seed](seed-profiles.md).
|
||||
|
||||
## 4. Проверьте версию API
|
||||
|
||||
```bash
|
||||
curl -sk https://localhost/api/appliance/system/version | jq .
|
||||
```
|
||||
|
||||
Catalog major при холодном старте по умолчанию — **9** (vSphere 8.0 U2 /
|
||||
поверхность Automation 9.1) в Docker Compose. Просмотр и hot-swap majors 6–9 —
|
||||
из Web UI или [Версии API](api-versions.md).
|
||||
|
||||
## 5. Аутентификация
|
||||
|
||||
```bash
|
||||
SID=$(curl -sk -u 'administrator@vsphere.local:VMware1!' \
|
||||
-X POST https://localhost/api/session | tr -d '"')
|
||||
echo "$SID"
|
||||
```
|
||||
|
||||
`SID` — это `vmware-api-session-id`. Передавайте его в каждом последующем
|
||||
вызове как заголовок (или опирайтесь на cookie, которую также выставляет
|
||||
ответ login):
|
||||
|
||||
```bash
|
||||
curl -sk -H "vmware-api-session-id: $SID" https://localhost/api/vcenter/vm
|
||||
```
|
||||
|
||||
Подробности: [Аутентификация](authentication.md).
|
||||
|
||||
## 6. Список VM и включение одной
|
||||
|
||||
```bash
|
||||
curl -sk -H "vmware-api-session-id: $SID" \
|
||||
https://localhost/api/vcenter/vm | jq .
|
||||
|
||||
curl -sk -X POST -H "vmware-api-session-id: $SID" \
|
||||
"https://localhost/api/vcenter/vm/vm-104/power?action=start" | jq .
|
||||
```
|
||||
|
||||
Power-действия и другие длительные операции возвращают CIS task id.
|
||||
Опрашивайте задачу до завершения:
|
||||
|
||||
```bash
|
||||
curl -sk -H "vmware-api-session-id: $SID" \
|
||||
"https://localhost/api/cis/tasks/${TASK_ID}" | jq .
|
||||
```
|
||||
|
||||
## 7. Откройте Web UI
|
||||
|
||||
Откройте [https://localhost/](https://localhost/) — интерактивная
|
||||
консоль, каталог эндпоинтов (vSphere majors 6–9), вид совместимости, apply
|
||||
runtime-контракта и управление demo-cluster. Скриншоты светлой/тёмной темы и
|
||||
полный список возможностей — [Web UI](web-ui.md).
|
||||
|
||||
## 8. Попробуйте клиентскую библиотеку
|
||||
|
||||
```bash
|
||||
# from the repository root after make up + seed
|
||||
python examples/python/vsphere_rest_smoke.py https://localhost
|
||||
python examples/python/vsphere_soap_smoke.py https://localhost
|
||||
```
|
||||
|
||||
Другие стеки: [Клиенты](clients.md) и [`examples/`](../../examples/README.ru.md).
|
||||
|
||||
## Готово, когда…
|
||||
|
||||
- `/health/ready` возвращает `{"status": "ok"}` (или эквивалентное OK-тело)
|
||||
- `/api/appliance/system/version` сообщает версию активного catalog major
|
||||
- Session login успешен для `administrator@vsphere.local`
|
||||
- `/api/vcenter/vm` перечисляет seeded VM
|
||||
- Power-действие возвращает task id, который доходит до `SUCCEEDED`
|
||||
|
||||
## Дальше
|
||||
|
||||
- [Конфигурация](configuration.md) — env vars, workers, размер seed
|
||||
- [Версии API](api-versions.md) — hot-swap catalog majors 6–9
|
||||
- [Клиенты](clients.md) — Python, Ansible, Terraform, Pulumi
|
||||
- [Эксплуатация](operations.md) — reseed, migrate, upgrades
|
||||
@@ -0,0 +1,166 @@
|
||||
**Language / Язык:** [English](../kubernetes.md) | [Русский](kubernetes.md)
|
||||
|
||||
# Kubernetes / Helm
|
||||
|
||||
Разверните опубликованный образ runtime из Docker Hub с помощью чарта
|
||||
[`helm/vmware-api-simulator`](../../helm/vmware-api-simulator).
|
||||
|
||||
Образ: [`inecs/vmware-api-simulator`](https://hub.docker.com/r/inecs/vmware-api-simulator)
|
||||
|
||||
## Требования
|
||||
|
||||
- Kubernetes 1.27+ (или сопоставимая версия)
|
||||
- Helm 3.14+
|
||||
- [Ingress NGINX](https://kubernetes.github.io/ingress-nginx/) (или другой
|
||||
IngressClass с поддержкой HTTP-01)
|
||||
- [cert-manager](https://cert-manager.io/), установленный на весь кластер
|
||||
|
||||
Пример установки cert-manager:
|
||||
|
||||
```bash
|
||||
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.yaml
|
||||
```
|
||||
|
||||
## Быстрая установка (Hub-релиз + Ingress + Let's Encrypt)
|
||||
|
||||
Из git checkout этого репозитория:
|
||||
|
||||
```bash
|
||||
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)" \
|
||||
--set postgresql.auth.password="$(openssl rand -hex 16)"
|
||||
```
|
||||
|
||||
Что это делает:
|
||||
|
||||
1. Скачивает `inecs/vmware-api-simulator:0.1.0` (см. `image.tag` в примерном файле).
|
||||
2. Устанавливает встроенный PostgreSQL 17 (`postgres:17.5-bookworm`, как и в Compose).
|
||||
3. Выполняет миграции схемы в init-контейнере (идемпотентно).
|
||||
4. Загружает лабораторный профиль `small` (`seed.enabled=true`).
|
||||
5. Создаёт ресурсы `ClusterIssuer`:
|
||||
- `letsencrypt-prod`
|
||||
- `letsencrypt-staging`
|
||||
6. Создаёт Ingress с
|
||||
`cert-manager.io/cluster-issuer: letsencrypt-prod` и TLS-секретом
|
||||
`vmware-api-simulator-tls`.
|
||||
|
||||
DNS для `vmware-sim.example.com` должен указывать на ваш Ingress-контроллер.
|
||||
Затем:
|
||||
|
||||
```bash
|
||||
kubectl -n vmware-sim get certificate,ingress,pods
|
||||
# дождитесь Certificate READY=True
|
||||
curl -sS https://vmware-sim.example.com/health/ready
|
||||
open https://vmware-sim.example.com/
|
||||
```
|
||||
|
||||
Seeded-логин по умолчанию: `administrator@vsphere.local` / `VMware1!`.
|
||||
|
||||
### Сначала staging (рекомендуется)
|
||||
|
||||
Проверьте HTTP-01, не расходуя лимиты запросов production:
|
||||
|
||||
```bash
|
||||
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 certManager.useStaging=true \
|
||||
--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)"
|
||||
```
|
||||
|
||||
Браузеры не будут доверять staging CA — используйте `curl -k` во время
|
||||
тестирования. Переключите `certManager.useStaging=false` и пересоздайте
|
||||
Certificate/TLS-секрет для production.
|
||||
|
||||
## Минимальная установка (ClusterIP + port-forward)
|
||||
|
||||
```bash
|
||||
helm upgrade --install vmware-sim ./helm/vmware-api-simulator \
|
||||
-n vmware-sim --create-namespace \
|
||||
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
|
||||
--set seed.enabled=true
|
||||
|
||||
kubectl -n vmware-sim port-forward svc/vmware-sim-vmware-api-simulator 8080:8080
|
||||
```
|
||||
|
||||
Откройте http://127.0.0.1:8080/. Service выставляет внутренний порт
|
||||
приложения (`8080`, см. [Порты](ports.md)) — чарт не запускает TLS-gateway
|
||||
nginx, используемый Compose; в production выставляйте TLS перед сервисом
|
||||
через Ingress, либо обращайтесь к обычному HTTP-сервису для локального
|
||||
тестирования.
|
||||
|
||||
## Внешний PostgreSQL
|
||||
|
||||
```bash
|
||||
helm upgrade --install vmware-sim ./helm/vmware-api-simulator \
|
||||
-n vmware-sim --create-namespace \
|
||||
--set postgresql.enabled=false \
|
||||
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
|
||||
--set secret.databaseUrl='postgresql://user:pass@pg.example.com:5432/vmware_simulator'
|
||||
```
|
||||
|
||||
Либо используйте `secret.existingSecret` с ключами `DATABASE_URL` и
|
||||
`TICKET_SIGNING_KEY`.
|
||||
|
||||
## Как работает выпуск TLS
|
||||
|
||||
Когда `certManager.enabled=true` и `certManager.createClusterIssuer=true`,
|
||||
чарт создаёт объекты ACME `ClusterIssuer`, которые решают HTTP-01 через ваш
|
||||
Ingress-класс. Шаблон Ingress добавляет:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
tls:
|
||||
- secretName: vmware-api-simulator-tls
|
||||
hosts: [vmware-sim.example.com]
|
||||
```
|
||||
|
||||
Затем cert-manager создаёт `Certificate`, проходит HTTP-01 и сохраняет пару
|
||||
ключей Let's Encrypt в этом TLS-секрете. Чарт **не** устанавливает
|
||||
cert-manager или Ingress-контроллер — только issuer'ы и связку с Ingress.
|
||||
|
||||
Если ClusterIssuer'ы уже существуют на уровне кластера, задайте:
|
||||
|
||||
```yaml
|
||||
certManager:
|
||||
enabled: true
|
||||
createClusterIssuer: false
|
||||
issuerName: your-existing-issuer
|
||||
```
|
||||
|
||||
## Эксплуатация
|
||||
|
||||
```bash
|
||||
# логи
|
||||
kubectl -n vmware-sim logs -l app.kubernetes.io/instance=vmware-sim -c simulator -f
|
||||
|
||||
# reseed
|
||||
kubectl -n vmware-sim exec deploy/vmware-sim-vmware-api-simulator -- \
|
||||
python -m app.simulation.seed_cli
|
||||
# SEED_VSPHERE_PROFILE через: kubectl set env ... либо --set seed.profile=demo-cluster и upgrade
|
||||
|
||||
# удаление
|
||||
helm -n vmware-sim uninstall vmware-sim
|
||||
```
|
||||
|
||||
## Справочник по values
|
||||
|
||||
См. [`helm/vmware-api-simulator/values.yaml`](../../helm/vmware-api-simulator/values.yaml)
|
||||
и [README чарта](../../helm/vmware-api-simulator/README.ru.md). Связанная
|
||||
документация:
|
||||
|
||||
- [Быстрый старт](getting-started.md) — пути через Compose
|
||||
- [Эксплуатация](operations.md) — публикация в Docker Hub / release compose
|
||||
- [Безопасность](security.md) — лабораторные учётные данные и граница доверия
|
||||
- [Порты](ports.md) — внутренний `8080` в сравнении с опубликованными портами gateway
|
||||
@@ -0,0 +1,47 @@
|
||||
**Language / Язык:** [English](../observability.md) | [Русский](observability.md)
|
||||
|
||||
# Наблюдаемость
|
||||
|
||||
## Health
|
||||
|
||||
| Path | Значение |
|
||||
|---|---|
|
||||
| `GET /health/live` | Liveness процесса — без проверки зависимостей |
|
||||
| `GET /health/ready` | База данных доступна через `database.is_ready()`; HTTP 503, если нет |
|
||||
|
||||
Пример:
|
||||
|
||||
```bash
|
||||
curl -sk https://localhost/health/live
|
||||
curl -sk https://localhost/health/ready
|
||||
```
|
||||
|
||||
Реализация: [`app/observability/health.py`](../../app/observability/health.py).
|
||||
|
||||
## Корреляция запросов
|
||||
|
||||
Входящие запросы принимают или генерируют ID через `REQUEST_ID_HEADER`
|
||||
(по умолчанию `X-Request-ID`). Структурированные логи содержат поля
|
||||
корреляции и маскируют известные шаблоны секретов (session id, пароли,
|
||||
токены в стиле ticket).
|
||||
|
||||
## Метрики / трейсинг
|
||||
|
||||
В текущем приложении **нет** endpoint для scrape `/metrics` Prometheus и
|
||||
**нет** встроенного экспортера OpenTelemetry. Заметки в архитектурной
|
||||
документации, где они упоминаются, описывают целевой дизайн, а не
|
||||
реально поставляемую телеметрию.
|
||||
|
||||
Не путайте пути vSphere REST под `/api/vcenter/activity-history` или
|
||||
seeded-эндпоинты health/timesync appliance с телеметрией самого процесса
|
||||
симулятора — эти обработчики симулируют состояние appliance vCenter внутри
|
||||
PostgreSQL, а не собственные метрики этого процесса.
|
||||
|
||||
## Evidence совместимости
|
||||
|
||||
Отчёты о совместимости в эксплуатации:
|
||||
|
||||
- `/ui/api/compatibility?major=N`
|
||||
|
||||
Также доступны через панель совместимости Web UI. См.
|
||||
[Совместимость](compatibility.md).
|
||||
@@ -0,0 +1,151 @@
|
||||
**Language / Язык:** [English](../operations.md) | [Русский](operations.md)
|
||||
|
||||
# Эксплуатация
|
||||
|
||||
## Команды day-2
|
||||
|
||||
```bash
|
||||
make up # запуск стека
|
||||
make down # остановка стека
|
||||
make restart
|
||||
make logs
|
||||
make dev # foreground-workflow, ориентированный на reload
|
||||
make db-migrate # идемпотентные миграции
|
||||
make seed # атомарный reseed (SEED_VSPHERE_PROFILE=large по умолчанию)
|
||||
make shell # интерактивный контейнер с инструментами
|
||||
```
|
||||
|
||||
## Миграции
|
||||
|
||||
Упорядоченные SQL-файлы применяются транзакционно и записывают контрольные
|
||||
суммы SHA-256. Повторный запуск `make db-migrate` безопасен. Изменение уже
|
||||
применённой миграции отклоняется. `/health/ready` остаётся недоступным, пока
|
||||
не появится последняя упакованная миграция.
|
||||
|
||||
## Reseed
|
||||
|
||||
```bash
|
||||
make seed # large (по умолчанию)
|
||||
VSPHERE_PROFILE=small make seed
|
||||
VSPHERE_PROFILE=demo-cluster make seed
|
||||
```
|
||||
|
||||
Reseed атомарно заменяет инвентарь в PostgreSQL. Состояние внешней
|
||||
автоматизации (файлы состояния Terraform, стеки Pulumi, инвентари Ansible,
|
||||
кодирующие MOID/имена ВМ) может после этого разойтись — обновите или
|
||||
пересоздайте эти внешние каналы. См. [Профили seed](seed-profiles.md).
|
||||
|
||||
## Восстановление workers
|
||||
|
||||
CIS task workers используют аренды PostgreSQL (`FOR UPDATE SKIP LOCKED`).
|
||||
После сбоя или перезапуска просроченные аренды переиспользуются, и
|
||||
незавершённая работа безопасно возобновляется. Настраиваемые параметры:
|
||||
`TASK_WORKER_CONCURRENCY`, `TASK_LEASE_SECONDS`, `SIMULATION_TIME_SCALE`.
|
||||
|
||||
## Изменение мажора каталога по умолчанию
|
||||
|
||||
1. Мажор каталога по умолчанию — **9** (поверхность 8.0 U2 / Automation 9.1)
|
||||
при холодном старте; это не ограничивает таблицу маршрутов runtime (см.
|
||||
[Версии API](api-versions.md)).
|
||||
2. Используйте «Apply as runtime» в Web UI или
|
||||
`POST /ui/api/contract/apply?major=N`, чтобы переключить мажор каталога
|
||||
локально для процесса, для целей просмотра/evidence.
|
||||
|
||||
## Резервное копирование состояния лаборатории
|
||||
|
||||
PostgreSQL — это система записи (system of record). Используйте обычные
|
||||
backup/restore для Postgres (`pg_dump` / снимки томов), если нужно сохранить
|
||||
seeded-лабораторию. Контейнеры приложения одноразовые, пока сохраняется том
|
||||
базы данных.
|
||||
|
||||
## Публикация в Docker Hub
|
||||
|
||||
`make release` собирает образ **runtime** (build target `runtime`, а не
|
||||
локальный bind-mounted образ `dev`) и публикует его в Docker Hub:
|
||||
|
||||
```bash
|
||||
docker login # один раз; учётная запись должна владеть или иметь права push в DOCKERHUB_USER
|
||||
make release
|
||||
```
|
||||
|
||||
Значения по умолчанию:
|
||||
|
||||
| Переменная | По умолчанию | Значение |
|
||||
|---|---|---|
|
||||
| `DOCKERHUB_USER` | `inecs` | Namespace/организация Docker Hub |
|
||||
| `IMAGE_NAME` | `vmware-api-simulator` | Имя репозитория |
|
||||
| `VERSION` | из `pyproject.toml` | Тег образа |
|
||||
| `PUSH_LATEST` | `1` | Также помечать/публиковать `:latest` |
|
||||
|
||||
Примеры:
|
||||
|
||||
```bash
|
||||
make release
|
||||
make release VERSION=0.2.0
|
||||
make release DOCKERHUB_USER=myorg PUSH_LATEST=0
|
||||
make release-build # локальная сборка/тегирование без публикации
|
||||
```
|
||||
|
||||
Опубликованные теги:
|
||||
|
||||
- `inecs/vmware-api-simulator:<version>`
|
||||
- `inecs/vmware-api-simulator:latest` (если не задано `PUSH_LATEST=0`)
|
||||
|
||||
## Быстрый старт с опубликованным compose-файлом
|
||||
|
||||
[`docker-compose.release.yml`](../../docker-compose.release.yml) скачивает
|
||||
runtime-образ из Hub и запускает PostgreSQL + migrate + симулятор + HTTPS
|
||||
gateway:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.release.yml up -d
|
||||
docker compose -f docker-compose.release.yml run --rm --entrypoint python \
|
||||
simulator -m app.simulation.seed_cli
|
||||
|
||||
curl -sk https://localhost/health/ready
|
||||
open https://localhost/
|
||||
```
|
||||
|
||||
Вспомогательные команды из git checkout:
|
||||
|
||||
```bash
|
||||
make release-up
|
||||
make release-seed PROFILE=small
|
||||
make release-down
|
||||
```
|
||||
|
||||
Полезные переопределения:
|
||||
|
||||
| Переменная | По умолчанию | Значение |
|
||||
|---|---|---|
|
||||
| `DOCKER_IMAGE` | `inecs/vmware-api-simulator` | Репозиторий образа |
|
||||
| `IMAGE_TAG` | `latest` | Тег для скачивания |
|
||||
| `HTTP_PORT` | `80` | Порт хоста для HTTP |
|
||||
| `HTTPS_PORT` | `443` | Порт хоста для HTTPS |
|
||||
| `POSTGRES_PORT` | `127.0.0.1:5434` | Bind хоста для Postgres |
|
||||
| `TICKET_SIGNING_KEY` | лабораторное значение по умолчанию | Меняйте вне игрушечных лабораторий |
|
||||
| `POSTGRES_PASSWORD` | `vmware` | Пароль БД |
|
||||
|
||||
Для Kubernetes с публичным TLS (cert-manager / Let's Encrypt) используйте
|
||||
Helm-чарт — см. [Kubernetes / Helm](kubernetes.md).
|
||||
|
||||
## Обновления
|
||||
|
||||
1. Скачайте / пересоберите образы (`make install` / `make docker-build` по
|
||||
ситуации).
|
||||
2. Выполните миграции (`make db-migrate`).
|
||||
3. Убедитесь, что `/health/ready` отвечает нормально.
|
||||
4. Перепроверьте `/ui/api/compatibility?major=9` и
|
||||
`/api/appliance/system/version`.
|
||||
5. При необходимости заново запустите `make test-vsphere` /
|
||||
`make vsphere-matrix`, если проверяете поверхность после обновления.
|
||||
|
||||
## Сброс лаборатории
|
||||
|
||||
```bash
|
||||
make seed PROFILE=small
|
||||
# или через UI: unload demo → small, затем снова seed
|
||||
```
|
||||
|
||||
Для жёсткого сброса базы данных используйте `make db-reset` (деструктивно —
|
||||
см. справку Makefile).
|
||||
@@ -0,0 +1,50 @@
|
||||
**Language / Язык:** [English](../ports.md) | [Русский](ports.md)
|
||||
|
||||
# Порты vCenter в этом симуляторе
|
||||
|
||||
Справочник: [vSphere Networking Ports](https://ports.esp.vmware.com/) (vCenter Server).
|
||||
|
||||
`api-gateway` (nginx) публикует **основной HTTPS-listener vCenter** плюс
|
||||
HTTP-грань для лабораторных нужд. Каждый опубликованный порт проксирует к
|
||||
одному и тому же процессу FastAPI, который сам маршрутизирует по path REST
|
||||
(`/api`, `/rest`) и SOAP (`/sdk`) — отдельного порта на протокол нет. Gateway
|
||||
также выставляет `X-VMware-Service` / `X-Forwarded-Port`, чтобы клиенты и
|
||||
будущие роутеры могли определить, какой порт был использован.
|
||||
|
||||
## Опубликовано через Compose (`api-gateway`)
|
||||
|
||||
| Сервис | Порт контейнера | Порт хоста (dev compose) |
|
||||
|---|---:|---:|
|
||||
| HTTP-грань для лабораторных нужд | 80 | 80 |
|
||||
| vCenter HTTPS (основная точка входа UI/API) | 443 | 443 |
|
||||
|
||||
Порты хоста совпадают с реальными defaults vCenter, чтобы удалённые клиенты
|
||||
ходили на `https://<host>/` и `http://<host>/` без нестандартного порта.
|
||||
При необходимости переопределяйте в release compose через `HTTP_PORT` /
|
||||
`HTTPS_PORT`.
|
||||
|
||||
Также публикуется Compose (не через gateway):
|
||||
|
||||
| Сервис | Порт хоста (dev compose) |
|
||||
|---|---:|
|
||||
| PostgreSQL | `5434` (только localhost) |
|
||||
|
||||
Внутренний процесс симулятора (не публикуется на хост): `8080`.
|
||||
|
||||
## Раскладка путей на HTTPS
|
||||
|
||||
| Поверхность | Префикс пути | Статус |
|
||||
|---|---|---|
|
||||
| vSphere REST | `/api/…`, `/rest/…` | реализовано (базовый инвентарь + сессия) |
|
||||
| SOAP / VIM SDK | `/sdk` | реализовано (подмножество RetrieveServiceContent / Login / RetrieveProperties) |
|
||||
| HttpNfcLease / NFC | `/nfc/…` | lab transfer handshake на том же HTTPS-слушателе |
|
||||
| Лабораторная консоль | `/` | да |
|
||||
| Health | `/health/live`, `/health/ready` | да |
|
||||
|
||||
## Задокументировано, но пока не опубликовано
|
||||
|
||||
| Сервис | Порты |
|
||||
|---|---|
|
||||
| VAMI / управление appliance | 5480 |
|
||||
| Управление хостом ESXi (если будет симулировано позже) | 443 (отдельный хост) |
|
||||
| Syslog / прочее | разное |
|
||||
@@ -0,0 +1,57 @@
|
||||
**Language / Язык:** [English](../security.md) | [Русский](security.md)
|
||||
|
||||
# Безопасность
|
||||
|
||||
## Модель угроз лаборатории
|
||||
|
||||
Этот проект — **локальный / CI лабораторный симулятор**. Он не защищён как
|
||||
multi-tenant публичный сервис vCenter. Учётные данные по умолчанию, демо-
|
||||
элементы управления в UI и endpoint'ы совместимости удобны для разработки и
|
||||
намеренно открыты в стандартном стеке Compose.
|
||||
|
||||
Не публикуйте порты `443` / `80` в недоверенные сети без дополнительных
|
||||
средств защиты, которые вы предоставляете самостоятельно.
|
||||
|
||||
## Учётные данные и секреты
|
||||
|
||||
- Пароли хранятся как хэши scrypt (`vsphere_credentials.password_hash`).
|
||||
- Session id — это непрозрачные токены (`vmware-api-session-id`) со
|
||||
скользящим сроком действия 2 часа, отслеживаемые в PostgreSQL
|
||||
(`vsphere_sessions`).
|
||||
- Логи маскируют распознанные представления session id и паролей.
|
||||
- Ответы сессий обновления/загрузки content library раскрывают только
|
||||
endpoint'ы загрузки/скачивания, а не сырые секреты.
|
||||
|
||||
Меняйте `TICKET_SIGNING_KEY` для любой общей лаборатории. Заменяйте seeded-
|
||||
пароли перед демонстрацией другим людям.
|
||||
|
||||
## Материалы TLS
|
||||
|
||||
`docker/tls/` содержит закоммиченный self-signed сертификат для локального
|
||||
сервиса nginx `api-gateway`. Он существует, чтобы немодифицированные
|
||||
TLS-клиенты (pyvmomi, govmomi, провайдер Terraform `hashicorp/vsphere`) могли
|
||||
подключаться с установленным `insecure`/`verify=False`. **Никогда** не
|
||||
используйте эти файлы повторно в production.
|
||||
|
||||
## Администрирование симулятора
|
||||
|
||||
На данный момент **нет** отдельно аутентифицируемой административной
|
||||
control plane. Вспомогательные маршруты Web UI под `/ui/api/*` доступны,
|
||||
когда процесс достижим по сети, — включая действия reseed и hot-swap.
|
||||
Считайте сетевую доступность границей доверия.
|
||||
|
||||
## Авторизация
|
||||
|
||||
Мутирующие REST-эндпоинты проверяют привилегии, производные от роли
|
||||
(`app/vsphere/security/authz.py`), прежде чем обращаться к инвентарю.
|
||||
Seeded-принципал `readonly@vsphere.local` не может включать/создавать/
|
||||
удалять ВМ (HTTP 403). См. [Авторизация](domains/authz.md).
|
||||
|
||||
## Симулированные внешние системы
|
||||
|
||||
Заменители NSX/Supervisor/vSAN/SAML-OIDC/VECS-сертификатов (см.
|
||||
[Покрытие API](api-coverage.md)) сохраняют только локальное состояние
|
||||
симулятора. Они не открывают реальных соединений с внешними IdP, NSX
|
||||
Manager или живым кластером vSAN. Не полагайтесь на симулятор для
|
||||
тестирования защиты от эксфильтрации живых учётных данных против реальных
|
||||
провайдеров.
|
||||
@@ -0,0 +1,76 @@
|
||||
**Language / Язык:** [English](../seed-profiles.md) | [Русский](seed-profiles.md)
|
||||
|
||||
# Профили seed
|
||||
|
||||
Seed **атомарно** заменяет инвентарь vSphere, используя детерминированные
|
||||
MOID, чтобы лаборатории были воспроизводимыми. Определения находятся в
|
||||
[`app/vsphere/profiles.py`](../../app/vsphere/profiles.py).
|
||||
|
||||
```bash
|
||||
make seed # по умолчанию: large (10 хостов / 1000 ВМ)
|
||||
VSPHERE_PROFILE=small make seed
|
||||
```
|
||||
|
||||
## Профили
|
||||
|
||||
| Профиль | Содержимое |
|
||||
|---|---|
|
||||
| `small` | 3 хоста ESXi, 2 datastore, 2 сети, один datacenter/cluster/resource-pool и пять именованных ВМ: `web-01`, `web-02`, `db-01`, `app-01`, `jumpbox` (смешанные состояния питания). Используется unit/integration-тестами. |
|
||||
| `large` (по умолчанию) | Настраиваемое число хостов/ВМ (`SEED_VSPHERE_LARGE_HOSTS` по умолчанию 10, `SEED_VSPHERE_LARGE_VMS` по умолчанию 1000), 4 datastore, 4 сети/portgroup, `VmwareDistributedVirtualSwitch`, папки ВМ production/staging/templates. Первые пять ВМ совпадают по именам с `small` для стабильности кулинарных книг; остальные генерируются (префиксы ролей `web-`, `app-`, `db-`, `cache-`, `batch-`, `jump-`, `ci-`, `mon-`, `log-`, `ml-`). |
|
||||
| `demo-cluster` | `large` с 20 хостами / 1000 ВМ — набор данных в форме предприятия для демо UI. |
|
||||
|
||||
Каждый профиль также загружает четыре лабораторные учётные записи, права,
|
||||
привязанные к ролям (см. [Авторизация](domains/authz.md)), и — там, где
|
||||
существуют таблицы платформы — стартовую content library, категории/теги
|
||||
тегирования и метаданные файлов datastore (`seed_platform_extras`).
|
||||
|
||||
## Примеры
|
||||
|
||||
```bash
|
||||
make seed # large, 10 хостов / 1000 ВМ
|
||||
VSPHERE_PROFILE=small make seed
|
||||
VSPHERE_PROFILE=demo-cluster make seed
|
||||
VSPHERE_PROFILE=large VSPHERE_HOSTS=20 VSPHERE_VMS=5000 make seed
|
||||
```
|
||||
|
||||
Либо запустите CLI seed напрямую с базовыми переменными окружения (например,
|
||||
из скрипта без `make` или на шаге CI):
|
||||
|
||||
```bash
|
||||
SEED_VSPHERE_PROFILE=small \
|
||||
docker compose run --rm --entrypoint python simulator -m app.simulation.seed_cli
|
||||
```
|
||||
|
||||
## Форма топологии
|
||||
|
||||
Каждый профиль строит один и тот же скелет (папка `Datacenters` →
|
||||
`Datacenter` → подпапки host/vm/datastore/network → один
|
||||
`ClusterComputeResource` + `ResourcePool`), затем масштабирует хосты,
|
||||
datastore, portgroup и ВМ. MOID ВМ имеют вид `vm-{100+n}`; MOID хостов —
|
||||
`host-{10+n}`; каждая ВМ несёт одинаковую форму оборудования, используемую
|
||||
как REST (`hardware/*`), так и SOAP (`VirtualMachineConfigInfo`) ответами —
|
||||
NIC, диски, CD-ROM, порядок загрузки и синтетический guest IP/файловая
|
||||
система.
|
||||
|
||||
## Демо-кластер через UI
|
||||
|
||||
Интерактивная консоль может загружать демо-набор данных и делать reseed по
|
||||
запросу:
|
||||
|
||||
- `POST /ui/api/demo/load` — загружает `demo-cluster`
|
||||
- `POST /ui/api/demo/unload` — очищает состояние, созданное через API, затем
|
||||
загружает `small`
|
||||
- `GET /ui/api/demo/state`
|
||||
- `POST /ui/api/vsphere/seed?profile=small|large|demo-cluster` — reseed
|
||||
любого профиля
|
||||
|
||||
Эти вспомогательные эндпоинты UI ориентированы на разработку и сегодня не
|
||||
имеют отдельной аутентификации. Считайте их только лабораторными органами
|
||||
управления.
|
||||
|
||||
## Reseed в сравнении с состоянием клиентов
|
||||
|
||||
Terraform, Pulumi и Ansible могут по-прежнему хранить состояние ресурсов
|
||||
после reseed (MOID и имена ВМ могут измениться). Выполните refresh или
|
||||
destroy/recreate внешнего состояния после замены инвентаря PostgreSQL. См.
|
||||
[Эксплуатация](operations.md) и [Клиенты](clients.md).
|
||||
@@ -0,0 +1,75 @@
|
||||
**Language / Язык:** [English](../troubleshooting.md) | [Русский](troubleshooting.md)
|
||||
|
||||
# Устранение неполадок
|
||||
|
||||
## Ready остаётся недоступным
|
||||
|
||||
1. Проверьте Postgres: `make logs` / health в Compose.
|
||||
2. Выполните `make db-migrate`.
|
||||
3. Снова вызовите `/health/ready`.
|
||||
|
||||
Task workers могут повторять попытки, пока миграции не догонят после позднего migrate.
|
||||
|
||||
## Неожиданный HTTP 501
|
||||
|
||||
У каждого зарегистрированного маршрута должен быть реальный обработчик или
|
||||
DB-backed стаб — 501 не должен появляться для известного пути. Если вы его видите:
|
||||
|
||||
- Убедитесь, что вызываете точный зарегистрированный path/verb (проверьте
|
||||
`app/vsphere/rest/coverage.py` или `/docs`).
|
||||
- 501 от опционального legacy-стаба (`ENABLE_PVE_STUB=true`) ожидается для
|
||||
необъявленных методов в стиле PVE, когда `CONTRACT_FALLBACK=error`; это
|
||||
не относится к native vSphere-поверхности.
|
||||
- Сообщите о регрессии — на native vSphere-плоскости ожидается полное
|
||||
покрытие реестра.
|
||||
|
||||
## 401 / 403
|
||||
|
||||
- Сессия истекла (скользящий TTL 2 часа) или заголовок/cookie
|
||||
`vmware-api-session-id` не отправлен.
|
||||
- Некорректный Basic auth на `/api/session` (отсутствует заголовок, неверный
|
||||
base64 от `user:password`).
|
||||
- Отказ по правам — попробуйте сравнить `administrator@vsphere.local` и
|
||||
`readonly@vsphere.local` (см. [Авторизация](domains/authz.md)).
|
||||
|
||||
## Задача никогда не завершается
|
||||
|
||||
- Изучите `/api/cis/tasks/{task}`.
|
||||
- Проверьте логи worker/симулятора (`make logs`).
|
||||
- Убедитесь, что `TASK_WORKER_CONCURRENCY` > 0 и аренды в базе данных можно
|
||||
забрать (claim).
|
||||
- Очень высокий `SIMULATION_TIME_SCALE` даёт необычные замедления (больше =
|
||||
быстрее симуляция); чаще виноваты неверно заданные worker-аренды.
|
||||
|
||||
## Сбои TLS / gateway
|
||||
|
||||
- Используйте порт хоста **443** (gateway) для TLS-клиентов — pyvmomi,
|
||||
govmomi, провайдер Terraform `hashicorp/vsphere`, Pulumi.
|
||||
- Устанавливайте `verify_ssl=False` / `allow_unverified_ssl=true` **только**
|
||||
для локального self-signed development-сертификата.
|
||||
- Внутри Compose обращайтесь напрямую к `simulator:8080` (обычный HTTP, без
|
||||
gateway).
|
||||
- Seeded-имена ВМ для `small` — `web-01`, `web-02`, `db-01`, `app-01`,
|
||||
`jumpbox`, а не Proxmox-style `pve01`/VMID.
|
||||
|
||||
## Drift Terraform / Pulumi / Ansible после reseed
|
||||
|
||||
Reseed заменяет инвентарь в PostgreSQL (MOID-ы и имена ВМ могут измениться);
|
||||
состояние внешних инструментов автоматически не обновляется. Выполните
|
||||
refresh, import или пересоберите стеки после `make seed`.
|
||||
|
||||
## Hot-swap «ничего не сделал»
|
||||
|
||||
- Просмотр каталога ≠ apply. Используйте **Apply as runtime** или
|
||||
`POST /ui/api/contract/apply?major=N`.
|
||||
- Применение мажора меняет **каталог Web UI / представление evidence**, а не
|
||||
живую таблицу маршрутов — runtime всегда обслуживает полную
|
||||
зарегистрированную поверхность. См. [Версии API](api-versions.md).
|
||||
- Apply локален для процесса; перезапуск Compose возвращает к значению по
|
||||
умолчанию (мажор 9).
|
||||
|
||||
## Demo unload удивил
|
||||
|
||||
`POST /ui/api/demo/unload` очищает состояние, созданное через API, и
|
||||
загружает `small`. Повторите `make seed` (или снова загрузите
|
||||
`demo-cluster`), чтобы восстановить более богатую фикстуру.
|
||||
@@ -0,0 +1,68 @@
|
||||
**Language / Язык:** [English](../web-ui.md) | [Русский](web-ui.md)
|
||||
|
||||
# Web UI
|
||||
|
||||
Откройте [https://localhost/](https://localhost/) после `make up`
|
||||
(gateway).
|
||||
Внутренний порт симулятора — `8080`; лабораторный UI также доступен на этом хосте.
|
||||
|
||||
UI — это лабораторная консоль для симулятора **vSphere**, а не замена
|
||||
vSphere Client. Она поддерживает светлую и тёмную темы, мажоры каталога
|
||||
**6–9** (уровни vSphere 7–8.0U2), редактирование запроса/ответа, историю и
|
||||
применение runtime-контракта.
|
||||
|
||||
## Возможности
|
||||
|
||||
- Дерево endpoint'ов и селектор метода, управляемые выбранным мажором каталога
|
||||
- Параметры и примеры payload, производные от контракта
|
||||
- Редактор запроса, просмотрщик ответа и история
|
||||
- Вход в сессию через `POST /api/session` (Basic) → заголовок/cookie
|
||||
`vmware-api-session-id`
|
||||
- Сводка окружения (версия runtime, хосты, ВМ, кластеры, datastore, сети)
|
||||
- Предпросмотр запросов в виде curl
|
||||
- Индикатор покрытия для реализованного реестра REST
|
||||
- Hot-swap **Apply as runtime** для активного уровня мажора
|
||||
- Загрузка demo / seed (профили large / demo-cluster)
|
||||
- Компактная консоль на `/console.html`
|
||||
- Ссылка на OpenAPI по адресу `/docs`
|
||||
|
||||
## Аутентификация (лаборатория)
|
||||
|
||||
| Пользователь | Пароль | Роль |
|
||||
|---|---|---|
|
||||
| `administrator@vsphere.local` | `VMware1!` | Administrator |
|
||||
| `readonly@vsphere.local` | `VMware1!` | ReadOnly |
|
||||
| `operator@vsphere.local` | `VMware1!` | VirtualMachinePowerUser |
|
||||
| `vmadmin@vsphere.local` | `VMware1!` | VirtualMachineAdministrator |
|
||||
|
||||
После входа кнопка Send автоматически прикладывает `vmware-api-session-id`.
|
||||
|
||||
## Вспомогательные методы backend
|
||||
|
||||
| Метод | Path | Назначение |
|
||||
|---|---|---|
|
||||
| GET | `/ui/api/versions` | Мажоры каталога в сравнении с runtime |
|
||||
| GET | `/ui/api/catalog?major=N` | Каталог для мажора 6–9 |
|
||||
| GET | `/ui/api/method?...` | Метаданные одного метода |
|
||||
| GET | `/ui/api/compatibility?major=N` | Payload покрытия |
|
||||
| POST | `/ui/api/contract/apply?major=N` | Hot-swap runtime-контракта |
|
||||
| GET | `/ui/api/demo/state` | Состояние демо-набора данных |
|
||||
| POST | `/ui/api/demo/load` | Загрузить `demo-cluster` |
|
||||
| POST | `/ui/api/vsphere/seed?profile=…` | Reseed `small` / `large` / `demo-cluster` |
|
||||
|
||||
## Workflow работы с версиями
|
||||
|
||||
1. Выберите мажор **6 / 7 / 8 / 9** в каталоге.
|
||||
2. Изучите методы и покрытие.
|
||||
3. Используйте **Apply as runtime**, когда нужно, чтобы живые маршруты были
|
||||
ограничены уровнем этого мажора.
|
||||
4. Подтвердите через `/api/appliance/system/version` и `/ui/api/compatibility`.
|
||||
|
||||
Hot-swap хранится только в памяти; перезапуск восстанавливает настройки по
|
||||
умолчанию. Подробности: [Версии API](api-versions.md).
|
||||
|
||||
## Замечание о безопасности
|
||||
|
||||
Эндпоинты UI и demo предназначены для локальной разработки. В текущей
|
||||
сборке они не защищены отдельным admin-токеном. Не выставляйте порт
|
||||
симулятора в недоверенные сети.
|
||||
@@ -0,0 +1,54 @@
|
||||
**Language / Язык:** [English](security.md) | [Русский](ru/security.md)
|
||||
|
||||
# Security
|
||||
|
||||
## Lab threat model
|
||||
|
||||
This project is a **local / CI laboratory simulator**. It is not hardened as
|
||||
a multi-tenant public vCenter service. Default credentials, UI demo controls,
|
||||
and compatibility endpoints are convenient for development and intentionally
|
||||
open in the default Compose stack.
|
||||
|
||||
Do not expose ports `443` / `80` to untrusted networks without additional
|
||||
controls you supply yourself.
|
||||
|
||||
## Credentials and secrets
|
||||
|
||||
- Passwords are stored as scrypt hashes (`vsphere_credentials.password_hash`).
|
||||
- Session ids are opaque tokens (`vmware-api-session-id`) with a 2-hour
|
||||
sliding expiry, tracked in PostgreSQL (`vsphere_sessions`).
|
||||
- Logs redact recognized session-id and password representations.
|
||||
- Content library update/download session responses expose upload/download
|
||||
endpoints, not raw secrets.
|
||||
|
||||
Change `TICKET_SIGNING_KEY` for any shared lab. Replace seeded passwords
|
||||
before demoing to others.
|
||||
|
||||
## TLS materials
|
||||
|
||||
`docker/tls/` contains a checked-in self-signed certificate for the local
|
||||
`api-gateway` nginx service. It exists so unmodified TLS clients (pyvmomi,
|
||||
govmomi, Terraform's `hashicorp/vsphere` provider) can connect with
|
||||
`insecure`/`verify=False` set. **Never** reuse these files in production.
|
||||
|
||||
## Simulator administration
|
||||
|
||||
There is currently **no** separately authenticated admin control plane. Web
|
||||
UI helper routes under `/ui/api/*` are available whenever the process is
|
||||
reachable — including reseed and hot-swap actions. Treat network exposure as
|
||||
the trust boundary.
|
||||
|
||||
## Authorization
|
||||
|
||||
Mutating REST endpoints check role-derived privileges
|
||||
(`app/vsphere/security/authz.py`) before touching inventory. The seeded
|
||||
`readonly@vsphere.local` principal cannot power on/create/delete VMs (HTTP
|
||||
403). See [Authorization](domains/authz.md).
|
||||
|
||||
## Simulated remotes
|
||||
|
||||
NSX/Supervisor/vSAN/SAML-OIDC/VECS-certificate stand-ins (see
|
||||
[API coverage](api-coverage.md)) persist local simulator state only. They do
|
||||
not open real connections to external IdPs, NSX Manager, or a live vSAN
|
||||
cluster. Do not rely on the simulator for testing live credential
|
||||
exfiltration defenses against real providers.
|
||||
@@ -0,0 +1,70 @@
|
||||
**Language / Язык:** [English](seed-profiles.md) | [Русский](ru/seed-profiles.md)
|
||||
|
||||
# Seed profiles
|
||||
|
||||
Seeds replace the vSphere inventory **atomically** using deterministic MOIDs
|
||||
so labs are reproducible. Definitions live in
|
||||
[`app/vsphere/profiles.py`](../app/vsphere/profiles.py).
|
||||
|
||||
```bash
|
||||
make seed # default: large (10 hosts / 1000 VMs)
|
||||
VSPHERE_PROFILE=small make seed
|
||||
```
|
||||
|
||||
## Profiles
|
||||
|
||||
| Profile | Contents |
|
||||
|---|---|
|
||||
| `small` | 3 ESXi hosts, 2 datastores, 2 networks, one datacenter/cluster/resource-pool, and five named VMs: `web-01`, `web-02`, `db-01`, `app-01`, `jumpbox` (mixed power states). Used by unit/integration tests. |
|
||||
| `large` (default) | Configurable hosts/VMs (`SEED_VSPHERE_LARGE_HOSTS` default 10, `SEED_VSPHERE_LARGE_VMS` default 1000), 4 datastores, 4 networks/portgroups, a `VmwareDistributedVirtualSwitch`, production/staging/templates VM folders. The first five VMs match the `small` names for cookbook stability; the rest are generated (`web-`, `app-`, `db-`, `cache-`, `batch-`, `jump-`, `ci-`, `mon-`, `log-`, `ml-` role prefixes). |
|
||||
| `demo-cluster` | `large` with 20 hosts / 1000 VMs — an enterprise-shaped dataset for UI demos. |
|
||||
|
||||
Every profile also seeds the four lab credentials, role-scoped permissions
|
||||
(see [Authorization](domains/authz.md)), and — where the platform tables
|
||||
exist — a starter content library, tag categories/tags, and datastore file
|
||||
metadata (`seed_platform_extras`).
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
make seed # large, 10 hosts / 1000 VMs
|
||||
VSPHERE_PROFILE=small make seed
|
||||
VSPHERE_PROFILE=demo-cluster make seed
|
||||
VSPHERE_PROFILE=large VSPHERE_HOSTS=20 VSPHERE_VMS=5000 make seed
|
||||
```
|
||||
|
||||
Or run the seed CLI directly with the underlying environment variables (for
|
||||
example from a non-`make` script or CI step):
|
||||
|
||||
```bash
|
||||
SEED_VSPHERE_PROFILE=small \
|
||||
docker compose run --rm --entrypoint python simulator -m app.simulation.seed_cli
|
||||
```
|
||||
|
||||
## Topology shape
|
||||
|
||||
Every profile builds the same skeleton (`Datacenters` folder → `Datacenter` →
|
||||
host/vm/datastore/network sub-folders → one `ClusterComputeResource` +
|
||||
`ResourcePool`), then scales hosts, datastores, portgroups, and VMs. VM MOIDs
|
||||
are `vm-{100+n}`; host MOIDs are `host-{10+n}`; each VM carries the same
|
||||
hardware shape used by both REST (`hardware/*`) and SOAP (`VirtualMachineConfigInfo`)
|
||||
responses — NICs, disks, CD-ROM, boot order, and a synthetic guest IP/filesystem.
|
||||
|
||||
## Demo cluster via UI
|
||||
|
||||
The interactive console can load the demo dataset and reseed on demand:
|
||||
|
||||
- `POST /ui/api/demo/load` — loads `demo-cluster`
|
||||
- `POST /ui/api/demo/unload` — wipes API-created state, then loads `small`
|
||||
- `GET /ui/api/demo/state`
|
||||
- `POST /ui/api/vsphere/seed?profile=small|large|demo-cluster` — reseed any profile
|
||||
|
||||
These UI helper endpoints are development-oriented and are not separately
|
||||
authenticated today. Treat them as lab controls only.
|
||||
|
||||
## Reseed vs client state
|
||||
|
||||
Terraform, Pulumi, and Ansible may still hold resource state after a reseed
|
||||
(VM MOIDs and names can change). Refresh or destroy/recreate external state
|
||||
after replacing the PostgreSQL inventory. See [Operations](operations.md) and
|
||||
[Clients](clients.md).
|
||||
@@ -0,0 +1,71 @@
|
||||
**Language / Язык:** [English](troubleshooting.md) | [Русский](ru/troubleshooting.md)
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
## Ready stays unavailable
|
||||
|
||||
1. Confirm Postgres: `make logs` / Compose health.
|
||||
2. Run `make db-migrate`.
|
||||
3. Hit `/health/ready` again.
|
||||
|
||||
Task workers may retry until migrations catch up after a late migrate.
|
||||
|
||||
## Unexpected HTTP 501
|
||||
|
||||
Every registered route should have a real handler or DB-backed stub — 501
|
||||
should not appear for a known path. If you see it:
|
||||
|
||||
- Confirm you are calling the exact registered path/verb (check
|
||||
`app/vsphere/rest/coverage.py` or `/docs`).
|
||||
- 501 from the optional legacy stub (`ENABLE_PVE_STUB=true`) is expected for
|
||||
undeclared PVE-style methods when `CONTRACT_FALLBACK=error`; it is
|
||||
unrelated to the vSphere surface.
|
||||
- Report a regression — full registry coverage is expected on the native
|
||||
vSphere plane.
|
||||
|
||||
## 401 / 403
|
||||
|
||||
- Session expired (2-hour sliding TTL) or `vmware-api-session-id` header/cookie
|
||||
not sent.
|
||||
- Basic auth malformed on `/api/session` (missing header, wrong
|
||||
`user:password` base64).
|
||||
- Privilege denial — try `administrator@vsphere.local` vs
|
||||
`readonly@vsphere.local` to compare (see [Authorization](domains/authz.md)).
|
||||
|
||||
## Task never finishes
|
||||
|
||||
- Inspect `/api/cis/tasks/{task}`.
|
||||
- Check worker/simulator logs (`make logs`).
|
||||
- Verify `TASK_WORKER_CONCURRENCY` > 0 and database leases can be claimed.
|
||||
- Extremely high `SIMULATION_TIME_SCALE` slowdowns are unusual (higher =
|
||||
faster simulation); mis-set worker leases are more common culprits.
|
||||
|
||||
## TLS / gateway failures
|
||||
|
||||
- Use host port **443** (gateway) for TLS clients — pyvmomi, govmomi,
|
||||
Terraform's `hashicorp/vsphere` provider, Pulumi.
|
||||
- Set `verify_ssl=False` / `allow_unverified_ssl=true` **only** for the local
|
||||
self-signed development certificate.
|
||||
- Inside Compose, target `simulator:8080` directly (plain HTTP, no gateway).
|
||||
- Seeded VM names for `small` are `web-01`, `web-02`, `db-01`, `app-01`,
|
||||
`jumpbox` — not Proxmox-style `pve01`/VMIDs.
|
||||
|
||||
## Terraform / Pulumi / Ansible drift after reseed
|
||||
|
||||
Reseed replaces PostgreSQL inventory (MOIDs and VM names can change);
|
||||
external tool state does not update automatically. Refresh, import, or
|
||||
rebuild stacks after `make seed`.
|
||||
|
||||
## Hot-swap "did nothing"
|
||||
|
||||
- Catalog browse ≠ apply. Use **Apply as runtime** or
|
||||
`POST /ui/api/contract/apply?major=N`.
|
||||
- Applying a major changes the **Web UI catalog / evidence view**, not the
|
||||
live route table — the runtime always serves the full registered surface.
|
||||
See [API versions](api-versions.md).
|
||||
- Apply is process-local; a Compose restart returns to the default (major 9).
|
||||
|
||||
## Demo unload surprised you
|
||||
|
||||
`POST /ui/api/demo/unload` clears API-created state and loads `small`. Re-run
|
||||
`make seed` (or load `demo-cluster` again) to restore a richer fixture.
|
||||
@@ -0,0 +1,64 @@
|
||||
**Language / Язык:** [English](web-ui.md) | [Русский](ru/web-ui.md)
|
||||
|
||||
# Web UI
|
||||
|
||||
Open [https://localhost/](https://localhost/) after `make up` (gateway).
|
||||
Internal simulator port is `8080`; the lab UI is also on that host.
|
||||
|
||||
The UI is a laboratory console for the **vSphere** simulator — not a vSphere Client
|
||||
replacement. It supports light and dark themes, catalog majors **6–9** (vSphere 7–8.0U2
|
||||
floors), request/response editing, history, and runtime contract apply.
|
||||
|
||||
## Features
|
||||
|
||||
- Endpoint tree and method selector driven by the selected catalog major
|
||||
- Contract-derived parameters and example payloads
|
||||
- Request editor, response viewer, and history
|
||||
- Session login via `POST /api/session` (Basic) → `vmware-api-session-id` header/cookie
|
||||
- Environment summary (runtime version, hosts, VMs, clusters, datastores, networks)
|
||||
- Curl / request previews
|
||||
- Coverage meter for the implemented REST registry
|
||||
- **Apply as runtime** hot-swap for the active major floor
|
||||
- Demo / seed load (large / demo-cluster profiles)
|
||||
- Compact console at `/console.html`
|
||||
- Link to OpenAPI at `/docs`
|
||||
|
||||
## Auth (lab)
|
||||
|
||||
| User | Password | Role |
|
||||
|---|---|---|
|
||||
| `administrator@vsphere.local` | `VMware1!` | Administrator |
|
||||
| `readonly@vsphere.local` | `VMware1!` | ReadOnly |
|
||||
| `operator@vsphere.local` | `VMware1!` | VirtualMachinePowerUser |
|
||||
| `vmadmin@vsphere.local` | `VMware1!` | VirtualMachineAdministrator |
|
||||
|
||||
After sign-in, Send attaches `vmware-api-session-id` automatically.
|
||||
|
||||
## Backend helpers
|
||||
|
||||
| Method | Path | Purpose |
|
||||
|---|---|---|
|
||||
| GET | `/ui/api/versions` | Catalog majors vs runtime |
|
||||
| GET | `/ui/api/catalog?major=N` | Catalog for major 6–9 |
|
||||
| GET | `/ui/api/method?...` | Single method metadata |
|
||||
| GET | `/ui/api/compatibility?major=N` | Coverage payload |
|
||||
| POST | `/ui/api/contract/apply?major=N` | Hot-swap runtime contract |
|
||||
| GET | `/ui/api/demo/state` | Demo dataset state |
|
||||
| POST | `/ui/api/demo/load` | Load `demo-cluster` |
|
||||
| POST | `/ui/api/vsphere/seed?profile=…` | Reseed `small` / `large` / `demo-cluster` |
|
||||
|
||||
## Version workflow
|
||||
|
||||
1. Pick major **6 / 7 / 8 / 9** in the catalog.
|
||||
2. Inspect methods and coverage.
|
||||
3. **Apply as runtime** when you want live routes gated to that major’s floor.
|
||||
4. Confirm with `/api/appliance/system/version` and `/ui/api/compatibility`.
|
||||
|
||||
Hot-swap is memory-only; restart restores the default settings. Details:
|
||||
[API versions](api-versions.md).
|
||||
|
||||
## Security note
|
||||
|
||||
UI and demo endpoints are intended for local development. They are not gated by
|
||||
a separate admin token in the current build. Do not expose the simulator port to
|
||||
untrusted networks.
|
||||
Reference in New Issue
Block a user