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:
@@ -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).
|
||||
@@ -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.
|
||||
@@ -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).
|
||||
@@ -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.
|
||||
@@ -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)
|
||||
@@ -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).
|
||||
@@ -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/`.
|
||||
@@ -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 (1–32) |
|
||||
| `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
|
||||
```
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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)).
|
||||
@@ -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).
|
||||
@@ -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.
|
||||
@@ -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
|
||||
```
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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`).
|
||||
@@ -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`
|
||||
@@ -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).
|
||||
@@ -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.
|
||||
@@ -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
@@ -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).
|
||||
@@ -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
|
||||
@@ -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
|
||||
```
|
||||
@@ -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/`
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
```
|
||||
@@ -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).
|
||||
@@ -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`.
|
||||
@@ -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).
|
||||
@@ -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.
|
||||
@@ -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)
|
||||
@@ -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).
|
||||
@@ -0,0 +1,6 @@
|
||||
**Language / Язык:** [English](../clients.md) | [Русский](clients.md)
|
||||
|
||||
# Клиенты
|
||||
|
||||
См. [Клиенты и примеры](examples/overview.md) — cookbook'и (Python, Ansible,
|
||||
Terraform) и запускаемые suites в `pulumi-tests/`.
|
||||
@@ -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
|
||||
```
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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)).
|
||||
@@ -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).
|
||||
@@ -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.
|
||||
@@ -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
|
||||
```
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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`).
|
||||
@@ -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`
|
||||
@@ -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).
|
||||
@@ -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/`.
|
||||
@@ -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).
|
||||
@@ -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) — типичные сбои
|
||||
@@ -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
|
||||
```
|
||||
@@ -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/`
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
```
|
||||
@@ -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 |
|
||||
@@ -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.
|
||||
@@ -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
|
||||
```
|
||||
@@ -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).
|
||||
@@ -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 |
|
||||
@@ -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.
|
||||
@@ -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
|
||||
```
|
||||
@@ -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).
|
||||
Reference in New Issue
Block a user