Initial release of the oVirt/RHV Engine API simulator.

Stateful FastAPI lab with contract packs, Compose/Helm, Docker Hub release
targets, and Pulumi coverage across all Engine series (GET/POST/PUT/DELETE/HEAD).
This commit is contained in:
2026-07-18 04:49:28 +03:00
commit cbd0adca91
218 changed files with 246804 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
**Language / Язык:** [English](README.md) | [Русский](ru/README.md)
# Documentation
Guides for the oVirt / RHV Engine 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 |
| [Ports](ports.md) | Published Engine + UI ports |
| [Configuration](configuration.md) | Environment variables and Compose |
| [Authentication](authentication.md) | Basic auth, OAuth2, sessions |
| [API versions](api-versions.md) | Series packs 3.x / 4.x and Version header |
| [API coverage](api_coverage.md) | Operation counts and deltas per series |
| [API surface](api-surface.md) | Routing, handlers, schema engine |
| [Clients & examples](clients.md) | curl, Python, Ansible, Terraform |
| [Seed profiles](seed-profiles.md) | `minimal` and `demo` fixtures |
| [Domains](domains/README.md) | VMs, hosts, storage, networks, identity, jobs |
| [Web UI](web-ui.md) | Interactive console and catalogs |
| [Operations](operations.md) | Migrate, reseed, upgrade |
| [Kubernetes / Helm](kubernetes.md) | Cluster install (Service `:8080`) |
| [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 |
Runnable cookbooks: [`examples/`](../examples/README.md).
Integration suites: [`pulumi-tests/`](../pulumi-tests/README.md).
Contract packs: [`contracts/`](../contracts/README.md).
+30
View File
@@ -0,0 +1,30 @@
**Language / Язык:** [English](api-surface.md) | [Русский](ru/api-surface.md)
# API surface
Entry points:
| Path | Role |
|---|---|
| `/ovirt-engine/api` | Engine REST root (v4 default on 4.x series) |
| `/ovirt-engine/api/v3``/v4` | Explicit API major |
| `/ovirt-engine/sso/oauth/*` | SSO OAuth2 |
| `/health/live`, `/health/ready` | Liveness / readiness |
| `/` (UI port) | Web console |
## Routing model
1. Contract routes from the active `contracts/ovirt/<series>` pack are registered
as individual OpenAPI operations.
2. Specialized semantic handlers persist inventory mutations (VMs, disks, hosts,
networks, storage domains, jobs, …).
3. A catch-all Engine router remains as a hidden fallback for remaining
collections via the schema engine.
Packs live under [`contracts/ovirt/`](../contracts/README.md). Coverage table:
[api_coverage.md](api_coverage.md). Domain guides: [domains/](domains/README.md).
## Representations
Request/response bodies may be JSON or XML depending on `Accept` /
`Content-Type`. Prefer `Accept: application/json` for modern clients.
+82
View File
@@ -0,0 +1,82 @@
**Language / Язык:** [English](api-versions.md) | [Русский](ru/api-versions.md)
# API versions (series packs)
The simulator ships Engine series packs under `contracts/ovirt/`:
| Series | API major | Cold-start env |
|---|---|---|
| `3.0``3.6` | v3 | `OVIRT_SERIES=3.6` |
| `4.3` | v4 | `OVIRT_SERIES=4.3` |
| `4.4` | v4 | `OVIRT_SERIES=4.4` |
| `4.5` | v4 | `OVIRT_SERIES=4.5` (default) |
| `master` | v4 | `OVIRT_SERIES=master` |
Operation counts and deltas: [API coverage](api_coverage.md).
## Selecting the API major (v3 / v4)
Clients can select the Engine API major in two ways:
1. **Path prefix:** `/ovirt-engine/api/v3/...` or `/ovirt-engine/api/v4/...`
2. **`Version` header:** `Version: 3` or `Version: 4` on `/ovirt-engine/api/...`
If neither is set, the default follows the active series (`3` for `3.x`, `4` for
`4.x` / `master`).
```bash
curl -k -u 'admin@internal:secret' \
-H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/vms
curl -k -u 'admin@internal:secret' \
-H 'Accept: application/xml' \
https://127.0.0.1/ovirt-engine/api/v3/vms
```
## Cold start
```bash
OVIRT_SERIES=4.4 docker compose up -d --build --wait
```
Helm:
```bash
--set config.ovirtSeries=3.6
```
## Hot-swap (in-memory)
Without recreating containers, activate another pack from the Web UI Environment
drawer or:
```bash
curl -s http://127.0.0.1:5000/ui/api/ovirt/contracts/activate \
-H 'Content-Type: application/json' \
-d '{"series":"4.4"}'
```
A process restart restores cold-start `OVIRT_SERIES`. Details: [Web UI](web-ui.md).
## Representations
Engine responses support **JSON** and **XML** via `Accept` /
`Content-Type` (`application/json`, `application/xml`).
## Pack layout
```
contracts/ovirt/<series>/
api.json
manifest.json
deltas.json
```
Regenerate:
```bash
make generate-packs
```
Index: [`contracts/ovirt/index.json`](../contracts/ovirt/index.json).
+26
View File
@@ -0,0 +1,26 @@
**Language / Язык:** [English](api_coverage.md) | [Русский](ru/api_coverage.md)
# API coverage
Contract pack operation counts (from `contracts/ovirt/*/manifest.json`):
| Series | API | Operations | Deltas (added / removed) |
|---|---|---:|---|
| 3.0 | v3 | 468 | 468 / 0 |
| 3.1 | v3 | 498 | 30 / 0 |
| 3.2 | v3 | 506 | 8 / 0 |
| 3.3 | v3 | 576 | 70 / 0 |
| 3.4 | v3 | 598 | 22 / 0 |
| 3.5 | v3 | 640 | 42 / 0 |
| 3.6 | v3 | 684 | 44 / 0 |
| 4.3 | v4 | 706 | 364 / 342 |
| 4.4 | v4 | 720 | 14 / 0 |
| 4.5 | v4 | 720 | 0 / 0 |
| master | v4 | 720 | 0 / 0 |
Specialized handlers cover core inventory collections (VMs, disks, hosts,
networks, storage, jobs, …). Remaining pack operations are served by the schema
engine. See [API surface](api-surface.md).
> Measurable contract coverage for a laboratory simulator — not a claim that
> every Engine edge case behaves identically to production RHV/oVirt.
+44
View File
@@ -0,0 +1,44 @@
**Language / Язык:** [English](architecture.md) | [Русский](ru/architecture.md)
# Architecture
## Goals
- Faithful Engine URL layout (`/ovirt-engine/api`, SSO)
- Stateful inventory in PostgreSQL
- Contract-driven route registration per series pack
- Lab-friendly Web UI and deterministic seeds
## Components
```
clients / Web UI
api-gateway (nginx TLS + UI)
simulator (FastAPI :8080)
PostgreSQL
```
| Package | Responsibility |
|---|---|
| `app/ovirt/` | Engine routes, SSO, seed, schema engine, versioning |
| `app/web/` | Console UI and UI API |
| `app/db/` | Migrations and connection pool |
| `contracts/ovirt/` | Generated series packs |
| `docker/gateway/` | nginx Engine + UI listeners |
## Request path
1. Client hits published Engine or UI port.
2. Gateway proxies to FastAPI.
3. Auth middleware resolves Basic / Bearer.
4. Contract or semantic handler mutates / reads PostgreSQL.
5. Response serialized as JSON or XML.
## Related
- [API surface](api-surface.md)
- [Seed profiles](seed-profiles.md)
- [Operations](operations.md)
+68
View File
@@ -0,0 +1,68 @@
**Language / Язык:** [English](authentication.md) | [Русский](ru/authentication.md)
# Authentication
The simulator implements Engine-style **HTTP Basic**, **SSO OAuth2** password
grant, and bearer tokens for subsequent API calls.
## Seeded principals
Password for all users: **`secret`**. Domain: **`internal`**.
| Principal | Typical role |
|---|---|
| `admin@internal` | SuperUser |
| `ops@internal` | lab operator |
| `developer@internal` | lab developer |
| `demo@internal` | demo user |
## HTTP Basic
```bash
curl -k -u 'admin@internal:secret' \
-H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/vms
```
## OAuth2 password grant
```bash
curl -k -X POST https://127.0.0.1/ovirt-engine/sso/oauth/token \
-d 'grant_type=password&username=admin@internal&password=secret&scope=ovirt-app-api'
```
Response includes `access_token`, `token_type`, `scope`, and `exp`. Use the
token as a Bearer credential:
```bash
TOKEN=... # access_token from the response
curl -k -H "Authorization: Bearer $TOKEN" \
-H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/vms
```
Related endpoints:
| Method | Path | Purpose |
|---|---|---|
| `POST` | `/ovirt-engine/sso/oauth/token` | Issue token |
| `GET` | `/ovirt-engine/sso/oauth/token-info` | Inspect token |
| `POST` | `/ovirt-engine/sso/oauth/revoke` | Revoke token |
## Errors
- Missing / invalid credentials → `401 Unauthorized`
- Wrong password → `401`
- Invalid or expired token → `401`
- Invalid OAuth scope → `400`
## Session cookie (lab)
After Basic authentication the simulator may establish a `JSESSIONID`-style
session cookie (or accept `Prefer: persistent-auth`). Prefer Bearer tokens for
automation; sessions are mainly for browser / Engine-client shaped flows.
## Web UI
The Auth drawer can issue a lab token for interactive catalog calls. See
[Web UI](web-ui.md).
+6
View File
@@ -0,0 +1,6 @@
**Language / Язык:** [English](clients.md) | [Русский](ru/clients.md)
# Clients
See [Clients & examples](examples/overview.md) for cookbooks (Python, Ansible,
Terraform) and the runnable suites under `pulumi-tests/`.
+87
View File
@@ -0,0 +1,87 @@
**Language / Язык:** [English](configuration.md) | [Русский](ru/configuration.md)
# Configuration
Application settings are loaded from the environment (see `.env.example`).
Docker Compose injects many of these for the `simulator` service.
## Core
| Variable | Default / example | Meaning |
|---|---|---|
| `APP_HOST` | `0.0.0.0` | Bind address |
| `APP_PORT` | `8080` | Internal FastAPI port (not the public Engine port) |
| `DATABASE_URL` | `postgresql://ovirt:ovirt@postgres:5432/ovirt_simulator` | asyncpg DSN |
| `TEST_DATABASE_URL` | same as above | Integration-test DSN |
| `DB_POOL_MIN_SIZE` | `1` | Pool minimum |
| `DB_POOL_MAX_SIZE` | `10` | Pool maximum |
| `LOG_LEVEL` | `INFO` | Logging level |
| `REQUEST_ID_HEADER` | `X-Request-ID` | Request correlation header |
## Engine series and seed
| Variable | Default | Meaning |
|---|---|---|
| `OVIRT_SERIES` | `4.5` | Contract pack at cold start (`3.0``3.6`, `4.3``4.5`, `master`) |
| `SEED_PROFILE` | `minimal` | Used by seed CLI / Helm seed Job (`minimal` / `demo`) |
## Security and tasks
| Variable | Meaning |
|---|---|
| `TICKET_SIGNING_KEY` | Signing material for lab tokens (**change outside toy labs**) |
| `TASK_WORKER_CONCURRENCY` | Leased asyncio workers (132) |
| `TASK_LEASE_SECONDS` | PostgreSQL task lease duration |
| `SIMULATION_TIME_SCALE` | Accelerates simulated job durations |
## Host publish ports
| Variable | Default | Meaning |
|---|---|---|
| `OVIRT_ENGINE_PORT` | `443` | Host → gateway `:443` (Engine HTTPS) |
| `OVIRT_UI_PORT` | `5000` | Host → gateway `:5000` (Web UI) |
See [Ports](ports.md).
## Compose
| File | Role |
|---|---|
| `docker-compose.yml` | Dev stack (build + bind mounts) |
| `docker-compose.release.yml` | Published Hub image |
| `.env` / `.env.example` | Local overrides |
Services:
- **simulator** — FastAPI on internal `8080`
- **api-gateway** — nginx publishing Engine + UI ([ports.md](ports.md))
- **postgres** — `postgres:17.5-bookworm` (host port omitted by default)
- **migrate** — one-shot schema migrations
## Helm
See [Kubernetes / Helm](kubernetes.md) and
[`helm/ovirt-api-simulator/values.yaml`](../helm/ovirt-api-simulator/values.yaml).
| Value | Purpose |
|---|---|
| `image.repository` / `image.tag` | Container image |
| `config.ovirtSeries` | Pack series env `OVIRT_SERIES` |
| `seed.profile` | `minimal` / `demo` |
| `postgresql.enabled` | Bundled DB |
| `databaseUrl` | External DSN when bundled Postgres is off |
| `secrets.ticketSigningKey` | Must be rotated for shared clusters |
| `service.port` | ClusterIP port (default `8080`) |
`gateway.*` / `ingress.*` in `values.yaml` are reserved; the chart currently
exposes FastAPI directly (no Compose-style nginx gateway).
## Contract packs
Location: `contracts/ovirt/<series>/`.
Each series has `api.json`, `manifest.json`, and `deltas.json`. Regenerate:
```bash
make generate-packs
```
+19
View File
@@ -0,0 +1,19 @@
**Language / Язык:** [English](README.md) | [Русский](../ru/domains/README.md)
# Domain guides
These pages summarize durable Engine semantics by area. For exhaustive method
lists, use the Web UI catalog or `contracts/ovirt/<series>/api.json`.
| Guide | Collections / focus |
|---|---|
| [Datacenters & clusters](datacenters-clusters.md) | `datacenters`, `clusters` |
| [Hosts](hosts.md) | `hosts` |
| [Virtual machines](vms.md) | `vms`, disks attachments, NICs, snapshots |
| [Storage](storage.md) | `storagedomains`, `disks`, connections |
| [Networks](networks.md) | `networks`, `vnicprofiles` |
| [Identity & access](identity.md) | `users`, `roles`, `permissions`, SSO |
| [Jobs & events](jobs.md) | `jobs`, `events` |
| [Schema collections](schema-collections.md) | Remaining pack-backed collections |
See also [API surface](../api-surface.md) and [API coverage](../api_coverage.md).
+21
View File
@@ -0,0 +1,21 @@
**Language / Язык:** [English](datacenters-clusters.md) | [Русский](../ru/domains/datacenters-clusters.md)
# Datacenters & clusters
| Collection | Path |
|---|---|
| Datacenters | `/ovirt-engine/api/datacenters` |
| Clusters | `/ovirt-engine/api/clusters` |
Minimal seed creates one datacenter and one cluster. Demo seed expands hosts and
VM density under the same topology.
```bash
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/datacenters
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/clusters
```
Related: [Hosts](hosts.md), [Virtual machines](vms.md).
+17
View File
@@ -0,0 +1,17 @@
**Language / Язык:** [English](hosts.md) | [Русский](../ru/domains/hosts.md)
# Hosts
| Collection | Path |
|---|---|
| Hosts | `/ovirt-engine/api/hosts` |
Hosts belong to a cluster and participate in VM placement for lab scenarios.
```bash
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/hosts
```
Demo seed creates multiple hosts to support ~1000 VMs. Related:
[Datacenters & clusters](datacenters-clusters.md).
+17
View File
@@ -0,0 +1,17 @@
**Language / Язык:** [English](identity.md) | [Русский](../ru/domains/identity.md)
# Identity & access
| Collection | Path |
|---|---|
| Domains | `/ovirt-engine/api/domains` |
| Users | `/ovirt-engine/api/users` |
| Groups | `/ovirt-engine/api/groups` |
| Roles | `/ovirt-engine/api/roles` |
| Permissions | `/ovirt-engine/api/permissions` |
| SSO | `/ovirt-engine/sso/oauth/*` |
Seed creates domain `internal` and principals `admin@internal`, `ops@internal`,
`developer@internal`, `demo@internal` (password `secret`).
Authentication flows: [Authentication](../authentication.md).
+20
View File
@@ -0,0 +1,20 @@
**Language / Язык:** [English](jobs.md) | [Русский](../ru/domains/jobs.md)
# Jobs & events
| Collection | Path |
|---|---|
| Jobs | `/ovirt-engine/api/jobs` |
| Events | `/ovirt-engine/api/events` |
Long-running Engine operations create job records with steps. Seed inserts a
finished sample job. Events capture inventory lifecycle signals for lab
inspection.
```bash
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/jobs
```
Task timing can be accelerated with `SIMULATION_TIME_SCALE`
([configuration.md](../configuration.md)).
+17
View File
@@ -0,0 +1,17 @@
**Language / Язык:** [English](networks.md) | [Русский](../ru/domains/networks.md)
# Networks
| Collection | Path |
|---|---|
| Networks | `/ovirt-engine/api/networks` |
| VNIC profiles | `/ovirt-engine/api/vnicprofiles` |
VMs attach NICs that reference vNIC profiles and logical networks.
```bash
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/networks
```
Related: [Virtual machines](vms.md).
+15
View File
@@ -0,0 +1,15 @@
**Language / Язык:** [English](schema-collections.md) | [Русский](../ru/domains/schema-collections.md)
# Schema collections
Operations declared in the active series pack that do not have a specialized
semantic handler are served by the **schema engine**. Responses follow the
contract shape and persist into `ov_api_objects` where applicable.
Browse the full catalog in the Web UI or open
`contracts/ovirt/<series>/api.json`. Coverage numbers:
[api_coverage.md](../api_coverage.md).
Examples of pack-backed entry points (availability depends on series):
`bookmarks`, `tags`, `quotas`, `affinitygroups`, and other Engine collections
linked from the API root.
+20
View File
@@ -0,0 +1,20 @@
**Language / Язык:** [English](storage.md) | [Русский](../ru/domains/storage.md)
# Storage
| Collection | Path |
|---|---|
| Storage domains | `/ovirt-engine/api/storagedomains` |
| Storage connections | `/ovirt-engine/api/storageconnections` |
| Disks | `/ovirt-engine/api/disks` |
Seed attaches storage domains to the datacenter and creates sample disks for
VMs. Disk attach/expand/delete paths are covered by client P0 smokes.
```bash
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/storagedomains
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/disks
```
+26
View File
@@ -0,0 +1,26 @@
**Language / Язык:** [English](vms.md) | [Русский](../ru/domains/vms.md)
# Virtual machines
| Collection | Path |
|---|---|
| VMs | `/ovirt-engine/api/vms` |
| Templates | `/ovirt-engine/api/templates` |
Nested resources (disk attachments, NICs, snapshots) are available under each VM
id where the pack declares them.
```bash
# List
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/vms
# Create (JSON sketch)
curl -k -u 'admin@internal:secret' -H 'Content-Type: application/json' -H 'Version: 4' \
-d '{"name":"lab-vm-1","cluster":{"name":"Default"}}' \
https://127.0.0.1/ovirt-engine/api/vms
```
Long-running actions surface as Engine [jobs](jobs.md). Client suites exercise
create/get/modify/delete VM plus disk and NIC flows — see
[`pulumi-tests/`](../../pulumi-tests/README.md).
+29
View File
@@ -0,0 +1,29 @@
**Language / Язык:** [English](ansible.md) | [Русский](../ru/examples/ansible.md)
# Ansible
Use `ansible.builtin.uri` against Engine HTTPS:
```yaml
- name: List oVirt VMs
hosts: local
gather_facts: false
vars:
engine_api: "https://127.0.0.1/ovirt-engine/api"
tasks:
- name: GET /vms
ansible.builtin.uri:
url: "{{ engine_api }}/vms"
user: admin@internal
password: secret
force_basic_auth: true
validate_certs: false
headers:
Accept: application/json
Version: "4"
status_code: [200]
register: vms
```
Native suite (150 cases): `make test-ansible` / `make test-ansible-smoke` under
[`pulumi-tests/ansible/`](../../pulumi-tests/README.md).
+35
View File
@@ -0,0 +1,35 @@
**Language / Язык:** [English](overview.md) | [Русский](../ru/examples/overview.md)
# Clients & examples
Use the **inline snippets** below and the Pulumi contract-coverage lab under
[`pulumi-tests/`](../../pulumi-tests/README.md).
## Base URL and credentials
| Setting | Value |
|---|---|
| Engine API | `https://127.0.0.1/ovirt-engine/api` |
| SSO token | `https://127.0.0.1/ovirt-engine/sso/oauth/token` |
| Web UI | `http://127.0.0.1:5000/` |
| User | `admin@internal` |
| Password | `secret` |
Disable HTTP proxies for local clients:
```bash
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY http_proxy https_proxy all_proxy
export NO_PROXY='*'
```
## Guides
| Guide | Focus |
|---|---|
| [Python requests](python-requests.md) | Raw HTTPS Basic / OAuth |
| [Ansible](ansible.md) | `uri` module against Engine |
| [Terraform](terraform.md) | IaC notes |
| [Pulumi](pulumi.md) | Full contract coverage + HTML report |
| [Troubleshooting clients](troubleshooting-clients.md) | Common client failures |
Prerequisites: `make up && make seed` (or `make seed-demo`).
+13
View File
@@ -0,0 +1,13 @@
**Language / Язык:** [English](pulumi.md) | [Русский](../ru/examples/pulumi.md)
# Pulumi
Contract-coverage lab under [`pulumi-tests/pulumi/`](../../pulumi-tests/README.md).
```bash
make up && make seed
make test-pulumi-smoke
make test-pulumi
```
HTML report: `pulumi-tests/reports/pulumi-contract-coverage.html`
+43
View File
@@ -0,0 +1,43 @@
**Language / Язык:** [English](python-requests.md) | [Русский](../ru/examples/python-requests.md)
# Python (`requests`)
Minimal pattern against the Engine gateway:
```python
import requests
BASE = "https://127.0.0.1/ovirt-engine/api"
AUTH = ("admin@internal", "secret")
HEADERS = {"Accept": "application/json", "Version": "4"}
r = requests.get(f"{BASE}/vms", auth=AUTH, headers=HEADERS, verify=False, timeout=60)
r.raise_for_status()
print(r.json())
```
OAuth password grant:
```python
token = requests.post(
"https://127.0.0.1/ovirt-engine/sso/oauth/token",
data={
"grant_type": "password",
"username": "admin@internal",
"password": "secret",
"scope": "ovirt-app-api",
},
verify=False,
timeout=60,
).json()["access_token"]
r = requests.get(
f"{BASE}/vms",
headers={**HEADERS, "Authorization": f"Bearer {token}"},
verify=False,
timeout=60,
)
```
Native suite: `make test-python` / `make test-python-smoke` under
[`pulumi-tests/`](../../pulumi-tests/README.md).
+15
View File
@@ -0,0 +1,15 @@
**Language / Язык:** [English](terraform.md) | [Русский](../ru/examples/terraform.md)
# Terraform
Native suite (150 cases) lives under
[`pulumi-tests/terraform/`](../../pulumi-tests/README.md):
```bash
make up && make seed
make test-terraform-smoke
make test-terraform
```
Configure providers against Engine HTTPS with lab credentials and disable TLS
verification for the Compose self-signed certificate.
+38
View File
@@ -0,0 +1,38 @@
**Language / Язык:** [English](troubleshooting-clients.md) | [Русский](../ru/examples/troubleshooting-clients.md)
# Troubleshooting clients
## TLS verification failures
Expected with the Compose self-signed Engine cert. Disable verification in the
client (`verify=False`, `insecure`, `validate_certs: false`).
## HTTP 401
Confirm principal format `user@internal` and password `secret`. For OAuth,
include `scope=ovirt-app-api`.
## Wrong host / port
On Compose, Engine is **`443`** (HTTPS) and UI is **`5000`** (HTTP) by default.
Helm without a custom Ingress exposes FastAPI on **`8080`**. See
[ports.md](../ports.md) and [kubernetes.md](../kubernetes.md).
## Empty lists after seed
Wait for `/health/ready`. Lifespan auto-loads `minimal` unless the DB is already
`demo`. For density: `make seed-demo`.
## Proxy interference
IDE sandboxes often inject proxies that break local HTTPS. Unset proxy env vars
([overview.md](overview.md)).
## Version / XML surprises
Send `Version: 4` and `Accept: application/json` unless you intentionally test
v3 or XML.
## Wrong tool / suite
Prefer the snippets in this docs tree or the suites under `pulumi-tests/`.
+42
View File
@@ -0,0 +1,42 @@
**Language / Язык:** [English](faq.md) | [Русский](ru/faq.md)
# FAQ
## Is this a real oVirt Engine?
No. It is a **surface-complete API laboratory**: PostgreSQL-backed state,
contract-shaped responses, no hypervisor orchestration.
## Which series should I use?
Default **4.5**. Switch with `OVIRT_SERIES` (Compose/Helm). See
[api-versions.md](api-versions.md).
## Why only two ports?
Engine API + SSO share HTTPS; the Web UI uses a separate HTTP listener. That
matches how labs typically expose Engine without publishing Postgres or the
internal FastAPI port. Details: [ports.md](ports.md).
## Compose vs Helm?
| Need | Use |
|---|---|
| Local hack / CI on Docker | Compose |
| Cluster install | Helm ([kubernetes.md](kubernetes.md)) |
## Demo seed wiped my resources
Lifecycle tests and reseed truncate lab tables. Reload with `make seed-demo`.
## Can I point Terraform / Ansible at it?
Yes — use Engine HTTPS URL and seeded credentials. Prefer the native suites under
[`pulumi-tests/`](../pulumi-tests/README.md). Expect lab limitations (policy
depth, async workflows, real storage backends). See
[examples/overview.md](examples/overview.md).
## Where is the Helm chart?
[`helm/ovirt-api-simulator`](../helm/ovirt-api-simulator) — guide in
[kubernetes.md](kubernetes.md).
+109
View File
@@ -0,0 +1,109 @@
**Language / Язык:** [English](getting-started.md) | [Русский](ru/getting-started.md)
# Getting started
Bring up a local Engine lab, authenticate, and run a first read against the
simulator.
## Prerequisites
- Docker and Docker Compose
- `make` (optional but used by the documented commands)
Python, linters, and tests run **inside** containers. You do not need a local
Python toolchain for day-to-day use.
## Choose a path
| Path | When to use |
|---|---|
| [Development checkout](#1a-development-checkout) | Contribute / bind-mount source |
| [Published image](#1b-published-image) | Fastest lab using the Hub image |
| [Helm / Kubernetes](kubernetes.md) | Cluster install (no nginx gateway yet) |
## 1a. Development checkout
```bash
cp .env.example .env
make install
make up
make seed
```
| Host port | Service |
|---|---|
| `443` | Engine API + SSO (HTTPS) |
| `5000` | Web UI console (HTTP) |
Only these two ports are published. Internal FastAPI listens on `:8080` inside
the compose network. See [Ports](ports.md).
Migrations run automatically via the `migrate` one-shot service.
## 1b. Published image
Uses [`docker-compose.release.yml`](../docker-compose.release.yml) — PostgreSQL +
migrate + simulator + Engine gateway from the Hub runtime image:
```bash
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.ovirt.seed_cli --profile minimal
```
Override the tag with `IMAGE_TAG=0.1.0` if needed. From a git checkout:
```bash
make release-up
make release-seed PROFILE=minimal
```
## 2. Wait until ready
```bash
curl -skf https://127.0.0.1/health/ready
curl -sf http://127.0.0.1:5000/health/live
```
`/health/ready` returns HTTP 503 until PostgreSQL is reachable **and** the
latest packaged migration is applied.
## 3. Seed a profile
```bash
make seed # minimal lab
# or
make seed-demo # ~1000 VMs
```
See [Seed profiles](seed-profiles.md).
## 4. Authenticate and list VMs
```bash
curl -k -u 'admin@internal:secret' \
-H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/vms
```
Or obtain an OAuth token:
```bash
curl -k -X POST https://127.0.0.1/ovirt-engine/sso/oauth/token \
-d 'grant_type=password&username=admin@internal&password=secret&scope=ovirt-app-api'
```
Details: [Authentication](authentication.md).
## 5. Open the Web UI
Browse [http://127.0.0.1:5000/](http://127.0.0.1:5000/) — Auth drawer, API
catalog, coverage, and Data reseed controls. See [Web UI](web-ui.md).
## Next steps
- [API versions](api-versions.md) — switch series packs (`OVIRT_SERIES`)
- [Clients & examples](examples/overview.md) — cookbooks
- [Domains](domains/README.md) — VMs, storage, networks
- [Troubleshooting](troubleshooting.md) — common failures
+90
View File
@@ -0,0 +1,90 @@
**Language / Язык:** [English](kubernetes.md) | [Русский](ru/kubernetes.md)
# Kubernetes / Helm
Deploy with the chart in
[`helm/ovirt-api-simulator`](../helm/ovirt-api-simulator).
Published image (when pushed):
[`inecs/ovirt-api-simulator`](https://hub.docker.com/r/inecs/ovirt-api-simulator)
## What the chart installs today
| Component | Role |
|---|---|
| **simulator** Deployment | FastAPI on container port `8080` |
| **Service** | ClusterIP → `8080` |
| **PostgreSQL** StatefulSet | Bundled Postgres 17 (optional) |
| **migrate** initContainer | Idempotent schema migrations |
| **seed** Job (optional) | `minimal` or `demo` lab data |
> The Compose stack publishes Engine HTTPS + UI via nginx `api-gateway`
> ([ports.md](ports.md)). The Helm chart **does not yet** ship that gateway:
> `gateway.*` / `ingress.*` keys in `values.yaml` are reserved and unused.
> Access the simulator Service on `:8080` (port-forward or your own Ingress).
## Prerequisites
- Kubernetes 1.27+ (or comparable)
- Helm 3.14+
## Install
```bash
helm upgrade --install ovirt-sim ./helm/ovirt-api-simulator \
-n ovirt-sim --create-namespace \
--set image.repository=inecs/ovirt-api-simulator \
--set image.tag=0.1.0 \
--set config.ovirtSeries=4.5 \
--set seed.profile=minimal \
--set secrets.ticketSigningKey="$(openssl rand -hex 32)"
```
For a locally built image, set `image.repository` / `image.tag` to match what
you loaded into the cluster.
Render locally:
```bash
make helm-template
```
## Important values
| Value | Purpose |
|---|---|
| `image.repository` / `image.tag` | Container image (default `inecs/ovirt-api-simulator:0.1.0`) |
| `config.ovirtSeries` | Cold-start pack (`4.5`, `3.6`, …) |
| `seed.enabled` / `seed.profile` | Post-install seed Job |
| `postgresql.enabled` | Bundled database |
| `databaseUrl` | External DSN when `postgresql.enabled=false` |
| `secrets.ticketSigningKey` | Rotate on shared clusters |
| `service.port` | Service port (default `8080`) |
See [`values.yaml`](../helm/ovirt-api-simulator/values.yaml).
## Access
Port-forward the simulator Service:
```bash
kubectl -n ovirt-sim port-forward svc/<release>-ovirt-api-simulator 8080:8080
```
Then:
| Surface | URL |
|---|---|
| Engine API | http://127.0.0.1:8080/ovirt-engine/api |
| SSO token | http://127.0.0.1:8080/ovirt-engine/sso/oauth/token |
| Web UI | http://127.0.0.1:8080/ |
| OpenAPI | http://127.0.0.1:8080/docs |
Default seeded login: `admin@internal` / `secret`.
## Manual reseed
```bash
kubectl exec deploy/<release>-ovirt-api-simulator -- \
python -m app.ovirt.seed_cli --profile demo
```
+45
View File
@@ -0,0 +1,45 @@
**Language / Язык:** [English](observability.md) | [Русский](ru/observability.md)
# Observability
## Health endpoints
| Path | Meaning |
|---|---|
| `/health/live` | Process is running |
| `/health/ready` | DB reachable + migrations applied |
Both are exposed on the simulator and via the Compose gateway (either published
port).
```bash
curl -skf https://127.0.0.1/health/ready
curl -sf http://127.0.0.1:5000/health/live
```
## Request IDs
Header `X-Request-ID` (configurable via `REQUEST_ID_HEADER`) is accepted and
echoed where middleware applies.
## Logs
Compose:
```bash
make logs
docker compose logs -f simulator api-gateway
```
Helm (chart labels use `app: ovirt-api-simulator`):
```bash
kubectl -n ovirt-sim logs -l app=ovirt-api-simulator -f
kubectl -n ovirt-sim logs -l app=ovirt-api-simulator-postgresql -f
```
## Coverage evidence
- Pack coverage: [api_coverage.md](api_coverage.md)
- Evidence JSON under `evidence/ovirt-*.json`
- pytest: `tests/ovirt/`
+120
View File
@@ -0,0 +1,120 @@
**Language / Язык:** [English](operations.md) | [Русский](ru/operations.md)
# Operations
## Day-2 Compose
```bash
make up # build + start + wait
make restart # force recreate
make logs # follow all services
make down # stop
make seed # reload minimal
make seed-demo # reload demo (~1000 VMs)
make smoke # Basic auth + list VMs
```
## Migrations
The `migrate` Compose service / Helm init container runs
`python -m app.db.migrate_cli` before the simulator becomes ready. Do not point
clients at Engine until `/health/ready` succeeds.
Schema history starts at `001_ovirt_core.sql`. If you upgraded from an earlier
pre-release lab DB, recreate the volume:
```bash
docker compose down -v
make up && make seed
```
## Reseed
Reseed **truncates** laboratory tables. Prefer `minimal` in shared CI jobs;
use `demo` when you need density.
```bash
make seed-demo
# or Web UI → Data → demo
```
## Series change
**Cold start** — change `OVIRT_SERIES` and recreate the simulator container:
```bash
OVIRT_SERIES=4.4 make restart
```
**Hot-swap** (in-memory, no rebuild) — Web UI Environment → Apply pack, or:
```bash
curl -s http://127.0.0.1:5000/ui/api/ovirt/contracts/activate \
-H 'Content-Type: application/json' \
-d '{"series":"4.4"}'
```
See [API versions](api-versions.md) and [Web UI](web-ui.md).
## Client lab cleanup
```bash
make clean-test-resources
```
Removes resources created by [`pulumi-tests/`](../pulumi-tests/README.md).
## Publish to Docker Hub
`make release` builds the **runtime** image (production target — not the local
bind-mounted `dev` image) and pushes it to Docker Hub:
```bash
docker login # once; account must own or can push to DOCKERHUB_USER
make release
```
Defaults:
| Variable | Default | Meaning |
|---|---|---|
| `DOCKERHUB_USER` | `inecs` | Docker Hub namespace/org |
| `IMAGE_NAME` | `ovirt-api-simulator` | Repository name |
| `VERSION` | from `pyproject.toml` | Image tag |
| `PUSH_LATEST` | `1` | Also tag/push `:latest` |
Examples:
```bash
make release
make release VERSION=0.2.0
make release DOCKERHUB_USER=myorg PUSH_LATEST=0
make release-build # build/tag locally without pushing
```
Published tags:
- `inecs/ovirt-api-simulator:<version>`
- `inecs/ovirt-api-simulator:latest` (unless `PUSH_LATEST=0`)
## Quick start with the published compose file
[`docker-compose.release.yml`](../docker-compose.release.yml) pulls the Hub
runtime image and starts PostgreSQL + migrate + simulator + Engine gateway:
```bash
docker compose -f docker-compose.release.yml up -d
docker compose -f docker-compose.release.yml run --rm --entrypoint python \
simulator -m app.ovirt.seed_cli --profile minimal
curl -skf https://127.0.0.1/health/ready
```
Helpers from a git checkout:
```bash
make release-up
make release-seed PROFILE=minimal
# or: make release-seed PROFILE=demo
make release-down
```
+30
View File
@@ -0,0 +1,30 @@
**Language / Язык:** [English](ports.md) | [Русский](ru/ports.md)
# Ports
Published host ports — **exactly two**, matching a typical Engine lab layout:
| Role | Container | Default host | Override env |
|------|-----------|--------------|--------------|
| Engine API + SSO | `443` | `443` | `OVIRT_ENGINE_PORT` |
| Web UI console | `5000` | `5000` | `OVIRT_UI_PORT` |
Examples:
```bash
https://127.0.0.1/ovirt-engine/api
http://127.0.0.1:5000/
# Optional override (only if the host already uses 443/5000):
# OVIRT_ENGINE_PORT=6443 OVIRT_UI_PORT=6080 docker compose up -d
```
Internal only (not published to the host): FastAPI `:8080`, PostgreSQL `:5432`.
The nginx `api-gateway` terminates TLS for Engine and proxies both listeners to
the simulator. Health checks work on either published port:
```bash
curl -skf https://127.0.0.1/health/ready
curl -sf http://127.0.0.1:5000/health/live
```
+32
View File
@@ -0,0 +1,32 @@
**Language / Язык:** [English](../README.md) | [Русский](README.md)
# Документация
Руководства по симулятору oVirt / RHV Engine API. Переключайте язык с помощью
заголовка на каждой странице. Русские версии находятся в каталоге
[`ru/`](README.md).
| Руководство | Описание |
|---|---|
| [Быстрый старт](getting-started.md) | Первая успешная лабораторная сессия |
| [Порты](ports.md) | Опубликованные порты Engine + UI |
| [Конфигурация](configuration.md) | Переменные окружения и Compose |
| [Аутентификация](authentication.md) | Basic auth, OAuth2, сессии |
| [Версии API](api-versions.md) | Series packs 3.x / 4.x и заголовок Version |
| [Покрытие API](api_coverage.md) | Число операций и дельты по series |
| [Поверхность API](api-surface.md) | Маршрутизация, handlers, schema engine |
| [Клиенты и примеры](clients.md) | curl, Python, Ansible, Terraform |
| [Профили seed](seed-profiles.md) | Фикстуры `minimal` и `demo` |
| [Домены](domains/README.md) | ВМ, хосты, storage, сети, identity, jobs |
| [Web UI](web-ui.md) | Интерактивная консоль и каталоги |
| [Эксплуатация](operations.md) | Миграции, reseed, обновление |
| [Kubernetes / Helm](kubernetes.md) | Установка в кластер (Service `:8080`) |
| [Безопасность](security.md) | Модель угроз лаборатории и учётные данные |
| [Наблюдаемость](observability.md) | Эндпоинты health и логирование |
| [Устранение неполадок](troubleshooting.md) | Типичные сбои |
| [FAQ](faq.md) | Краткие ответы |
| [Архитектура](architecture.md) | Границы компонентов |
Исполняемые cookbook'и: [`examples/`](../../examples/README.ru.md).
Интеграционные наборы: [`pulumi-tests/`](../../pulumi-tests/README.ru.md).
Контрактные packs: [`contracts/`](../../contracts/README.ru.md).
+31
View File
@@ -0,0 +1,31 @@
**Language / Язык:** [English](../api-surface.md) | [Русский](api-surface.md)
# Поверхность API
Точки входа:
| Путь | Роль |
|---|---|
| `/ovirt-engine/api` | Корень Engine REST (v4 по умолчанию на series 4.x) |
| `/ovirt-engine/api/v3``/v4` | Явный major API |
| `/ovirt-engine/sso/oauth/*` | SSO OAuth2 |
| `/health/live`, `/health/ready` | Liveness / readiness |
| `/` (порт UI) | Web-консоль |
## Модель маршрутизации
1. Контрактные маршруты активного pack `contracts/ovirt/<series>` регистрируются
как отдельные OpenAPI-операции.
2. Специализированные semantic handlers сохраняют мутации инвентаря (ВМ, диски,
хосты, сети, storage domains, jobs, …).
3. Catch-all роутер Engine остаётся скрытым fallback для остальных коллекций
через schema engine.
Packs: [`contracts/ovirt/`](../../contracts/README.ru.md). Таблица покрытия:
[api_coverage.md](api_coverage.md). Домены: [domains/](domains/README.md).
## Представления
Тела запросов/ответов — JSON или XML в зависимости от `Accept` /
`Content-Type`. Для современных клиентов предпочитайте
`Accept: application/json`.
+83
View File
@@ -0,0 +1,83 @@
**Language / Язык:** [English](../api-versions.md) | [Русский](api-versions.md)
# Версии API (series packs)
Симулятор поставляет Engine series packs в `contracts/ovirt/`:
| Series | Major API | Env при cold start |
|---|---|---|
| `3.0``3.6` | v3 | `OVIRT_SERIES=3.6` |
| `4.3` | v4 | `OVIRT_SERIES=4.3` |
| `4.4` | v4 | `OVIRT_SERIES=4.4` |
| `4.5` | v4 | `OVIRT_SERIES=4.5` (по умолчанию) |
| `master` | v4 | `OVIRT_SERIES=master` |
Числа операций и дельты: [Покрытие API](api_coverage.md).
## Выбор major API (v3 / v4)
Клиенты выбирают major Engine API двумя способами:
1. **Префикс пути:** `/ovirt-engine/api/v3/...` или `/ovirt-engine/api/v4/...`
2. **Заголовок `Version`:** `Version: 3` или `Version: 4` на `/ovirt-engine/api/...`
Если ничего не задано, default следует активному series (`3` для `3.x`, `4` для
`4.x` / `master`).
```bash
curl -k -u 'admin@internal:secret' \
-H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/vms
curl -k -u 'admin@internal:secret' \
-H 'Accept: application/xml' \
https://127.0.0.1/ovirt-engine/api/v3/vms
```
## Cold start
```bash
OVIRT_SERIES=4.4 docker compose up -d --build --wait
```
Helm:
```bash
--set config.ovirtSeries=3.6
```
## Hot-swap (in-memory)
Без пересоздания контейнеров активируйте другой pack из ящика Environment в
Web UI или:
```bash
curl -s http://127.0.0.1:5000/ui/api/ovirt/contracts/activate \
-H 'Content-Type: application/json' \
-d '{"series":"4.4"}'
```
Рестарт процесса возвращает cold-start `OVIRT_SERIES`. Подробности:
[Web UI](web-ui.md).
## Представления
Ответы Engine поддерживают **JSON** и **XML** через `Accept` /
`Content-Type` (`application/json`, `application/xml`).
## Структура pack
```
contracts/ovirt/<series>/
api.json
manifest.json
deltas.json
```
Перегенерация:
```bash
make generate-packs
```
Индекс: [`contracts/ovirt/index.json`](../../contracts/ovirt/index.json).
+26
View File
@@ -0,0 +1,26 @@
**Language / Язык:** [English](../api_coverage.md) | [Русский](api_coverage.md)
# Покрытие API
Число операций в контрактных packs (из `contracts/ovirt/*/manifest.json`):
| Series | API | Операции | Дельты (added / removed) |
|---|---|---:|---|
| 3.0 | v3 | 468 | 468 / 0 |
| 3.1 | v3 | 498 | 30 / 0 |
| 3.2 | v3 | 506 | 8 / 0 |
| 3.3 | v3 | 576 | 70 / 0 |
| 3.4 | v3 | 598 | 22 / 0 |
| 3.5 | v3 | 640 | 42 / 0 |
| 3.6 | v3 | 684 | 44 / 0 |
| 4.3 | v4 | 706 | 364 / 342 |
| 4.4 | v4 | 720 | 14 / 0 |
| 4.5 | v4 | 720 | 0 / 0 |
| master | v4 | 720 | 0 / 0 |
Специализированные handlers покрывают основные коллекции инвентаря (ВМ, диски,
хосты, сети, storage, jobs, …). Остальные операции pack обслуживает schema
engine. См. [Поверхность API](api-surface.md).
> Это измеримое покрытие контракта лабораторного симулятора — не утверждение,
> что каждый краевой случай Engine ведёт себя идентично продакшен RHV/oVirt.
+44
View File
@@ -0,0 +1,44 @@
**Language / Язык:** [English](../architecture.md) | [Русский](architecture.md)
# Архитектура
## Цели
- Верная раскладка URL Engine (`/ovirt-engine/api`, SSO)
- Stateful-инвентарь в PostgreSQL
- Регистрация маршрутов по контрактным series packs
- Удобный лабораторный Web UI и детерминированные seeds
## Компоненты
```
clients / Web UI
api-gateway (nginx TLS + UI)
simulator (FastAPI :8080)
PostgreSQL
```
| Пакет | Ответственность |
|---|---|
| `app/ovirt/` | Маршруты Engine, SSO, seed, schema engine, versioning |
| `app/web/` | Консоль UI и UI API |
| `app/db/` | Миграции и пул соединений |
| `contracts/ovirt/` | Сгенерированные series packs |
| `docker/gateway/` | nginx listener'ы Engine + UI |
## Путь запроса
1. Клиент обращается к опубликованному порту Engine или UI.
2. Gateway проксирует на FastAPI.
3. Auth middleware разрешает Basic / Bearer.
4. Контрактный или semantic handler читает / меняет PostgreSQL.
5. Ответ сериализуется в JSON или XML.
## Связанное
- [Поверхность API](api-surface.md)
- [Профили seed](seed-profiles.md)
- [Эксплуатация](operations.md)
+69
View File
@@ -0,0 +1,69 @@
**Language / Язык:** [English](../authentication.md) | [Русский](authentication.md)
# Аутентификация
Симулятор реализует Engine-стиль **HTTP Basic**, **SSO OAuth2** password grant
и bearer-токены для последующих вызовов API.
## Засеянные учётные записи
Пароль для всех пользователей: **`secret`**. Домен: **`internal`**.
| Principal | Типичная роль |
|---|---|
| `admin@internal` | SuperUser |
| `ops@internal` | оператор лаборатории |
| `developer@internal` | разработчик лаборатории |
| `demo@internal` | демо-пользователь |
## HTTP Basic
```bash
curl -k -u 'admin@internal:secret' \
-H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/vms
```
## OAuth2 password grant
```bash
curl -k -X POST https://127.0.0.1/ovirt-engine/sso/oauth/token \
-d 'grant_type=password&username=admin@internal&password=secret&scope=ovirt-app-api'
```
В ответе: `access_token`, `token_type`, `scope` и `exp`. Используйте токен как
Bearer:
```bash
TOKEN=... # access_token из ответа
curl -k -H "Authorization: Bearer $TOKEN" \
-H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/vms
```
Связанные эндпоинты:
| Метод | Путь | Назначение |
|---|---|---|
| `POST` | `/ovirt-engine/sso/oauth/token` | Выдать токен |
| `GET` | `/ovirt-engine/sso/oauth/token-info` | Просмотреть токен |
| `POST` | `/ovirt-engine/sso/oauth/revoke` | Отозвать токен |
## Ошибки
- Нет / неверные учётные данные → `401 Unauthorized`
- Неверный пароль → `401`
- Недействительный или просроченный токен → `401`
- Неверный OAuth scope → `400`
## Session cookie (лаборатория)
После Basic-аутентификации симулятор может установить session cookie в стиле
`JSESSIONID` (или принять `Prefer: persistent-auth`). Для автоматизации
предпочитайте Bearer-токены; сессии в основном для браузера / Engine-подобных
клиентов.
## Web UI
Ящик Auth может выдать лабораторный токен для интерактивных вызовов каталога.
См. [Web UI](web-ui.md).
+6
View File
@@ -0,0 +1,6 @@
**Language / Язык:** [English](../clients.md) | [Русский](clients.md)
# Клиенты
См. [Клиенты и примеры](examples/overview.md) — cookbook'и (Python, Ansible,
Terraform) и запускаемые suites в `pulumi-tests/`.
+87
View File
@@ -0,0 +1,87 @@
**Language / Язык:** [English](../configuration.md) | [Русский](configuration.md)
# Конфигурация
Настройки приложения загружаются из окружения (см. `.env.example`).
Docker Compose подставляет многие из них для сервиса `simulator`.
## Основные
| Переменная | По умолчанию / пример | Назначение |
|---|---|---|
| `APP_HOST` | `0.0.0.0` | Адрес привязки |
| `APP_PORT` | `8080` | Внутренний порт FastAPI (не публичный Engine) |
| `DATABASE_URL` | `postgresql://ovirt:ovirt@postgres:5432/ovirt_simulator` | DSN asyncpg |
| `TEST_DATABASE_URL` | как выше | DSN для интеграционных тестов |
| `DB_POOL_MIN_SIZE` | `1` | Минимум пула |
| `DB_POOL_MAX_SIZE` | `10` | Максимум пула |
| `LOG_LEVEL` | `INFO` | Уровень логирования |
| `REQUEST_ID_HEADER` | `X-Request-ID` | Заголовок корреляции запросов |
## Series Engine и seed
| Переменная | По умолчанию | Назначение |
|---|---|---|
| `OVIRT_SERIES` | `4.5` | Контрактный pack при cold start (`3.0``3.6`, `4.3``4.5`, `master`) |
| `SEED_PROFILE` | `minimal` | Для seed CLI / Helm seed Job (`minimal` / `demo`) |
## Безопасность и задачи
| Переменная | Назначение |
|---|---|
| `TICKET_SIGNING_KEY` | Материал подписи лабораторных токенов (**меняйте вне игрушечных стендов**) |
| `TASK_WORKER_CONCURRENCY` | Число воркеров с арендой (1–32) |
| `TASK_LEASE_SECONDS` | Длительность аренды задач в PostgreSQL |
| `SIMULATION_TIME_SCALE` | Ускоряет длительность симулируемых jobs |
## Публикация портов на хост
| Переменная | По умолчанию | Назначение |
|---|---|---|
| `OVIRT_ENGINE_PORT` | `443` | Host → gateway `:443` (Engine HTTPS) |
| `OVIRT_UI_PORT` | `5000` | Host → gateway `:5000` (Web UI) |
См. [Порты](ports.md).
## Compose
| Файл | Роль |
|---|---|
| `docker-compose.yml` | Dev-стек (сборка + bind mounts) |
| `docker-compose.release.yml` | Опубликованный образ Hub |
| `.env` / `.env.example` | Локальные переопределения |
Сервисы:
- **simulator** — FastAPI на внутреннем `8080`
- **api-gateway** — nginx, публикующий Engine + UI ([ports.md](ports.md))
- **postgres**`postgres:17.5-bookworm` (host-порт по умолчанию не публикуется)
- **migrate** — one-shot миграции схемы
## Helm
См. [Kubernetes / Helm](kubernetes.md) и
[`helm/ovirt-api-simulator/values.yaml`](../../helm/ovirt-api-simulator/values.yaml).
| Value | Назначение |
|---|---|
| `image.repository` / `image.tag` | Образ контейнера |
| `config.ovirtSeries` | Pack series → env `OVIRT_SERIES` |
| `seed.profile` | `minimal` / `demo` |
| `postgresql.enabled` | Встроенная БД |
| `databaseUrl` | Внешний DSN, если встроенный Postgres выключен |
| `secrets.ticketSigningKey` | Нужно ротировать на общих кластерах |
| `service.port` | Порт ClusterIP (по умолчанию `8080`) |
`gateway.*` / `ingress.*` в `values.yaml` зарезервированы; чарт сейчас отдаёт
FastAPI напрямую (без nginx gateway как в Compose).
## Контрактные packs
Расположение: `contracts/ovirt/<series>/`.
В каждом series: `api.json`, `manifest.json` и `deltas.json`. Перегенерация:
```bash
make generate-packs
```
+19
View File
@@ -0,0 +1,19 @@
**Language / Язык:** [English](../../domains/README.md) | [Русский](README.md)
# Руководства по доменам
Эти страницы кратко описывают устойчивую семантику Engine по областям. Полные
списки методов — в каталоге Web UI или `contracts/ovirt/<series>/api.json`.
| Руководство | Коллекции / фокус |
|---|---|
| [Datacenters и clusters](datacenters-clusters.md) | `datacenters`, `clusters` |
| [Hosts](hosts.md) | `hosts` |
| [Виртуальные машины](vms.md) | `vms`, attachments дисков, NIC, snapshots |
| [Storage](storage.md) | `storagedomains`, `disks`, connections |
| [Сети](networks.md) | `networks`, `vnicprofiles` |
| [Identity и доступ](identity.md) | `users`, `roles`, `permissions`, SSO |
| [Jobs и events](jobs.md) | `jobs`, `events` |
| [Schema-коллекции](schema-collections.md) | Остальные коллекции из pack |
Также: [Поверхность API](../api-surface.md) и [Покрытие API](../api_coverage.md).
+21
View File
@@ -0,0 +1,21 @@
**Language / Язык:** [English](../../domains/datacenters-clusters.md) | [Русский](datacenters-clusters.md)
# Datacenters и clusters
| Коллекция | Путь |
|---|---|
| Datacenters | `/ovirt-engine/api/datacenters` |
| Clusters | `/ovirt-engine/api/clusters` |
Minimal seed создаёт один datacenter и один cluster. Demo seed увеличивает число
хостов и плотность ВМ в той же топологии.
```bash
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/datacenters
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/clusters
```
Связанное: [Hosts](hosts.md), [Виртуальные машины](vms.md).
+17
View File
@@ -0,0 +1,17 @@
**Language / Язык:** [English](../../domains/hosts.md) | [Русский](hosts.md)
# Hosts
| Коллекция | Путь |
|---|---|
| Hosts | `/ovirt-engine/api/hosts` |
Хосты принадлежат cluster и участвуют в размещении ВМ в лабораторных сценариях.
```bash
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/hosts
```
Demo seed создаёт несколько хостов для ~1000 ВМ. Связанное:
[Datacenters и clusters](datacenters-clusters.md).
+17
View File
@@ -0,0 +1,17 @@
**Language / Язык:** [English](../../domains/identity.md) | [Русский](identity.md)
# Identity и доступ
| Коллекция | Путь |
|---|---|
| Domains | `/ovirt-engine/api/domains` |
| Users | `/ovirt-engine/api/users` |
| Groups | `/ovirt-engine/api/groups` |
| Roles | `/ovirt-engine/api/roles` |
| Permissions | `/ovirt-engine/api/permissions` |
| SSO | `/ovirt-engine/sso/oauth/*` |
Seed создаёт домен `internal` и principals `admin@internal`, `ops@internal`,
`developer@internal`, `demo@internal` (пароль `secret`).
Потоки аутентификации: [Аутентификация](../authentication.md).
+20
View File
@@ -0,0 +1,20 @@
**Language / Язык:** [English](../../domains/jobs.md) | [Русский](jobs.md)
# Jobs и events
| Коллекция | Путь |
|---|---|
| Jobs | `/ovirt-engine/api/jobs` |
| Events | `/ovirt-engine/api/events` |
Длительные операции Engine создают записи jobs со steps. Seed вставляет
завершённый sample job. Events фиксируют сигналы жизненного цикла инвентаря для
лабораторного просмотра.
```bash
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/jobs
```
Длительность задач можно ускорить через `SIMULATION_TIME_SCALE`
([configuration.md](../configuration.md)).
+17
View File
@@ -0,0 +1,17 @@
**Language / Язык:** [English](../../domains/networks.md) | [Русский](networks.md)
# Сети
| Коллекция | Путь |
|---|---|
| Networks | `/ovirt-engine/api/networks` |
| VNIC profiles | `/ovirt-engine/api/vnicprofiles` |
ВМ подключают NIC, ссылающиеся на vNIC profiles и логические сети.
```bash
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/networks
```
Связанное: [Виртуальные машины](vms.md).
+13
View File
@@ -0,0 +1,13 @@
**Language / Язык:** [English](../../domains/schema-collections.md) | [Русский](schema-collections.md)
# Schema-коллекции
Операции активного series pack без специализированного semantic handler
обслуживает **schema engine**. Ответы следуют форме контракта и при необходимости
сохраняются в `ov_api_objects`.
Полный каталог — в Web UI или в `contracts/ovirt/<series>/api.json`. Числа
покрытия: [api_coverage.md](../api_coverage.md).
Примеры коллекций из pack (доступность зависит от series): `bookmarks`, `tags`,
`quotas`, `affinitygroups` и другие коллекции Engine, связанные с корнем API.
+20
View File
@@ -0,0 +1,20 @@
**Language / Язык:** [English](../../domains/storage.md) | [Русский](storage.md)
# Storage
| Коллекция | Путь |
|---|---|
| Storage domains | `/ovirt-engine/api/storagedomains` |
| Storage connections | `/ovirt-engine/api/storageconnections` |
| Disks | `/ovirt-engine/api/disks` |
Seed подключает storage domains к datacenter и создаёт sample-диски для ВМ.
Пути attach/expand/delete дисков покрыты клиентскими P0 smoke.
```bash
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/storagedomains
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/disks
```
+26
View File
@@ -0,0 +1,26 @@
**Language / Язык:** [English](../../domains/vms.md) | [Русский](vms.md)
# Виртуальные машины
| Коллекция | Путь |
|---|---|
| VMs | `/ovirt-engine/api/vms` |
| Templates | `/ovirt-engine/api/templates` |
Вложенные ресурсы (disk attachments, NIC, snapshots) доступны под id ВМ, если
они объявлены в pack.
```bash
# Список
curl -k -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/vms
# Создание (эскиз JSON)
curl -k -u 'admin@internal:secret' -H 'Content-Type: application/json' -H 'Version: 4' \
-d '{"name":"lab-vm-1","cluster":{"name":"Default"}}' \
https://127.0.0.1/ovirt-engine/api/vms
```
Длительные действия отражаются как Engine [jobs](jobs.md). Клиентские suites
проверяют create/get/modify/delete ВМ, а также диски и NIC — см.
[`pulumi-tests/`](../../../pulumi-tests/README.ru.md).
+29
View File
@@ -0,0 +1,29 @@
**Language / Язык:** [English](../../examples/ansible.md) | [Русский](ansible.md)
# Ansible
Используйте `ansible.builtin.uri` против Engine HTTPS:
```yaml
- name: List oVirt VMs
hosts: local
gather_facts: false
vars:
engine_api: "https://127.0.0.1/ovirt-engine/api"
tasks:
- name: GET /vms
ansible.builtin.uri:
url: "{{ engine_api }}/vms"
user: admin@internal
password: secret
force_basic_auth: true
validate_certs: false
headers:
Accept: application/json
Version: "4"
status_code: [200]
register: vms
```
Нативный suite (150 кейсов): `make test-ansible` / `make test-ansible-smoke` в
[`pulumi-tests/ansible/`](../../../pulumi-tests/README.ru.md).
+35
View File
@@ -0,0 +1,35 @@
**Language / Язык:** [English](../../examples/overview.md) | [Русский](overview.md)
# Клиенты и примеры
Используйте **inline-сниппеты** ниже и лабораторию Pulumi в
[`pulumi-tests/`](../../../pulumi-tests/README.ru.md).
## Base URL и учётные данные
| Параметр | Значение |
|---|---|
| Engine API | `https://127.0.0.1/ovirt-engine/api` |
| SSO token | `https://127.0.0.1/ovirt-engine/sso/oauth/token` |
| Web UI | `http://127.0.0.1:5000/` |
| Пользователь | `admin@internal` |
| Пароль | `secret` |
Отключите HTTP-прокси для локальных клиентов:
```bash
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY http_proxy https_proxy all_proxy
export NO_PROXY='*'
```
## Руководства
| Руководство | Фокус |
|---|---|
| [Python requests](python-requests.md) | Сырой HTTPS Basic / OAuth |
| [Ansible](ansible.md) | Модуль `uri` против Engine |
| [Terraform](terraform.md) | Заметки по IaC |
| [Pulumi](pulumi.md) | Полное покрытие контрактов + HTML-отчёт |
| [Troubleshooting clients](troubleshooting-clients.md) | Типичные сбои клиентов |
Предварительно: `make up && make seed` (или `make seed-demo`).
+13
View File
@@ -0,0 +1,13 @@
**Language / Язык:** [English](../../examples/pulumi.md) | [Русский](pulumi.md)
# Pulumi
Лаборатория покрытия контрактов: [`pulumi-tests/pulumi/`](../../../pulumi-tests/README.ru.md).
```bash
make up && make seed
make test-pulumi-smoke
make test-pulumi
```
HTML-отчёт: `pulumi-tests/reports/pulumi-contract-coverage.html`
+43
View File
@@ -0,0 +1,43 @@
**Language / Язык:** [English](../../examples/python-requests.md) | [Русский](python-requests.md)
# Python (`requests`)
Минимальный паттерн против Engine gateway:
```python
import requests
BASE = "https://127.0.0.1/ovirt-engine/api"
AUTH = ("admin@internal", "secret")
HEADERS = {"Accept": "application/json", "Version": "4"}
r = requests.get(f"{BASE}/vms", auth=AUTH, headers=HEADERS, verify=False, timeout=60)
r.raise_for_status()
print(r.json())
```
OAuth password grant:
```python
token = requests.post(
"https://127.0.0.1/ovirt-engine/sso/oauth/token",
data={
"grant_type": "password",
"username": "admin@internal",
"password": "secret",
"scope": "ovirt-app-api",
},
verify=False,
timeout=60,
).json()["access_token"]
r = requests.get(
f"{BASE}/vms",
headers={**HEADERS, "Authorization": f"Bearer {token}"},
verify=False,
timeout=60,
)
```
Нативный suite: `make test-python` / `make test-python-smoke` в
[`pulumi-tests/`](../../../pulumi-tests/README.ru.md).
+15
View File
@@ -0,0 +1,15 @@
**Language / Язык:** [English](../../examples/terraform.md) | [Русский](terraform.md)
# Terraform
Нативный suite (150 кейсов) находится в
[`pulumi-tests/terraform/`](../../../pulumi-tests/README.ru.md):
```bash
make up && make seed
make test-terraform-smoke
make test-terraform
```
Направляйте провайдеры на Engine HTTPS с лабораторными учётными данными и
отключайте проверку TLS для self-signed сертификата Compose.
@@ -0,0 +1,38 @@
**Language / Язык:** [English](../../examples/troubleshooting-clients.md) | [Русский](troubleshooting-clients.md)
# Устранение неполадок клиентов
## Ошибки проверки TLS
Ожидаемо для self-signed сертификата Engine в Compose. Отключите проверку в
клиенте (`verify=False`, `insecure`, `validate_certs: false`).
## HTTP 401
Проверьте формат principal `user@internal` и пароль `secret`. Для OAuth укажите
`scope=ovirt-app-api`.
## Неверный host / порт
В Compose Engine по умолчанию на **`443`** (HTTPS), UI на **`5000`** (HTTP).
Helm без своего Ingress отдаёт FastAPI на **`8080`**. См.
[ports.md](../ports.md) и [kubernetes.md](../kubernetes.md).
## Пустые списки после seed
Дождитесь `/health/ready`. Lifespan сам загружает `minimal`, если БД ещё не
`demo`. Для плотности: `make seed-demo`.
## Помехи прокси
Песочницы IDE часто подставляют прокси, ломая локальный HTTPS. Сбросьте
переменные прокси ([overview.md](overview.md)).
## Сюрпризы Version / XML
Отправляйте `Version: 4` и `Accept: application/json`, если вы намеренно не
тестируете v3 или XML.
## Неверный инструмент / suite
Предпочитайте сниппеты в этой документации или suites в `pulumi-tests/`.
+43
View File
@@ -0,0 +1,43 @@
**Language / Язык:** [English](../faq.md) | [Русский](faq.md)
# FAQ
## Это настоящий oVirt Engine?
Нет. Это **лаборатория с полной API-поверхностью**: состояние в PostgreSQL,
ответы по форме контракта, без оркестрации гипервизоров.
## Какой series использовать?
По умолчанию **4.5**. Переключение через `OVIRT_SERIES` (Compose/Helm). См.
[api-versions.md](api-versions.md).
## Почему только два порта?
Engine API + SSO делят HTTPS; Web UI — отдельный HTTP listener. Так удобно
экспонировать Engine в лаборатории без публикации Postgres и внутреннего
FastAPI. Подробности: [ports.md](ports.md).
## Compose или Helm?
| Нужно | Использовать |
|---|---|
| Локальная разработка / CI на Docker | Compose |
| Установка в кластер | Helm ([kubernetes.md](kubernetes.md)) |
## Demo seed стёр мои ресурсы
Lifecycle-тесты и reseed очищают лабораторные таблицы. Перезагрузите:
`make seed-demo`.
## Можно ли направить Terraform / Ansible?
Да — HTTPS URL Engine и засеянные учётные данные. Предпочитайте нативные suites в
[`pulumi-tests/`](../../pulumi-tests/README.ru.md). Ожидайте лабораторные
ограничения (глубина policy, async workflows, реальные storage backends). См.
[examples/overview.md](examples/overview.md).
## Где Helm-чарт?
[`helm/ovirt-api-simulator`](../../helm/ovirt-api-simulator) — руководство в
[kubernetes.md](kubernetes.md).
+109
View File
@@ -0,0 +1,109 @@
**Language / Язык:** [English](../getting-started.md) | [Русский](getting-started.md)
# Быстрый старт
Поднимите локальную Engine-лабораторию, аутентифицируйтесь и выполните первый
запрос к симулятору.
## Требования
- Docker и Docker Compose
- `make` (опционально, но используется в документированных командах)
Python, линтеры и тесты запускаются **внутри** контейнеров. Локальный Python
toolchain для повседневной работы не нужен.
## Выберите путь
| Путь | Когда использовать |
|---|---|
| [Разработка из репозитория](#1a-разработка-из-репозитория) | Вклад в код / bind-mount исходников |
| [Опубликованный образ](#1b-опубликованный-образ) | Быстрый стенд с образом Hub |
| [Helm / Kubernetes](kubernetes.md) | Установка в кластер (nginx gateway пока нет) |
## 1a. Разработка из репозитория
```bash
cp .env.example .env
make install
make up
make seed
```
| Host-порт | Сервис |
|---|---|
| `443` | Engine API + SSO (HTTPS) |
| `5000` | Web UI консоль (HTTP) |
Публикуются только эти два порта. Внутренний FastAPI слушает `:8080` в сети
Compose. См. [Порты](ports.md).
Миграции применяются автоматически через one-shot сервис `migrate`.
## 1b. Опубликованный образ
Использует [`docker-compose.release.yml`](../../docker-compose.release.yml) —
PostgreSQL + migrate + simulator + Engine gateway из runtime-образа Hub:
```bash
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.ovirt.seed_cli --profile minimal
```
При необходимости переопределите тег через `IMAGE_TAG=0.1.0`. Из git checkout:
```bash
make release-up
make release-seed PROFILE=minimal
```
## 2. Дождитесь готовности
```bash
curl -skf https://127.0.0.1/health/ready
curl -sf http://127.0.0.1:5000/health/live
```
`/health/ready` возвращает HTTP 503, пока PostgreSQL недоступен **или** не
применена последняя упакованная миграция.
## 3. Загрузите профиль seed
```bash
make seed # минимальная лаборатория
# или
make seed-demo # ~1000 ВМ
```
См. [Профили seed](seed-profiles.md).
## 4. Аутентификация и список ВМ
```bash
curl -k -u 'admin@internal:secret' \
-H 'Accept: application/json' -H 'Version: 4' \
https://127.0.0.1/ovirt-engine/api/vms
```
Или получите OAuth-токен:
```bash
curl -k -X POST https://127.0.0.1/ovirt-engine/sso/oauth/token \
-d 'grant_type=password&username=admin@internal&password=secret&scope=ovirt-app-api'
```
Подробности: [Аутентификация](authentication.md).
## 5. Откройте Web UI
Откройте [http://127.0.0.1:5000/](http://127.0.0.1:5000/) — ящик Auth, каталог
API, покрытие и управление reseed в Data. См. [Web UI](web-ui.md).
## Дальше
- [Версии API](api-versions.md) — переключение series packs (`OVIRT_SERIES`)
- [Клиенты и примеры](examples/overview.md) — cookbook'и
- [Домены](domains/README.md) — ВМ, storage, сети
- [Устранение неполадок](troubleshooting.md) — типичные сбои
+91
View File
@@ -0,0 +1,91 @@
**Language / Язык:** [English](../kubernetes.md) | [Русский](kubernetes.md)
# Kubernetes / Helm
Установка чартом
[`helm/ovirt-api-simulator`](../../helm/ovirt-api-simulator).
Опубликованный образ (когда запушен):
[`inecs/ovirt-api-simulator`](https://hub.docker.com/r/inecs/ovirt-api-simulator)
## Что чарт ставит сейчас
| Компонент | Роль |
|---|---|
| **simulator** Deployment | FastAPI на порту контейнера `8080` |
| **Service** | ClusterIP → `8080` |
| **PostgreSQL** StatefulSet | Встроенный Postgres 17 (опционально) |
| **migrate** initContainer | Идемпотентные миграции схемы |
| **seed** Job (опционально) | Лабораторные данные `minimal` или `demo` |
> Compose публикует Engine HTTPS + UI через nginx `api-gateway`
> ([ports.md](ports.md)). Helm-чарт **пока не** включает этот gateway:
> ключи `gateway.*` / `ingress.*` в `values.yaml` зарезервированы и не
> используются. Доступ — к Service симулятора на `:8080` (port-forward или
> свой Ingress).
## Требования
- Kubernetes 1.27+ (или аналог)
- Helm 3.14+
## Установка
```bash
helm upgrade --install ovirt-sim ./helm/ovirt-api-simulator \
-n ovirt-sim --create-namespace \
--set image.repository=inecs/ovirt-api-simulator \
--set image.tag=0.1.0 \
--set config.ovirtSeries=4.5 \
--set seed.profile=minimal \
--set secrets.ticketSigningKey="$(openssl rand -hex 32)"
```
Для локально собранного образа задайте `image.repository` / `image.tag` под то,
что загружено в кластер.
Локальный render:
```bash
make helm-template
```
## Важные values
| Value | Назначение |
|---|---|
| `image.repository` / `image.tag` | Образ контейнера (по умолчанию `inecs/ovirt-api-simulator:0.1.0`) |
| `config.ovirtSeries` | Pack при cold start (`4.5`, `3.6`, …) |
| `seed.enabled` / `seed.profile` | Post-install seed Job |
| `postgresql.enabled` | Встроенная БД |
| `databaseUrl` | Внешний DSN при `postgresql.enabled=false` |
| `secrets.ticketSigningKey` | Ротировать на общих кластерах |
| `service.port` | Порт сервиса (по умолчанию `8080`) |
См. [`values.yaml`](../../helm/ovirt-api-simulator/values.yaml).
## Доступ
Port-forward Service симулятора:
```bash
kubectl -n ovirt-sim port-forward svc/<release>-ovirt-api-simulator 8080:8080
```
Далее:
| Поверхность | URL |
|---|---|
| Engine API | http://127.0.0.1:8080/ovirt-engine/api |
| SSO token | http://127.0.0.1:8080/ovirt-engine/sso/oauth/token |
| Web UI | http://127.0.0.1:8080/ |
| OpenAPI | http://127.0.0.1:8080/docs |
Логин по умолчанию после seed: `admin@internal` / `secret`.
## Ручной reseed
```bash
kubectl exec deploy/<release>-ovirt-api-simulator -- \
python -m app.ovirt.seed_cli --profile demo
```
+44
View File
@@ -0,0 +1,44 @@
**Language / Язык:** [English](../observability.md) | [Русский](observability.md)
# Наблюдаемость
## Health-эндпоинты
| Путь | Смысл |
|---|---|
| `/health/live` | Процесс запущен |
| `/health/ready` | БД доступна + миграции применены |
Оба доступны на симуляторе и через Compose gateway (любой опубликованный порт).
```bash
curl -skf https://127.0.0.1/health/ready
curl -sf http://127.0.0.1:5000/health/live
```
## Request ID
Заголовок `X-Request-ID` (настраивается через `REQUEST_ID_HEADER`) принимается и
эхоится там, где работает middleware.
## Логи
Compose:
```bash
make logs
docker compose logs -f simulator api-gateway
```
Helm (лейблы чарта: `app: ovirt-api-simulator`):
```bash
kubectl -n ovirt-sim logs -l app=ovirt-api-simulator -f
kubectl -n ovirt-sim logs -l app=ovirt-api-simulator-postgresql -f
```
## Evidence покрытия
- Покрытие pack: [api_coverage.md](api_coverage.md)
- Evidence JSON в `evidence/ovirt-*.json`
- pytest: `tests/ovirt/`
+120
View File
@@ -0,0 +1,120 @@
**Language / Язык:** [English](../operations.md) | [Русский](operations.md)
# Эксплуатация
## Compose день за днём
```bash
make up # сборка + старт + wait
make restart # force recreate
make logs # логи всех сервисов
make down # остановка
make seed # перезагрузка minimal
make seed-demo # перезагрузка demo (~1000 ВМ)
make smoke # Basic auth + список ВМ
```
## Миграции
Сервис Compose `migrate` / init-контейнер Helm запускает
`python -m app.db.migrate_cli` до готовности симулятора. Не направляйте клиенты
на Engine, пока `/health/ready` не успешен.
История схемы начинается с `001_ovirt_core.sql`. Если обновляетесь с более
ранней pre-release БД, пересоздайте том:
```bash
docker compose down -v
make up && make seed
```
## Reseed
Reseed **очищает** лабораторные таблицы. В общем CI предпочитайте `minimal`;
`demo` — когда нужна плотность.
```bash
make seed-demo
# или Web UI → Data → demo
```
## Смена series
**Cold start** — измените `OVIRT_SERIES` и пересоздайте контейнер симулятора:
```bash
OVIRT_SERIES=4.4 make restart
```
**Hot-swap** (in-memory, без пересборки) — Web UI Environment → Apply pack, или:
```bash
curl -s http://127.0.0.1:5000/ui/api/ovirt/contracts/activate \
-H 'Content-Type: application/json' \
-d '{"series":"4.4"}'
```
См. [Версии API](api-versions.md) и [Web UI](web-ui.md).
## Очистка клиентской лаборатории
```bash
make clean-test-resources
```
Удаляет ресурсы, созданные [`pulumi-tests/`](../../pulumi-tests/README.ru.md).
## Публикация в 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` | `ovirt-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/ovirt-api-simulator:<version>`
- `inecs/ovirt-api-simulator:latest` (если не `PUSH_LATEST=0`)
## Быстрый старт с опубликованным compose-файлом
[`docker-compose.release.yml`](../../docker-compose.release.yml) подтягивает
runtime-образ из Hub и запускает PostgreSQL + migrate + simulator + Engine gateway:
```bash
docker compose -f docker-compose.release.yml up -d
docker compose -f docker-compose.release.yml run --rm --entrypoint python \
simulator -m app.ovirt.seed_cli --profile minimal
curl -skf https://127.0.0.1/health/ready
```
Вспомогательные команды из git checkout:
```bash
make release-up
make release-seed PROFILE=minimal
# или: make release-seed PROFILE=demo
make release-down
```
+30
View File
@@ -0,0 +1,30 @@
**Language / Язык:** [English](../ports.md) | [Русский](ports.md)
# Порты
Опубликованные host-порты — ровно **два**, как у типичного Engine-стенда:
| Роль | Контейнер | Host по умолчанию | Переопределение |
|------|-----------|-------------------|-----------------|
| Engine API + SSO | `443` | `443` | `OVIRT_ENGINE_PORT` |
| Web UI консоль | `5000` | `5000` | `OVIRT_UI_PORT` |
Примеры:
```bash
https://127.0.0.1/ovirt-engine/api
http://127.0.0.1:5000/
# Опциональный override (только если на хосте уже заняты 443/5000):
# OVIRT_ENGINE_PORT=6443 OVIRT_UI_PORT=6080 docker compose up -d
```
Только внутри сети (не публикуются на хост): FastAPI `:8080`, PostgreSQL `:5432`.
Nginx `api-gateway` завершает TLS для Engine и проксирует оба listener'а на
симулятор. Health-проверки работают на любом опубликованном порту:
```bash
curl -skf https://127.0.0.1/health/ready
curl -sf http://127.0.0.1:5000/health/live
```
+34
View File
@@ -0,0 +1,34 @@
**Language / Язык:** [English](../security.md) | [Русский](security.md)
# Безопасность
Этот проект — **лабораторный симулятор**, а не hardened-развёртывание Engine.
## Учётные данные
Пароль seed по умолчанию — `secret` для всех лабораторных пользователей.
TLS-сертификаты Compose в `docker/tls/` считайте **только для разработки**.
## Ключ подписи
`TICKET_SIGNING_KEY` / Helm `secrets.ticketSigningKey` нужно ротировать на любом
общем или долгоживущем кластере. Значение в `.env.example` намеренно слабое.
## Сетевая экспозиция
Публикуйте порты Engine + UI только в доверенные сети. Не выставляйте симулятор
в публичный Интернет без дополнительных мер.
## TLS
Gateway Compose отдаёт локальный self-signed сертификат на
`OVIRT_ENGINE_PORT`. В лаборатории используйте `curl -k` / флаги `insecure`
клиентов или замените сертификаты в `docker/tls/`.
## Модель угроз (лаборатория)
| В scope | Вне scope |
|---|---|
| Форма auth (Basic / OAuth) для тестов клиентов | Реальная AAA / AD / IPA |
| Изоляция игрушечных учёток в документации | Продакшен-менеджмент секретов |
| Избежание случайного публичного bind | Полный чеклист hardening Engine |
+41
View File
@@ -0,0 +1,41 @@
**Language / Язык:** [English](../seed-profiles.md) | [Русский](seed-profiles.md)
# Профили seed
| Профиль | Как загрузить | Содержимое |
|---|---|---|
| `minimal` | Startup симулятора (если БД ещё не `demo`) / `make seed` / `python -m app.ovirt.seed_cli --profile minimal` / Helm seed Job | 1 datacenter, 1 cluster, 1 host, Blank template, 4 пользователя, небольшой sample инвентаря |
| `demo` | `make seed-demo` / ящик Data в UI / Helm `seed.profile=demo` / `--profile demo` | ~1000 ВМ, multi-host DC, сети, storage domains, диски, nested samples |
В Compose lifespan FastAPI загружает **`minimal`**, если БД пуста или не
помечена как `demo`. Для большого профиля — `make seed-demo` (или ящик Data в
UI). Helm дополнительно может запускать seed Job (`seed.enabled`).
Пароль для всех пользователей: **`secret`**. Домен: **`internal`**.
Principals: `admin@internal`, `ops@internal`, `developer@internal`,
`demo@internal`.
## CLI
```bash
make seed
make seed-demo
# эквивалент
docker compose run --rm --entrypoint python simulator \
-m app.ovirt.seed_cli --profile demo
```
## Helm
```yaml
seed:
enabled: true
profile: demo # или minimal
```
## Поведение
Оба профиля **очищают** (truncate) лабораторные таблицы oVirt и загружают данные
заново. `demo` — для плотности и nested GET; `minimal` — для быстрого CI.
+60
View File
@@ -0,0 +1,60 @@
**Language / Язык:** [English](../troubleshooting.md) | [Русский](troubleshooting.md)
# Устранение неполадок
## `/health/ready` возвращает 503
- Дождитесь завершения `migrate`: `docker compose ps`
- Проверьте Postgres: `docker compose logs postgres`
- Пересоздайте: `make restart`
## Ошибки TLS / сертификата
Compose использует self-signed сертификат на порту Engine. В лаборатории —
`curl -k` или флаги `insecure` / `verify=False` клиентов. См.
[Безопасность](security.md).
## Порт уже занят
Смените host-порты публикации:
```bash
OVIRT_ENGINE_PORT=7443 OVIRT_UI_PORT=7080 make up
```
## Пустой инвентарь / нет пользователей
Запустите seed:
```bash
make seed
# или
make seed-demo
```
## Неверный major API / нет полей
Задайте `Version: 4` (или `3`) либо используйте `/ovirt-engine/api/v4/...`.
Проверьте, что `OVIRT_SERIES` соответствует ожидаемому pack
([api-versions.md](api-versions.md)).
## Падения клиентских suites
Убедитесь, что стек поднят и засеян, затем сначала smoke:
```bash
make up && make seed && make smoke
make test-smoke-all
```
Отключите HTTP-прокси для локальных клиентов (`unset HTTP_PROXY HTTPS_PROXY …`).
## Всё ещё не ясно
Соберите:
```bash
docker compose ps
docker compose logs --tail=200 simulator api-gateway migrate
curl -sk -i https://127.0.0.1/health/ready
```
+33
View File
@@ -0,0 +1,33 @@
**Language / Язык:** [English](../web-ui.md) | [Русский](web-ui.md)
# Web UI
URL консоли (Compose по умолчанию): [http://127.0.0.1:5000/](http://127.0.0.1:5000/)
UX ящиков совпадает с другими лабораторными симуляторами этого семейства:
| Область | Назначение |
|---|---|
| Auth | Выдача лабораторных токенов / показ principal |
| API catalog | Обзор операций контракта активного series |
| Coverage | Сводка покрытия pack / handlers |
| Help | Краткие заметки оператора |
| Data | Reseed `minimal` / `demo` |
| Environment | Активный series, runtime-подсказки, hot-swap **Apply pack** |
## Hot-swap series
Из Environment (или UI API):
- `POST /ui/api/ovirt/contracts/activate` с `{"series":"4.4"}`
- `POST /ui/api/contract/apply?major=N`
Перемонтирует in-memory контрактные маршруты без пересборки образа. Рестарт
процесса возвращает cold-start значение `OVIRT_SERIES`. См.
[Версии API](api-versions.md).
Брендинг: oVirt blue `#0076B6` и charcoal `#1D2226`.
UI обращается к тому же процессу симулятора, что и Engine API; отличается только
опубликованный listener ([ports.md](ports.md)). Схема OpenAPI:
[http://127.0.0.1:5000/docs](http://127.0.0.1:5000/docs) (также на порту Engine).
+34
View File
@@ -0,0 +1,34 @@
**Language / Язык:** [English](security.md) | [Русский](ru/security.md)
# Security
This project is a **laboratory simulator**, not a hardened Engine deployment.
## Credentials
Default seeded password is `secret` for all lab users. Treat Compose TLS
certificates under `docker/tls/` as **dev-only**.
## Signing key
`TICKET_SIGNING_KEY` / Helm `secrets.ticketSigningKey` must be rotated on any
shared or long-lived cluster. The `.env.example` value is intentionally weak.
## Network exposure
Only publish Engine + UI ports to trusted networks. Do not expose the simulator
to the public Internet without additional controls.
## TLS
Compose gateway presents a local self-signed certificate on
`OVIRT_ENGINE_PORT`. Use `curl -k` / client `insecure` flags in labs, or replace
the certs under `docker/tls/`.
## Threat model (lab)
| In scope | Out of scope |
|---|---|
| Auth shape (Basic / OAuth) for client testing | Real AAA / AD / IPA integration |
| Isolating toy credentials in docs | Production secret management |
| Avoiding accidental public bind | Full Engine hardening checklist |
+41
View File
@@ -0,0 +1,41 @@
**Language / Язык:** [English](seed-profiles.md) | [Русский](ru/seed-profiles.md)
# Seed profiles
| Profile | How to load | Contents |
|---|---|---|
| `minimal` | Simulator startup (if DB is not already `demo`) / `make seed` / `python -m app.ovirt.seed_cli --profile minimal` / Helm seed Job | 1 datacenter, 1 cluster, 1 host, Blank template, 4 users, small inventory sample |
| `demo` | `make seed-demo` / UI Data drawer / Helm `seed.profile=demo` / `--profile demo` | ~1000 VMs, multi-host DC, networks, storage domains, disks, nested samples |
On Compose, the FastAPI lifespan loads **`minimal`** automatically when the DB
is empty or not marked as `demo`. Use `make seed-demo` (or the UI Data drawer)
for the large profile. Helm can also run a seed Job (`seed.enabled`).
Password for all users: **`secret`**. Domain: **`internal`**.
Principals: `admin@internal`, `ops@internal`, `developer@internal`,
`demo@internal`.
## CLI
```bash
make seed
make seed-demo
# equivalent
docker compose run --rm --entrypoint python simulator \
-m app.ovirt.seed_cli --profile demo
```
## Helm
```yaml
seed:
enabled: true
profile: demo # or minimal
```
## Behaviour
Both profiles **truncate** oVirt lab tables then reload. Prefer `demo` for
density and nested GET probes; `minimal` for fast CI.
+58
View File
@@ -0,0 +1,58 @@
**Language / Язык:** [English](troubleshooting.md) | [Русский](ru/troubleshooting.md)
# Troubleshooting
## `/health/ready` returns 503
- Wait for `migrate` to finish: `docker compose ps`
- Check Postgres: `docker compose logs postgres`
- Recreate: `make restart`
## TLS / certificate errors
Compose uses a self-signed cert on the Engine port. Use `curl -k` or client
`insecure` / `verify=False` flags in labs. See [Security](security.md).
## Port already in use
Change host publish ports:
```bash
OVIRT_ENGINE_PORT=7443 OVIRT_UI_PORT=7080 make up
```
## Empty inventory / missing users
Run seed:
```bash
make seed
# or
make seed-demo
```
## Wrong API major / missing fields
Set `Version: 4` (or `3`) or use `/ovirt-engine/api/v4/...`. Confirm
`OVIRT_SERIES` matches the pack you expect ([api-versions.md](api-versions.md)).
## Client suite failures
Ensure the stack is up and seeded, then run smoke first:
```bash
make up && make seed && make smoke
make test-smoke-all
```
Disable HTTP proxies for local multi-hop clients (`unset HTTP_PROXY HTTPS_PROXY …`).
## Still stuck
Collect:
```bash
docker compose ps
docker compose logs --tail=200 simulator api-gateway migrate
curl -sk -i https://127.0.0.1/health/ready
```
+33
View File
@@ -0,0 +1,33 @@
**Language / Язык:** [English](web-ui.md) | [Русский](ru/web-ui.md)
# Web UI
Console URL (Compose default): [http://127.0.0.1:5000/](http://127.0.0.1:5000/)
Drawer UX matches the other laboratory simulators in this family:
| Area | Purpose |
|---|---|
| Auth | Issue lab tokens / show principal |
| API catalog | Browse contract operations for the active series |
| Coverage | Pack / handler coverage summary |
| Help | Short operator notes |
| Data | Reseed `minimal` / `demo` |
| Environment | Active series, runtime hints, **Apply pack** hot-swap |
## Series hot-swap
From Environment (or UI API):
- `POST /ui/api/ovirt/contracts/activate` with `{"series":"4.4"}`
- `POST /ui/api/contract/apply?major=N`
This remounts the in-memory contract routes without rebuilding the image. A
process restart restores the cold-start `OVIRT_SERIES` value. See
[API versions](api-versions.md).
Branding uses oVirt blue `#0076B6` and charcoal `#1D2226`.
The UI talks to the same simulator process as the Engine API; only the published
listener differs ([ports.md](ports.md)). OpenAPI schema:
[http://127.0.0.1:5000/docs](http://127.0.0.1:5000/docs) (also on Engine port).