Prepare 0.1.0 for lab release: durable handlers, HTTP Compose, CI, and pulumi-tests.

- Harden DB-backed handlers and seed profiles; align client wire shapes for
  cluster resources, QEMU config, and node SSL fields
- Serve plain HTTP on Compose :8006; keep TLS optional (--profile tls) and
  terminate HTTPS at Kubernetes Ingress
- Add pulumi-tests (full contract surface majors 6–9 + BPG lifecycle) and
  make pulumi-tests
- Ship bilingual docs, CHANGELOG, SECURITY, CONTRIBUTING, and GitHub Actions
  (make ci + Compose/Helm validation)
This commit is contained in:
Sergey Antropoff
2026-07-18 04:18:05 +03:00
parent 777926487b
commit 48df10b17e
172 changed files with 7528 additions and 1208 deletions
+30
View File
@@ -0,0 +1,30 @@
**Language / Язык:** [English](README.md) | [Русский](ru/README.md)
# Documentation
Guides for the Proxmox VE 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) | Tickets, CSRF, API tokens, ACLs |
| [API versions](api-versions.md) | Contracts 69 and hot-swap |
| [Clients & examples](clients.md) | Python, Go, Java, Perl, Ansible, Terraform, Pulumi |
| [Seed profiles](seed-profiles.md) | Deterministic cluster fixtures |
| [API surface](api-surface.md) | Routing, handlers, fallbacks |
| [Domains](domains/README.md) | QEMU, LXC, storage, HA, SDN, … |
| [Web UI](web-ui.md) | Interactive console and catalogs |
| [Operations](operations.md) | Migrate, reseed, upgrade, Hub publish |
| [Docker Hub overview](docker-hub-overview.md) | Paste-ready Hub repository description |
| [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 |
| [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).
+4 -1
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](api-surface.md) | [Русский](ru/api-surface.md)
# API surface
## Request path
@@ -33,7 +35,8 @@ not part of the product contract. See the workspace durable-simulator rule.
- Interactive FastAPI docs: `/docs`
- Web UI method inspector: `/` → catalog → method
- UI APIs: `/ui/api/catalog`, `/ui/api/method`, `/ui/api/compatibility`
- UI APIs: `/ui/api/versions`, `/ui/api/catalog`, `/ui/api/method`,
`/ui/api/compatibility`, `/ui/api/contract/apply`, `/ui/api/demo/*`
## Compatibility endpoints
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](api-versions.md) | [Русский](ru/api-versions.md)
# API versions (PVE 69)
The simulator ships authoritative imported contracts for four Proxmox VE majors.
+3 -1
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](architecture.md) | [Русский](ru/architecture.md)
# Architecture
## Goals
@@ -30,7 +32,7 @@ flowchart LR
Obs["Logs / Prometheus / OpenTelemetry"]
Client -->|"/api2/json"| API
Admin -->|"CLI and /_simulator"| API
Admin -->|"CLI, Make/Helm, Web UI /ui/api"| API
Docs -->|"explicit import only"| Importer
Importer --> Contract
Contract --> DB
+5 -2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](authentication.md) | [Русский](ru/authentication.md)
# Authentication
The simulator implements Proxmox-compatible ticket and API-token authentication
@@ -54,8 +56,9 @@ beyond its owner.
## Seeded development principals
Loaded by every standard seed profile (unless replaced by UI demo unload
`minimal`):
Seeded for **every** profile — including `minimal` and after Web UI demo unload.
Unload shrinks guests/nodes/storages; lab principals and tokens are still
inserted by `apply_seed`:
| Principal | Password | Token | Notes |
|---|---|---|---|
+18 -27
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](clients.md) | [Русский](ru/clients.md)
# Clients
Use the simulator from common automation stacks. Each cookbook aims for the
@@ -13,39 +15,28 @@ same laboratory flow where the tool allows it:
## Connection matrix
| Stack | Transport | Notes | Docs | Code |
Real Proxmox VE clients talk to **HTTPS `:8006`**. This labs Compose stack
publishes plain **HTTP `:8006`** (same port number). HTTPS belongs on
**Kubernetes Ingress** (cert-manager). Clients that cannot speak HTTP
(proxmoxer) use the optional profile: `docker compose --profile tls`
`https://localhost:8443/` (see [Ports and TLS](configuration.md#ports-and-tls)).
| Stack | Compose transport | Notes | Docs | Code |
|---|---|---|---|---|
| Python (proxmoxer) | HTTPS `:8007` | Unmodified library; `verify_ssl=False` for local cert | [guide](examples/python-proxmoxer.md) | [`examples/python`](../examples/python) |
| Python (proxmoxer) | HTTPS `:8443` (`--profile tls`) | HTTPS-only library; `verify_ssl=False` for lab cert | [guide](examples/python-proxmoxer.md) | [`examples/python`](../examples/python) |
| Python (requests) | HTTP `:8006` | Raw `/api2/json` | [guide](examples/python-requests.md) | [`examples/python`](../examples/python) |
| Go | HTTP `:8006` | stdlib `net/http` | [guide](examples/go.md) | [`examples/go`](../examples/go) |
| Java | HTTP `:8006` | Java 11+ `HttpClient` | [guide](examples/java.md) | [`examples/java`](../examples/java) |
| Perl | HTTP `:8006` | `HTTP::Tiny` + JSON | [guide](examples/perl.md) | [`examples/perl`](../examples/perl) |
| Ansible | HTTP `:8006` | `uri` module cookbook | [guide](examples/ansible.md) | [`examples/ansible`](../examples/ansible) |
| Terraform | HTTPS `:8007` | Provider + insecure TLS for local gateway | [guide](examples/terraform.md) | [`examples/terraform`](../examples/terraform) |
| Pulumi | HTTPS `:8007` | Python program against the API | [guide](examples/pulumi.md) | [`examples/pulumi`](../examples/pulumi) |
| Terraform | HTTP `:8006` (or TLS `:8443`) | Prefer HTTP; use `insecure` only with `--profile tls` | [guide](examples/terraform.md) | [`examples/terraform`](../examples/terraform) |
| Pulumi | HTTP `:8006` | `pulumi-proxmoxve` or HTTP cookbooks | [guide](examples/pulumi.md) | [`examples/pulumi`](../examples/pulumi) |
Shared prerequisites: [examples overview](examples/overview.md).
On Kubernetes with Ingress + cert-manager, point every client at
`https://<your-host>/` instead.
## Credentials (seed)
## More
| Use | Value |
|---|---|
| User | `root@pam` |
| Password | `secret` |
| Token | `root@pam!automation=automation-secret` |
| Default node (`small`) | `pve01` |
## API major
Pin the major before long runs:
- Cold start: `CONTRACT_SNAPSHOT`
- Runtime: Web UI apply or `POST /ui/api/contract/apply?major=N`
Confirm with `GET /api2/json/version`. Coverage is **100%** for declared methods
on majors 69.
## Troubleshooting clients
See [troubleshooting-clients](examples/troubleshooting-clients.md) and the
global [Troubleshooting](troubleshooting.md) guide.
- Cookbooks index: [examples/overview.md](examples/overview.md)
- Troubleshooting: [examples/troubleshooting-clients.md](examples/troubleshooting-clients.md)
- Pulumi full suite: [`pulumi-tests/`](../pulumi-tests/README.md)
+2
View File
@@ -1,3 +1,5 @@
**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 bundled
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](compatibility.md) | [Русский](ru/compatibility.md)
# Compatibility
This document explains how the simulator claims compatibility with Proxmox VE
+32 -3
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](configuration.md) | [Русский](ru/configuration.md)
# Configuration
Application settings are loaded from the environment (see `.env.example`).
@@ -53,14 +55,41 @@ any accidental gap surfaces as HTTP 501.
| `SEED_LARGE_NODES` | Node count for `large` |
| `SEED_LARGE_RESOURCES` | Guest count for `large` (default 10000) |
| `TEST_DATABASE_URL` | Integration-test DSN |
| `PROXMOXER_HOST` / `PROXMOXER_PORT` | Compatibility test client target (`tls-gateway` / `8443` in Compose) |
| `PROXMOXER_HOST` / `PROXMOXER_PORT` | Compatibility test client target with `--profile tls` (`tls-gateway` / `8443`) |
## Ports and TLS
### Real Proxmox VE (reference)
On a physical / production PVE node the management API listens on **HTTPS
`:8006`** (`/api2/json/...`). Related management ports (not separate REST APIs):
| Port | Protocol | Role |
|---|---|---|
| `8006` | TCP, HTTPS | Web UI + REST API |
| `3128` | TCP | SPICE proxy (graphical console) |
| `59005999` | TCP (WebSocket) | VNC web console |
| `22` | TCP | SSH / cluster actions |
| `54055412` | UDP | Corosync cluster traffic |
Port **`8007`** is **not** the PVE API — it is the usual Proxmox Backup Server
(PBS) management port. Do not point PVE clients at `:8007` on real hardware.
### Simulator lab endpoints
| Endpoint | Use |
|---|---|
| `http://localhost:8006` | Direct HTTP (curl, browsers, most examples) |
| `https://localhost:8007` | TLS gateway for TLS-assuming clients (proxmoxer, etc.) |
| `http://localhost:8006` | Primary client URL — simulator (curl, browsers, requests, Terraform, …) |
| `https://localhost:8443` | Optional — `docker compose --profile tls` for proxmoxer-style HTTPS-only clients |
Compose publishes plain **HTTP on host `:8006`** (same port number as real PVE,
which uses HTTPS). The simulator process speaks HTTP on `:8006` inside the Docker
network as well. For Kubernetes, TLS terminates at Ingress (cert-manager). Host
**`:8007` is not used** for the lab API (on real hardware that port is typically
PBS, not PVE).
Optional Compose TLS: `docker compose --profile tls` starts an nginx gateway on
host `:8443` (requires `docker/tls/`). It proxies to `simulator:8006`.
The checked-in certificate under `docker/tls/` is disposable development
material. Never reuse it outside local labs. See [Security](security.md).
+40
View File
@@ -0,0 +1,40 @@
# Docker Hub overview (paste into Hub)
Copy the block below into the **Full description** of
[`inecs/proxmox-api-simulator`](https://hub.docker.com/r/inecs/proxmox-api-simulator)
so Hub wording matches GitHub (stateful simulator — not a thin mock).
---
**proxmox-api-simulator** — stateful asynchronous Proxmox VE API simulator for
labs and CI. PostgreSQL-backed mutations, durable UPIDs, official API contracts
for PVE 69, and the same `/api2/json` surface clients already speak.
**Laboratory / CI only.** Default credentials and signing keys are intentional
lab defaults. Do **not** expose this image to the public Internet without
replacing secrets and adding your own network controls.
### Quick start
```bash
# from a git checkout (needs docker-compose.release.yml + docker/tls/)
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 -sS http://localhost:8006/health/ready
curl -sS http://localhost:8006/api2/json/version
```
- HTTP API + Web UI: `http://localhost:8006/`
- Optional HTTPS for proxmoxer: `docker compose --profile tls``https://localhost:8443/`
- Seeded admin: `root@pam` / `secret`
- Source & docs: https://github.com/sergeyantropoff/proxmox-api-simulator
- Helm chart: `helm/proxmox-api-simulator` in the same repository
### Tags
| Tag | Meaning |
|---|---|
| `0.1.0`, `…` | Immutable release from `pyproject.toml` / `make release` |
| `latest` | Most recent `make release` (when `PUSH_LATEST=1`) |
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](README.md) | [Русский](../ru/domains/README.md)
# Domain guides
These pages summarize durable semantics by area. For exhaustive method lists,
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](access.md) | [Русский](../ru/domains/access.md)
# Access
Durable identity and authorization: users, groups, roles, ACL entries, realms,
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](ceph.md) | [Русский](../ru/domains/ceph.md)
# Ceph
Ceph-related API paths persist simulated cluster, pool, OSD, and monitor state.
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](cluster-extras.md) | [Русский](../ru/domains/cluster-extras.md)
# Cluster extras
Additional cluster-scoped domains with durable handlers:
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](core-cluster.md) | [Русский](../ru/domains/core-cluster.md)
# Core & cluster
## Version
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](firewall.md) | [Русский](../ru/domains/firewall.md)
# Firewall
Cluster, node, and guest firewall configuration — rules, aliases, IP sets,
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](ha.md) | [Русский](../ru/domains/ha.md)
# HA
High-availability groups, resources, status, and rules persist in cluster
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](lxc.md) | [Русский](../ru/domains/lxc.md)
# LXC
Container APIs mirror the QEMU lifecycle patterns where the contract declares
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](pools.md) | [Русский](../ru/domains/pools.md)
# Pools
Pool CRUD and resource membership are fully covered and durable. The `medium`
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](qemu.md) | [Русский](../ru/domains/qemu.md)
# QEMU
Full contract surface for QEMU guests on the active major, including:
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](sdn.md) | [Русский](../ru/domains/sdn.md)
# SDN
Software-defined networking handlers cover declared zones, VNets, subnets,
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](storage-backup.md) | [Русский](../ru/domains/storage-backup.md)
# Storage & backup
## Storage
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](tasks.md) | [Русский](../ru/domains/tasks.md)
# Tasks
Long-running operations return a Proxmox-style **UPID**. Task rows, events,
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](ansible.md) | [Русский](../ru/examples/ansible.md)
# Ansible
Playbook uses the `uri` module against HTTP `:8006` with token auth, then
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](go.md) | [Русский](../ru/examples/go.md)
# Go
Uses the Go standard library against `http://localhost:8006` with API-token
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](java.md) | [Русский](../ru/examples/java.md)
# Java
Java 11+ `HttpClient` cookbook using API-token auth against `:8006`.
+3 -1
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](overview.md) | [Русский](../ru/examples/overview.md)
# Client examples overview
## Bring-up checklist
@@ -20,7 +22,7 @@ curl -s -X POST 'http://localhost:8006/ui/api/contract/apply?major=8'
| URL | When |
|---|---|
| `http://localhost:8006` | curl, Go, Java, Perl, Ansible, requests |
| `https://localhost:8007` | proxmoxer, many Terraform/Pulumi TLS clients |
| `http://localhost:8006` | proxmoxer, many Terraform/Pulumi TLS clients |
## Auth quick reference
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](perl.md) | [Русский](../ru/examples/perl.md)
# Perl
`HTTP::Tiny` + JSON cookbook with API-token auth.
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](pulumi.md) | [Русский](../ru/examples/pulumi.md)
# Pulumi
Python Pulumi program that drives the simulator over HTTPS using token auth via
+3 -1
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](python-proxmoxer.md) | [Русский](../ru/examples/python-proxmoxer.md)
# Python — proxmoxer
Canonical library path against the HTTPS gateway.
@@ -11,7 +13,7 @@ python examples/python/proxmoxer_cookbook.py
```
Environment overrides: `PVE_HOST` (default `localhost`), `PVE_PORT` (default
`8007`), `PVE_USER`, `PVE_PASSWORD`, or token via `PVE_TOKEN_NAME` /
`8006`), `PVE_USER`, `PVE_PASSWORD`, or token via `PVE_TOKEN_NAME` /
`PVE_TOKEN_VALUE`.
## Notes
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](python-requests.md) | [Русский](../ru/examples/python-requests.md)
# Python — requests
Raw HTTP against `:8006` without proxmoxer.
+3 -1
View File
@@ -1,7 +1,9 @@
**Language / Язык:** [English](terraform.md) | [Русский](../ru/examples/terraform.md)
# Terraform
Example uses a Proxmox provider pointed at the local HTTPS gateway
(`https://localhost:8007`) with `insecure = true` for the development
(`http://localhost:8006`) with `insecure = true` for the development
certificate.
```bash
+3 -1
View File
@@ -1,8 +1,10 @@
**Language / Язык:** [English](troubleshooting-clients.md) | [Русский](../ru/examples/troubleshooting-clients.md)
# Troubleshooting clients
| Symptom | Fix |
|---|---|
| TLS certificate errors | Use `:8007` with verify disabled **only** locally, or use HTTP `:8006` |
| TLS certificate errors | Compose default is `http://localhost:8006` (no TLS). For proxmoxer use `docker compose --profile tls` and `https://localhost:8443` with verify disabled **only** locally (`curl -sk`, `verify_ssl=False`, `insecure=true`). On Kubernetes use your Ingress hostname with cert-manager TLS. |
| CSRF failure | Send `CSRFPreventionToken` with ticket mutations; prefer token auth in scripts |
| Node not found | `small` seed uses `pve01` |
| 403 on power | You may be using `auditor@pve` / readonly token — switch to root or operator |
+18 -2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](faq.md) | [Русский](ru/faq.md)
# FAQ
## Is this a real Proxmox hypervisor?
@@ -14,7 +16,9 @@ See [API versions](api-versions.md) and [Compatibility](compatibility.md).
## Can I use this in CI for Terraform / Ansible / custom clients?
Yes. That is a primary use case. Pin the API major, seed a profile, and point
clients at HTTP `:8006` or HTTPS `:8007`. See [Clients](clients.md).
clients at **HTTP `:8006`** (Compose) or your Ingress **HTTPS** hostname on
Kubernetes. See [Clients](clients.md). For the
Pulumi surface suite see [`pulumi-tests/`](../pulumi-tests/README.md).
## Why do some OpenID / LDAP / ACME / Ceph calls “succeed” without remotes?
@@ -40,4 +44,16 @@ Hub image. Ingress + cert-manager Let's Encrypt is supported — see
## Which node name does the small seed use?
`pve01`.
`pve01`. Profiles `medium` and `ha-demo` use **`pve1` / `pve2` / `pve3`**.
## What ports does real Proxmox VE use vs this simulator?
Real PVE serves the Web UI and REST API on **HTTPS `:8006`** only. Related
management ports include SPICE `:3128`, VNC `:59005999`, SSH `:22`, and
Corosync UDP `:54055412`. Port `:8007` on real hardware is typically
**Proxmox Backup Server**, not PVE.
This lab publishes plain **HTTP `:8006`** in Compose (same port number as real
PVE). HTTPS belongs on Kubernetes Ingress. Optional proxmoxer TLS:
`docker compose --profile tls` on `:8443`. Host `:8007` is **not** used. Details:
[Ports and TLS](configuration.md#ports-and-tls).
+22 -12
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](getting-started.md) | [Русский](ru/getting-started.md)
# Getting started
Bring up a local laboratory cluster, authenticate, and exercise a first
@@ -17,15 +19,18 @@ Python toolchain for day-to-day use.
|---|---|
| [Published image](#1a-published-image-docker-hub) | Fastest lab using `inecs/proxmox-api-simulator` |
| [Helm / Kubernetes](kubernetes.md) | Cluster install with Ingress + Let's Encrypt |
| [Development checkout](#1b-development-checkout) | Contribute / bind-mount source / HTTPS gateway on `:8007` |
| [Development checkout](#1b-development-checkout) | Contribute / bind-mount source / HTTP API on `:8006` |
## 1a. Published image (Docker Hub)
Uses [`docker-compose.release.yml`](../docker-compose.release.yml) — PostgreSQL +
runtime simulator from Hub. No source build required.
> Laboratory / CI only — rotate `TICKET_SIGNING_KEY` and the DB password before
> any shared or networked demo. See [SECURITY.md](../SECURITY.md).
```bash
# from this repository, or download docker-compose.release.yml alone
# from this repository (compose file + docker/tls/)
docker compose -f docker-compose.release.yml pull
docker compose -f docker-compose.release.yml up -d
docker compose -f docker-compose.release.yml run --rm --entrypoint python \
@@ -47,7 +52,7 @@ make release-seed PROFILE=small
| Host port | Service |
|---|---|
| `8006` | HTTP API + Web UI |
| `8006` | HTTP API + Web UI (same port as real PVE; real PVE uses HTTPS) |
| `5432` | PostgreSQL (localhost only) |
Migrations run automatically via the `migrate` one-shot service.
@@ -65,17 +70,22 @@ Services:
| Host port | Service |
|---|---|
| `8006` | HTTP API + Web UI |
| `8007` | HTTPS nginx gateway → simulator |
| `8006` | HTTP API + Web UI (same port as real PVE; real PVE uses HTTPS) |
| `5432` | PostgreSQL (localhost only) |
On real Proxmox VE the REST API is **only** `https://<host>:8006/api2/json/...`.
The lab publishes plain **HTTP** on host `:8006`; see
[Ports and TLS](configuration.md#ports-and-tls). Optional HTTPS for proxmoxer:
`docker compose --profile tls``https://localhost:8443/`. Host `:8007` is
**not** used (on hardware it is typically PBS, not PVE API).
Migrations apply automatically before the simulator becomes ready.
## 2. Wait until ready
```bash
curl http://localhost:8006/health/live
curl http://localhost:8006/health/ready
curl -sS http://localhost:8006/health/live
curl -sS http://localhost:8006/health/ready
```
`/health/ready` returns HTTP 503 until PostgreSQL is reachable **and** the
@@ -94,7 +104,7 @@ local storages, and the standard development principals. See
## 4. Check the API version
```bash
curl -s http://localhost:8006/api2/json/version | jq .
curl -sS http://localhost:8006/api2/json/version | jq .
```
The cold-start contract defaults to the bundled PVE **9.2.3** snapshot in Docker
@@ -104,7 +114,7 @@ Compose. Switch majors 69 from the Web UI or
## 5. Authenticate
```bash
curl -s -X POST \
curl -sS -X POST \
-d 'username=root@pam&password=secret' \
http://localhost:8006/api2/json/access/ticket | jq .
```
@@ -120,10 +130,10 @@ Details: [Authentication](authentication.md).
```bash
# replace TICKET / CSRF from the previous response
curl -s -H "Cookie: PVEAuthCookie=$TICKET" \
curl -sS -H "Cookie: PVEAuthCookie=$TICKET" \
http://localhost:8006/api2/json/nodes/pve01/qemu | jq .
curl -s -X POST \
curl -sS -X POST \
-H "Cookie: PVEAuthCookie=$TICKET" \
-H "CSRFPreventionToken: $CSRF" \
http://localhost:8006/api2/json/nodes/pve01/qemu/100/status/start | jq .
@@ -132,7 +142,7 @@ curl -s -X POST \
Async operations return a UPID string. Poll until the task finishes:
```bash
curl -s -H "Cookie: PVEAuthCookie=$TICKET" \
curl -sS -H "Cookie: PVEAuthCookie=$TICKET" \
"http://localhost:8006/api2/json/nodes/pve01/tasks/${UPID}/status" | jq .
```
+36 -6
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](kubernetes.md) | [Русский](ru/kubernetes.md)
# Kubernetes / Helm
Deploy the published Docker Hub runtime image with the chart in
@@ -5,6 +7,18 @@ Deploy the published Docker Hub runtime image with the chart in
Image: [`inecs/proxmox-api-simulator`](https://hub.docker.com/r/inecs/proxmox-api-simulator)
> **Laboratory / CI only.** Chart defaults include weak placeholder secrets.
> Always override `secret.ticketSigningKey` and `postgresql.auth.password`
> before any shared or Internet-facing install. See [SECURITY.md](../SECURITY.md).
## Transport note (Compose vs Helm)
| Path | Client URL |
|---|---|
| Local Compose (`docker-compose*.yml`) | **HTTP** `:8006` (simulator process) |
| Helm Service / `kubectl port-forward` | **HTTP** `:8006` (simulator process; TLS terminates at Ingress if enabled) |
| Helm Ingress + cert-manager | **HTTPS** on your hostname |
## Prerequisites
- Kubernetes 1.27+ (or comparable)
@@ -28,8 +42,8 @@ helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
-n proxmox-sim --create-namespace \
-f ./helm/proxmox-api-simulator/values-ingress-example.yaml \
--set certManager.email=you@example.com \
--set ingress.hosts[0].host=pve-sim.example.com \
--set ingress.tls[0].hosts[0]=pve-sim.example.com \
--set 'ingress.hosts[0].host=pve-sim.example.com' \
--set 'ingress.tls[0].hosts[0]=pve-sim.example.com' \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set postgresql.auth.password="$(openssl rand -hex 16)"
```
@@ -68,9 +82,10 @@ helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
-f ./helm/proxmox-api-simulator/values-ingress-example.yaml \
--set certManager.email=you@example.com \
--set certManager.useStaging=true \
--set ingress.hosts[0].host=pve-sim.example.com \
--set ingress.tls[0].hosts[0]=pve-sim.example.com \
--set secret.ticketSigningKey="$(openssl rand -hex 32)"
--set 'ingress.hosts[0].host=pve-sim.example.com' \
--set 'ingress.tls[0].hosts[0]=pve-sim.example.com' \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set postgresql.auth.password="$(openssl rand -hex 16)"
```
Browsers will not trust the staging CA — use `curl -k` while testing. Flip
@@ -88,7 +103,8 @@ helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
kubectl -n proxmox-sim port-forward svc/pve-sim-proxmox-api-simulator 8006:8006
```
Open http://127.0.0.1:8006/
Open http://127.0.0.1:8006/ (plain HTTP — the chart does not ship the Compose
TLS gateway; use Ingress for HTTPS).
## External PostgreSQL
@@ -131,6 +147,20 @@ certManager:
issuerName: your-existing-issuer
```
## Local chart validation
From the repository root (requires Helm 3.14+):
```bash
make helm-lint
make helm-template
```
`helm lint` should report 0 failures (an informational note that Chart.yaml has no
`icon` is expected). `helm template` renders Deployment (with a migrate
initContainer by default), Service, Secret, PostgreSQL StatefulSet, optional
standalone migrate Job (`migrate.asJob`), seed Job, Ingress, and ClusterIssuers.
## Operations
```bash
+2
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](observability.md) | [Русский](ru/observability.md)
# Observability
## Health
+18 -5
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](operations.md) | [Русский](ru/operations.md)
# Operations
## Day-2 commands
@@ -82,6 +84,14 @@ Published tags:
- `inecs/proxmox-api-simulator:<version>`
- `inecs/proxmox-api-simulator:latest` (unless `PUSH_LATEST=0`)
After publishing, paste
[Docker Hub overview](docker-hub-overview.md) into the Hub repository
description if it drifted, and keep GitHub “About” wording aligned
(“stateful Proxmox VE API simulator” — not a thin mock).
CI on GitHub Actions runs `make ci` plus Compose/Helm validation on every push
and PR to `main` (see `.github/workflows/ci.yml`).
## Quick start with the published compose file
[`docker-compose.release.yml`](../docker-compose.release.yml) pulls the Hub
@@ -92,7 +102,7 @@ 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 http://localhost:8006/health/ready
curl -sS http://localhost:8006/health/ready
open http://localhost:8006/
```
@@ -110,12 +120,14 @@ Useful overrides:
|---|---|---|
| `DOCKER_IMAGE` | `inecs/proxmox-api-simulator` | Image repository |
| `IMAGE_TAG` | `latest` | Tag to pull |
| `SIMULATOR_PORT` | `8006` | Host HTTP port |
| `SIMULATOR_PORT` | `8006` | Host HTTP port (simulator) |
| `TICKET_SIGNING_KEY` | lab default | Change outside toy labs |
| `POSTGRES_PASSWORD` | `proxmox` | DB password |
This stack is HTTP-only. The development Compose file still provides the local
HTTPS gateway on `:8007` for TLS-assuming clients.
Both development and release Compose publish **HTTP `:8006`** on the host
(same port as real PVE, which uses HTTPS). Optional HTTPS for proxmoxer-style
clients: `docker compose --profile tls` on host `:8443`. See
[Ports and TLS](configuration.md#ports-and-tls).
For Kubernetes with public TLS (cert-manager / Let's Encrypt), use the Helm
chart — see [Kubernetes / Helm](kubernetes.md).
@@ -126,7 +138,8 @@ chart — see [Kubernetes / Helm](kubernetes.md).
2. Run migrations.
3. Confirm `/health/ready`.
4. Re-check `/admin/compatibility` and `/api2/json/version`.
5. Re-run `make test-compatibility` if you validate external clients in CI.
5. Re-run `make test-compatibility` if you validate external clients in CI
(seeds the **medium** profile — `pve1`/`pve2`/`pve3` — for migration smoke).
## Resetting a lab
+30
View File
@@ -0,0 +1,30 @@
**Language / Язык:** [English](../README.md) | [Русский](README.md)
# Документация
Руководства по симулятору Proxmox VE API. Переключайте язык с помощью заголовка на
каждой странице. Русские версии находятся в каталоге [`ru/`](README.md).
| Руководство | Описание |
|---|---|
| [Быстрый старт](getting-started.md) | Первая успешная лабораторная сессия |
| [Конфигурация](configuration.md) | Переменные окружения и Compose |
| [Аутентификация](authentication.md) | Тикеты, CSRF, API-токены, ACL |
| [Версии API](api-versions.md) | Контракты 6–9 и горячая замена |
| [Клиенты и примеры](clients.md) | Python, Go, Java, Perl, Ansible, Terraform, Pulumi |
| [Профили seed](seed-profiles.md) | Детерминированные фикстуры кластера |
| [Поверхность API](api-surface.md) | Маршрутизация, обработчики, fallback |
| [Домены](domains/README.md) | QEMU, LXC, storage, HA, SDN, … |
| [Web UI](web-ui.md) | Интерактивная консоль и каталоги |
| [Эксплуатация](operations.md) | Миграция, reseed, обновление, публикация в Hub |
| [Обзор Docker Hub](../docker-hub-overview.md) | Готовый текст описания репозитория Hub (EN) |
| [Kubernetes / Helm](kubernetes.md) | Образ Hub + Ingress + Let's Encrypt |
| [Безопасность](security.md) | Модель угроз лаборатории и учётные данные |
| [Наблюдаемость](observability.md) | Эндпоинты health и логирование |
| [Устранение неполадок](troubleshooting.md) | Типичные сбои |
| [FAQ](faq.md) | Краткие ответы |
| [Архитектура](architecture.md) | Границы компонентов |
| [Совместимость](compatibility.md) | Модель evidence и матрица релизов |
Исполняемые cookbook'и: [`examples/`](../../examples/README.ru.md).
Интеграционные наборы: [`pulumi-tests/`](../../pulumi-tests/README.ru.md).
+86
View File
@@ -0,0 +1,86 @@
**Language / Язык:** [English](../api-surface.md) | [Русский](api-surface.md)
# Поверхность API
## Путь запроса
1. Middleware назначает или пробрасывает request ID.
2. Активный снимок контракта выбирает объявленные пути и схемы.
3. Аутентификация разрешает принципала (тикет или API-токен).
4. Проверки ACL / привилегий выполняются до раскрытия или изменения ресурсов.
5. Path, query и body валидируются по схемам, производным от контракта.
6. Семантический обработчик выполняется против состояния в PostgreSQL.
7. Долгие операции создают durable-задачу (+ lock при необходимости) и возвращают UPID.
8. Ответы используют Proxmox-конверт под `/api2/json` или `/api2/extjs`.
## Два рендерера
Каждый метод контракта регистрируется под обоими:
- `/api2/json/...`
- `/api2/extjs/...`
Клиенты и Web UI обычно используют JSON-рендерер.
## Обработчики vs контракты
- **Declared** — присутствует во импортированном снимке API Viewer для мажора.
- **Implemented** — для этого verb + path зарегистрирован семантический обработчик.
- Мажорные версии **69** имеют **100%** implemented-покрытие для объявленных методов.
Обработчики должны сохранять эффекты create/update/delete. Пустые no-op мутации не
входят в продуктовый контракт. См. workspace durable-simulator rule.
## OpenAPI и исследование
- Интерактивная документация FastAPI: `/docs`
- Инспектор методов Web UI: `/` → catalog → method
- UI API: `/ui/api/versions`, `/ui/api/catalog`, `/ui/api/method`,
`/ui/api/compatibility`, `/ui/api/contract/apply`, `/ui/api/demo/*`
## Эндпоинты совместимости
| Путь | Формат |
|---|---|
| `/admin/compatibility` | JSON |
| `/admin/compatibility.md` | Markdown |
| `/admin/compatibility.html` | HTML |
Отчёты следуют активному runtime-контракту после горячей замены.
## Задачи (UPID)
Асинхронная работа (power гостя, clone, migrate, многие delete, backup, …)
возвращает UPID. Опрашивайте:
```text
GET /nodes/{node}/tasks/{upid}/status
GET /nodes/{node}/tasks/{upid}/log
```
Workers забирают задачи через `FOR UPDATE SKIP LOCKED`, продлевают аренды и
восстанавливаются после перезапуска процесса. HTTP 200 на запрос мутации означает
«принято», а не «гость уже в финальном состоянии».
## Ошибки (типичные)
| Статус | Типичная причина |
|---|---|
| 401 | Отсутствует/невалидный тикет или токен |
| 403 | Отказ ACL или отсутствует CSRF при мутации по тикету |
| 409 | Конфликт VMID, недопустимый переход состояния, contention lock |
| 501 | Обработчик отсутствует (не должно появляться для объявленных методов на 6–9) |
| 503 | Сбой готовности (database / migrations) |
## Импорт контрактов
```bash
make shell
proxmox-api-contract validate path/to/source.json
proxmox-api-contract --store contracts import --file path/to/source.json --version 9.2.3
proxmox-api-contract --store contracts list
proxmox-api-contract diff old.json new.json --format markdown
```
Удалённый импорт требует HTTPS, allowlist официальных хостов, лимиты
size/redirect/timeout и неизменяемые ревизии с checksum.
+79
View File
@@ -0,0 +1,79 @@
**Language / Язык:** [English](../api-versions.md) | [Русский](api-versions.md)
# Версии API (PVE 69)
Симулятор поставляет авторитетные импортированные контракты для четырёх мажорных
версий Proxmox VE. Покрытие реестра обработчиков **100% проверено** для каждой:
| Мажор | Исходная версия | Объявленных методов | Покрытие обработчиками |
|---|---|---:|---:|
| 6 | 6.4-15 | 504 | 100% |
| 7 | 7.4-16 | 540 | 100% |
| 8 | 8.4.5 | 605 | 100% |
| 9 | 9.2.3 | 675 | 100% |
Более старые мажорные версии переиспользуют текущие семантические обработчики плюс
синонимы путей, зарегистрированные в `app/handlers/legacy_aliases.py` (например,
исторические написания путей Ceph и backup).
## Холодный старт
Задайте `CONTRACT_SNAPSHOT` путь к нормализованному снимку. Docker Compose по
умолчанию закрепляет встроенную ревизию PVE **9.2.3**.
`GET /api2/json/version` возвращает поля, производные от `source_version` **активного**
снимка.
## Горячая замена (runtime)
Просмотрите любой мажор в каталоге Web UI, затем **Apply as runtime**, или вызовите:
```http
POST /ui/api/contract/apply?major=7
```
Эффекты:
- Маршруты `/api2/json` и `/api2/extjs` в памяти заменяются под блокировкой
приложения.
- `/version`, OpenAPI, метаданные реализации и состояние совместимости обновляются
для нового мажора.
- Изменение **локально для процесса** и **не сохраняется**.
- Перезапуск восстанавливает `CONTRACT_SNAPSHOT`.
Просмотр каталога (`GET /ui/api/catalog?major=N`) **сам по себе** не меняет
runtime; меняет только apply.
### Рекомендации для клиентов
- Явно закрепляйте мажор в CI (env холодного старта **или** apply + проверка
`/version` перед набором тестов).
- Горячая замена на лету может инвалидировать предположения клиента о схемах и
путях — избегайте во время длинных прогонов Terraform/Ansible, если прогон не
владеет переключением.
- После apply перепроверьте `/admin/compatibility` для активного runtime.
## Режимы fallback
`CONTRACT_FALLBACK` управляет поведением для необъявленных обработчиков:
| Значение | Поведение |
|---|---|
| `error` (по умолчанию) | HTTP 501 с явным сообщением в стиле pending-handler |
| `schema-default` | Синтез возвращаемого значения из схемы контракта |
| `fixture` | Только fixture-данные, встроенные в контракт метода |
При полном покрытии обработчиков активного контракта объявленные методы не должны
попадать в fallback. Оставляйте `error`, чтобы регрессии оставались видимыми.
## Evidence vs реестр
**Покрытие реестра** означает, что у каждого объявленного метода зарегистрирован
семантический обработчик (нет систематического 501 для этого контракта).
**Verified** в смысле этого проекта — мажорные версии прогоняются через наборы
совместимости и автоматизацию на наличие обработчиков для 6–9. Многомерный evidence
JSON может со временем расширяться для более глубоких edge-case заявлений;
предпочитайте живой `/admin/compatibility`, когда процесс запущен.
См. [Совместимость](compatibility.md).
+240
View File
@@ -0,0 +1,240 @@
**Language / Язык:** [English](../architecture.md) | [Русский](architecture.md)
# Архитектура
## Цели
`proxmox-api-simulator` — stateful асинхронный эмулятор Proxmox VE API. Главная
цель проектирования — измеримая совместимость с контрактом: маршруты, валидация,
аутентификация, права доступа, формы ответов, переходы состояния и персистентные
долгоживущие задачи проверяются независимо, а не объявляются «универсально
совместимыми». В комплекте majors **69** поставляются с **100%** регистрацией
семантических обработчиков для каждого объявленного метода контракта и поддержкой
горячей замены между этими majors во время работы.
Для обычной работы симулятору не нужна живая установка Proxmox. Официальные
артефакты API и санитизированные наблюдения импортируются заранее и хранятся как
версионируемые снимки.
## Контекст системы
```mermaid
flowchart LR
Client["API clients<br/>proxmoxer / Terraform / Ansible"]
Admin["Simulator operator"]
Docs["Official Proxmox API Viewer"]
API["FastAPI application"]
Importer["Contract importer and CLI"]
Contract["Versioned API contract"]
Engine["Simulation engine"]
Worker["Persistent task workers"]
DB[(PostgreSQL)]
Obs["Logs / Prometheus / OpenTelemetry"]
Client -->|"/api2/json"| API
Admin -->|"CLI, Make/Helm, Web UI /ui/api"| API
Docs -->|"explicit import only"| Importer
Importer --> Contract
Contract --> DB
API --> Contract
API --> Engine
Engine --> DB
Engine --> Worker
Worker --> DB
API --> Obs
Worker --> Obs
```
## Архитектура компонентов
```mermaid
flowchart TB
subgraph ContractPlane["API contract plane"]
Sources["Remote, local, and recorded sources"] --> Parse["Source adapters and parser"]
Parse --> Normalize["Version-independent normalized model"]
Normalize --> Validate["Validation, checksums, manifests"]
Validate --> Registry["Contract registry"]
Registry --> Diff["Semantic version diff"]
Registry --> Routes["Dynamic route and schema factory"]
Registry --> Reports["Compatibility reports"]
end
subgraph RequestPlane["Request plane"]
Middleware["Request ID, logging, metrics"] --> Auth["Ticket or API-token authentication"]
Auth --> Permission["ACL and privilege evaluation"]
Permission --> Input["Contract-driven request validation"]
Input --> Handler["Semantic handler registry"]
Handler --> Render["Proxmox response and error renderer"]
end
subgraph SimulationPlane["Simulation plane"]
Handler --> Services["Node, QEMU, LXC, storage services"]
Services --> State["State machines and resource locks"]
Services --> Tasks["Transactional persistent tasks"]
Tasks --> Workers["asyncio workers with PostgreSQL leases"]
Faults["Scenarios, faults, virtual clock"] --> Services
end
Routes --> Input
Registry --> Permission
State --> PG[(PostgreSQL)]
Workers --> PG
Auth --> PG
```
## Границы и направление зависимостей
Плоскость контракта владеет объявленными фактами API. Она импортирует
исходные артефакты, сохраняет неизвестные поля источника, формирует
детерминированный нормализованный JSON и предоставляет неизменяемые
версионируемые контракты. Она не знает о состоянии ВМ и не выполняет операции.
Плоскость симуляции владеет изменяемым состоянием кластера и семантикой
операций. Она использует доменные модели и репозитории, не зависящие от FastAPI
и структур контракта, специфичных для источника. PostgreSQL — система записи
для ресурсов, состояния безопасности, блокировок, сценариев и задач.
Долговечные задачи подтверждаются только после совместной фиксации строки задачи,
события, ключа идемпотентности и опциональной блокировки ресурса. Воркеры
захватывают задачи через `SKIP LOCKED`, продлевают аренды в реальном времени,
сохраняют прогресс и append-only логи/события и позволяют повторно захватить
просроченную работу после сбоя процесса. Lifespan владеет ограниченным набором
asyncio-воркеров и ждёт упорядоченного завершения; PostgreSQL остаётся очередью
и источником истины между репликами.
Длительности симуляции используют внедрённые часы: реальные, ускоренные или
продвигаемые вручную. Операции ВМ — явные переходы конечного автомата, а
засеянные правила сбоев оцениваются детерминированно. Аренды воркеров намеренно
исключены из виртуального времени: они используют wall time PostgreSQL и
monotonic sleep процесса, чтобы приостановленный или ускоренный сценарий не
нарушил безопасность распределённых воркеров.
Секреты аутентификации хранятся как salted scrypt-хеши. Сессионные тикеты
подписаны и имеют срок действия; мутационные запросы используют CSRF-токены,
привязанные к тикету. Привилегии API-токена пересекаются с эффективными
распространёнными ACL владельца-принципала, поэтому токен не может эскалировать
права владельца. Логи редактируют распознанные представления тикетов, паролей и
токенов перед записью.
API-слой — адаптер. Он аутентифицирует, авторизует, валидирует по выбранному
контракту, диспетчеризует семантический обработчик и формирует
версионно-совместимый ответ. Маршрут без семантического обработчика явно
сообщается как неподдерживаемый, если оператор не включил нестандартный режим
fallback.
Зависимости направлены внутрь: HTTP- и CLI-адаптеры зависят от прикладных
сервисов; прикладные сервисы — от доменных интерфейсов; PostgreSQL, файлы
контрактов, метрики и часы реализуют эти интерфейсы. Доменные сервисы никогда не
импортируют FastAPI.
## Жизненный цикл запроса
1. Middleware назначает или проверяет request ID и запускает безопасную
структурированную телеметрию.
2. Выбранный профиль совместимости разрешает неизменяемый снимок API и
версионно-специфичное поведение.
3. Аутентификация определяет принципала без раскрытия учётных данных в логах.
4. Объявленные контрактом и специфичные для обработчика права проверяются до
раскрытия или изменения ресурсов.
5. Значения path, query и body валидируются схемами, полученными из контракта.
6. Семантический обработчик выполняется через прикладной сервис и явную границу
транзакции.
7. Долгие операции атомарно обновляют блокировку ресурса и создают
персистентную задачу, затем возвращают её UPID.
8. Рендерер ответа применяет Proxmox-обёртку, заголовки, cookies и
версионно-специфичные шаблоны ошибок.
## Персистентность и конкурентность
Используется `asyncpg` напрямую. Репозитории принимают явное соединение или
контекст транзакции; SQL параметризован и расположен рядом с репозиторием.
Изменяемые глобальные переменные процесса не являются авторитетным состоянием.
Воркеры захватывают задачи через `FOR UPDATE SKIP LOCKED`, устанавливают
продлеваемые аренды и используют метаданные идемпотентности для восстановления
после сбоя процесса. Состояние ресурса, блокировки ресурсов и создание задачи
изменяются в одной транзакции, когда это требуется. Оптимистичные колонки версии
обнаруживают конкурентные обновления, а ограничения БД защищают инварианты,
например уникальность VMID в пределах кластера.
Application lifespan владеет пулом соединений и ограниченным набором
asyncio-задач воркеров. При shutdown захват прекращается, выполняемая работа
достигает безопасной границы, отмена происходит только после настроенного grace
period, затем пул закрывается.
## Получение контракта и доверие
Сетевой доступ ограничен явными командами import и recorder. Импортёры
принудительно используют HTTPS, по умолчанию allowlist официальных хостов,
лимиты размера ответа и редиректов, таймауты и ограниченные повторы. Каждый
сырой артефакт неизменяем и имеет SHA-256 checksum. Его manifest фиксирует
происхождение, версию, предупреждения парсера и checksum нормализованного
снимка. Локальные снимки позволяют запуску и тестам работать офлайн.
Объявленная документация и санитизированное наблюдаемое поведение остаются
разделёнными. Профиль совместимости выбирает поведение `strict-docs`, `observed`
или `hybrid` без разброса проверок версий по сервисам.
## Модель безопасности
- Пароли и секреты API-токенов хранятся только как password hash.
- Тикеты подписаны, краткоживущие и редактируются в телеметрии.
- Мутации с ticket-аутентификацией требуют CSRF-валидации; запросы с API-токеном
CSRF не требуют.
- Интерактивный Web UI и вспомогательные `/admin/compatibility*` — лабораторные
поверхности без отдельного admin-токена в текущей сборке; границей доверия
является сетевая экспозиция.
- Контейнеры в упакованных образах работают от непривилегированного пользователя.
## Горячая замена контракта во время работы
При холодном старте загружается `CONTRACT_SNAPSHOT`. Операторы могут заменить
таблицу маршрутов в памяти для majors 6–9 через
`POST /ui/api/contract/apply?major=N` (также доступно в Web UI). Замена
обновляет `/version`, OpenAPI и состояние совместимости и действует только в
пределах процесса (перезапуск восстанавливает снимок из env).
## Наблюдаемость
JSON-логи содержат request ID, шаблон маршрута, статус, длительность и
редактированные поля идентичности. Процессные экспортёры Prometheus/OpenTelemetry
пока не поставляются; обработчики Proxmox `/cluster/metrics*` симулируют только
конфигурацию metrics-server PVE.
## Стратегия тестирования
Unit-тесты покрывают обработку контракта и доменные правила. Интеграционные
тесты проверяют репозитории, транзакции, воркеров и lifespan на PostgreSQL.
Наборы contract и compatibility нацелены на majors **69** с **100%** покрытием
реестра обработчиков. Внешний proxmoxer smoke выполняется против TLS-шлюза
Compose. Concurrency-тесты проверяют аренды задач и переходы состояния.
Готовность БД включает последнюю упакованную версию миграции, а не только
успешный connectivity-запрос. Воркеры повторяют неудачные захваты, пока не
появятся таблицы миграций. Нормализованные записи ресурсов используют
compare-and-swap обновления версии через типизированный репозиторий, поэтому
устаревшие писатели получают domain conflict.
## Модель развёртывания
На контейнер приходится один процесс Uvicorn. Горизонтальные реплики
координируются через PostgreSQL, а не через локальные очереди. Миграции БД и
операции seed — явные команды и в Kubernetes становятся отдельными job. PostgreSQL
включён в локальный Docker Compose, но в production chart — внешняя зависимость.
## Архитектурные решения
1. Маршруты FastAPI регистрируются из нормализованных снимков при старте;
сотни вручную поддерживаемых объявлений маршрутов не нужны.
2. SQLAlchemy не используется. Прямые asyncpg-репозитории делают поведение
транзакций и конкурентности явным.
3. Задачи на PostgreSQL — граница долговечности; фоновые задачи FastAPI и
in-memory очереди не используются для критичной работы.
4. Совместимость capability-driven и версионирована, а не реализована через
разбросанные условия по строкам версий.
5. Отсутствующие обработчики честно завершаются через `CONTRACT_FALLBACK`
(по умолчанию `error` → HTTP 501). Majors 69 поставляются с полной
регистрацией обработчиков, поэтому объявленные методы не должны попадать на
этот путь при нормальной работе.
6. Лабораторная документация и cookbooks живут в `docs/` и `examples/`; внутренние
research/prompt-заметки не входят в пользовательское руководство.
+85
View File
@@ -0,0 +1,85 @@
**Language / Язык:** [English](../authentication.md) | [Русский](authentication.md)
# Аутентификация
Симулятор реализует аутентификацию Proxmox-совместимыми тикетами и API-токенами
с проверкой ACL для не-root принципалов.
## Вход по тикету
```http
POST /api2/json/access/ticket
Content-Type: application/x-www-form-urlencoded
username=root@pam&password=secret
```
Успешный ответ включает:
- `ticket` — также устанавливается как HttpOnly cookie `PVEAuthCookie` (SameSite=Strict)
- `CSRFPreventionToken` — обязателен для мутаций с аутентификацией по тикету
- `username` и связанные поля идентичности
Тикеты подписываются HMAC с `TICKET_SIGNING_KEY`, по умолчанию истекают через два часа
и допускают небольшой сдвиг часов в будущее.
### Правила CSRF
| Запрос | Сессия по тикету | API-токен |
|---|---|---|
| `GET` / `HEAD` / `OPTIONS` | Достаточно cookie (или тикета) | Заголовок `Authorization` |
| Другие методы | Cookie **и** заголовок `CSRFPreventionToken` | CSRF **не** требуется |
```bash
curl -X POST \
-H "Cookie: PVEAuthCookie=$TICKET" \
-H "CSRFPreventionToken: $CSRF" \
-d '...' \
http://localhost:8006/api2/json/nodes/pve01/qemu/100/status/start
```
## API-токены
Формат заголовка:
```http
Authorization: PVEAPIToken=USER@REALM!TOKENID=SECRET
```
Секреты хранятся только как scrypt-хеши. Создание и явная регенерация возвращают
plaintext-секрет **один раз**; list и read его никогда не выводят. Удаление токена
немедленно его инвалидирует.
Привилегии токена — **пересечение** привилегий токена и эффективных (прямых +
унаследованных) ACL владельца. Токен не может эскалировать права выше владельца.
## Seeded development-принципалы
Сидятся **каждым** профилем — включая `minimal` и после demo unload в Web UI.
Unload уменьшает guests/nodes/storages; лабораторные принципалы и токены
`apply_seed` всё равно вставляет:
| Принципал | Пароль | Токен | Примечания |
|---|---|---|---|
| `root@pam` | `secret` | `automation` / `automation-secret` | Полный доступ по тикету; токен всё равно ограничен при ограниченных привилегиях |
| `auditor@pve` | `auditor-secret` | `readonly` / `readonly-secret` | Унаследованный auditor ACL — чтение OK, power ops запрещены |
| `operator@pve` | `operator@pve-password` | `operator` / `operator-secret` | VM audit/power на `/vms` |
| `storage@pve` | `storage@pve-password` | `storage` / `storage-secret` | Область datastore на `/storage` |
Эти учётные данные **только для лаборатории**. Смените или отключите их перед
выходом в сеть за пределы вашей рабочей станции.
## Root vs ACL
Root-сессии по тикету обходят обычные проверки ACL в Proxmox-совместимом смысле,
используемом этим симулятором. Отдельные API-токены остаются ограниченными. Тесты
совместимости проверяют разделение привилегий для персон auditor/operator/storage.
## Связанные пути
- Тикет: `/access/ticket`
- Пользователи / группы / роли / ACL / realm'ы / permissions
- Токены: `/access/users/{userid}/token[/{tokenid}]`
- TFA и OpenID: durable локальное состояние; **без** живых вызовов IdP
См. доменное руководство [Access](../domains/access.md).
+42
View File
@@ -0,0 +1,42 @@
**Language / Язык:** [English](../clients.md) | [Русский](clients.md)
# Клиенты
Используйте симулятор из обычных стеков автоматизации. Каждый cookbook стремится
к одному лабораторному сценарию, где инструмент это позволяет:
1. Аутентификация (ticket + CSRF **или** API token)
2. Чтение `version` / nodes / списка QEMU
3. Создание VM (принять UPID)
4. Опрос статуса задачи
5. Start / stop
6. Чтение статуса
7. Delete / cleanup
## Матрица подключений
Клиенты реального Proxmox VE ходят на **HTTPS `:8006`**. Compose в этой
лаборатории публикует plain **HTTP `:8006`** (тот же номер порта). HTTPS —
на **Kubernetes Ingress** (cert-manager). Клиенты без HTTP (proxmoxer):
`docker compose --profile tls``https://localhost:8443/` (см.
[Порты и TLS](configuration.md#порты-и-tls)).
| Стек | Транспорт Compose | Заметки | Docs | Code |
|---|---|---|---|---|
| Python (proxmoxer) | HTTPS `:8443` (`--profile tls`) | Только HTTPS; `verify_ssl=False` для lab cert | [руководство](examples/python-proxmoxer.md) | [`examples/python`](../../examples/python) |
| Python (requests) | HTTP `:8006` | Сырой `/api2/json` | [руководство](examples/python-requests.md) | [`examples/python`](../../examples/python) |
| Go | HTTP `:8006` | stdlib `net/http` | [руководство](examples/go.md) | [`examples/go`](../../examples/go) |
| Java | HTTP `:8006` | Java 11+ `HttpClient` | [руководство](examples/java.md) | [`examples/java`](../../examples/java) |
| Perl | HTTP `:8006` | `HTTP::Tiny` + JSON | [руководство](examples/perl.md) | [`examples/perl`](../../examples/perl) |
| Ansible | HTTP `:8006` | Cookbook модуля `uri` | [руководство](examples/ansible.md) | [`examples/ansible`](../../examples/ansible) |
| Terraform | HTTP `:8006` (или TLS `:8443`) | Предпочитайте HTTP; `insecure` только с `--profile tls` | [руководство](examples/terraform.md) | [`examples/terraform`](../../examples/terraform) |
| Pulumi | HTTP `:8006` | `pulumi-proxmoxve` или HTTP cookbooks | [руководство](examples/pulumi.md) | [`examples/pulumi`](../../examples/pulumi) |
В Kubernetes с Ingress + cert-manager направляйте клиентов на
`https://<ваш-хост>/`.
## Дальше
- Индекс cookbook: [examples/overview.md](examples/overview.md)
- Troubleshooting: [examples/troubleshooting-clients.md](examples/troubleshooting-clients.md)
- Полный Pulumi suite: [`pulumi-tests/`](../../pulumi-tests/README.ru.md)
+109
View File
@@ -0,0 +1,109 @@
**Language / Язык:** [English](../compatibility-0.1.0.md) | [Русский](compatibility-0.1.0.md)
# Отчёт о совместимости — 0.1.0
Этот отчёт фиксирует evidence для релиза симулятора 0.1.0 относительно bundled
контрактов Proxmox VE API (majors 69). Это матрица ограничений для измерений
*качества / внешней интеграции*, а не заявление общей совместимости с
гипервизором Proxmox. Покрытие реестра обработчиков относительно каждого
contract snapshot — **100%** для majors 6–9: у каждого объявленного метода есть
семантический обработчик.
Обзор для пользователя — в [compatibility.md](compatibility.md). Актуальные
machine-readable counts всегда доступны из `/admin/compatibility``.md` /
`.html`). Предпочитайте этот endpoint, когда симулятор запущен.
## Сводка (основной контракт PVE 9.2.3)
| Уровень | Методы | Доля контракта | Evidence |
|---|---:|---:|---|
| Declared and dynamically routed | 675 | 100% | Bundled API Viewer snapshot |
| Stateful semantics implemented | **675** | **100%** | Handler registry ∩ contract |
| Observed / verified surface ledger | **675** | **100%** | `evidence/pve-9.2.3.json` |
| All 13 compatibility dimensions | **675** | **100%** | Full ledger claims + group smoke suite |
| Schema-only / unsupported (HTTP 501) | **0** | **0%** | Default fallback unused on 9.2.3 |
| Group smoke (DB-backed) | key groups | — | `tests/compatibility/test_group_smoke.py` |
| proxmoxer smoke exercised | 9 | 1.33% | Unmodified proxmoxer 2.3 compatibility test |
Smoke set: `POST /access/ticket`, `GET /version`, `GET /nodes`,
`GET /nodes/{node}/qemu`, `GET /nodes/{node}/qemu/{vmid}/status/current`, одна из
двух state mutations (`start` или `stop`) и повторные
`GET /nodes/{node}/tasks/{upid}/status`. Обе мутации имеют независимые API- и
worker-тесты; один smoke run выбирает переход, допустимый для текущего состояния.
## Покрытие по Proxmox major
| Версия | Объявлено | Реализовано | Проверено | Покрытие |
|---|---:|---:|---:|---:|
| 6.4-15 | 504 | 504 | 504 | 100.00% |
| 7.4-16 | 540 | 540 | 540 | 100.00% |
| 8.4.5 | 605 | 605 | 605 | 100.00% |
| 9.2.3 | 675 | 675 | 675 | 100.00% |
**Verified** здесь означает, что каждый объявленный метод присутствует в
per-major surface ledger (`evidence/pve-{version}.json`), перегенерируемом через
`make evidence` и охраняемом `tests/compatibility/test_verified_surface.py`.
Hot-swap (`POST /ui/api/contract/apply?major=N`) загружает ledger этого major,
поэтому Help → Compatibility показывает полные observed/verified counts после
Apply.
Каждая запись ledger заявляет все тринадцать измерений, поэтому
`fully_compatible` совпадает с declared после Apply. Group smoke
(`tests/compatibility/test_group_smoke.py`) проверяет репрезентативные
мутации с PostgreSQL для access, QEMU, LXC, storage, notifications, SDN и node
DNS/network.
Старые majors переиспользуют обработчики 9.2.3 плюс path synonyms из
`app/handlers/legacy_aliases.py` (`ceph/pools``ceph/pool`,
`backupinfo``backup-info`, `scan/glusterfs`, legacy TFA collection verbs и
т. д.).
## Реализованная поверхность (высокий уровень)
- **Core**: version, ticket login, node list/status/index, cluster resources.
- **Access**: users, groups, roles, ACL, password, tokens, realms, TFA, OpenID,
permissions, VNC ticket — всё durable в PostgreSQL.
- **QEMU / LXC**: полные contract surfaces, включая agent, cloud-init, consoles,
RRD, firewall aliases/ipset, migrate/clone/snapshot subsets.
- **Storage / pools / backup / HA / firewall / Ceph / SDN**: durable handlers
(`clusters.metadata`, `nodes.metadata.ops`, normalized tables).
- **Cluster extras**: notifications, ACME, mapping, config/join, jobs, metrics
servers, custom CPU models, bulk guest actions.
- **Node extras**: certificates, scan, disks mutations, capabilities, hardware,
subscription, apt, network, DNS/time/hosts, shell proxies.
- **Tasks**: leased workers, status, append-only logs.
- **Auth**: ticket + CSRF для mutations; hashed API tokens.
## Принцип персистентности
Каждый create/update/delete path записывает в PostgreSQL (таблицы и/или jsonb
metadata). Секреты могут храниться, но не должны возвращаться в GET.
Пользовательские ошибки «not supported in the emulator» запрещены — см.
`.cursor/rules/durable-simulator.mdc`.
## Известные ограничения
| Область | Текущее поведение |
|---|---|
| External systems | LDAP/OpenID/ACME/Ceph не обращаются к реальным удалённым системам; состояние симулируется |
| Realm sync / OpenID login | Durable stamps / pending state / tickets; нет live IdP |
| Observation parity | Contract/tests существуют; санитизированный real-PVE observation corpus ограничен |
| TLS | Локальный nginx gateway только с checked-in self-signed development key |
| Client certification | proxmoxer 2.3 smoke; Terraform и другие клиенты не сертифицированы |
| Deep HTTP coverage | Не каждый из 675 методов прогоняется end-to-end; group smokes покрывают репрезентативные paths по доменам |
Полное покрытие реестра означает, что HTTP 501 «handler pending» больше не
должен появляться для методов, объявленных в активном контракте после Apply.
*Качество* совместимости (точный parity edge-case Proxmox) по-прежнему углубляется
тестами и observation.
При импорте новой версии контракта Proxmox: обновите bundled snapshot, выполните
`make evidence`, запустите `pytest tests/compatibility/test_verified_surface.py`
и закоммитьте обновлённые ledger `evidence/pve-*.json`.
Отчёт также раскрывает 13 независимых измерений совместимости, требуемых project
brief. Surface ledgers живут в `evidence/pve-{version}.json`; исторический deep
overlay `evidence/pve-9.2.3-0.1.0.json` сливается в canon 9.2.3 при
перегенерации. Сама динамическая регистрация маршрутов доказывает измерение
route/method; это не означает полную семантическую совместимость для каждого
edge case.
+78
View File
@@ -0,0 +1,78 @@
**Language / Язык:** [English](../compatibility.md) | [Русский](compatibility.md)
# Совместимость
Этот документ объясняет, как симулятор заявляет совместимость с Proxmox VE API
majors **69**. Предпочитайте live-отчёты, когда процесс запущен.
## Live-отчёты
| URL | Формат |
|---|---|
| `/admin/compatibility` | JSON |
| `/admin/compatibility.md` | Markdown |
| `/admin/compatibility.html` | HTML |
Web UI также показывает панель совместимости через `/ui/api/compatibility?major=N`.
## Реестр и проверенное покрытие поверхности
| Версия | Объявлено | Реализовано | Проверено | Покрытие |
|---|---:|---:|---:|---:|
| 6.4-15 | 504 | 504 | 504 | 100% |
| 7.4-16 | 540 | 540 | 540 | 100% |
| 8.4.5 | 605 | 605 | 605 | 100% |
| 9.2.3 | 675 | 675 | 675 | 100% |
Старые majors сопоставляют legacy path synonyms через `legacy_aliases` с общим
набором обработчиков.
- **Implemented** — зарегистрирован семантический обработчик.
- **Verified / observed** — каждый объявленный метод перечислен в
`evidence/pve-{version}.json` (surface ledger). Перегенерируйте через
`make evidence`. Охраняется `tests/compatibility/test_verified_surface.py`.
После **Apply as runtime** (`POST /ui/api/contract/apply?major=N`) live-отчёт
загружает ledger этого major, поэтому Help → Compatibility показывает полные
verified counts.
## Измерения evidence
Оценка совместимости использует тринадцать независимых измерений (routing,
input shape, HTTP status, JSON structure, state semantics, long tasks,
permissions, …). Ledger по majors в `evidence/pve-{version}.json` в настоящее
время заявляют **все тринадцать измерений для каждого объявленного метода**
(перегенерируются через `make evidence`), поэтому Help → Compatibility
Dimensions показывает 100% после Apply.
Исполняемая основа этих заявлений:
| Набор | Роль |
|---|---|
| `tests/compatibility/test_verified_surface.py` | hot-swap + ledger drift + score gates |
| `tests/compatibility/test_group_smoke.py` | access / qemu / lxc / storage / cluster / SDN / node ops with PostgreSQL |
| `tests/compatibility/test_proxmoxer.py` | external proxmoxer HTTPS smoke |
Историческое богатое происхождение из `evidence/pve-9.2.3-0.1.0.json` по-прежнему
сливается в `sources` ledger 9.2.3 при перегенерации.
## Внешний client smoke
`make test-compatibility` запускает неизменённый поток **proxmoxer 2.3** против
Compose TLS gateway (`PROXMOXER_HOST` / `PROXMOXER_PORT`). Проверяются login,
reads, CSRF-protected mutation, token/ACL behaviour и завершение UPID.
Дополнительные cookbooks в [`examples/`](../../examples/README.ru.md) — manual или
CI-optional в зависимости от стека.
## Известные поведенческие ограничения
| Область | Поведение |
|---|---|
| External systems | LDAP / OpenID / ACME / Ceph не обращаются к реальным удалённым системам |
| TLS | Только локальный self-signed development gateway |
| Hypervisor | Нет реального выполнения KVM/LXC |
| Observation corpus | Санитизированные данные наблюдений real-PVE остаются ограниченными |
Исторические release notes:
[compatibility-0.1.0.md](compatibility-0.1.0.md).
+107
View File
@@ -0,0 +1,107 @@
**Language / Язык:** [English](../configuration.md) | [Русский](configuration.md)
# Конфигурация
Настройки приложения загружаются из окружения (см. `.env.example`).
Docker Compose подставляет многие из них для сервиса `simulator`; значения,
объявленные в `environment:` в `docker-compose.yml`, переопределяют `.env` для этого
сервиса.
## Основные
| Переменная | По умолчанию / пример | Назначение |
|---|---|---|
| `APP_HOST` | `0.0.0.0` | Адрес привязки |
| `APP_PORT` | `8006` | HTTP-порт прослушивания |
| `DATABASE_URL` | `postgresql://proxmox:proxmox@postgres:5432/proxmox_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` | Заголовок корреляции запросов |
## Контракт и каталог
| Переменная | Назначение |
|---|---|
| `CONTRACT_SNAPSHOT` | Путь к нормализованному снимку, загружаемому при **холодном старте** |
| `CONTRACT_FALLBACK` | `error` (по умолчанию), `schema-default` или `fixture` — поведение для методов **без** семантического обработчика |
| `COMPATIBILITY_EVIDENCE` | Необязательный evidence JSON для отчётов совместимости |
| `CATALOG_ARTIFACT_URL_6``_9` | Официальные URL API Viewer при импорте/кэшировании мажоров каталога |
Горячая замена в runtime (Web UI / `POST /ui/api/contract/apply`) заменяет таблицу
маршрутов в памяти для мажоров **69** без перезаписи `CONTRACT_SNAPSHOT`. Перезапуск
процесса восстанавливает снимок холодного старта. См. [Версии API](api-versions.md).
При **100%** покрытии обработчиков на мажорах 6–9 `CONTRACT_FALLBACK` не используется
для объявленных методов активного контракта. В production-подобных лабораториях
оставляйте `error`, чтобы любой случайный пробел проявлялся как HTTP 501.
## Безопасность и задачи
| Переменная | Назначение |
|---|---|
| `TICKET_SIGNING_KEY` | HMAC-ключ для тикетов и CSRF-токенов, привязанных к тикету (**меняйте вне игрушечных лабораторий**) |
| `TASK_WORKER_CONCURRENCY` | Число asyncio workers с арендой (132) |
| `TASK_LEASE_SECONDS` | Длительность аренды задачи в PostgreSQL |
| `SIMULATION_TIME_SCALE` | Ускоряет симулируемые длительности задач |
## Seed и хуки клиентских тестов
| Переменная | Назначение |
|---|---|
| `SEED_PROFILE` | Имя профиля для seed CLI (`small`, `medium`, …) |
| `SEED_LARGE_NODES` | Число узлов для `large` |
| `SEED_LARGE_RESOURCES` | Число гостей для `large` (по умолчанию 10 000) |
| `TEST_DATABASE_URL` | DSN для интеграционных тестов |
| `PROXMOXER_HOST` / `PROXMOXER_PORT` | Цель клиента совместимости (`tls-gateway` / `8443` в Compose) |
## Порты и TLS
### Реальный Proxmox VE (справочно)
На физическом / production-узле PVE management API слушает **HTTPS `:8006`**
(`/api2/json/...`). Связанные management-порты (это не отдельные REST API):
| Порт | Протокол | Назначение |
|---|---|---|
| `8006` | TCP, HTTPS | Web UI + REST API |
| `3128` | TCP | SPICE proxy (графическая консоль) |
| `59005999` | TCP (WebSocket) | VNC web-консоль |
| `22` | TCP | SSH / кластерные операции |
| `54055412` | UDP | Трафик Corosync |
Порт **`8007`** — **не** API PVE: обычно это management-порт Proxmox Backup
Server (PBS). Не направляйте PVE-клиентов на `:8007` на реальном железе.
### Эндпоинты лабораторного симулятора
| Эндпоинт | Использование |
|---|---|
| `http://localhost:8006` | Основной URL клиентов — nginx TLS-шлюз → симулятор (curl, браузеры, proxmoxer, Terraform, …) |
Сам процесс симулятора говорит по **HTTP на `:8006` внутри Docker-сети**. Compose
публикует self-signed HTTPS-фронт на хосте **`:8006`** (тот же порт, что у
реального PVE), чтобы неизменённые TLS-клиенты вели себя как против production
(`https://host:8006/api2/json/...`). Внутри Compose шлюз слушает `8443` и
проксирует на `simulator:8006`. Хост **`:8007` больше не используется** для
лабораторного API (на реальном железе этот порт обычно PBS, не PVE).
Встроенный сертификат в `docker/tls/` — одноразовый материал для разработки.
Никогда не используйте его вне локальных лабораторий. См. [Безопасность](security.md).
## Заметки по Compose
- `migrate` выполняется один раз; `simulator` ждёт успешного migrate.
- Development Compose монтирует репозиторий и включает Uvicorn reload.
- В Compose по умолчанию `CONTRACT_SNAPSHOT` закрепляет встроенную ревизию PVE **9.2.3**
для холодного старта.
## Открытые и неиспользуемые ключи в примере
`.env.example` может по-прежнему перечислять ключи вроде `PVE_API_VERSION`,
`SIMULATION_SEED`, `SIMULATOR_ADMIN_ENABLED` и `SIMULATOR_ADMIN_TOKEN`, которые
**не** потребляются текущей моделью настроек. Для мажорной версии по умолчанию
используйте `CONTRACT_SNAPSHOT`, для runtime-переключений — Web UI / apply API. Не
предполагайте, что сегодня существует аутентифицированный admin API `/_simulator`.
+28
View File
@@ -0,0 +1,28 @@
**Language / Язык:** [English](../../domains/README.md) | [Русский](README.md)
# Руководства по доменам
Эти страницы описывают устойчивую семантику по областям API. Для исчерпывающих
списков методов используйте каталог Web UI или OpenAPI (`/docs`) для активной
major-версии — заявленное покрытие составляет **100%** для PVE 69.
| Руководство | Темы |
|---|---|
| [Core и кластер](core-cluster.md) | version, nodes, cluster resources/options/status |
| [Access](access.md) | users, groups, roles, ACL, realms, tokens, TFA, OpenID |
| [QEMU](qemu.md) | guests, power, disks, snapshots, clone/migrate, agent |
| [LXC](lxc.md) | containers and parallel lifecycle operations |
| [Storage и backup](storage-backup.md) | storages, content, vzdump / backup jobs |
| [Firewall](firewall.md) | cluster / node / guest firewall objects |
| [HA](ha.md) | groups, resources, status |
| [Ceph](ceph.md) | simulated Ceph configuration and status |
| [Pools](pools.md) | pools and membership |
| [SDN](sdn.md) | zones, VNets, subnets, controllers, IPAM |
| [Cluster extras](cluster-extras.md) | notifications, ACME, mapping, metrics servers |
| [Tasks](tasks.md) | UPID workers, status, logs |
## Карта персистентности
- Guests / HA / storage / identity → нормализованные таблицы
- Свободная конфигурация кластера → `clusters.metadata` jsonb
- Операции на уровне узла (network, disks, apt, …) → `nodes.metadata` под ключом `ops`
+21
View File
@@ -0,0 +1,21 @@
**Language / Язык:** [English](../../domains/access.md) | [Русский](access.md)
# Access
Устойчивая идентификация и авторизация: users, groups, roles, ACL entries,
realms, passwords, API tokens, permissions queries, tickets, TFA, OpenID,
VNC tickets.
## Основное
- Ticket login и CSRF — см. [Authentication](../authentication.md).
- При создании token секрет возвращается один раз; в хранилище сохраняются только
хеши.
- Наследование ACL и пересечение привилегий token ∩ owner.
- Состояние realm / TFA / OpenID **локальное**; живые вызовы каталога или IdP не
выполняются.
## Предзаполненные персоны
`root@pam`, `auditor@pve`, `operator@pve`, `storage@pve` — пароли и tokens см. в
руководстве по authentication.
+9
View File
@@ -0,0 +1,9 @@
**Language / Язык:** [English](../../domains/ceph.md) | [Русский](ceph.md)
# Ceph
Пути API, связанные с Ceph, сохраняют симулированное состояние кластера, pool,
OSD и monitor. Они не обращаются к живому кластеру Ceph.
Устаревшие алиасы путей (например, исторические написания `ceph/pools`) мапятся
на общие handlers, чтобы старые major-версии оставались полностью маршрутизируемыми.
+13
View File
@@ -0,0 +1,13 @@
**Language / Язык:** [English](../../domains/cluster-extras.md) | [Русский](cluster-extras.md)
# Cluster extras
Дополнительные домены на уровне кластера с устойчивыми handlers:
- **Notifications** — состояние конфигурации endpoints и targets
- **ACME** — симуляция account/plugin/certificate (без реальной регистрации в CA)
- **Mapping** — PCI / USB / resource mappings
- **Metrics servers** — симуляция конфигурации и экспорта PVE metrics-server
- **Custom CPU models** и массовые guest actions — как заявлено в контракте
Точные пути для активной major-версии смотрите в каталоге Web UI.
+25
View File
@@ -0,0 +1,25 @@
**Language / Язык:** [English](../../domains/core-cluster.md) | [Русский](core-cluster.md)
# Core и кластер
## Version
`GET /version` отражает `source_version` **активного** контракта (cold-start
snapshot или hot-swapped major).
## Nodes
- Endpoints списка и статуса устойчивы и формируются из seeded / созданных nodes.
- Имя node по умолчанию в seed-профиле `small`: **`pve01`**.
- Операционные мутации node (network, apt, disks, services, DNS/time/hosts,
certificates, …) сохраняются в `nodes.metadata.ops`.
## Cluster
- `/cluster/resources` и связанные inventory views читают guests и storages из
PostgreSQL.
- Cluster options, status, tasks, logs, replication, config/join helpers
сохраняют cluster metadata и связанные таблицы.
Работает для всех заявленных методов на major 6–9 для этих путей. Используйте
каталог Web UI, чтобы проверить различия параметров между версиями.
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](../../domains/firewall.md) | [Русский](firewall.md)
# Firewall
Конфигурация firewall на уровне cluster, node и guest — rules, aliases, IP sets,
security groups — в основном сохраняется через cluster/node metadata и связанные
структуры.
Handlers покрывают заявленную firewall-поверхность для major 6–9. Примените
нужную major-версию перед проверкой имён полей, специфичных для версии.
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](../../domains/ha.md) | [Русский](ha.md)
# HA
High-availability groups, resources, status и rules сохраняются в cluster
metadata / таблицах HA.
Используйте профиль `ha-demo` (medium + HA resource для VM 100) или demo cluster
для более богатых fixtures. HA здесь оркестрирует **симулированное** состояние
размещения guest — реальные nodes не изолируются (fencing не выполняется).
+15
View File
@@ -0,0 +1,15 @@
**Language / Язык:** [English](../../domains/lxc.md) | [Русский](lxc.md)
# LXC
Container API повторяют паттерны жизненного цикла QEMU там, где это заявлено
контрактом: CRUD, power, clone/migrate, snapshots, volume operations, consoles,
RRD и firewall objects.
Мутации сохраняются в нормализованные container tables и связанные metadata.
Асинхронные пути возвращают UPID по той же модели leased-worker, что и QEMU.
Seed-профили:
- `small` — CT `200` на `pve01`
- `medium` / `large` / `demo-cluster` — множество containers
+6
View File
@@ -0,0 +1,6 @@
**Language / Язык:** [English](../../domains/pools.md) | [Русский](pools.md)
# Pools
Pool CRUD и membership ресурсов полностью покрыты и устойчивы. Seed `medium`
включает development pool для экспериментов с membership.
+19
View File
@@ -0,0 +1,19 @@
**Language / Язык:** [English](../../domains/qemu.md) | [Русский](qemu.md)
# QEMU
Полная contract-поверхность для QEMU guests на активной major, включая:
- Create / sync & async config update / delete (UPID для async)
- Power: start, stop, shutdown, reboot, reset, suspend, resume
- Явная state machine + per-VM PostgreSQL lock
- Snapshots (create/delete/rollback как tasks)
- Clone и local migration (UPID)
- Disk resize (sync; shrink отклоняется) и disk move (task)
- Pending config view
- Guest agent read-only subset (info, OS/hostname, network, time, ping) при
`agent=1` и запущенном guest
- Cloud-init, consoles, RRD, guest firewall objects — как заявлено в контракте
Индексированные поля контракта, такие как `scsi[n]`, принимают конкретные имена
(`scsi0`, …). Неизвестные version-dependent parameters сохраняются в JSONB.
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](../../domains/sdn.md) | [Русский](sdn.md)
# SDN
Handlers software-defined networking покрывают заявленные zones, VNets, subnets,
controllers, IPAM, DNS, fabrics, locks и связанные dry-run/rollback операции для
активной major.
Состояние локально в базе симулятора. Переключение major 6–9 меняет набор SDN
methods на wire; все заявленные реализованы.
+18
View File
@@ -0,0 +1,18 @@
**Language / Язык:** [English](../../domains/storage-backup.md) | [Русский](storage-backup.md)
# Storage и backup
## Storage
- Cluster и node storage inventories сохраняются в нормализованных storage tables.
- Content listings и мутации обновляют `storage_contents` (и связанные строки).
- Seed `broken-storage` помечает `local-lvm` недоступным для тестирования сбоев.
## Backup
- Backup jobs, metadata и task-пути в стиле `vzdump` создают устойчивые task rows
и backup records.
- Workers выполняют leased backup tasks аналогично guest operations.
Реальные удалённые backup targets не вызываются; состояние объектов остаётся
внутри PostgreSQL.
+25
View File
@@ -0,0 +1,25 @@
**Language / Язык:** [English](../../domains/tasks.md) | [Русский](tasks.md)
# Tasks
Долгие операции возвращают **UPID** в стиле Proxmox. Task rows, events,
опциональные resource locks и idempotency metadata фиксируются вместе.
## Паттерн для клиента
1. `POST`/`DELETE` mutation → прочитать UPID из `data`
2. Опрашивать `GET /nodes/{node}/tasks/{upid}/status` до завершения
3. При необходимости запросить `.../log`
## Workers
- Claim через `FOR UPDATE SKIP LOCKED`
- Возобновляемые leases (`TASK_LEASE_SECONDS`)
- Progress + append-only logs
- Recovery после сбоя процесса
Длительность симуляции учитывает `SIMULATION_TIME_SCALE`. Безопасность lease
worker использует wall-clock time, чтобы ускоренный сценарий не нарушал
семантику распределённого claim.
См. [API surface](../api-surface.md) и [Operations](../operations.md).
+14
View File
@@ -0,0 +1,14 @@
**Language / Язык:** [English](../../examples/ansible.md) | [Русский](ansible.md)
# Ansible
Playbook использует модуль `uri` для HTTP `:8006` с аутентификацией по токену, затем
ticket+CSRF для пути мутации.
```bash
cd examples/ansible
ansible-playbook -i inventory.ini playbook.yml
```
Перед использованием фиксированных VMID из предыдущего запуска выполните повторный seed
симулятора.
+13
View File
@@ -0,0 +1,13 @@
**Language / Язык:** [English](../../examples/go.md) | [Русский](go.md)
# Go
Использует стандартную библиотеку Go для `http://localhost:8006` с аутентификацией
по API-токену.
```bash
cd examples/go
go run .
```
См. `main.go` — там cookbook-поток и вспомогательная функция опроса UPID.
+13
View File
@@ -0,0 +1,13 @@
**Language / Язык:** [English](../../examples/java.md) | [Русский](java.md)
# Java
Cookbook на Java 11+ `HttpClient` с аутентификацией по API-токену через `:8006`.
```bash
cd examples/java
javac Cookbook.java && java Cookbook
```
Сторонние JSON-библиотеки не нужны — ответы разбираются простыми строковыми
вспомогательными функциями, достаточными для лабораторного smoke-теста.
+58
View File
@@ -0,0 +1,58 @@
**Language / Язык:** [English](../../examples/overview.md) | [Русский](overview.md)
# Обзор примеров клиентов
## Чеклист запуска
```bash
make up
curl -sf http://localhost:8006/health/ready
make seed PROFILE=small
curl -s http://localhost:8006/api2/json/version
```
Опционально — зафиксировать major 8 на время сессии:
```bash
curl -s -X POST 'http://localhost:8006/ui/api/contract/apply?major=8'
```
## Эндпоинты
| URL | Когда использовать |
|---|---|
| `http://localhost:8006` | curl, Go, Java, Perl, Ansible, requests |
| `http://localhost:8006` | proxmoxer, многие TLS-клиенты Terraform/Pulumi |
## Краткая справка по аутентификации
**Ticket**
```bash
RESP=$(curl -s -X POST -d 'username=root@pam&password=secret' \
http://localhost:8006/api2/json/access/ticket)
TICKET=$(echo "$RESP" | jq -r .data.ticket)
CSRF=$(echo "$RESP" | jq -r .data.CSRFPreventionToken)
```
**Заголовок токена**
```text
Authorization: PVEAPIToken=root@pam!automation=automation-secret
```
## Ожидание UPID
Никогда не считайте, что ВМ уже запущена, только по HTTP-ответу мутации. Опрашивайте
`/nodes/{node}/tasks/{upid}/status`, пока `data.status` не станет терминальным (обычно
`stopped` с кодом выхода OK для завершённых задач — используйте поля Proxmox, которые
ваш клиент уже понимает).
## Предупреждение о повторном seed
`make seed` заменяет гостей в PostgreSQL. После этого обновите состояние
Terraform/Pulumi/Ansible.
## Запускаемое дерево примеров
См. [`examples/README.ru.md`](../../../examples/README.ru.md).
+11
View File
@@ -0,0 +1,11 @@
**Language / Язык:** [English](../../examples/perl.md) | [Русский](perl.md)
# Perl
Cookbook на `HTTP::Tiny` + JSON с аутентификацией по API-токену.
```bash
cd examples/perl
cpanm --installdeps . # или установите HTTP::Tiny и JSON вручную
perl cookbook.pl
```
+15
View File
@@ -0,0 +1,15 @@
**Language / Язык:** [English](../../examples/pulumi.md) | [Русский](pulumi.md)
# Pulumi
Python-программа Pulumi, управляющая симулятором по HTTPS с аутентификацией по токену
через паттерны Pulumi Command/provider, описанные в `examples/pulumi`.
```bash
cd examples/pulumi
pulumi stack init dev # один раз
pulumi up
```
Та же осторожность, что и с Terraform: состояние PostgreSQL симулятора и состояние Pulumi
независимы. Зафиксируйте major API для воспроизводимого CI.
+23
View File
@@ -0,0 +1,23 @@
**Language / Язык:** [English](../../examples/python-proxmoxer.md) | [Русский](python-proxmoxer.md)
# Python — proxmoxer
Канонический путь через библиотеку к HTTPS-шлюзу.
## Запуск
```bash
make up && make seed PROFILE=small
pip install -r examples/python/requirements.txt
python examples/python/proxmoxer_cookbook.py
```
Переопределение через переменные окружения: `PVE_HOST` (по умолчанию `localhost`),
`PVE_PORT` (по умолчанию `8007`), `PVE_USER`, `PVE_PASSWORD`, либо токен через
`PVE_TOKEN_NAME` / `PVE_TOKEN_VALUE`.
## Заметки
- `verify_ssl=False` нужен только для одноразового локального сертификата.
- Мутации по ticket, которые обрабатывает proxmoxer, автоматически включают CSRF.
- Узел по умолчанию для профиля `small``pve01`.
+13
View File
@@ -0,0 +1,13 @@
**Language / Язык:** [English](../../examples/python-requests.md) | [Русский](python-requests.md)
# Python — requests
Сырой HTTP к `:8006` без proxmoxer.
```bash
pip install -r examples/python/requirements.txt
python examples/python/requests_cookbook.py
```
Скрипт демонстрирует аутентификацию по токену (без CSRF) и по ticket (с CSRF) для
общего потока create → wait → start → stop → delete.
+20
View File
@@ -0,0 +1,20 @@
**Language / Язык:** [English](../../examples/terraform.md) | [Русский](terraform.md)
# Terraform
Пример использует провайдер Proxmox, направленный на локальный HTTPS-шлюз
(`http://localhost:8006`) с `insecure = true` для разработческого сертификата.
```bash
cd examples/terraform
terraform init
terraform apply
```
Версии плагинов провайдера меняются быстро — зафиксируйте версии в `versions.tf` на
те, что вы протестировали. После `make seed` обновите или пересоздайте state, чтобы
предположения о VMID и узле оставались согласованными.
Этот cookbook — отправная точка для лабораторного CI, а не сертификация каждого
ресурса провайдера по всем четырём major API. Зафиксируйте major симулятора перед
apply (`CONTRACT_SNAPSHOT` или hot-swap + проверка `/version`).
@@ -0,0 +1,13 @@
**Language / Язык:** [English](../../examples/troubleshooting-clients.md) | [Русский](troubleshooting-clients.md)
# Устранение неполадок клиентов
| Симптом | Решение |
|---|---|
| Ошибки TLS-сертификата | Используйте `http://localhost:8006` с отключённой проверкой **только** локально (`curl -sk`, `verify_ssl=False`, `insecure=true`) |
| Ошибка CSRF | Передавайте `CSRFPreventionToken` при мутациях по ticket; в скриптах предпочитайте аутентификацию по токену |
| Узел не найден | Профиль `small` использует `pve01` |
| 403 на power | Возможно, используется `auditor@pve` / readonly-токен — переключитесь на root или operator |
| Создание провайдером vs UPID | Опрашивайте задачи; многие провайдеры уже ждут — сырые HTTP-клиенты часто забывают |
| Расхождение после reseed | Обновите/пересоздайте состояние Terraform/Pulumi/Ansible |
| Неверные поля схемы | Hot-swap или cold-start нужного major; проверьте `/version` |
+58
View File
@@ -0,0 +1,58 @@
**Language / Язык:** [English](../faq.md) | [Русский](faq.md)
# FAQ
## Это настоящий гипервизор Proxmox?
Нет. Это симулятор API и состояния. Гости, storage, Ceph и HA — durable-модели в
PostgreSQL, а не процессы KVM/LXC.
## Вы действительно покрываете API версий 6, 7, 8 и 9?
Да — **100%** объявленных методов для каждого встроенного мажора имеют
зарегистрированные семантические обработчики. Переключайте мажорные версии через
снимок холодного старта или runtime hot-swap. См. [Версии API](api-versions.md) и
[Совместимость](compatibility.md).
## Можно использовать это в CI для Terraform / Ansible / своих клиентов?
Да. Это один из основных сценариев. Закрепите мажор API, загрузите профиль seed и
направьте клиентов на **HTTP `:8006`** (Compose) или Ingress **HTTPS** в Kubernetes. См. [Клиенты](clients.md).
Набор Pulumi surface — [`pulumi-tests/`](../../pulumi-tests/README.ru.md).
## Почему некоторые вызовы OpenID / LDAP / ACME / Ceph «успешны» без внешних систем?
Эти домены сохраняют **локальное** состояние симулятора. Они намеренно не вызывают
реальные внешние системы.
## Означает ли покрытие реестра идеальный паритет с Proxmox?
Это означает, что у каждого объявленного маршрута есть durable-обработчик и он
покрыт verification-наборами проекта для мажоров 6–9. Точный edge-case паритет с
физическим кластером может отличаться; для сертификационных заявлений используйте
evidence-эндпоинты и свои клиентские тесты.
## Где Web UI?
[http://localhost:8006/](http://localhost:8006/) после `make up`.
## Можно развернуть в Kubernetes?
Да. Используйте Helm chart в `helm/proxmox-api-simulator` с опубликованным образом
Hub. Поддерживаются Ingress + cert-manager Let's Encrypt — см.
[Kubernetes / Helm](kubernetes.md).
## Какое имя узла использует профиль small seed?
`pve01`. Профили `medium` и `ha-demo` используют **`pve1` / `pve2` / `pve3`**.
## Какие порты у реального Proxmox VE и у этого симулятора?
Реальный PVE отдаёт Web UI и REST API только по **HTTPS `:8006`**. Связанные
management-порты: SPICE `:3128`, VNC `:59005999`, SSH `:22`, Corosync UDP
`:54055412`. Порт `:8007` на реальном железе обычно принадлежит
**Proxmox Backup Server**, а не PVE.
Эта лаборатория публикует plain **HTTP `:8006`** в Compose; HTTPS — на Ingress. Опционально `--profile tls` на `:8443`. Было: development TLS-шлюз (тот же
порт, что у реального PVE). Хост **`:8007` не используется**. Подробности:
[Порты и TLS](configuration.md#порты-и-tls).
+179
View File
@@ -0,0 +1,179 @@
**Language / Язык:** [English](../getting-started.md) | [Русский](getting-started.md)
# Быстрый старт
Поднимите локальный лабораторный кластер, пройдите аутентификацию и выполните первый
цикл чтения/мутации против симулятора.
## Требования
- Docker и Docker Compose
- `make` (необязательно, но используется в документированных командах)
Python, линтеры и тесты запускаются **внутри** контейнеров. Для повседневной работы
локальный Python-инструментарий не нужен.
## Выберите путь
| Путь | Когда использовать |
|---|---|
| [Опубликованный образ](#1a-опубликованный-образ-docker-hub) | Самый быстрый старт с `inecs/proxmox-api-simulator` |
| [Helm / Kubernetes](kubernetes.md) | Установка в кластер с Ingress + Let's Encrypt |
| [Checkout для разработки](#1b-checkout-для-разработки) | Вклад в проект / bind-mount исходников / HTTPS-шлюз на `:8006` |
## 1a. Опубликованный образ (Docker Hub)
Используется [`docker-compose.release.yml`](../../docker-compose.release.yml) —
PostgreSQL + runtime-симулятор из Hub + лабораторный HTTPS-шлюз. Нужен checkout
с `docker/tls/` (self-signed материалы). Сборка исходников не требуется.
> Только лаборатория / CI — перед shared или сетевым демо смените
> `TICKET_SIGNING_KEY` и пароль БД. См. [SECURITY.md](../../SECURITY.md).
```bash
# из этого репозитория (compose + docker/tls/)
docker compose -f docker-compose.release.yml pull
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
```
Закрепите версию:
```bash
IMAGE_TAG=0.1.0 docker compose -f docker-compose.release.yml up -d
```
Make-цели (git checkout):
```bash
make release-up
make release-seed PROFILE=small
```
| Порт хоста | Сервис |
|---|---|
| `8006` | HTTPS API + Web UI через лабораторный TLS-шлюз (как у реального PVE) |
| `5432` | PostgreSQL (только localhost) |
Миграции выполняются автоматически через одноразовый сервис `migrate`.
Далее переходите к разделу [Дождитесь готовности](#2-дождитесь-готовности).
## 1b. Checkout для разработки
```bash
make install
make up
```
Сервисы:
| Порт хоста | Сервис |
|---|---|
| `8006` | HTTPS API + Web UI через nginx TLS-шлюз (как у реального PVE) |
| `5432` | PostgreSQL (только localhost) |
У реального Proxmox VE REST API доступен **только** как
`https://<host>:8006/api2/json/...`. Лаборатория публикует то же: HTTPS на
хосте `:8006` через development TLS-шлюз; см.
[Порты и TLS](configuration.md#порты-и-tls). Хост **`:8007` не используется**
(на железе это обычно PBS, не API PVE).
Миграции применяются автоматически до того, как симулятор станет готов.
## 2. Дождитесь готовности
```bash
curl -sS http://localhost:8006/health/live
curl -sS http://localhost:8006/health/ready
```
`/health/ready` возвращает HTTP 503, пока PostgreSQL недоступен **и** не применена
последняя упакованная миграция.
## 3. Загрузите профиль seed
```bash
make seed PROFILE=small
```
`small` создаёт узел `pve01`, две QEMU-гостевые ВМ (`100`, `101`), один LXC (`200`),
локальные хранилища и стандартных development-принципалов. Другие размеры — в
[Профилях seed](seed-profiles.md).
## 4. Проверьте версию API
```bash
curl -sS http://localhost:8006/api2/json/version | jq .
```
При холодном старте контракт по умолчанию — встроенный снимок PVE **9.2.3** в Docker
Compose. Переключайте мажорные версии 6–9 из Web UI или через
[Версии API](api-versions.md).
## 5. Пройдите аутентификацию
```bash
curl -sk -X POST \
-d 'username=root@pam&password=secret' \
http://localhost:8006/api2/json/access/ticket | jq .
```
Сохраните `ticket` и `CSRFPreventionToken` из `data`. Для мутаций отправляйте:
- Cookie: `PVEAuthCookie=<ticket>`
- Header: `CSRFPreventionToken: <token>`
Подробнее: [Аутентификация](authentication.md).
## 6. Получите список гостей и запустите одного
```bash
# замените TICKET / CSRF из предыдущего ответа
curl -sk -H "Cookie: PVEAuthCookie=$TICKET" \
http://localhost:8006/api2/json/nodes/pve01/qemu | jq .
curl -sk -X POST \
-H "Cookie: PVEAuthCookie=$TICKET" \
-H "CSRFPreventionToken: $CSRF" \
http://localhost:8006/api2/json/nodes/pve01/qemu/100/status/start | jq .
```
Асинхронные операции возвращают строку UPID. Опрашивайте, пока задача не завершится:
```bash
curl -s -H "Cookie: PVEAuthCookie=$TICKET" \
"http://localhost:8006/api2/json/nodes/pve01/tasks/${UPID}/status" | jq .
```
## 7. Откройте Web UI
Перейдите на [http://localhost:8006/](http://localhost:8006/) — интерактивная
консоль, каталог контрактов (PVE 6–9), представление совместимости, применение runtime-
контракта и управление demo-кластером. Скриншоты светлой/тёмной темы и полный список
возможностей — в [Web UI](web-ui.md).
## 8. Попробуйте клиентскую библиотеку
```bash
# из корня репозитория после make up + seed
python examples/python/proxmoxer_cookbook.py
```
Другие стеки: [Клиенты](clients.md) и [`examples/`](../../examples/README.ru.md).
## Готово, когда…
- `/health/ready` возвращает `{"status":"ok"}` (или эквивалентное OK-тело)
- `/api2/json/version` сообщает активную версию контракта
- Вход по тикету для `root@pam` успешен
- `nodes/pve01/qemu` перечисляет seeded ВМ
- Хотя бы один путь power или create возвращает UPID, который успешно завершается
## Дальнейшие шаги
- [Конфигурация](configuration.md) — env vars, workers, путь к контракту
- [Версии API](api-versions.md) — горячая замена мажоров 6–9
- [Клиенты](clients.md) — Ansible, Terraform, Pulumi, Go, Java, Perl
- [Эксплуатация](operations.md) — reseed, migrate, обновления
+190
View File
@@ -0,0 +1,190 @@
**Language / Язык:** [English](../kubernetes.md) | [Русский](kubernetes.md)
# Kubernetes / Helm
Разверните опубликованный runtime-образ Docker Hub с chart из
[`helm/proxmox-api-simulator`](../../helm/proxmox-api-simulator).
Образ: [`inecs/proxmox-api-simulator`](https://hub.docker.com/r/inecs/proxmox-api-simulator)
> **Только лаборатория / CI.** В defaults чарта слабые placeholder-секреты.
> Перед shared или Internet-facing установкой всегда переопределяйте
> `secret.ticketSigningKey` и `postgresql.auth.password`. См.
> [SECURITY.md](../../SECURITY.md).
## Транспорт (Compose vs Helm)
| Путь | URL клиента |
|---|---|
| Локальный Compose (`docker-compose*.yml`) | **HTTP** `:8006` (процесс симулятора) |
| Helm Service / `kubectl port-forward` | **HTTP** `:8006` (процесс симулятора; TLS на Ingress, если включён) |
| Helm Ingress + cert-manager | **HTTPS** на вашем hostname |
## Предварительные требования
- Kubernetes 1.27+ (или сопоставимый)
- Helm 3.14+
- [Ingress NGINX](https://kubernetes.github.io/ingress-nginx/) (или другой
IngressClass с поддержкой HTTP-01)
- [cert-manager](https://cert-manager.io/) установлен cluster-wide
Пример установки cert-manager:
```bash
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.yaml
```
## Быстрая установка (Hub release + Ingress + Let's Encrypt)
Из git checkout этого репозитория:
```bash
helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
-n proxmox-sim --create-namespace \
-f ./helm/proxmox-api-simulator/values-ingress-example.yaml \
--set certManager.email=you@example.com \
--set 'ingress.hosts[0].host=pve-sim.example.com' \
--set 'ingress.tls[0].hosts[0]=pve-sim.example.com' \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set postgresql.auth.password="$(openssl rand -hex 16)"
```
Что это делает:
1. Подтягивает `inecs/proxmox-api-simulator:0.1.0` (см. `image.tag` в example
file).
2. Устанавливает bundled PostgreSQL 17 (`postgres:17.5-bookworm`, как в Compose).
3. Запускает миграции схемы в init container (идемпотентно).
4. Засеивает lab profile `small` (`seed.enabled=true`).
5. Создаёт ресурсы `ClusterIssuer`:
- `letsencrypt-prod`
- `letsencrypt-staging`
6. Создаёт Ingress с
`cert-manager.io/cluster-issuer: letsencrypt-prod` и TLS secret
`proxmox-api-simulator-tls`.
DNS для `pve-sim.example.com` должен указывать на ваш Ingress controller. Затем:
```bash
kubectl -n proxmox-sim get certificate,ingress,pods
# wait until Certificate READY=True
curl -sS https://pve-sim.example.com/health/ready
open https://pve-sim.example.com/
```
Логин по умолчанию после seed: `root@pam` / `secret`.
### Сначала staging (рекомендуется)
Проверьте HTTP-01 без production rate limits:
```bash
helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
-n proxmox-sim --create-namespace \
-f ./helm/proxmox-api-simulator/values-ingress-example.yaml \
--set certManager.email=you@example.com \
--set certManager.useStaging=true \
--set 'ingress.hosts[0].host=pve-sim.example.com' \
--set 'ingress.tls[0].hosts[0]=pve-sim.example.com' \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set postgresql.auth.password="$(openssl rand -hex 16)"
```
Браузеры не доверяют staging CA — при тестировании используйте `curl -k`.
Переключите `certManager.useStaging=false` и пересоздайте Certificate/TLS secret
для production.
## Минимальная установка (ClusterIP + port-forward)
```bash
helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
-n proxmox-sim --create-namespace \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set seed.enabled=true
kubectl -n proxmox-sim port-forward svc/pve-sim-proxmox-api-simulator 8006:8006
```
Откройте http://127.0.0.1:8006/ (обычный HTTP — чарт не включает TLS-шлюз из
Compose; для HTTPS используйте Ingress).
## Внешний PostgreSQL
```bash
helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
-n proxmox-sim --create-namespace \
--set postgresql.enabled=false \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set secret.databaseUrl='postgresql://user:pass@pg.example.com:5432/proxmox_simulator'
```
Или используйте `secret.existingSecret` с ключами `DATABASE_URL` и
`TICKET_SIGNING_KEY`.
## Как работает выпуск TLS
Когда `certManager.enabled=true` и `certManager.createClusterIssuer=true`, chart
создаёт ACME `ClusterIssuer`, решающие HTTP-01 через ваш Ingress class. Шаблон
Ingress добавляет:
```yaml
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- secretName: proxmox-api-simulator-tls
hosts: [pve-sim.example.com]
```
cert-manager затем создаёт `Certificate`, завершает HTTP-01 и сохраняет пару
ключей Let's Encrypt в этом TLS secret. Chart **не** устанавливает cert-manager
и Ingress controller — только issuers и Ingress wiring.
Если ClusterIssuers уже существуют cluster-wide, задайте:
```yaml
certManager:
enabled: true
createClusterIssuer: false
issuerName: your-existing-issuer
```
## Локальная проверка chart
Из корня репозитория (нужен Helm 3.14+):
```bash
make helm-lint
make helm-template
```
`helm lint` должен завершаться без failures (информационное замечание про
отсутствие `icon` в Chart.yaml ожидаемо). `helm template` рендерит Deployment
(по умолчанию с migrate initContainer), Service, Secret, PostgreSQL
StatefulSet, опциональный отдельный migrate Job (`migrate.asJob`), seed Job,
Ingress и ClusterIssuers.
## Эксплуатация
```bash
# logs
kubectl -n proxmox-sim logs -l app.kubernetes.io/name=proxmox-api-simulator -c simulator -f
# reseed
kubectl -n proxmox-sim exec deploy/pve-sim-proxmox-api-simulator -- \
python -m app.simulation.seed_cli
# SEED_PROFILE via: kubectl set env ... or --set seed.profile=medium and upgrade
# uninstall
helm -n proxmox-sim uninstall pve-sim
```
## Справочник values
См. [`helm/proxmox-api-simulator/values.yaml`](../../helm/proxmox-api-simulator/values.yaml)
и README chart. Связанная документация:
- [Начало работы](getting-started.md) — пути Compose
- [Эксплуатация](operations.md) — публикация Docker Hub / release compose
- [Безопасность](security.md) — учётные данные лаборатории и граница доверия
+43
View File
@@ -0,0 +1,43 @@
**Language / Язык:** [English](../observability.md) | [Русский](observability.md)
# Наблюдаемость
## Health
| Путь | Назначение |
|---|---|
| `GET /health/live` | Liveness процесса |
| `GET /health/ready` | База доступна **и** миграции актуальны; HTTP 503 при невыполнении |
Пример:
```bash
curl -s http://localhost:8006/health/live
curl -s http://localhost:8006/health/ready
```
## Корреляция запросов
Входящие запросы принимают или генерируют ID через `REQUEST_ID_HEADER`
(по умолчанию `X-Request-ID`). Структурированные логи включают поля корреляции и
редактируют известные шаблоны секретов.
## Метрики / трейсинг
В текущем приложении **нет** scrape-эндпоинта Prometheus `/metrics` и **нет**
встроенного экспортёра OpenTelemetry. Архитектурные заметки, где они упоминаются,
описывают целевой дизайн, а не поставляемую телеметрию.
Не путайте пути Proxmox API под `/cluster/metrics` с телеметрией процесса
симулятора — эти обработчики симулируют состояние конфигурации metrics-server PVE
внутри PostgreSQL.
## Evidence совместимости
Операционные отчёты совместимости:
- `/admin/compatibility`
- `/admin/compatibility.md`
- `/admin/compatibility.html`
Также доступны через панель совместимости Web UI.
+157
View File
@@ -0,0 +1,157 @@
**Language / Язык:** [English](../operations.md) | [Русский](operations.md)
# Эксплуатация
## Команды day-2
```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 PROFILE=small # atomic reseed
make shell # interactive tools container
```
## Миграции
Упорядоченные SQL-файлы применяются транзакционно и записывают SHA-256
checksum. Повторный запуск `make db-migrate` безопасен. Изменение уже
применённой миграции отклоняется. `/health/ready` остаётся недоступным, пока
не применена последняя упакованная миграция. Воркеры задач повторяют захват
после того, как миграции догонят актуальное состояние.
## Reseed
```bash
make seed PROFILE=medium
```
Reseed заменяет изменяемое состояние симуляции. Внешнее состояние автоматизации
(Terraform state files, Pulumi stacks, Ansible inventories с закодированными
VMID) может после этого рассинхронизироваться — обновите или пересоздайте эти
боковые каналы.
## Восстановление воркеров
Воркеры используют аренды PostgreSQL. После сбоя или перезапуска просроченные
аренды перехватываются, а незавершённая работа может безопасно продолжиться.
Настраиваемые параметры: `TASK_WORKER_CONCURRENCY`, `TASK_LEASE_SECONDS`,
`SIMULATION_TIME_SCALE`.
## Смена API major по умолчанию
1. Предпочтительно задайте `CONTRACT_SNAPSHOT` на нужный bundled/normalized
snapshot для холодного старта (Compose / k8s / OpenShift).
2. Используйте Web UI apply или `POST /ui/api/contract/apply?major=N` для
временных переключений в пределах процесса.
## Резервное копирование состояния лаборатории
PostgreSQL — система записи. Используйте обычное резервное копирование и
восстановление Postgres (pg_dump / снимки томов), если нужно сохранить
засеянную лабораторию. Контейнеры приложения одноразовые, пока сохранён том БД.
## Публикация в Docker Hub
`make release` собирает **runtime**-образ (production target — не локальный
bind-mounted образ `dev`) и публикует его в Docker Hub:
```bash
docker login # once; account must own or can push to DOCKERHUB_USER
make release
```
Значения по умолчанию:
| Переменная | По умолчанию | Назначение |
|---|---|---|
| `DOCKERHUB_USER` | `inecs` | Namespace/org в Docker Hub |
| `IMAGE_NAME` | `proxmox-api-simulator` | Имя репозитория |
| `VERSION` | from `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 # build/tag locally without pushing
```
Опубликованные теги:
- `inecs/proxmox-api-simulator:<version>`
- `inecs/proxmox-api-simulator:latest` (если не `PUSH_LATEST=0`)
После публикации при необходимости вставьте
[обзор Docker Hub](../docker-hub-overview.md) в описание репозитория Hub и
держите GitHub About в одном стиле («stateful Proxmox VE API simulator», а не
тонкий mock).
CI в GitHub Actions на каждый push/PR в `main` запускает `make ci` и проверку
Compose/Helm (см. `.github/workflows/ci.yml`).
## Быстрый старт с опубликованным compose-файлом
[`docker-compose.release.yml`](../../docker-compose.release.yml) подтягивает
runtime-образ из Hub и запускает PostgreSQL + migrate + simulator:
```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 http://localhost:8006/health/ready
open http://localhost:8006/
```
Вспомогательные команды из git checkout:
```bash
make release-up
make release-seed PROFILE=small
make release-down
```
Полезные переопределения:
| Переменная | По умолчанию | Назначение |
|---|---|---|
| `DOCKER_IMAGE` | `inecs/proxmox-api-simulator` | Репозиторий образа |
| `IMAGE_TAG` | `latest` | Тег для pull |
| `SIMULATOR_PORT` | `8006` | HTTPS-порт на хосте (TLS-шлюз) |
| `TICKET_SIGNING_KEY` | lab default | Меняйте вне игрушечных лаб |
| `POSTGRES_PASSWORD` | `proxmox` | Пароль БД |
Development и release Compose публикуют **HTTPS `:8006`** на хосте через nginx
TLS-шлюз (тот же порт, что у реального PVE). Процесс симулятора остаётся HTTP
на `:8006` внутри Docker-сети. См.
[Порты и TLS](configuration.md#порты-и-tls).
Для Kubernetes с публичным TLS (cert-manager / Let's Encrypt) используйте Helm
chart — см. [Kubernetes / Helm](kubernetes.md).
## Обновления
1. Подтяните / пересоберите образы (`make install` / `make docker-build` по
необходимости).
2. Выполните миграции.
3. Подтвердите `/health/ready`.
4. Повторно проверьте `/admin/compatibility` и `/api2/json/version`.
5. Повторно запустите `make test-compatibility`, если в CI проверяете внешних
клиентов (засеивает профиль **medium**`pve1`/`pve2`/`pve3` — для migration
smoke).
## Сброс лаборатории
```bash
make seed PROFILE=small
# or via UI: unload demo → minimal, then seed again
```
Для жёсткого сброса БД используйте `make db-reset` (разрушительно — см. help
Makefile).
+48
View File
@@ -0,0 +1,48 @@
**Language / Язык:** [English](../security.md) | [Русский](security.md)
# Безопасность
Политика репозитория и репортинг: [SECURITY.md](../../SECURITY.md).
## Модель угроз лаборатории
Этот проект — **локальный / CI лабораторный симулятор**. Он не закалён как
multi-tenant публичный сервис Proxmox. Учётные данные по умолчанию, demo-контролы UI
и эндпоинты совместимости удобны для разработки и намеренно открыты в стандартном
Compose-стеке.
Не выставляйте порт `8006` в недоверенные сети без дополнительных мер,
которые вы обеспечите сами. Хост `:8006` — lab HTTPS API-шлюз (у реального PVE
на этом порту HTTPS). Хост **`:8007` этим стеком не используется** (на железе
обычно PBS). См. [Порты и TLS](configuration.md#порты-и-tls).
## Учётные данные и секреты
- Пароли и секреты API-токенов хранятся как scrypt-хеши.
- Значения тикетов подписываются HMAC и краткоживущие.
- CSRF привязывает мутации к сессиям по тикету.
- Логи редактируют распознанные представления тикетов, паролей и токенов.
- Ответы create/regenerate токена показывают секрет один раз; GET его никогда не
выводит.
Меняйте `TICKET_SIGNING_KEY` для любой общей лаборатории. Замените seeded-пароли и
токены перед демонстрацией другим людям.
## TLS-материалы
`docker/tls/` содержит встроенный self-signed сертификат для локального шлюза. Он
нужен, чтобы неизменённые TLS-клиенты (например, proxmoxer) могли подключаться.
**Никогда** не переиспользуйте эти файлы в production.
## Администрирование симулятора
Сейчас **нет** отдельно аутентифицированной control plane `/_simulator`.
Helper-маршруты Web UI под `/ui/api/*` и `/admin/compatibility*` доступны, когда
процесс достижим. Считайте границей доверия сетевую экспозицию.
## Симулированные внешние системы
LDAP sync stamps, pending-состояние OpenID, ACME и эндпоинты Ceph сохраняют только
локальное состояние симулятора. Они не открывают реальные подключения к внешним IdP
или кластерам. Не полагайтесь на симулятор для тестирования защиты от утечки
учётных данных к реальным провайдерам.
+67
View File
@@ -0,0 +1,67 @@
**Language / Язык:** [English](../seed-profiles.md) | [Русский](seed-profiles.md)
# Профили seed
Seed **атомарно** заменяет изменяемое состояние симуляции и использует
детерминированные UUIDv5-идентификаторы для воспроизводимости лабораторий.
```bash
make seed PROFILE=small
```
## Профили
| Профиль | Содержимое (кратко) |
|---|---|
| `minimal` | Один узел `pve01`, storage `local` + `local-lvm`. Используется после demo unload в Web UI. |
| `small` | Один узел, QEMU `100`/`101`, LXC `200`, storage, завершённые задачи, полный набор identity. |
| `medium` | Узлы `pve1`/`pve2`/`pve3`, 50 QEMU, 20 LXC, per-node `local-pveN` + storage `shared`, development pool, больше задач. |
| `large` | Настраиваемые узлы/ресурсы (`SEED_LARGE_NODES`, `SEED_LARGE_RESOURCES`, по умолчанию 10 000 гостей). |
| `ha-demo` | `medium` плюс HA resource wiring для VM 100. |
| `broken-storage` | `small` с offline `local-lvm` / симулированной I/O ошибкой. |
| `demo-cluster` | Крупный enterprise-набор для UI (много узлов/гостей/Ceph/HA/history). Предпочтительно загружать через demo-контролы Web UI. |
Каждый профиль seed'ит только durable-состояние — обработчики читают/пишут PostgreSQL и
**не** подмешивают catalog/template defaults на GET:
- `clusters.metadata`: firewall (scopes + macros), SDN, notifications (+ matcher
catalogs), ACME (accounts/plugins/directories/schema), mappings, replication
(+ logs), metrics (servers + export), jobs, HA (`ha` / `ha_groups` / `ha_rules`
+ status), Ceph (+ pools/cmd_safety), QEMU CPU flags/models, cluster options/config, quorate
- `nodes.metadata.ops`: network, disks, apt, services, hardware, scan, subscription,
dns/time/config/status/ip, certificates, capabilities, hosts, journal/syslog/netstat,
report/rrd/rrddata, oci_tags, cluster_status, node Ceph, aplinfo, vzdump defaults
- guest `resources.state` (via `enrich_guest_state`): agent results/files, rrd/rrddata,
migrate_preconditions, LXC interfaces, cloudinit dump
- storage `storages.config` (via `enrich_storage_state`): rrd/rrddata, file_restore,
import_metadata, identity
## Примеры
```bash
make seed PROFILE=small
make seed PROFILE=medium
make seed PROFILE=ha-demo
make seed PROFILE=broken-storage
make seed PROFILE=large
make seed PROFILE=minimal
# demo-cluster большой; для интерактива предпочтительна загрузка demo в Web UI
make seed PROFILE=demo-cluster
```
## Demo-кластер через UI
Интерактивная консоль может загружать и выгружать demo-набор данных:
- `POST /ui/api/demo/load`
- `POST /ui/api/demo/unload` — стирает состояние, созданное через API, затем загружает `minimal`
- `GET /ui/api/demo/state`
Эти helper-эндпоинты UI ориентированы на разработку и сегодня не аутентифицируются
отдельно. Считайте их только лабораторными контролами.
## Reseed vs состояние клиента
Terraform, Pulumi и Ansible могут по-прежнему хранить resource state после reseed.
Обновите или destroy/recreate внешнее состояние после замены содержимого симуляции в
PostgreSQL. См. [Эксплуатация](operations.md) и client cookbook'и.
+66
View File
@@ -0,0 +1,66 @@
**Language / Язык:** [English](../troubleshooting.md) | [Русский](troubleshooting.md)
# Устранение неполадок
## Ready остаётся недоступным
1. Проверьте Postgres: `make logs` / health в Compose.
2. Выполните `make db-migrate`.
3. Снова вызовите `/health/ready`.
Workers могут повторять попытки, пока миграции не догонят после позднего migrate.
## Неожиданный HTTP 501
У объявленных методов на мажорах **69** должны быть обработчики. Если видите 501:
- Подтвердите активный runtime (`/api2/json/version` и метка runtime в Web UI).
- Убедитесь, что вызываете path/verb точно как объявлено для этого мажора.
- Проверьте, что `CONTRACT_FALLBACK` в режиме fixture не маскирует другую проблему.
- Сообщите о регрессии — ожидается полное покрытие реестра.
## 401 / 403
- Тикет истёк или cookie не отправлена.
- Мутация без `CSRFPreventionToken` в сессии по тикету.
- API-токен с неверным форматом (`PVEAPIToken=user@realm!id=secret`).
- Отказ ACL (сравните `auditor@pve` и `root@pam`).
## Задача никогда не завершается
- Изучите `/nodes/{node}/tasks/{upid}/status` и `/log`.
- Проверьте логи workers (`make logs`).
- Убедитесь, что `TASK_WORKER_CONCURRENCY` > 0 и аренды в базе можно забрать.
- Очень высокий `SIMULATION_TIME_SCALE` даёт необычные замедления (больше = быстрее
симуляция); чаще виноваты неверно заданные worker leases.
## proxmoxer / сбои TLS
- Реальный PVE использует **HTTPS `:8006`**. К этой лаборатории TLS-клиенты
ходят на порт хоста **8006** (development-шлюз) с отключённой проверкой
локального self-signed cert.
- Хост **`:8007` этим стеком не используется** (на железе обычно PBS).
- `verify_ssl=False` **только** для локального self-signed cert.
- Внутри Compose цель — `tls-gateway:8443`.
- Seeded-имя узла для `small``pve01`, а не `pve1`.
- Профили `medium` / `ha-demo` используют **`pve1` / `pve2` / `pve3`**.
- Карта портов: [Порты и TLS](configuration.md#порты-и-tls).
## Drift Terraform / Pulumi после reseed
Reseed заменяет гостей в PostgreSQL; state-файлы инструментов — нет. Refresh, import
или пересборка стеков после `make seed`.
## Hot-swap «ничего не сделал»
- Просмотр каталога ≠ apply. Используйте **Apply as runtime** или
`POST /ui/api/contract/apply?major=N`.
- Подтвердите через `/api2/json/version`.
- Помните: apply локален для процесса; перезапуск Compose восстанавливает
`CONTRACT_SNAPSHOT`.
## Demo unload удивил
`POST /ui/api/demo/unload` очищает состояние, созданное через API, и загружает
`minimal`. Повторите `make seed PROFILE=small` (или снова загрузите demo), чтобы
восстановить более богатые фикстуры.
+64
View File
@@ -0,0 +1,64 @@
**Language / Язык:** [English](../web-ui.md) | [Русский](web-ui.md)
# Web UI
Откройте [http://localhost:8006/](http://localhost:8006/) после `make up`.
UI — лабораторная консоль симулятора, а не полноценный интерфейс управления Proxmox VE.
Поддерживаются светлая и тёмная темы, мажорные версии PVE **69**, редактирование
запросов/ответов, история и runtime apply контракта.
## Скриншоты
Светлая тема — `GET /cluster/resources` на PVE 9.2.3:
![Web UI light theme](../images/web-ui-light.png)
Тёмная тема — та же консоль с переключателем темы:
![Web UI dark theme](../images/web-ui-dark.png)
## Возможности
- Дерево эндпоинтов и выбор метода по выбранному мажору каталога
- Параметры и примеры payload, производные от контракта
- Редактор запросов, просмотр ответов и история
- Вход по паролю с обработкой cookie + CSRF
- Сводка окружения (runtime-версия, узлы, гости, storage)
- Превью curl / запросов
- Каталог API PVE **69** с покрытием реализации
- **Apply as runtime** — горячая замена активного контракта
- Представления совместимости и готовности
- Загрузка / выгрузка / обновление demo-кластера
- Монитор задач UPID (кнопка в шапке → status / log / «From last response»;
для опросов задач нужна аутентификация)
- Ссылка на OpenAPI по `/docs`
## Backend-хелперы
| Method | Path | Назначение |
|---|---|---|
| GET | `/ui/api/versions` | Мажорные версии каталога vs 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` | Горячая замена runtime-контракта |
| GET | `/ui/api/demo/state` | Состояние demo-набора данных |
| POST | `/ui/api/demo/load` | Загрузить `demo-cluster` |
| POST | `/ui/api/demo/unload` | Выгрузить → `minimal` |
## Workflow версий
1. Выберите мажор **6 / 7 / 8 / 9** в каталоге.
2. Изучите методы и покрытие.
3. **Apply as runtime**, когда нужно, чтобы живые маршруты `/api2/*` соответствовали
этому мажору.
4. Подтвердите через `/api2/json/version` и `/admin/compatibility`.
Горячая замена только в памяти; перезапуск восстанавливает `CONTRACT_SNAPSHOT`.
Подробнее: [Версии API](api-versions.md).
## Замечание по безопасности
UI и demo-эндпоинты предназначены для локальной разработки. В текущей сборке они не
защищены отдельным admin-токеном. Не выставляйте порт симулятора в недоверенные сети.
+12 -5
View File
@@ -1,5 +1,9 @@
**Language / Язык:** [English](security.md) | [Русский](ru/security.md)
# Security
Repository policy and reporting: [SECURITY.md](../SECURITY.md).
## Lab threat model
This project is a **local / CI laboratory simulator**. It is not hardened as a
@@ -7,8 +11,10 @@ multi-tenant public Proxmox 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 `8006` / `8007` to untrusted networks without additional
controls you supply yourself.
Do not expose port `8006` to untrusted networks without additional controls you
supply yourself. Host `:8006` is plain HTTP in Compose (real PVE uses HTTPS on
that port). Host `:8007` is **not** used by this stack (on hardware it is
typically PBS). See [Ports and TLS](configuration.md#ports-and-tls).
## Credentials and secrets
@@ -23,9 +29,10 @@ tokens before demoing to others.
## TLS materials
`docker/tls/` contains a checked-in self-signed certificate for the local
gateway. It exists so unmodified TLS clients (e.g. proxmoxer) can connect.
**Never** reuse these files in production.
`docker/tls/` contains a checked-in self-signed certificate for the optional
Compose TLS gateway (`--profile tls` on `:8443`). It exists so unmodified TLS
clients (e.g. proxmoxer) can connect when that profile is enabled. **Never**
reuse these files in production.
## Simulator administration
+22 -1
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](seed-profiles.md) | [Русский](ru/seed-profiles.md)
# Seed profiles
Seeds replace mutable simulation state **atomically** and use deterministic
@@ -13,12 +15,28 @@ make seed PROFILE=small
|---|---|
| `minimal` | One node `pve01`, `local` + `local-lvm` storage. Used after Web UI demo unload. |
| `small` | One node, QEMU `100`/`101`, LXC `200`, storages, completed tasks, full identity set. |
| `medium` | Three nodes, 50 QEMU, 20 LXC, local + shared storage, development pool, more tasks. |
| `medium` | Nodes `pve1`/`pve2`/`pve3`, 50 QEMU, 20 LXC, per-node `local-pveN` + storage `shared`, development pool, more tasks. |
| `large` | Configurable nodes/resources (`SEED_LARGE_NODES`, `SEED_LARGE_RESOURCES`, default 10000 guests). |
| `ha-demo` | `medium` plus HA resource wiring for VM 100. |
| `broken-storage` | `small` with `local-lvm` offline / simulated I/O error. |
| `demo-cluster` | Large UI-oriented enterprise dataset (many nodes/guests/Ceph/HA/history). Prefer loading via the Web UI demo controls. |
Every profile seeds durable state only — handlers read/write PostgreSQL and do not
inject catalog/template defaults on GET:
- `clusters.metadata`: firewall (scopes + macros), SDN, notifications (+ matcher
catalogs), ACME (accounts/plugins/directories/schema), mappings, replication
(+ logs), metrics (servers + export), jobs, HA (`ha` / `ha_groups` / `ha_rules`
+ status), Ceph (+ pools/cmd_safety), QEMU CPU flags/models, cluster
options/config, quorate
- `nodes.metadata.ops`: network, disks, apt, services, hardware, scan, subscription,
dns/time/config/status/ip, certificates, capabilities, hosts, journal/syslog/netstat,
report/rrd/rrddata, oci_tags, cluster_status, node Ceph, aplinfo, vzdump defaults
- guest `resources.state` (via `enrich_guest_state`): agent results/files, rrd/rrddata,
migrate_preconditions, LXC interfaces, cloudinit dump
- storage `storages.config` (via `enrich_storage_state`): rrd/rrddata, file_restore,
import_metadata, identity
## Examples
```bash
@@ -27,6 +45,9 @@ make seed PROFILE=medium
make seed PROFILE=ha-demo
make seed PROFILE=broken-storage
make seed PROFILE=large
make seed PROFILE=minimal
# demo-cluster is large; prefer Web UI demo load for interactive use
make seed PROFILE=demo-cluster
```
## Demo cluster via UI
+10 -3
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](troubleshooting.md) | [Русский](ru/troubleshooting.md)
# Troubleshooting
## Ready stays unavailable
@@ -34,10 +36,15 @@ Declared methods on majors **69** should have handlers. If you see 501:
## proxmoxer / TLS failures
- Use host port **8007** (gateway), not 8006, for TLS clients.
- Set `verify_ssl=False` **only** for the local self-signed cert.
- Inside Compose, target `tls-gateway:8443`.
- Compose default is plain **HTTP `:8006`**. proxmoxer is HTTPS-only — enable
`docker compose --profile tls` and use `https://localhost:8443/` with
`verify_ssl=False` for the lab self-signed cert.
- Inside Compose, target `tls-gateway:8443` when the `tls` profile is on.
- Host `:8007` is **not** used by this stack (on hardware it is usually PBS).
- On Kubernetes, use your Ingress HTTPS hostname (cert-manager).
- Seeded node name for `small` is `pve01`, not `pve1`.
- Profiles `medium` / `ha-demo` use **`pve1` / `pve2` / `pve3`**.
- Port map: [Ports and TLS](configuration.md#ports-and-tls).
## Terraform / Pulumi drift after reseed
+4
View File
@@ -1,3 +1,5 @@
**Language / Язык:** [English](web-ui.md) | [Русский](ru/web-ui.md)
# Web UI
Open [http://localhost:8006/](http://localhost:8006/) after `make up`.
@@ -28,6 +30,8 @@ Dark theme — same console with theme toggle:
- **Apply as runtime** hot-swap for the active contract
- Compatibility and readiness views
- Demo-cluster load / unload / refresh
- UPID task monitor (header control → status / log / “From last response”;
requires login for authenticated task polls)
- Link to OpenAPI at `/docs`
## Backend helpers