Initial commit: stateful OpenStack API laboratory simulator.

Ship Keystone auth, multi-service handlers (Yoga→Dalmatian), Compose/Helm
packaging, API contract packs, and pytest/Pulumi coverage labs.
This commit is contained in:
2026-07-18 04:26:48 +03:00
commit 6033967e6a
509 changed files with 464404 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
**Language / Язык:** [English](README.md) | [Русский](ru/README.md)
# Documentation
Guides for the OpenStack API Simulator laboratory. Switch language with the
header on each page. Russian mirrors live under [`ru/`](ru/README.md).
| Guide | Topic |
|---|---|
| [Getting started](getting-started.md) | First lab session (Compose) |
| [Kubernetes / Helm](kubernetes.md) | Cluster install, Ingress, cert-manager |
| [Configuration](configuration.md) | Env vars, Compose, Helm knobs |
| [Authentication](authentication.md) | Keystone tokens & seeded users |
| [Ports](ports.md) | Real OpenStack API ports (1:1 host publish) |
| [API surface](api-surface.md) | Specialized vs schema packs |
| [API versions](api-versions.md) | Yoga → Dalmatian series |
| [API coverage](api_coverage.md) | Generated operation counts |
| [Seed profiles](seed-profiles.md) | `minimal` / `demo` |
| [Clients](clients.md) | SDK / CLI |
| [Web UI](web-ui.md) | Console drawers |
| [Operations](operations.md) | Day-2, release, reseed |
| [Architecture](architecture.md) | Components & request path |
| [Security](security.md) | Lab threat model |
| [Observability](observability.md) | Health & logs |
| [Troubleshooting](troubleshooting.md) | Common failures |
| [FAQ](faq.md) | Short Q&A |
| [Domains](domains/README.md) | Per-service notes |
| [Examples](examples/overview.md) | Client cookbooks |
| [Hypervisor-lab](hypervisor-lab.md) | Pulumi API coverage (all ops × series) |
Runnable cookbooks: [`examples/`](../examples/README.md).
Integration suites: [`pulumi-tests/`](../pulumi-tests/README.md).
Back to [README](../README.md).
+44
View File
@@ -0,0 +1,44 @@
**Language / Язык:** [English](api-surface.md) | [Русский](ru/api-surface.md)
# API surface
## Surface-complete packs
Each OpenStack series pack lists **method + path** operations. At startup every
unique `(method, path)` is registered as its own FastAPI route (`os-contract:…`),
Proxmox-style. Stateful handlers from specialized modules are looked up via a
`HandlerRegistry`; everything else falls through to the schema engine
(`os_api_objects` lab JSON).
| Series | Services | Operations (approx.) |
|---|---|---|
| Yoga | 28 | ~1060 |
| Antelope | 28 | ~1108 |
| Caracal | 28 | ~1196 |
| Dalmatian | 28 | ~1357 |
Authoritative numbers: [api_coverage.md](api_coverage.md).
## Handlers vs schema fallback
| Layer | Services / resources |
|---|---|
| **Specialized handlers** | Keystone tokens/catalog, Nova servers/flavors/keypairs/…, Neutron nets/ports/…, Glance images, Cinder volumes, Heat stacks, Swift, Ironic nodes, Octavia LBs, Placement RPs |
| **Schema fallback** | Remaining pack collections (Barbican, Manila, Designate, Magnum, …) including nested paths |
## Microversions
Headers such as `OpenStack-API-Version: compute 2.79` and
`X-OpenStack-Nova-API-Version` are accepted and gated per pack metadata.
Overrides can be set in the Web UI Environment drawer.
## Actions
Nova-style `POST /servers/{id}/action` and similar pack `kind=action` ops are
handled by the schema/action path (power state updates for common actions).
## Errors
OpenStack-shaped errors (`OpenStackError`) with `code`, `title`, `message`.
Unknown routes that are not in the active contract pack return standard
FastAPI `404`.
+56
View File
@@ -0,0 +1,56 @@
**Language / Язык:** [English](api-versions.md) | [Русский](ru/api-versions.md)
# API versions (series packs)
The simulator ships **four** OpenStack release series as contract packs:
| Series | OpenStack release family | Cold-start env |
|---|---|---|
| `yoga` | Yoga | `OPENSTACK_SERIES=yoga` |
| `antelope` | Antelope | `OPENSTACK_SERIES=antelope` |
| `caracal` | Caracal | `OPENSTACK_SERIES=caracal` |
| `dalmatian` | Dalmatian (default) | `OPENSTACK_SERIES=dalmatian` |
## Cold start
Compose / process:
```bash
OPENSTACK_SERIES=caracal docker compose up -d
```
Helm:
```bash
--set config.openstackSeries=yoga
```
## Hot-swap
```bash
curl -X POST http://127.0.0.1:5000/ui/api/openstack/contracts/activate \
-H 'Content-Type: application/json' \
-d '{"series":"dalmatian"}'
```
Or Web UI → Environment → OpenStack API pack → Activate.
Hot-swap remounts schema routes (`remount_schema_services`) without rebuilding
the image.
## Pack layout
```
contracts/openstack/<series>/
manifest.json
keystone/api.json
nova/api.json
neutron/api.json
```
Regenerate:
```bash
PYTHONPATH=tools python3 tools/os_api_inventory/generate_packs.py
```
+64
View File
@@ -0,0 +1,64 @@
**Language / Язык:** [English](api_coverage.md) | [Русский](ru/api_coverage.md)
# OpenStack API coverage — dalmatian
Generated from `contracts/openstack/dalmatian/manifest.json`.
- **Services:** 28
- **Operations:** 1357
- **Checksum:** `5d8f32baa835db2b556b6f33ac3c1b67b74db8194f00ce7d6eb8c59e3bbd7063`
- **Generated at:** 2026-07-16T00:28:30Z
## Series deltas
| Series | Major | Operations |
|---|---:|---:|
| Antelope | 7 | 1108 |
| Caracal | 8 | 1196 |
| Dalmatian | 9 | 1357 |
| Yoga | 6 | 1060 |
Older series omit paths introduced later (`tools/os_api_inventory/series_deltas.py`)
and use lower microversion ceilings. Apply a pack in the Environment drawer to hot-swap.
Surface-complete means every operation in the pack is mounted by the schema engine
(specialized routers still win on overlapping stateful paths).
| Service | Type | Port | Operations | Microversions |
|---|---|---:|---:|---|
| adjutant | admin-logic | 5050 | 24 | — |
| aodh | alarming | 8042 | 19 | — |
| barbican | key-manager | 9311 | 25 | — |
| blazar | reservation | 1234 | 19 | — |
| cinder | volumev3 | 8776 | 98 | 3.03.70 |
| cloudkitty | rating | 8889 | 25 | — |
| designate | dns | 9001 | 37 | — |
| freezer | backup | 9090 | 31 | — |
| glance | image | 9292 | 39 | — |
| heat | orchestration | 8004 | 38 | — |
| heat-cfn | cloudformation | 8000 | 8 | — |
| ironic | baremetal | 6385 | 58 | 1.11.90 |
| keystone | identity | 5000 | 77 | — |
| magnum | container-infra | 9511 | 25 | — |
| manila | sharev2 | 8786 | 50 | 2.02.82 |
| masakari | instance-ha | 15868 | 19 | — |
| mistral | workflowv2 | 8989 | 37 | — |
| neutron | network | 9696 | 290 | — |
| nova | compute | 8774 | 124 | 2.12.96 |
| octavia | load-balancer | 9876 | 74 | — |
| placement | placement | 8003 | 30 | 1.01.39 |
| swift | object-store | 8080 | 10 | — |
| tacker | nfv-orchestration | 9890 | 30 | — |
| trove | database | 8779 | 31 | — |
| vitrage | rca | 8999 | 30 | — |
| watcher | infra-optim | 9322 | 49 | — |
| zaqar | messaging | 8888 | 27 | — |
| zun | container | 9517 | 33 | — |
## Core minimums
| Service | Required | Actual |
|---|---:|---:|
| keystone | 40 | 77 (OK) |
| neutron | 70 | 290 (OK) |
| nova | 70 | 124 (OK) |
+58
View File
@@ -0,0 +1,58 @@
**Language / Язык:** [English](architecture.md) | [Русский](ru/architecture.md)
# Architecture
## Components
```
┌─────────────┐ ┌──────────────────┐ ┌────────────┐
│ Clients │────▶│ api-gateway │────▶│ simulator │
│ SDK / CLI │ │ nginx multi-port│ │ FastAPI │
│ Web UI │ │ :5000,:8774,… │ │ :8080 │
└─────────────┘ └──────────────────┘ └─────┬──────┘
┌─────▼──────┐
│ PostgreSQL │
└────────────┘
```
| Piece | Responsibility |
|---|---|
| **api-gateway** | Publish OpenStack default ports; set `X-OpenStack-Service` / `X-Forwarded-Port` |
| **ServiceDispatchMiddleware** | Rewrite to `/_os/<service>/…` |
| **Specialized routers** | Stateful Keystone, Nova, Neutron, Glance, Cinder, Heat, Swift, Ironic, Octavia, Placement |
| **Schema engine** | Surface-complete ops from `contracts/openstack/<series>/` |
| **PostgreSQL** | Identity, IaaS tables, `os_api_objects` generic store |
## Request lifecycle
1. Client hits e.g. `http://host:8774/v2.1/servers`.
2. Gateway injects service headers.
3. Dispatch mounts the request under `/_os/nova/…`.
4. Specialized Nova handler **or** schema pack operation runs.
5. Reads/writes go to PostgreSQL (typed tables or `os_api_objects`).
## Contract packs
- Generated inventory → `contracts/openstack/{yoga,antelope,caracal,dalmatian}/`
- Hot-swap via Web UI / `/ui/api/openstack/contracts/activate`
- Coverage report: [api_coverage.md](api_coverage.md)
## Seed profiles
| Profile | Contents |
|---|---|
| `minimal` | Small Keystone + few IaaS resources |
| `demo` | ~1000 servers, multi-project topology, nested collections |
Details: [seed-profiles.md](seed-profiles.md).
## Deployment model
| Mode | Gateway | DB |
|---|---|---|
| Compose | nginx container | bundled Postgres |
| Helm | nginx Deployment + multi-port Service | bundled StatefulSet or external |
| Ingress | TLS terminates at Ingress → gateway:5000 | — |
See [kubernetes.md](kubernetes.md).
+80
View File
@@ -0,0 +1,80 @@
**Language / Язык:** [English](authentication.md) | [Русский](ru/authentication.md)
# Authentication
The simulator implements **Keystone v3** password authentication and project
scoping (lab subset).
## Password auth
```http
POST /v3/auth/tokens
Content-Type: application/json
{
"auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "admin",
"domain": {"name": "Default"},
"password": "secret"
}
}
},
"scope": {
"project": {"name": "demo", "domain": {"name": "Default"}}
}
}
}
```
Response:
- Header **`X-Subject-Token`** — use as **`X-Auth-Token`** on subsequent calls
- Body `token.catalog` — service endpoints (ports match [ports.md](ports.md))
## Seeded principals
Password for all users: **`secret`**. Domain: **`Default`**.
### Minimal seed
| User | Projects | Role |
|---|---|---|
| `admin` | `admin`, `demo` | admin |
| `demo` | `demo` | member |
### Demo cloud
| User | Typical projects |
|---|---|
| `admin` | all |
| `ops` | production, staging |
| `developer` | development, staging |
| `demo` / `auditor` | demo / production |
## Unscoped / errors
- Missing token → `401 Unauthorized`
- Wrong password → `401`
- Project-scoped APIs without project scope → `401` with a clear message
## openstacksdk / CLI
```bash
export OS_AUTH_URL=http://127.0.0.1:5000/v3
export OS_USERNAME=admin
export OS_PASSWORD=secret
export OS_PROJECT_NAME=demo
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_IDENTITY_API_VERSION=3
openstack server list
openstack network list
```
Against Helm Ingress, set `OS_AUTH_URL=https://os-sim.example.com/v3`
(and trust the certificate or use `--insecure` in labs).
+46
View File
@@ -0,0 +1,46 @@
**Language / Язык:** [English](clients.md) | [Русский](ru/clients.md)
# Clients
## Connection matrix
| Client | Auth URL | Notes |
|---|---|---|
| curl | `http://127.0.0.1:5000/v3` | Use `X-Subject-Token``X-Auth-Token` |
| openstack CLI | `OS_AUTH_URL=…/v3` | See [authentication.md](authentication.md) |
| openstacksdk | same | Service catalog ports must match gateway |
| Terraform OpenStack provider | `auth_url` | Point at Keystone; catalog drives Nova/Neutron |
| Ansible `openstack.*` | clouds.yaml | Same credentials as CLI |
## Compose (local)
```bash
export OS_AUTH_URL=http://127.0.0.1:5000/v3
export OS_USERNAME=admin
export OS_PASSWORD=secret
export OS_PROJECT_NAME=demo
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_IDENTITY_API_VERSION=3
```
## Helm / Ingress
```bash
export OS_AUTH_URL=https://os-sim.example.com/v3
# Other services: either port-forward gateway ports or rely on catalog URLs
# that your Ingress/DNS map correctly.
```
For multi-port access without Ingress TCP, port-forward the gateway Service
(see [kubernetes.md](kubernetes.md)).
## Examples in-repo
| Path | Purpose |
|---|---|
| `examples/python/openstack_smoke.py` | Multi-port GET smoke |
| `examples/python/openstack_conformance.py` | Write-path sample |
| `examples/python/openstack_surface_probe.py` | Full pack lifecycle probe |
Cookbooks: [examples/](examples/).
+59
View File
@@ -0,0 +1,59 @@
**Language / Язык:** [English](configuration.md) | [Русский](ru/configuration.md)
# Configuration
## Environment variables
| Variable | Default | Purpose |
|---|---|---|
| `APP_HOST` | `0.0.0.0` | Bind address |
| `APP_PORT` | `8080` | Internal FastAPI port (not the public Keystone port) |
| `DATABASE_URL` | (compose/helm) | PostgreSQL DSN |
| `TICKET_SIGNING_KEY` | lab secret | Token/signing material (rotate in shared labs) |
| `LOG_LEVEL` | `INFO` | Logging |
| `OPENSTACK_SERIES` | `dalmatian` | Contract pack series at cold start |
| `REQUEST_ID_HEADER` | `X-Request-ID` | Request correlation header |
| `SEED_PROFILE` | `minimal` | Used by `seed_cli` / Helm seed Job (`minimal` / `demo`) |
## 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 real OpenStack API ports 1:1 ([ports.md](ports.md))
- **postgres** — `postgres:17.5-bookworm` on host `127.0.0.1:5433`
## Helm
See [kubernetes.md](kubernetes.md) and
[`helm/openstack-api-simulator/values.yaml`](../helm/openstack-api-simulator/values.yaml).
Important knobs:
| Value | Purpose |
|---|---|
| `gateway.enabled` | Multi-port nginx (default `true`) |
| `config.openstackSeries` | Pack series env `OPENSTACK_SERIES` |
| `seed.profile` | `minimal` / `demo` |
| `postgresql.enabled` | Bundled DB |
| `secret.ticketSigningKey` | Must be rotated for shared clusters |
## Contract packs
Location: `contracts/openstack/<series>/`.
Each series has per-service `api.json` packs consumed by the schema engine.
Specialized routers (Keystone, Nova, Neutron, …) remain stateful for happy-paths.
## Web UI overrides
Environment drawer → **OpenStack API pack**:
- Activate series (hot remount)
- Per-service microversion override
+22
View File
@@ -0,0 +1,22 @@
**Language / Язык:** [English](README.md) | [Русский](../ru/domains/README.md)
# OpenStack service domains
Guides for the main specialized surfaces. Pack-only services (Barbican, Manila,
Designate, …) are covered generically by the schema engine and seeded into
`os_api_objects` — see [api-surface.md](../api-surface.md) and
[api_coverage.md](../api_coverage.md).
| Guide | Service | Port |
|---|---|---|
| [keystone.md](keystone.md) | Identity | 5000 |
| [nova.md](nova.md) | Compute | 8774 |
| [neutron.md](neutron.md) | Network | 9696 |
| [glance.md](glance.md) | Image | 9292 |
| [cinder.md](cinder.md) | Block storage | 8776 |
| [placement.md](placement.md) | Placement | 8003 |
| [heat.md](heat.md) | Orchestration | 8004 |
| [swift.md](swift.md) | Object storage | 8080 |
| [ironic.md](ironic.md) | Bare metal | 6385 |
| [octavia.md](octavia.md) | Load balancer | 9876 |
| [schema-services.md](schema-services.md) | Remaining pack services | various |
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](cinder.md) | [Русский](../ru/domains/cinder.md)
# Cinder (block storage)
Port **8776**. Paths under `/v3/` (and `/v3/{project_id}/…`).
## Stateful
Volumes CRUD. Demo cloud: ~600 volumes (`in-use` / `available`).
Snapshots, types, backups, and related collections are pack/schema-backed.
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](glance.md) | [Русский](../ru/domains/glance.md)
# Glance (image)
Port **9292**. Paths under `/v2/`.
## Stateful
Image list/show/create/update/delete; public + project-owned images.
Members/tags served from `os_api_objects` in the demo seed.
+11
View File
@@ -0,0 +1,11 @@
**Language / Язык:** [English](heat.md) | [Русский](../ru/domains/heat.md)
# Heat (orchestration)
Port **8004**. Paths `/v1/{tenant_id}/…`.
## Stateful
Stacks in `os_stacks`. Demo seed adds stacks plus nested
`stack_resource` / `stack_event` / `software_config` / `software_deployment`
rows for pack GET probes.
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](ironic.md) | [Русский](../ru/domains/ironic.md)
# Ironic (bare metal)
Port **6385**.
## Stateful
Nodes in `os_nodes`. Demo seed creates a pool of ironic nodes; ports/chassis/
allocations are schema-backed samples.
+21
View File
@@ -0,0 +1,21 @@
**Language / Язык:** [English](keystone.md) | [Русский](../ru/domains/keystone.md)
# Keystone (identity)
Port **5000**. Paths under `/v3/`.
## Implemented (lab)
- `POST /v3/auth/tokens` — password auth, project scope
- Catalog with multi-port endpoints
- Projects, users, roles, role assignments (seeded + CRUD via pack/schema)
- Domains (Default)
## Seed
Minimal and demo profiles create `Default` domain, roles `admin`/`member`, and
users documented in [authentication.md](../authentication.md).
## Notes
Federation, application credentials, and full policy engine are out of scope.
+16
View File
@@ -0,0 +1,16 @@
**Language / Язык:** [English](neutron.md) | [Русский](../ru/domains/neutron.md)
# Neutron (network)
Port **9696**. Paths under `/v2.0/`.
## Stateful resources
Networks, subnets, ports, routers, security groups/rules, floating IPs, agents.
## Schema / seeded extensions
QoS, trunks, RBAC, address scopes, subnet pools, conntrack helpers, port
forwardings, FWaaS/VPNaaS/BGP VPN samples in demo seed.
Demo adds multiple nets/SGs/routers per project for realistic list density.
+20
View File
@@ -0,0 +1,20 @@
**Language / Язык:** [English](nova.md) | [Русский](../ru/domains/nova.md)
# Nova (compute)
Port **8774**. Paths under `/v2.1/`.
## Stateful resources
Servers, flavors, keypairs, server groups, AZ, hypervisors, aggregates,
services, migrations, volume/interface attachments, metadata, tags,
instance actions, consoles (lab URLs).
## Demo cloud
~1000 servers across projects, metadata/`_tags`, attachments linked to volumes
and ports.
## Microversions
Send `OpenStack-API-Version: compute X.Y` or Nova legacy header. Pack gates apply.
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](octavia.md) | [Русский](../ru/domains/octavia.md)
# Octavia (load balancer)
Port **9876**. Paths under `/v2/lbaas/…`.
## Stateful
Load balancers in `os_loadbalancers`. Listeners/pools/healthmonitors/providers/
flavors are served from `os_api_objects` (demo seed populates them).
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](placement.md) | [Русский](../ru/domains/placement.md)
# Placement
Port **8003**.
## Lab behaviour
- `GET /resource_providers` — from demo `os_api_objects` (or fallback stub)
- `GET/PUT /allocations/{consumer_uuid}` — persisted allocations with lab fallback
+14
View File
@@ -0,0 +1,14 @@
**Language / Язык:** [English](schema-services.md) | [Русский](../ru/domains/schema-services.md)
# Schema-backed services
These projects are primarily driven by contract packs + `os_api_objects`
(demo seed inserts multiple rows per resource type):
Barbican, Manila, Designate, Magnum, Zun, Trove, Mistral, Aodh, CloudKitty,
Freezer, Blazar, Vitrage, Masakari, Tacker, Adjutant, Watcher, Zaqar, Heat-CFN.
Ports: [ports.md](../ports.md). Operations: [api_coverage.md](../api_coverage.md).
CRUD lifecycle is exercised by `examples/python/openstack_surface_probe.py`
and `tests/openstack/conformance/`.
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](swift.md) | [Русский](../ru/domains/swift.md)
# Swift (object storage)
Port **8080** on the **gateway** (internal simulator remains on 8080 behind nginx).
## Stateful
Accounts/containers/objects in `os_swift_*` tables. Demo seed creates
`images` / `backups` / `artifacts` containers with a readme object per project.
+20
View File
@@ -0,0 +1,20 @@
**Language / Язык:** [English](ansible.md) | [Русский](../ru/examples/ansible.md)
# Ansible (openstack.cloud)
## Cookbook (single stack)
[`examples/ansible/playbook.yml`](../../examples/ansible/playbook.yml) uses
`ansible.builtin.uri` against Keystone/Nova/Neutron/Glance — no Galaxy collections
required. Good for a minimal “create server + metadata + cleanup” walkthrough.
```bash
make up && make seed-demo
cd examples/ansible
ansible-playbook -i inventory.ini playbook.yml
```
Auth: `http://127.0.0.1:5000/v3`, user `admin`, password `secret`, project `demo`.
API coverage integration suites now live under [`pulumi-tests/`](../../pulumi-tests/)
(Pulumi / `pulumi_openstack`). See [hypervisor-lab.md](../hypervisor-lab.md).
+19
View File
@@ -0,0 +1,19 @@
**Language / Язык:** [English](openstack-cli.md) | [Русский](../ru/examples/openstack-cli.md)
# OpenStack CLI
```bash
export OS_AUTH_URL=http://127.0.0.1:5000/v3
export OS_USERNAME=admin
export OS_PASSWORD=secret
export OS_PROJECT_NAME=demo
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_IDENTITY_API_VERSION=3
openstack token issue
openstack server list
openstack network list
openstack volume list
openstack stack list
```
+53
View File
@@ -0,0 +1,53 @@
**Language / Язык:** [English](overview.md) | [Русский](../ru/examples/overview.md)
# Client examples overview
Runnable scripts live under [`examples/`](../../examples/).
Pulumi API coverage lab lives under [`pulumi-tests/`](../../pulumi-tests/).
## Quick reference
| Path | Tool | Purpose |
|---|---|---|
| `examples/python/openstacksdk_cookbook.py` | openstacksdk | net + server + volume lifecycle |
| `examples/ansible/playbook.yml` | Ansible `uri` | minimal Keystone/Nova/Neutron |
| `examples/terraform/main.tf` | Terraform | `openstack_compute_instance_v2` + volume |
| `examples/pulumi/` | Pulumi | `pulumi_openstack` Instance + Network |
| `examples/run_iac_stack.sh` | all four | sequential smoke of cookbooks |
| `pulumi-tests/` | Pulumi | every pack operation × yoga→dalmatian + HTML report |
## Auth quick reference
1. `POST /v3/auth/tokens``X-Subject-Token`
2. Call services with `X-Auth-Token` on the correct [port](../ports.md)
Default lab: `admin` / `secret`, project `demo`, domain `Default`.
## Cookbooks
- [Python (requests)](python-requests.md)
- [Python (openstacksdk)](python-openstacksdk.md)
- [Ansible](ansible.md)
- [Terraform](terraform.md)
- [Pulumi](pulumi.md)
- [CLI](openstack-cli.md)
- [Troubleshooting](troubleshooting-clients.md)
## API coverage lab (Pulumi)
Full guide: [hypervisor-lab.md](../hypervisor-lab.md)
```bash
cd pulumi-tests
make up
make test-pulumi-smoke
make test-pulumi
open reports/pulumi-report.html
```
Probe scripts (simulator conformance helpers):
| Script | Purpose |
|---|---|
| `examples/python/openstack_smoke.py` | Multi-port GET smoke |
| `examples/python/openstack_surface_probe.py` | Pack operation probe (also used by Pulumi lab) |
+30
View File
@@ -0,0 +1,30 @@
**Language / Язык:** [English](pulumi.md) | [Русский](../ru/examples/pulumi.md)
# Pulumi (pulumi_openstack)
## Cookbook (single stack)
[`examples/pulumi/`](../../examples/pulumi/) — `pulumi_openstack` Instance,
Network, Subnet against the simulator.
```bash
make up && make seed-demo
cd examples/pulumi
pulumi stack init dev --secrets-provider passphrase
export PULUMI_CONFIG_PASSPHRASE=lab
pulumi up
pulumi destroy
```
## Coverage lab (`pulumi-tests`)
[`pulumi-tests/`](../../pulumi-tests/) runs `pulumi_openstack` coverage stacks for
every series, asserts non-empty exports, then HTTP-probes pack operations with
non-empty body checks.
```bash
make pulumi-tests
open pulumi-tests/reports/pulumi-report.html
```
See [hypervisor-lab.md](../hypervisor-lab.md).
+24
View File
@@ -0,0 +1,24 @@
**Language / Язык:** [English](python-openstacksdk.md) | [Русский](../ru/examples/python-openstacksdk.md)
# Python + openstacksdk
```python
import openstack
conn = openstack.connect(
auth_url="http://127.0.0.1:5000/v3",
project_name="demo",
username="admin",
password="secret",
user_domain_name="Default",
project_domain_name="Default",
)
for server in conn.compute.servers():
print(server.name, server.status)
for network in conn.network.networks():
print(network.name)
```
Ensure the service catalog ports are reachable (Compose gateway or Helm
port-forward). See [clients.md](../clients.md).
+35
View File
@@ -0,0 +1,35 @@
**Language / Язык:** [English](python-requests.md) | [Русский](../ru/examples/python-requests.md)
# Python + requests
```python
import requests
AUTH = "http://127.0.0.1:5000/v3/auth/tokens"
r = requests.post(
AUTH,
json={
"auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "admin",
"domain": {"name": "Default"},
"password": "secret",
}
},
},
"scope": {
"project": {"name": "demo", "domain": {"name": "Default"}}
},
}
},
)
r.raise_for_status()
token = r.headers["X-Subject-Token"]
headers = {"X-Auth-Token": token}
servers = requests.get("http://127.0.0.1:8774/v2.1/servers", headers=headers)
print(servers.status_code, len(servers.json().get("servers", [])))
```
+23
View File
@@ -0,0 +1,23 @@
**Language / Язык:** [English](terraform.md) | [Русский](../ru/examples/terraform.md)
# Terraform (openstack provider)
## Cookbook (single stack)
[`examples/terraform/main.tf`](../../examples/terraform/main.tf) uses
**`terraform-provider-openstack/openstack`** (`openstack_compute_instance_v2`,
network, volume attach) against the local gateway ports.
```bash
make up && make seed-demo
cd examples/terraform
terraform init
terraform apply
terraform destroy
```
Defaults: `auth_url = http://127.0.0.1:5000/v3`, user `admin`, project `demo`,
`insecure = true` (lab HTTP gateway).
API coverage integration suites now live under [`pulumi-tests/`](../../pulumi-tests/)
(Pulumi / `pulumi_openstack`). See [hypervisor-lab.md](../hypervisor-lab.md).
+26
View File
@@ -0,0 +1,26 @@
**Language / Язык:** [English](troubleshooting-clients.md) | [Русский](../ru/examples/troubleshooting-clients.md)
# Client troubleshooting
## Catalog points at unreachable hosts
The seed catalog uses `host.docker.internal` or compose service hostnames in
some setups. Override endpoints or use the gateway host you actually expose
(`127.0.0.1` with port-forward).
## SSL errors against Ingress
Lab staging issuers are untrusted — use `curl -k` / `OS_INSECURE=true` only in labs.
## Empty server list
Wrong project scope, or demo not loaded. Check:
```bash
openstack project list
make seed-demo
```
## Microversion rejected
Lower the requested compute microversion or clear Web UI overrides.
+39
View File
@@ -0,0 +1,39 @@
**Language / Язык:** [English](faq.md) | [Русский](ru/faq.md)
# FAQ
## Is this a real OpenStack cloud?
No. It is a **surface-complete API laboratory**: PostgreSQL-backed state,
API-ref-shaped responses, no hypervisor orchestration.
## Which release should I use?
Default **Dalmatian** pack. Switch with `OPENSTACK_SERIES` or the Web UI.
See [api-versions.md](api-versions.md).
## Compose vs Helm?
| Need | Use |
|---|---|
| Local hack / CI on Docker | Compose |
| Cluster + Ingress TLS | Helm ([kubernetes.md](kubernetes.md)) |
## Why so many ports?
OpenStack service catalog expects distinct endpoints. The api-gateway publishes
the [real default port matrix](ports.md) **1:1** (no host remapping).
## Demo cloud wiped my resources
Lifecycle tests and reseed truncate lab tables. Reload with `make seed-demo`.
## Can I point Terraform / Ansible at it?
Yes — use Keystone URL and seeded credentials. Expect lab limitations
(policy, async workflows, Ceph, etc.). See [clients.md](clients.md).
## Where is the Helm chart?
[`helm/openstack-api-simulator`](../helm/openstack-api-simulator) — guide in
[kubernetes.md](kubernetes.md).
+123
View File
@@ -0,0 +1,123 @@
**Language / Язык:** [English](getting-started.md) | [Русский](ru/getting-started.md)
# Getting started
End-to-end first lab session with Docker Compose. For Kubernetes see
[kubernetes.md](kubernetes.md).
## Prerequisites
- Docker / Docker Compose
- Python 3.13+ (optional, for host-side smoke scripts)
- `curl` or `openstack` CLI / `openstacksdk`
## Choose a path
| Path | When |
|---|---|
| **1a. Published image** | Running lab from Hub image (`docker-compose.release.yml`; needs a repo checkout for gateway/TLS mounts) |
| **1b. Development checkout** | You will change code / packs |
| **Helm** | Cluster install — [kubernetes.md](kubernetes.md) |
## 1a. Published image (Docker Hub)
Requires a **git checkout** of this repo: Compose bind-mounts
`./docker/gateway` and `./docker/tls` into the nginx gateway. The simulator
container itself comes from Docker Hub (no local app build).
```bash
git clone https://github.com/inecs/openstack-api-simulator.git
cd openstack-api-simulator
docker compose -f docker-compose.release.yml up -d --wait
# or: make release-up
```
Image: [`inecs/openstack-api-simulator`](https://hub.docker.com/r/inecs/openstack-api-simulator).
Override tag with `IMAGE_TAG=0.1.0` if needed.
## 1b. Development checkout
```bash
cp .env.example .env
docker compose up -d --build --wait
```
## 2. Wait until ready
```bash
curl -sf http://127.0.0.1:5000/health/ready
```
## 3. Seed a profile
Minimal seed runs on first start. Optional full synthetic cloud:
```bash
make seed-demo
# or
docker compose exec simulator python -m app.openstack.seed_cli --profile demo
```
Profiles: [seed-profiles.md](seed-profiles.md).
## 4. Authenticate (Keystone)
```bash
export OS_AUTH_URL=http://127.0.0.1:5000/v3
TOKEN=$(curl -si -X POST "$OS_AUTH_URL/auth/tokens" \
-H 'Content-Type: application/json' \
-d '{
"auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "admin",
"domain": {"name": "Default"},
"password": "secret"
}
}
},
"scope": {
"project": {"name": "demo", "domain": {"name": "Default"}}
}
}
}' | awk -F': ' 'tolower($1)=="x-subject-token"{print $2}' | tr -d '\r')
echo "token=$TOKEN"
```
## 5. Call Nova / Neutron
```bash
curl -sH "X-Auth-Token: $TOKEN" http://127.0.0.1:8774/v2.1/servers/detail | head -c 400
curl -sH "X-Auth-Token: $TOKEN" http://127.0.0.1:9696/v2.0/networks
```
## 6. Open the Web UI
[http://localhost:5000/](http://localhost:5000/) — console, Environment drawer
(OpenStack pack series + microversions), Data drawer (load/unload demo cloud).
## 7. Smoke / conformance
```bash
make smoke
python3 examples/python/openstack_smoke.py
python3 examples/python/openstack_conformance.py
```
## You're done when…
- `/health/ready` returns 200
- Keystone issues `X-Subject-Token`
- Nova/Neutron lists return seeded resources
- (optional) demo cloud shows ~1000 servers
## Next steps
- [Ports](ports.md) — full service port matrix
- [API coverage](api_coverage.md) — pack operations by series
- [Clients](clients.md) — openstacksdk / CLI
- [Kubernetes / Helm](kubernetes.md)
- [Hypervisor-lab](hypervisor-lab.md) — Pulumi API coverage (all ops × series)
- [Operations](operations.md)
+33
View File
@@ -0,0 +1,33 @@
**Language / Язык:** [English](hypervisor-lab.md) | [Русский](ru/hypervisor-lab.md)
# Pulumi OpenStack coverage lab
Suite under [`pulumi-tests/`](../pulumi-tests/) that maximises
**`pulumi_openstack`**, then HTTP-probes pack operations with **non-empty**
response checks across **yoga → dalmatian**.
## Quick start
```bash
make pulumi-tests # from repo root (full suite)
make test-pulumi-smoke # fast collection mode
```
Or:
```bash
cd pulumi-tests
make up && make build
make test-pulumi
open reports/pulumi-report.html
```
## Flow (per series)
1. Activate series pack
2. Pulumi Automation API → `programs/os_coverage` (`pulumi_openstack` resources + data sources)
3. Assert every export is non-empty
4. HTTP probe remaining/all pack ops; require non-empty bodies on successful GET/POST
5. Destroy stack; emit HTML + JUnit
See [`pulumi-tests/README.md`](../pulumi-tests/README.md).
+184
View File
@@ -0,0 +1,184 @@
**Language / Язык:** [English](kubernetes.md) | [Русский](ru/kubernetes.md)
# Kubernetes / Helm
Deploy the published Docker Hub runtime image with the chart in
[`helm/openstack-api-simulator`](../helm/openstack-api-simulator).
Image: [`inecs/openstack-api-simulator`](https://hub.docker.com/r/inecs/openstack-api-simulator)
The chart mirrors Docker Compose:
| Component | Role |
|---|---|
| **simulator** Deployment | FastAPI app on `:8080` |
| **api-gateway** Deployment | nginx multi-port OpenStack gateway |
| **PostgreSQL** StatefulSet | Bundled Postgres 17 (optional) |
| **migrate** initContainer | Idempotent schema migrations |
| **seed** Job (optional) | `minimal` or `demo` lab data |
## Prerequisites
- Kubernetes 1.27+ (or comparable)
- Helm 3.14+
- For Ingress TLS: [Ingress NGINX](https://kubernetes.github.io/ingress-nginx/) and
[cert-manager](https://cert-manager.io/)
Example cert-manager install:
```bash
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.yaml
```
## Quick install (Hub release + Ingress + Let's Encrypt)
From a git checkout of this repository:
```bash
helm upgrade --install os-sim ./helm/openstack-api-simulator \
-n openstack-sim --create-namespace \
-f ./helm/openstack-api-simulator/values-ingress-example.yaml \
--set certManager.email=you@example.com \
--set ingress.hosts[0].host=os-sim.example.com \
--set ingress.tls[0].hosts[0]=os-sim.example.com \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set postgresql.auth.password="$(openssl rand -hex 16)"
```
What this does:
1. Pulls `inecs/openstack-api-simulator:0.1.0`.
2. Installs bundled PostgreSQL 17 (`postgres:17.5-bookworm`).
3. Runs schema migrations in an init container (idempotent).
4. Seeds the **demo** lab profile (`seed.enabled=true`, ~1000 servers).
5. Deploys nginx **api-gateway** with OpenStack default ports (5000, 8774, 9696, …).
6. Creates `ClusterIssuer` resources (`letsencrypt-prod` / `letsencrypt-staging`).
7. Creates an Ingress → gateway `:5000` (Keystone + Web UI) with TLS.
DNS for `os-sim.example.com` must point at your Ingress controller. Then:
```bash
kubectl -n openstack-sim get certificate,ingress,pods
curl -sS https://os-sim.example.com/health/ready
open https://os-sim.example.com/
```
Default seeded login: `admin` / `secret` (project `demo` or `admin`, domain `Default`).
### Staging first (recommended)
```bash
helm upgrade --install os-sim ./helm/openstack-api-simulator \
-n openstack-sim --create-namespace \
-f ./helm/openstack-api-simulator/values-ingress-example.yaml \
--set certManager.email=you@example.com \
--set certManager.useStaging=true \
--set ingress.hosts[0].host=os-sim.example.com \
--set ingress.tls[0].hosts[0]=os-sim.example.com \
--set secret.ticketSigningKey="$(openssl rand -hex 32)"
```
Use `curl -k` against the staging CA. Flip `certManager.useStaging=false` for production.
## Minimal install (ClusterIP + port-forward)
```bash
helm upgrade --install os-sim ./helm/openstack-api-simulator \
-n openstack-sim --create-namespace \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set seed.enabled=true \
--set seed.profile=minimal
kubectl -n openstack-sim port-forward \
svc/os-sim-openstack-api-simulator-gateway \
5000:5000 8774:8774 9696:9696 9292:9292 8776:8776
```
| URL | Service |
|---|---|
| http://127.0.0.1:5000/ | Keystone + console |
| http://127.0.0.1:8774/v2.1/ | Nova |
| http://127.0.0.1:9696/v2.0/ | Neutron |
Full port matrix: [ports.md](ports.md).
## External PostgreSQL
```bash
helm upgrade --install os-sim ./helm/openstack-api-simulator \
-n openstack-sim --create-namespace \
--set postgresql.enabled=false \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set secret.databaseUrl='postgresql://user:pass@pg.example.com:5432/openstack_simulator'
```
Or use `secret.existingSecret` with keys `DATABASE_URL` and `TICKET_SIGNING_KEY`.
## How the api-gateway works
Same model as Compose (`docker/gateway/openstack-ports.conf`):
1. Client connects to a **service-specific port** (e.g. Nova `8774`).
2. nginx sets `X-OpenStack-Service` and `X-Forwarded-Port`.
3. FastAPI rewrites to `/_os/<service>/…` so `/v3` (Keystone vs Cinder) does not collide.
Ingress (when enabled) fronts **Keystone/UI on port 5000**. For Nova/Neutron from
outside the cluster, either:
- `kubectl port-forward` additional ports, or
- expose `*-gateway` as `LoadBalancer` / `NodePort` (`gateway.service.type`), or
- add extra Ingress rules / TCP services for those ports.
## How TLS issuance works
When `certManager.enabled=true` and `certManager.createClusterIssuer=true`, the
chart creates ACME `ClusterIssuer` objects (HTTP-01). The Ingress template adds:
```yaml
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- secretName: openstack-api-simulator-tls
hosts: [os-sim.example.com]
```
The chart does **not** install cert-manager or the Ingress controller.
## Operations
```bash
# logs
kubectl -n openstack-sim logs -l app.kubernetes.io/component=simulator -f
kubectl -n openstack-sim logs -l app.kubernetes.io/component=gateway -f
# reseed minimal
kubectl -n openstack-sim exec deploy/os-sim-openstack-api-simulator -- \
python -m app.openstack.seed_cli --profile minimal
# reseed demo cloud
kubectl -n openstack-sim exec deploy/os-sim-openstack-api-simulator -- \
python -m app.openstack.seed_cli --profile demo
# activate OpenStack pack series
kubectl -n openstack-sim set env deploy/os-sim-openstack-api-simulator \
OPENSTACK_SERIES=caracal
# then restart the pod / helm upgrade with --set config.openstackSeries=caracal
# uninstall
helm -n openstack-sim uninstall os-sim
```
## Values reference
See [`helm/openstack-api-simulator/values.yaml`](../helm/openstack-api-simulator/values.yaml)
and the [chart README](../helm/openstack-api-simulator/README.md).
Related docs:
- [Getting started](getting-started.md) — Compose path
- [Operations](operations.md) — Docker Hub publish / day-2
- [Ports](ports.md) — OpenStack port matrix
- [Seed profiles](seed-profiles.md) — `minimal` / `demo`
- [Security](security.md) — lab credentials
+39
View File
@@ -0,0 +1,39 @@
**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 gateway (any published port).
## 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:
```bash
kubectl logs -l app.kubernetes.io/component=simulator -f
kubectl logs -l app.kubernetes.io/component=gateway -f
```
## Compatibility / coverage evidence
- Pack coverage: [api_coverage.md](api_coverage.md)
- Live lifecycle: `examples/python/openstack_surface_probe.py`
- pytest: `tests/openstack/` (includes real-DB conformance)
+117
View File
@@ -0,0 +1,117 @@
**Language / Язык:** [English](operations.md) | [Русский](ru/operations.md)
# Operations
## Day-2 commands (Compose)
```bash
make up # start stack
make down # stop stack
make restart
make logs
make db-migrate # idempotent migrations
make seed # minimal OpenStack seed
make seed-demo # demo cloud (~1000 servers)
make smoke # multi-service GET smoke
```
## Migrations
Ordered SQL under `app/db/migrations/` applies transactionally.
Re-running `make db-migrate` is safe. `/health/ready` stays unavailable until
migrations are applied. Helm runs the same migrate step as an initContainer.
## Reseed
```bash
make seed # minimal
make seed-demo # replaces state with demo cloud
```
Or:
```bash
docker compose exec simulator python -m app.openstack.seed_cli --profile demo
```
Reseed **truncates** OpenStack lab tables and reloads. External automation that
cached resource UUIDs must refresh.
## OpenStack pack series
Cold start (env):
```bash
OPENSTACK_SERIES=caracal docker compose up -d
```
Helm:
```bash
--set config.openstackSeries=yoga
```
Hot-swap (Web UI or API):
```bash
curl -X POST http://127.0.0.1:5000/ui/api/openstack/contracts/activate \
-H 'Content-Type: application/json' \
-d '{"series":"dalmatian"}'
```
Series: `yoga`, `antelope`, `caracal`, `dalmatian`. Coverage:
[api_coverage.md](api_coverage.md).
## Regenerating contract packs
```bash
PYTHONPATH=tools python3 tools/os_api_inventory/generate_packs.py
PYTHONPATH=tools python3 tools/os_api_inventory/coverage_report.py
```
## Backing up lab state
PostgreSQL is the system of record. Use `pg_dump` / volume snapshots.
Application containers are disposable when the database volume remains.
## Publishing to Docker Hub
```bash
docker login
make release
```
| Variable | Default | Meaning |
|---|---|---|
| `DOCKERHUB_USER` | `inecs` | Docker Hub namespace |
| `IMAGE_NAME` | `openstack-api-simulator` | Repository name |
| `VERSION` | from `pyproject.toml` | Image tag |
```bash
make release VERSION=0.2.0
make release-build # local tags only
```
## Kubernetes day-2
See [kubernetes.md](kubernetes.md) for logs, reseed via `kubectl exec`, and
uninstall.
## API coverage lab CI (pulumi-tests)
Pulumi probes every pack operation across series — see
[hypervisor-lab.md](hypervisor-lab.md).
```bash
make test-pulumi-smoke # from repo root
make test-pulumi
```
Reports: `pulumi-tests/reports/pulumi-report.html` and `pulumi-junit.xml`.
## Upgrades
1. Pull / build new image tag.
2. Apply migrations (automatic on start / Helm initContainer).
3. Optionally reseed if the seed schema changed.
4. Re-run `make smoke` or lifecycle probes.
+56
View File
@@ -0,0 +1,56 @@
**Language / Язык:** [English](ports.md) | [Русский](ru/ports.md)
# OpenStack default ports in this simulator
Reference: [Firewalls and default ports](https://docs.openstack.org/install-guide/firewalls-default-ports.html).
These are the **real OpenStack public API defaults**. Compose and Helm publish
them **1:1** on the host / Service (no remapping): host `5000` is Keystone,
host `8774` is Nova, and so on. Run this stack on its own host/VM so these
ports do not collide with other lab simulators.
Clients talk to **api-gateway** (nginx) — Compose service or Helm
`*-gateway` Deployment/Service. Each listen port sets `X-OpenStack-Service`
and `X-Forwarded-Port`; the FastAPI process rewrites the path to
`/_os/<service>/…` so overlapping API roots (`/v3`, `/v1`, …) do not collide.
Typical auth URL: `http://127.0.0.1:5000/v3` (or HTTPS on `:5000` / `:443`
via the gateway).
Helm values list: `gateway.service.ports` in
[`helm/openstack-api-simulator/values.yaml`](../helm/openstack-api-simulator/values.yaml).
| Port | Service | Role | Primary paths |
|------|---------|------|---------------|
| 5000 | keystone | Identity — tokens, projects, users, roles, service catalog | `/v3/auth/tokens`, `/v3/projects`, … |
| 8774 | nova | Compute — servers (VMs), flavors, keypairs, AZ, hypervisors | `/v2.1/servers`, flavors, keypairs, AZ, hypervisors, … |
| 9696 | neutron | Network — networks, subnets, ports, routers, SG, floating IPs | `/v2.0/networks`, subnets, ports, routers, SG, FIPs, QoS, trunks, … |
| 9292 | glance | Image — glance images | `/v2/images` |
| 8776 | cinder | Block storage — volumes, snapshots, volume types | `/v3/volumes` |
| 8003 | placement | Placement — resource providers and inventories | `/resource_providers` |
| 8004 | heat | Orchestration — Heat stacks | `/v1/{project_id}/stacks` |
| 8000 | heat-cfn | CloudFormation-compatible Heat API | `/stacks` |
| 8080 | swift | Object storage — accounts, containers, objects | `/v1/{account}/{container}/…`, `/info` |
| 6385 | ironic | Bare metal — nodes, ports, chassis | `/v1/nodes` |
| 9876 | octavia | Load balancing — load balancers, listeners, pools | `/v2/lbaas/loadbalancers` |
| 9311 | barbican | Key manager — secrets, containers | `/v1/secrets` |
| 8786 | manila | Shared file systems — shares | `/v2/shares` |
| 9001 | designate | DNS — zones and recordsets | `/v2/zones` |
| 9511 | magnum | Container infra — clusters (e.g. Kubernetes) | `/v1/clusters` |
| 9517 | zun | Containers — container lifecycle | `/v1/containers` |
| 8779 | trove | Database as a service — DB instances | `/v1.0/instances` |
| 8989 | mistral | Workflows | `/v2/workflows` |
| 8042 | aodh | Alarming | `/v2/alarms` |
| 8889 | cloudkitty | Rating / billing metering | `/v1/rating/…` |
| 9090 | freezer | Backup jobs | `/v2/jobs` |
| 1234 | blazar | Reservation — leases | `/leases` |
| 8999 | vitrage | Root cause analysis (RCA) | `/v1/alarm` |
| 15868 | masakari | Instance high availability | `/v1/segments` |
| 9890 | tacker | NFV orchestration | `/v1.0/vnfs` |
| 5050 | adjutant | Admin workflows / self-service tasks | `/v1/tasks` |
| 9322 | watcher | Infrastructure optimization | `/v1/…` |
| 8888 | zaqar | Messaging | `/v2/…` |
| 80 | http | Console UI reverse proxy (Compose + Helm gateway) | — |
| 443 | https | TLS reverse proxy (**Compose only**; Helm terminates TLS at Ingress) | — |
Internal FastAPI listens on `8080` inside Docker only (not the Swift public port from the host — host `8080` is Swift via gateway). Postgres is published only as `127.0.0.1:5433` (not an OpenStack API port).
+35
View File
@@ -0,0 +1,35 @@
**Language / Язык:** [English](../README.md) | [Русский](README.md)
# Документация
Руководства по лабораторному симулятору OpenStack API. Переключайте язык
заголовком на каждой странице. Английские оригиналы — в родительском
каталоге [`docs/`](../README.md).
| Руководство | Тема |
|---|---|
| [Быстрый старт](getting-started.md) | Первая лабораторная сессия (Compose) |
| [Kubernetes / Helm](kubernetes.md) | Установка в кластер, Ingress, cert-manager |
| [Конфигурация](configuration.md) | Переменные окружения, Compose, Helm |
| [Аутентификация](authentication.md) | Токены Keystone и seed-пользователи |
| [Порты](ports.md) | Реальные порты API OpenStack (публикация 1:1) |
| [API surface](api-surface.md) | Специализированные vs schema-пакеты |
| [Версии API](api-versions.md) | Серии Yoga → Dalmatian |
| [Покрытие API](api_coverage.md) | Счётчики операций |
| [Seed-профили](seed-profiles.md) | `minimal` / `demo` |
| [Клиенты](clients.md) | SDK / CLI |
| [Web UI](web-ui.md) | Консоль и drawers |
| [Эксплуатация](operations.md) | Day-2, релиз, reseed |
| [Архитектура](architecture.md) | Компоненты и путь запроса |
| [Безопасность](security.md) | Threat model лаборатории |
| [Наблюдаемость](observability.md) | Health и логи |
| [Устранение неполадок](troubleshooting.md) | Типичные сбои |
| [FAQ](faq.md) | Краткие ответы |
| [Домены](domains/README.md) | Заметки по сервисам |
| [Примеры](examples/overview.md) | Cookbook'и клиентов |
| [Hypervisor-lab](hypervisor-lab.md) | Pulumi-покрытие API (все ops × серии) |
Исполняемые cookbook'и: [`examples/`](../../examples/README.ru.md).
Интеграционные сьюты: [`pulumi-tests/`](../../pulumi-tests/README.ru.md).
Назад к [README](../../README.ru.md).
+44
View File
@@ -0,0 +1,44 @@
**Language / Язык:** [English](../api-surface.md) | [Русский](api-surface.md)
# Поверхность API
## Surface-complete пакеты
Каждый пакет серии OpenStack перечисляет операции **method + path**. При старте
каждая уникальная пара `(method, path)` регистрируется как отдельный маршрут FastAPI
(`os-contract:…`), в стиле Proxmox. Stateful-обработчики из специализированных
модулей ищутся через `HandlerRegistry`; всё остальное уходит в schema-движок
(лабораторный JSON `os_api_objects`).
| Series | Services | Operations (approx.) |
|---|---|---|
| Yoga | 28 | ~1060 |
| Antelope | 28 | ~1108 |
| Caracal | 28 | ~1196 |
| Dalmatian | 28 | ~1357 |
Авторитетные числа: [api_coverage.md](api_coverage.md).
## Handlers vs schema fallback
| Слой | Сервисы / ресурсы |
|---|---|
| **Специализированные handlers** | Keystone tokens/catalog, Nova servers/flavors/keypairs/…, Neutron nets/ports/…, Glance images, Cinder volumes, Heat stacks, Swift, Ironic nodes, Octavia LBs, Placement RPs |
| **Schema fallback** | Остальные коллекции пакета (Barbican, Manila, Designate, Magnum, …), включая вложенные пути |
## Microversions
Заголовки вроде `OpenStack-API-Version: compute 2.79` и
`X-OpenStack-Nova-API-Version` принимаются и фильтруются по метаданным пакета.
Переопределения можно задать в Web UI Environment drawer.
## Actions
Nova-style `POST /servers/{id}/action` и аналогичные ops пакета `kind=action`
обрабатываются schema/action-путём (обновление power state для типичных actions).
## Ошибки
Ошибки в форме OpenStack (`OpenStackError`) с `code`, `title`, `message`.
Неизвестные маршруты, отсутствующие в активном contract-пакете, возвращают
стандартный FastAPI `404`.
+56
View File
@@ -0,0 +1,56 @@
**Language / Язык:** [English](../api-versions.md) | [Русский](api-versions.md)
# Версии API (series packs)
Симулятор поставляет **четыре** серии релизов OpenStack как contract-пакеты:
| Series | OpenStack release family | Cold-start env |
|---|---|---|
| `yoga` | Yoga | `OPENSTACK_SERIES=yoga` |
| `antelope` | Antelope | `OPENSTACK_SERIES=antelope` |
| `caracal` | Caracal | `OPENSTACK_SERIES=caracal` |
| `dalmatian` | Dalmatian (default) | `OPENSTACK_SERIES=dalmatian` |
## Cold start
Compose / процесс:
```bash
OPENSTACK_SERIES=caracal docker compose up -d
```
Helm:
```bash
--set config.openstackSeries=yoga
```
## Hot-swap
```bash
curl -X POST http://127.0.0.1:5000/ui/api/openstack/contracts/activate \
-H 'Content-Type: application/json' \
-d '{"series":"dalmatian"}'
```
Или Web UI → Environment → OpenStack API pack → Activate.
Hot-swap перемонтирует schema-маршруты (`remount_schema_services`) без пересборки
образа.
## Структура пакета
```
contracts/openstack/<series>/
manifest.json
keystone/api.json
nova/api.json
neutron/api.json
```
Перегенерация:
```bash
PYTHONPATH=tools python3 tools/os_api_inventory/generate_packs.py
```
+64
View File
@@ -0,0 +1,64 @@
**Language / Язык:** [English](../api_coverage.md) | [Русский](api_coverage.md)
# Покрытие OpenStack API — dalmatian
Сгенерировано из `contracts/openstack/dalmatian/manifest.json`.
- **Services:** 28
- **Operations:** 1357
- **Checksum:** `5d8f32baa835db2b556b6f33ac3c1b67b74db8194f00ce7d6eb8c59e3bbd7063`
- **Generated at:** 2026-07-16T00:28:30Z
## Дельты серий
| Series | Major | Operations |
|---|---:|---:|
| Antelope | 7 | 1108 |
| Caracal | 8 | 1196 |
| Dalmatian | 9 | 1357 |
| Yoga | 6 | 1060 |
Более старые серии опускают пути, добавленные позже (`tools/os_api_inventory/series_deltas.py`),
и используют более низкие потолки microversion. Примените пакет в Environment drawer для hot-swap.
Surface-complete означает, что каждая операция пакета смонтирована schema-движком
(специализированные роутеры по-прежнему выигрывают на пересекающихся stateful-путях).
| Service | Type | Port | Operations | Microversions |
|---|---|---:|---:|---|
| adjutant | admin-logic | 5050 | 24 | — |
| aodh | alarming | 8042 | 19 | — |
| barbican | key-manager | 9311 | 25 | — |
| blazar | reservation | 1234 | 19 | — |
| cinder | volumev3 | 8776 | 98 | 3.03.70 |
| cloudkitty | rating | 8889 | 25 | — |
| designate | dns | 9001 | 37 | — |
| freezer | backup | 9090 | 31 | — |
| glance | image | 9292 | 39 | — |
| heat | orchestration | 8004 | 38 | — |
| heat-cfn | cloudformation | 8000 | 8 | — |
| ironic | baremetal | 6385 | 58 | 1.11.90 |
| keystone | identity | 5000 | 77 | — |
| magnum | container-infra | 9511 | 25 | — |
| manila | sharev2 | 8786 | 50 | 2.02.82 |
| masakari | instance-ha | 15868 | 19 | — |
| mistral | workflowv2 | 8989 | 37 | — |
| neutron | network | 9696 | 290 | — |
| nova | compute | 8774 | 124 | 2.12.96 |
| octavia | load-balancer | 9876 | 74 | — |
| placement | placement | 8003 | 30 | 1.01.39 |
| swift | object-store | 8080 | 10 | — |
| tacker | nfv-orchestration | 9890 | 30 | — |
| trove | database | 8779 | 31 | — |
| vitrage | rca | 8999 | 30 | — |
| watcher | infra-optim | 9322 | 49 | — |
| zaqar | messaging | 8888 | 27 | — |
| zun | container | 9517 | 33 | — |
## Минимумы core
| Service | Required | Actual |
|---|---:|---:|
| keystone | 40 | 77 (OK) |
| neutron | 70 | 290 (OK) |
| nova | 70 | 124 (OK) |
+58
View File
@@ -0,0 +1,58 @@
**Language / Язык:** [English](../architecture.md) | [Русский](architecture.md)
# Архитектура
## Компоненты
```
┌─────────────┐ ┌──────────────────┐ ┌────────────┐
│ Clients │────▶│ api-gateway │────▶│ simulator │
│ SDK / CLI │ │ nginx multi-port│ │ FastAPI │
│ Web UI │ │ :5000,:8774,… │ │ :8080 │
└─────────────┘ └──────────────────┘ └─────┬──────┘
┌─────▼──────┐
│ PostgreSQL │
└────────────┘
```
| Компонент | Ответственность |
|---|---|
| **api-gateway** | Публикация стандартных портов OpenStack; выставление `X-OpenStack-Service` / `X-Forwarded-Port` |
| **ServiceDispatchMiddleware** | Переписывание в `/_os/<service>/…` |
| **Специализированные роутеры** | Stateful Keystone, Nova, Neutron, Glance, Cinder, Heat, Swift, Ironic, Octavia, Placement |
| **Schema engine** | Surface-complete ops из `contracts/openstack/<series>/` |
| **PostgreSQL** | Identity, IaaS-таблицы, generic store `os_api_objects` |
## Жизненный цикл запроса
1. Клиент обращается, например, к `http://host:8774/v2.1/servers`.
2. Gateway добавляет service headers.
3. Dispatch монтирует запрос под `/_os/nova/…`.
4. Выполняется специализированный Nova handler **или** schema pack operation.
5. Чтение/запись идут в PostgreSQL (типизированные таблицы или `os_api_objects`).
## Contract-пакеты
- Сгенерированный inventory → `contracts/openstack/{yoga,antelope,caracal,dalmatian}/`
- Hot-swap через Web UI / `/ui/api/openstack/contracts/activate`
- Отчёт покрытия: [api_coverage.md](api_coverage.md)
## Seed-профили
| Profile | Содержимое |
|---|---|
| `minimal` | Небольшой Keystone + несколько IaaS-ресурсов |
| `demo` | ~1000 servers, multi-project topology, nested collections |
Подробности: [seed-profiles.md](seed-profiles.md).
## Модель развёртывания
| Mode | Gateway | DB |
|---|---|---|
| Compose | nginx container | bundled Postgres |
| Helm | nginx Deployment + multi-port Service | bundled StatefulSet или external |
| Ingress | TLS terminates at Ingress → gateway:5000 | — |
См. [kubernetes.md](kubernetes.md).
+80
View File
@@ -0,0 +1,80 @@
**Language / Язык:** [English](../authentication.md) | [Русский](authentication.md)
# Аутентификация
Симулятор реализует **Keystone v3** password-аутентификацию и project scoping
(лабораторное подмножество).
## Password auth
```http
POST /v3/auth/tokens
Content-Type: application/json
{
"auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "admin",
"domain": {"name": "Default"},
"password": "secret"
}
}
},
"scope": {
"project": {"name": "demo", "domain": {"name": "Default"}}
}
}
}
```
Ответ:
- Заголовок **`X-Subject-Token`** — используйте как **`X-Auth-Token`** в следующих запросах
- Тело `token.catalog` — endpoints сервисов (порты соответствуют [ports.md](ports.md))
## Seed-принципалы
Пароль для всех пользователей: **`secret`**. Домен: **`Default`**.
### Minimal seed
| Пользователь | Проекты | Роль |
|---|---|---|
| `admin` | `admin`, `demo` | admin |
| `demo` | `demo` | member |
### Demo cloud
| Пользователь | Типичные проекты |
|---|---|
| `admin` | все |
| `ops` | production, staging |
| `developer` | development, staging |
| `demo` / `auditor` | demo / production |
## Unscoped / ошибки
- Нет токена → `401 Unauthorized`
- Неверный пароль → `401`
- Project-scoped API без project scope → `401` с понятным сообщением
## openstacksdk / CLI
```bash
export OS_AUTH_URL=http://127.0.0.1:5000/v3
export OS_USERNAME=admin
export OS_PASSWORD=secret
export OS_PROJECT_NAME=demo
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_IDENTITY_API_VERSION=3
openstack server list
openstack network list
```
Против Helm Ingress задайте `OS_AUTH_URL=https://os-sim.example.com/v3`
(и доверьте сертификат или используйте `--insecure` в лаборатории).
+46
View File
@@ -0,0 +1,46 @@
**Language / Язык:** [English](../clients.md) | [Русский](clients.md)
# Клиенты
## Матрица подключения
| Client | Auth URL | Примечания |
|---|---|---|
| curl | `http://127.0.0.1:5000/v3` | Используйте `X-Subject-Token``X-Auth-Token` |
| openstack CLI | `OS_AUTH_URL=…/v3` | См. [authentication.md](authentication.md) |
| openstacksdk | same | Порты service catalog должны совпадать с gateway |
| Terraform OpenStack provider | `auth_url` | Укажите Keystone; catalog направляет Nova/Neutron |
| Ansible `openstack.*` | clouds.yaml | Те же credentials, что и для CLI |
## Compose (локально)
```bash
export OS_AUTH_URL=http://127.0.0.1:5000/v3
export OS_USERNAME=admin
export OS_PASSWORD=secret
export OS_PROJECT_NAME=demo
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_IDENTITY_API_VERSION=3
```
## Helm / Ingress
```bash
export OS_AUTH_URL=https://os-sim.example.com/v3
# Другие сервисы: port-forward портов gateway или catalog URLs,
# которые ваш Ingress/DNS корректно мапят.
```
Для multi-port доступа без Ingress TCP используйте port-forward gateway Service
(см. [kubernetes.md](kubernetes.md)).
## Примеры в репозитории
| Path | Назначение |
|---|---|
| `examples/python/openstack_smoke.py` | Multi-port GET smoke |
| `examples/python/openstack_conformance.py` | Write-path sample |
| `examples/python/openstack_surface_probe.py` | Полный lifecycle probe пакета |
Cookbook'и: [examples/overview.md](examples/overview.md).
+59
View File
@@ -0,0 +1,59 @@
**Language / Язык:** [English](../configuration.md) | [Русский](configuration.md)
# Конфигурация
## Переменные окружения
| Переменная | По умолчанию | Назначение |
|---|---|---|
| `APP_HOST` | `0.0.0.0` | Адрес привязки |
| `APP_PORT` | `8080` | Внутренний порт FastAPI (не публичный порт Keystone) |
| `DATABASE_URL` | (compose/helm) | PostgreSQL DSN |
| `TICKET_SIGNING_KEY` | lab secret | Материал подписи токенов (ротируйте в общих лабораториях) |
| `LOG_LEVEL` | `INFO` | Уровень логирования |
| `OPENSTACK_SERIES` | `dalmatian` | Серия contract-пакета при холодном старте |
| `REQUEST_ID_HEADER` | `X-Request-ID` | Заголовок корреляции запросов |
| `SEED_PROFILE` | `minimal` | Для `seed_cli` / Helm seed Job (`minimal` / `demo`) |
## Compose
| Файл | Роль |
|---|---|
| `docker-compose.yml` | Dev-стек (build + bind mounts) |
| `docker-compose.release.yml` | Опубликованный Hub-образ |
| `.env` / `.env.example` | Локальные переопределения |
Сервисы:
- **simulator** — FastAPI на внутреннем `8080`
- **api-gateway** — nginx, публикующий реальные порты API OpenStack 1:1 ([ports.md](ports.md))
- **postgres** — `postgres:17.5-bookworm` на хосте `127.0.0.1:5433`
## Helm
См. [kubernetes.md](kubernetes.md) и
[`helm/openstack-api-simulator/values.yaml`](../../helm/openstack-api-simulator/values.yaml).
Важные параметры:
| Value | Назначение |
|---|---|
| `gateway.enabled` | Multi-port nginx (по умолчанию `true`) |
| `config.openstackSeries` | Env `OPENSTACK_SERIES` |
| `seed.profile` | `minimal` / `demo` |
| `postgresql.enabled` | Встроенная БД |
| `secret.ticketSigningKey` | Нужно ротировать для общих кластеров |
## Contract-пакеты
Расположение: `contracts/openstack/<series>/`.
В каждой серии — per-service пакеты `api.json`, потребляемые schema-движком.
Специализированные роутеры (Keystone, Nova, Neutron, …) остаются stateful для happy-path'ов.
## Переопределения Web UI
Environment drawer → **OpenStack API pack**:
- Активация серии (hot remount)
- Переопределение microversion по сервисам
+22
View File
@@ -0,0 +1,22 @@
**Language / Язык:** [English](../../domains/README.md) | [Русский](README.md)
# Домены сервисов OpenStack
Руководства по основным специализированным поверхностям. Pack-only сервисы
(Barbican, Manila, Designate, …) покрываются schema-движком и засеваются в
`os_api_objects` — см. [api-surface.md](../api-surface.md) и
[api_coverage.md](../api_coverage.md).
| Руководство | Сервис | Порт |
|---|---|---|
| [keystone.md](keystone.md) | Identity | 5000 |
| [nova.md](nova.md) | Compute | 8774 |
| [neutron.md](neutron.md) | Network | 9696 |
| [glance.md](glance.md) | Image | 9292 |
| [cinder.md](cinder.md) | Block storage | 8776 |
| [placement.md](placement.md) | Placement | 8003 |
| [heat.md](heat.md) | Orchestration | 8004 |
| [swift.md](swift.md) | Object storage | 8080 |
| [ironic.md](ironic.md) | Bare metal | 6385 |
| [octavia.md](octavia.md) | Load balancer | 9876 |
| [schema-services.md](schema-services.md) | Остальные pack-сервисы | разные |
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](../../domains/cinder.md) | [Русский](cinder.md)
# Cinder (block storage)
Порт **8776**. Пути под `/v3/``/v3/{project_id}/…`).
## Stateful
CRUD томов. Demo cloud: ~600 volumes (`in-use` / `available`).
Snapshots, types, backups и связанные коллекции — pack/schema-backed.
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](../../domains/glance.md) | [Русский](glance.md)
# Glance (image)
Порт **9292**. Пути под `/v2/`.
## Stateful
Список/просмотр/создание/обновление/удаление образов; публичные и project-owned
images. Members/tags обслуживаются из `os_api_objects` в demo seed.
+11
View File
@@ -0,0 +1,11 @@
**Language / Язык:** [English](../../domains/heat.md) | [Русский](heat.md)
# Heat (orchestration)
Порт **8004**. Пути `/v1/{tenant_id}/…`.
## Stateful
Стеки в `os_stacks`. Demo seed добавляет stacks плюс вложенные строки
`stack_resource` / `stack_event` / `software_config` / `software_deployment`
для pack GET-probe'ов.
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](../../domains/ironic.md) | [Русский](ironic.md)
# Ironic (bare metal)
Порт **6385**.
## Stateful
Nodes в `os_nodes`. Demo seed создаёт пул ironic-нод; ports/chassis/
allocations — schema-backed примеры.
+21
View File
@@ -0,0 +1,21 @@
**Language / Язык:** [English](../../domains/keystone.md) | [Русский](keystone.md)
# Keystone (identity)
Порт **5000**. Пути под `/v3/`.
## Реализовано (lab)
- `POST /v3/auth/tokens` — password auth, project scope
- Catalog с multi-port endpoints
- Projects, users, roles, role assignments (seed + CRUD через pack/schema)
- Domains (`Default`)
## Seed
Профили minimal и demo создают домен `Default`, роли `admin`/`member` и
пользователей, описанных в [authentication.md](../authentication.md).
## Примечания
Federation, application credentials и полный policy engine вне scope.
+16
View File
@@ -0,0 +1,16 @@
**Language / Язык:** [English](../../domains/neutron.md) | [Русский](neutron.md)
# Neutron (network)
Порт **9696**. Пути под `/v2.0/`.
## Stateful-ресурсы
Networks, subnets, ports, routers, security groups/rules, floating IPs, agents.
## Schema / seeded-расширения
QoS, trunks, RBAC, address scopes, subnet pools, conntrack helpers, port
forwardings, примеры FWaaS/VPNaaS/BGP VPN в demo seed.
Demo добавляет несколько nets/SGs/routers на проект для реалистичной плотности списков.
+21
View File
@@ -0,0 +1,21 @@
**Language / Язык:** [English](../../domains/nova.md) | [Русский](nova.md)
# Nova (compute)
Порт **8774**. Пути под `/v2.1/`.
## Stateful-ресурсы
Servers, flavors, keypairs, server groups, AZ, hypervisors, aggregates,
services, migrations, volume/interface attachments, metadata, tags,
instance actions, consoles (лабораторные URL).
## Demo cloud
~1000 серверов по проектам, metadata/`_tags`, attachments, связанные с volumes
и ports.
## Microversions
Отправляйте `OpenStack-API-Version: compute X.Y` или legacy-заголовок Nova.
Применяются ограничения пакета.
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](../../domains/octavia.md) | [Русский](octavia.md)
# Octavia (load balancer)
Порт **9876**. Пути под `/v2/lbaas/…`.
## Stateful
Load balancers в `os_loadbalancers`. Listeners/pools/healthmonitors/providers/
flavors обслуживаются из `os_api_objects` (demo seed их заполняет).
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](../../domains/placement.md) | [Русский](placement.md)
# Placement
Порт **8003**.
## Поведение в лаборатории
- `GET /resource_providers` — из demo `os_api_objects` (или fallback stub)
- `GET/PUT /allocations/{consumer_uuid}` — сохраняемые allocations с lab fallback
+14
View File
@@ -0,0 +1,14 @@
**Language / Язык:** [English](../../domains/schema-services.md) | [Русский](schema-services.md)
# Schema-backed сервисы
Эти проекты в основном обслуживаются contract-пакетами + `os_api_objects`
(demo seed вставляет несколько строк на тип ресурса):
Barbican, Manila, Designate, Magnum, Zun, Trove, Mistral, Aodh, CloudKitty,
Freezer, Blazar, Vitrage, Masakari, Tacker, Adjutant, Watcher, Zaqar, Heat-CFN.
Порты: [ports.md](../ports.md). Операции: [api_coverage.md](../api_coverage.md).
CRUD lifecycle проверяется через `examples/python/openstack_surface_probe.py`
и `tests/openstack/conformance/`.
+10
View File
@@ -0,0 +1,10 @@
**Language / Язык:** [English](../../domains/swift.md) | [Русский](swift.md)
# Swift (object storage)
Порт **8080** на **gateway** (внутренний simulator остаётся на 8080 за nginx).
## Stateful
Accounts/containers/objects в таблицах `os_swift_*`. Demo seed создаёт
контейнеры `images` / `backups` / `artifacts` с readme-объектом на проект.
+19
View File
@@ -0,0 +1,19 @@
**Language / Язык:** [English](../../examples/ansible.md) | [Русский](ansible.md)
# Ansible (openstack.cloud)
## Cookbook (один stack)
[`examples/ansible/playbook.yml`](../../../examples/ansible/playbook.yml) —
`ansible.builtin.uri` против Keystone/Nova/Neutron/Glance.
```bash
make up && make seed-demo
cd examples/ansible
ansible-playbook -i inventory.ini playbook.yml
```
Auth: `http://127.0.0.1:5000/v3`, `admin` / `secret`, проект `demo`.
Интеграционное покрытие API теперь в [`pulumi-tests/`](../../../pulumi-tests/)
(Pulumi / `pulumi_openstack`). См. [hypervisor-lab.md](../hypervisor-lab.md).
+21
View File
@@ -0,0 +1,21 @@
**Language / Язык:** [English](../../examples/openstack-cli.md) | [Русский](openstack-cli.md)
# OpenStack CLI
Типовой набор переменных окружения и команд против локального gateway:
```bash
export OS_AUTH_URL=http://127.0.0.1:5000/v3
export OS_USERNAME=admin
export OS_PASSWORD=secret
export OS_PROJECT_NAME=demo
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_IDENTITY_API_VERSION=3
openstack token issue
openstack server list
openstack network list
openstack volume list
openstack stack list
```
+53
View File
@@ -0,0 +1,53 @@
**Language / Язык:** [English](../../examples/overview.md) | [Русский](overview.md)
# Обзор примеров клиентов
Исполняемые скрипты — в [`examples/`](../../../examples/).
Лаборатория покрытия API на Pulumi — в [`pulumi-tests/`](../../../pulumi-tests/).
## Краткая справка
| Path | Tool | Purpose |
|---|---|---|
| `examples/python/openstacksdk_cookbook.py` | openstacksdk | net + server + volume lifecycle |
| `examples/ansible/playbook.yml` | Ansible `uri` | минимальный Keystone/Nova/Neutron |
| `examples/terraform/main.tf` | Terraform | `openstack_compute_instance_v2` + volume |
| `examples/pulumi/` | Pulumi | `pulumi_openstack` Instance + Network |
| `examples/run_iac_stack.sh` | все четыре | последовательный smoke cookbook'ов |
| `pulumi-tests/` | Pulumi | каждая pack-операция × yoga→dalmatian + HTML-отчёт |
## Auth
1. `POST /v3/auth/tokens``X-Subject-Token`
2. Вызовы сервисов с `X-Auth-Token` на нужном [порту](../ports.md)
Лаборатория по умолчанию: `admin` / `secret`, проект `demo`, домен `Default`.
## Cookbook'и
- [Python (requests)](python-requests.md)
- [Python (openstacksdk)](python-openstacksdk.md)
- [Ansible](ansible.md)
- [Terraform](terraform.md)
- [Pulumi](pulumi.md)
- [CLI](openstack-cli.md)
- [Troubleshooting](troubleshooting-clients.md)
## Лаборатория покрытия API (Pulumi)
Полное руководство: [hypervisor-lab.md](../hypervisor-lab.md)
```bash
cd pulumi-tests
make up
make test-pulumi-smoke
make test-pulumi
open reports/pulumi-report.html
```
Probe-скрипты:
| Script | Purpose |
|---|---|
| `examples/python/openstack_smoke.py` | Multi-port GET smoke |
| `examples/python/openstack_surface_probe.py` | Pack operation probe (также используется Pulumi-лабой) |
+30
View File
@@ -0,0 +1,30 @@
**Language / Язык:** [English](../../examples/pulumi.md) | [Русский](pulumi.md)
# Pulumi (pulumi_openstack)
## Cookbook (один stack)
[`examples/pulumi/`](../../../examples/pulumi/) — `pulumi_openstack` Instance,
Network, Subnet.
```bash
make up && make seed-demo
cd examples/pulumi
pulumi stack init dev --secrets-provider passphrase
export PULUMI_CONFIG_PASSPHRASE=lab
pulumi up
pulumi destroy
```
## Лаборатория покрытия (`pulumi-tests`)
[`pulumi-tests/`](../../../pulumi-tests/) — стеки `pulumi_openstack` на каждую
серию, проверка непустых export'ов, затем HTTP-probe pack-операций с
непустыми телами.
```bash
make pulumi-tests
open pulumi-tests/reports/pulumi-report.html
```
См. [hypervisor-lab.md](../hypervisor-lab.md).
+24
View File
@@ -0,0 +1,24 @@
**Language / Язык:** [English](../../examples/python-openstacksdk.md) | [Русский](python-openstacksdk.md)
# Python + openstacksdk
```python
import openstack
conn = openstack.connect(
auth_url="http://127.0.0.1:5000/v3",
project_name="demo",
username="admin",
password="secret",
user_domain_name="Default",
project_domain_name="Default",
)
for server in conn.compute.servers():
print(server.name, server.status)
for network in conn.network.networks():
print(network.name)
```
Убедитесь, что порты из service catalog доступны (Compose gateway или Helm
port-forward). См. [clients.md](../clients.md).
+37
View File
@@ -0,0 +1,37 @@
**Language / Язык:** [English](../../examples/python-requests.md) | [Русский](python-requests.md)
# Python + requests
Минимальный пример password-auth и списка серверов Nova:
```python
import requests
AUTH = "http://127.0.0.1:5000/v3/auth/tokens"
r = requests.post(
AUTH,
json={
"auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "admin",
"domain": {"name": "Default"},
"password": "secret",
}
},
},
"scope": {
"project": {"name": "demo", "domain": {"name": "Default"}}
},
}
},
)
r.raise_for_status()
token = r.headers["X-Subject-Token"]
headers = {"X-Auth-Token": token}
servers = requests.get("http://127.0.0.1:8774/v2.1/servers", headers=headers)
print(servers.status_code, len(servers.json().get("servers", [])))
```
+21
View File
@@ -0,0 +1,21 @@
**Language / Язык:** [English](../../examples/terraform.md) | [Русский](terraform.md)
# Terraform (openstack provider)
## Cookbook (один stack)
[`examples/terraform/main.tf`](../../../examples/terraform/main.tf) —
**`terraform-provider-openstack/openstack`**.
```bash
make up && make seed-demo
cd examples/terraform
terraform init
terraform apply
terraform destroy
```
По умолчанию: `auth_url = http://127.0.0.1:5000/v3`, `admin` / `secret`, проект `demo`.
Интеграционное покрытие API — в [`pulumi-tests/`](../../../pulumi-tests/)
(Pulumi / `pulumi_openstack`). См. [hypervisor-lab.md](../hypervisor-lab.md).
@@ -0,0 +1,27 @@
**Language / Язык:** [English](../../examples/troubleshooting-clients.md) | [Русский](troubleshooting-clients.md)
# Устранение неполадок клиентов
## Каталог указывает на недоступные хосты
Seed-каталог в некоторых конфигурациях использует `host.docker.internal` или
имена compose-сервисов. Переопределите endpoints или используйте host gateway,
который вы реально публикуете (`127.0.0.1` с port-forward).
## SSL-ошибки против Ingress
Staging-issuers лаборатории не доверенные — используйте `curl -k` /
`OS_INSECURE=true` только в lab.
## Пустой список серверов
Неверный project scope или demo не загружен. Проверьте:
```bash
openstack project list
make seed-demo
```
## Microversion отклонён
Понизьте запрошенную compute microversion или сбросьте переопределения в Web UI.
+39
View File
@@ -0,0 +1,39 @@
**Language / Язык:** [English](../faq.md) | [Русский](faq.md)
# FAQ
## Это настоящее OpenStack cloud?
Нет. Это **surface-complete API laboratory**: состояние в PostgreSQL,
ответы в форме API-ref, без оркестрации гипервизора.
## Какой релиз использовать?
По умолчанию пакет **Dalmatian**. Переключайте через `OPENSTACK_SERIES` или Web UI.
См. [api-versions.md](api-versions.md).
## Compose vs Helm?
| Need | Use |
|---|---|
| Local hack / CI on Docker | Compose |
| Cluster + Ingress TLS | Helm ([kubernetes.md](kubernetes.md)) |
## Зачем так много портов?
Service catalog OpenStack ожидает отдельные endpoints. api-gateway публикует
[реальную матрицу портов по умолчанию](ports.md) **один в один** (без смещения на хосте).
## Demo cloud стёр мои ресурсы
Lifecycle-тесты и reseed очищают lab tables. Перезагрузите через `make seed-demo`.
## Можно ли направить Terraform / Ansible сюда?
Да — используйте Keystone URL и seed credentials. Ожидайте lab limitations
(policy, async workflows, Ceph и т.д.). См. [clients.md](clients.md).
## Где Helm chart?
[`helm/openstack-api-simulator`](../../helm/openstack-api-simulator/README.ru.md) — руководство в
[kubernetes.md](kubernetes.md).
+123
View File
@@ -0,0 +1,123 @@
**Language / Язык:** [English](../getting-started.md) | [Русский](getting-started.md)
# Быстрый старт
Сквозная первая лабораторная сессия на Docker Compose. Для Kubernetes см.
[kubernetes.md](kubernetes.md).
## Требования
- Docker / Docker Compose
- Python 3.13+ (опционально, для smoke-скриптов на хосте)
- `curl` или OpenStack CLI / `openstacksdk`
## Выберите путь
| Путь | Когда |
|---|---|
| **1a. Опубликованный образ** | Лаборатория с Hub-образом (`docker-compose.release.yml`; нужен checkout репо для mount gateway/TLS) |
| **1b. Development checkout** | Будете менять код / пакеты |
| **Helm** | Установка в кластер — [kubernetes.md](kubernetes.md) |
## 1a. Опубликованный образ (Docker Hub)
Нужен **git checkout** этого репозитория: Compose монтирует
`./docker/gateway` и `./docker/tls` в nginx gateway. Контейнер симулятора
берётся с Docker Hub (локальная сборка приложения не нужна).
```bash
git clone https://github.com/inecs/openstack-api-simulator.git
cd openstack-api-simulator
docker compose -f docker-compose.release.yml up -d --wait
# или: make release-up
```
Образ: [`inecs/openstack-api-simulator`](https://hub.docker.com/r/inecs/openstack-api-simulator).
Тег при необходимости: `IMAGE_TAG=0.1.0`.
## 1b. Development checkout
```bash
cp .env.example .env
docker compose up -d --build --wait
```
## 2. Дождитесь готовности
```bash
curl -sf http://127.0.0.1:5000/health/ready
```
## 3. Загрузите seed-профиль
Minimal seed выполняется при первом старте. Опционально — полное синтетическое облако:
```bash
make seed-demo
# или
docker compose exec simulator python -m app.openstack.seed_cli --profile demo
```
Профили: [seed-profiles.md](seed-profiles.md).
## 4. Аутентификация (Keystone)
```bash
export OS_AUTH_URL=http://127.0.0.1:5000/v3
TOKEN=$(curl -si -X POST "$OS_AUTH_URL/auth/tokens" \
-H 'Content-Type: application/json' \
-d '{
"auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "admin",
"domain": {"name": "Default"},
"password": "secret"
}
}
},
"scope": {
"project": {"name": "demo", "domain": {"name": "Default"}}
}
}
}' | awk -F': ' 'tolower($1)=="x-subject-token"{print $2}' | tr -d '\r')
echo "token=$TOKEN"
```
## 5. Вызовы Nova / Neutron
```bash
curl -sH "X-Auth-Token: $TOKEN" http://127.0.0.1:8774/v2.1/servers/detail | head -c 400
curl -sH "X-Auth-Token: $TOKEN" http://127.0.0.1:9696/v2.0/networks
```
## 6. Откройте Web UI
[http://localhost:5000/](http://localhost:5000/) — консоль, Environment drawer
(серия OpenStack pack + microversions), Data drawer (загрузка/выгрузка demo cloud).
## 7. Smoke / conformance
```bash
make smoke
python3 examples/python/openstack_smoke.py
python3 examples/python/openstack_conformance.py
```
## Готово, когда…
- `/health/ready` возвращает 200
- Keystone выдаёт `X-Subject-Token`
- списки Nova/Neutron содержат seed-ресурсы
- (опционально) demo cloud показывает ~1000 серверов
## Дальше
- [Порты](ports.md) — полная матрица портов сервисов
- [Покрытие API](api_coverage.md) — операции пакетов по сериям
- [Клиенты](clients.md) — openstacksdk / CLI
- [Kubernetes / Helm](kubernetes.md)
- [Hypervisor-lab](hypervisor-lab.md) — Pulumi-покрытие API (все ops × серии)
- [Эксплуатация](operations.md)
+33
View File
@@ -0,0 +1,33 @@
**Language / Язык:** [English](../hypervisor-lab.md) | [Русский](hypervisor-lab.md)
# Лаборатория покрытия Pulumi OpenStack
Сьют в [`pulumi-tests/`](../../pulumi-tests/): максимально **`pulumi_openstack`**,
затем HTTP-probe pack-операций с проверкой **непустых** ответов для серий
**yoga → dalmatian**.
## Быстрый старт
```bash
make pulumi-tests # из корня (полный сьют)
make test-pulumi-smoke # быстрый режим
```
Или:
```bash
cd pulumi-tests
make up && make build
make test-pulumi
open reports/pulumi-report.html
```
## Ход (на серию)
1. Активация pack серии
2. Pulumi Automation API → `programs/os_coverage` (`pulumi_openstack`)
3. Каждый export стека должен быть непустым
4. HTTP-probe pack-операций; непустые тела на успешных GET/POST
5. Destroy; HTML + JUnit
См. [`pulumi-tests/README.ru.md`](../../pulumi-tests/README.ru.md).
+184
View File
@@ -0,0 +1,184 @@
**Language / Язык:** [English](../kubernetes.md) | [Русский](kubernetes.md)
# Kubernetes / Helm
Развёртывание опубликованного runtime-образа с Docker Hub чартом
[`helm/openstack-api-simulator`](../../helm/openstack-api-simulator/README.ru.md).
Образ: [`inecs/openstack-api-simulator`](https://hub.docker.com/r/inecs/openstack-api-simulator)
Чарт зеркалирует Docker Compose:
| Компонент | Роль |
|---|---|
| **simulator** Deployment | FastAPI-приложение на `:8080` |
| **api-gateway** Deployment | nginx multi-port шлюз OpenStack |
| **PostgreSQL** StatefulSet | Встроенный Postgres 17 (опционально) |
| **migrate** initContainer | Идемпотентные миграции схемы |
| **seed** Job (опционально) | Лабораторные данные `minimal` или `demo` |
## Требования
- Kubernetes 1.27+ (или аналог)
- Helm 3.14+
- Для Ingress TLS: [Ingress NGINX](https://kubernetes.github.io/ingress-nginx/) и
[cert-manager](https://cert-manager.io/)
Пример установки cert-manager:
```bash
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.yaml
```
## Быстрая установка (Hub release + Ingress + Let's Encrypt)
Из git checkout этого репозитория:
```bash
helm upgrade --install os-sim ./helm/openstack-api-simulator \
-n openstack-sim --create-namespace \
-f ./helm/openstack-api-simulator/values-ingress-example.yaml \
--set certManager.email=you@example.com \
--set ingress.hosts[0].host=os-sim.example.com \
--set ingress.tls[0].hosts[0]=os-sim.example.com \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set postgresql.auth.password="$(openssl rand -hex 16)"
```
Что происходит:
1. Скачивается `inecs/openstack-api-simulator:0.1.0`.
2. Устанавливается PostgreSQL 17 (`postgres:17.5-bookworm`).
3. Выполняются миграции схемы в init-контейнере (идемпотентно).
4. Засевается профиль **demo** (`seed.enabled=true`, ~1000 серверов).
5. Разворачивается nginx **api-gateway** со стандартными портами OpenStack (5000, 8774, 9696, …).
6. Создаются ресурсы `ClusterIssuer` (`letsencrypt-prod` / `letsencrypt-staging`).
7. Создаётся Ingress → gateway `:5000` (Keystone + Web UI) с TLS.
DNS для `os-sim.example.com` должен указывать на Ingress controller. Затем:
```bash
kubectl -n openstack-sim get certificate,ingress,pods
curl -sS https://os-sim.example.com/health/ready
open https://os-sim.example.com/
```
Логин по умолчанию: `admin` / `secret` (проект `demo` или `admin`, домен `Default`).
### Сначала staging (рекомендуется)
```bash
helm upgrade --install os-sim ./helm/openstack-api-simulator \
-n openstack-sim --create-namespace \
-f ./helm/openstack-api-simulator/values-ingress-example.yaml \
--set certManager.email=you@example.com \
--set certManager.useStaging=true \
--set ingress.hosts[0].host=os-sim.example.com \
--set ingress.tls[0].hosts[0]=os-sim.example.com \
--set secret.ticketSigningKey="$(openssl rand -hex 32)"
```
Используйте `curl -k` против staging CA. Для production переключите `certManager.useStaging=false`.
## Минимальная установка (ClusterIP + port-forward)
```bash
helm upgrade --install os-sim ./helm/openstack-api-simulator \
-n openstack-sim --create-namespace \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set seed.enabled=true \
--set seed.profile=minimal
kubectl -n openstack-sim port-forward \
svc/os-sim-openstack-api-simulator-gateway \
5000:5000 8774:8774 9696:9696 9292:9292 8776:8776
```
| URL | Сервис |
|---|---|
| http://127.0.0.1:5000/ | Keystone + консоль |
| http://127.0.0.1:8774/v2.1/ | Nova |
| http://127.0.0.1:9696/v2.0/ | Neutron |
Полная матрица портов: [ports.md](ports.md).
## Внешний PostgreSQL
```bash
helm upgrade --install os-sim ./helm/openstack-api-simulator \
-n openstack-sim --create-namespace \
--set postgresql.enabled=false \
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
--set secret.databaseUrl='postgresql://user:pass@pg.example.com:5432/openstack_simulator'
```
Или `secret.existingSecret` с ключами `DATABASE_URL` и `TICKET_SIGNING_KEY`.
## Как работает api-gateway
Та же модель, что и в Compose (`docker/gateway/openstack-ports.conf`):
1. Клиент подключается к **порту сервиса** (например Nova `8774`).
2. nginx выставляет `X-OpenStack-Service` и `X-Forwarded-Port`.
3. FastAPI переписывает путь в `/_os/<service>/…`, чтобы `/v3` (Keystone vs Cinder) не конфликтовал.
Ingress (если включён) обслуживает **Keystone/UI на порту 5000**. Для Nova/Neutron
извне кластера:
- `kubectl port-forward` дополнительных портов, или
- expose `*-gateway` как `LoadBalancer` / `NodePort` (`gateway.service.type`), или
- дополнительные Ingress rules / TCP-сервисы для этих портов.
## Как выпускается TLS
При `certManager.enabled=true` и `certManager.createClusterIssuer=true` чарт
создаёт ACME `ClusterIssuer` (HTTP-01). Шаблон Ingress добавляет:
```yaml
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- secretName: openstack-api-simulator-tls
hosts: [os-sim.example.com]
```
Чарт **не** устанавливает cert-manager или Ingress controller.
## Эксплуатация
```bash
# логи
kubectl -n openstack-sim logs -l app.kubernetes.io/component=simulator -f
kubectl -n openstack-sim logs -l app.kubernetes.io/component=gateway -f
# reseed minimal
kubectl -n openstack-sim exec deploy/os-sim-openstack-api-simulator -- \
python -m app.openstack.seed_cli --profile minimal
# reseed demo cloud
kubectl -n openstack-sim exec deploy/os-sim-openstack-api-simulator -- \
python -m app.openstack.seed_cli --profile demo
# активировать серию OpenStack pack
kubectl -n openstack-sim set env deploy/os-sim-openstack-api-simulator \
OPENSTACK_SERIES=caracal
# затем перезапустить pod / helm upgrade с --set config.openstackSeries=caracal
# удаление
helm -n openstack-sim uninstall os-sim
```
## Справка по values
См. [`helm/openstack-api-simulator/values.yaml`](../../helm/openstack-api-simulator/values.yaml)
и [README чарта](../../helm/openstack-api-simulator/README.ru.md).
Связанные документы:
- [Быстрый старт](getting-started.md) — путь Compose
- [Эксплуатация](operations.md) — публикация на Docker Hub / day-2
- [Порты](ports.md) — матрица портов OpenStack
- [Seed-профили](seed-profiles.md) — `minimal` / `demo`
- [Безопасность](security.md) — лабораторные учётные данные
+39
View File
@@ -0,0 +1,39 @@
**Language / Язык:** [English](../observability.md) | [Русский](observability.md)
# Наблюдаемость
## Health endpoints
| Path | Значение |
|---|---|
| `/health/live` | Процесс работает |
| `/health/ready` | БД доступна + миграции применены |
Оба доступны на simulator и через gateway (на любом опубликованном порту).
## Request IDs
Заголовок `X-Request-ID` (настраивается через `REQUEST_ID_HEADER`) принимается и
эхом возвращается там, где применяется middleware.
## Логи
Compose:
```bash
make logs
docker compose logs -f simulator api-gateway
```
Helm:
```bash
kubectl logs -l app.kubernetes.io/component=simulator -f
kubectl logs -l app.kubernetes.io/component=gateway -f
```
## Доказательства совместимости / покрытия
- Покрытие пакетов: [api_coverage.md](api_coverage.md)
- Live lifecycle: `examples/python/openstack_surface_probe.py`
- pytest: `tests/openstack/` (включая real-DB conformance)
+117
View File
@@ -0,0 +1,117 @@
**Language / Язык:** [English](../operations.md) | [Русский](operations.md)
# Эксплуатация
## Day-2 команды (Compose)
```bash
make up # start stack
make down # stop stack
make restart
make logs
make db-migrate # idempotent migrations
make seed # minimal OpenStack seed
make seed-demo # demo cloud (~1000 servers)
make smoke # multi-service GET smoke
```
## Миграции
Упорядоченный SQL в `app/db/migrations/` применяется транзакционно.
Повторный запуск `make db-migrate` безопасен. `/health/ready` остаётся недоступным,
пока миграции не применены. Helm выполняет тот же migrate-шаг как initContainer.
## Reseed
```bash
make seed # minimal
make seed-demo # replaces state with demo cloud
```
Или:
```bash
docker compose exec simulator python -m app.openstack.seed_cli --profile demo
```
Reseed **очищает** лабораторные таблицы OpenStack и перезагружает данные. Внешняя
автоматизация с закэшированными UUID ресурсов должна обновить их.
## OpenStack pack series
Cold start (env):
```bash
OPENSTACK_SERIES=caracal docker compose up -d
```
Helm:
```bash
--set config.openstackSeries=yoga
```
Hot-swap (Web UI или API):
```bash
curl -X POST http://127.0.0.1:5000/ui/api/openstack/contracts/activate \
-H 'Content-Type: application/json' \
-d '{"series":"dalmatian"}'
```
Серии: `yoga`, `antelope`, `caracal`, `dalmatian`. Покрытие:
[api_coverage.md](api_coverage.md).
## Перегенерация contract-пакетов
```bash
PYTHONPATH=tools python3 tools/os_api_inventory/generate_packs.py
PYTHONPATH=tools python3 tools/os_api_inventory/coverage_report.py
```
## Резервное копирование состояния лаборатории
PostgreSQL — источник истины. Используйте `pg_dump` / снимки volume.
Контейнеры приложения одноразовые, если volume БД сохранён.
## Публикация на Docker Hub
```bash
docker login
make release
```
| Variable | Default | Meaning |
|---|---|---|
| `DOCKERHUB_USER` | `inecs` | Docker Hub namespace |
| `IMAGE_NAME` | `openstack-api-simulator` | Repository name |
| `VERSION` | from `pyproject.toml` | Image tag |
```bash
make release VERSION=0.2.0
make release-build # local tags only
```
## Kubernetes day-2
См. [kubernetes.md](kubernetes.md) для логов, reseed через `kubectl exec` и
удаления.
## CI лаборатории покрытия API (pulumi-tests)
Pulumi прогоняет каждую pack-операцию по сериям — см.
[hypervisor-lab.md](hypervisor-lab.md).
```bash
make test-pulumi-smoke # from repo root
make test-pulumi
```
Отчёты: `pulumi-tests/reports/pulumi-report.html` и `pulumi-junit.xml`.
## Обновления
1. Pull / build нового тега образа.
2. Примените миграции (автоматически при старте / Helm initContainer).
3. Опционально reseed, если изменилась seed-схема.
4. Повторите `make smoke` или lifecycle probes.
+56
View File
@@ -0,0 +1,56 @@
**Language / Язык:** [English](../ports.md) | [Русский](ports.md)
# Стандартные порты OpenStack в этом симуляторе
Справка: [Firewalls and default ports](https://docs.openstack.org/install-guide/firewalls-default-ports.html).
Это **реальные публичные порты API OpenStack по умолчанию**. Compose и Helm
публикуют их **один в один** на хосте / Service (без смещения): хост `5000`
Keystone, хост `8774` — Nova и т.д. Запускайте стек на отдельном хосте/ВМ,
чтобы эти порты не пересекались с другими лабораторными симуляторами.
Клиенты обращаются к **api-gateway** (nginx) — сервис Compose или Helm
Deployment/Service `*-gateway`. На каждом listen-порту выставляются
`X-OpenStack-Service` и `X-Forwarded-Port`; процесс FastAPI переписывает путь в
`/_os/<service>/…`, чтобы пересекающиеся корни API (`/v3`, `/v1`, …) не конфликтовали.
Типичный auth URL: `http://127.0.0.1:5000/v3` (или HTTPS на `:5000` / `:443`
через gateway).
Список в Helm values: `gateway.service.ports` в
[`helm/openstack-api-simulator/values.yaml`](../../helm/openstack-api-simulator/values.yaml).
| Порт | Сервис | За что отвечает | Основные пути |
|------|--------|-----------------|---------------|
| 5000 | keystone | Identity — токены, проекты, пользователи, роли, service catalog | `/v3/auth/tokens`, `/v3/projects`, … |
| 8774 | nova | Compute — серверы (ВМ), flavors, keypairs, AZ, hypervisors | `/v2.1/servers`, flavors, keypairs, AZ, hypervisors, … |
| 9696 | neutron | Network — сети, подсети, порты, роутеры, SG, floating IP | `/v2.0/networks`, subnets, ports, routers, SG, FIPs, QoS, trunks, … |
| 9292 | glance | Image — образы | `/v2/images` |
| 8776 | cinder | Block storage — тома, снапшоты, типы томов | `/v3/volumes` |
| 8003 | placement | Placement — resource providers и inventories | `/resource_providers` |
| 8004 | heat | Orchestration — стеки Heat | `/v1/{project_id}/stacks` |
| 8000 | heat-cfn | CloudFormation-совместимый API Heat | `/stacks` |
| 8080 | swift | Object storage — аккаунты, контейнеры, объекты | `/v1/{account}/{container}/…`, `/info` |
| 6385 | ironic | Bare metal — ноды, порты, chassis | `/v1/nodes` |
| 9876 | octavia | Load balancing — балансировщики, listeners, pools | `/v2/lbaas/loadbalancers` |
| 9311 | barbican | Key manager — секреты, контейнеры | `/v1/secrets` |
| 8786 | manila | Shared file systems — shares | `/v2/shares` |
| 9001 | designate | DNS — зоны и recordsets | `/v2/zones` |
| 9511 | magnum | Container infra — кластеры (например Kubernetes) | `/v1/clusters` |
| 9517 | zun | Containers — жизненный цикл контейнеров | `/v1/containers` |
| 8779 | trove | Database as a service — экземпляры БД | `/v1.0/instances` |
| 8989 | mistral | Workflows | `/v2/workflows` |
| 8042 | aodh | Alarming — алармы | `/v2/alarms` |
| 8889 | cloudkitty | Rating / биллинг-метрики | `/v1/rating/…` |
| 9090 | freezer | Backup — задания резервного копирования | `/v2/jobs` |
| 1234 | blazar | Reservation — leases | `/leases` |
| 8999 | vitrage | Root cause analysis (RCA) | `/v1/alarm` |
| 15868 | masakari | Instance HA — высокая доступность инстансов | `/v1/segments` |
| 9890 | tacker | NFV orchestration | `/v1.0/vnfs` |
| 5050 | adjutant | Admin workflows / self-service задачи | `/v1/tasks` |
| 9322 | watcher | Infrastructure optimization | `/v1/…` |
| 8888 | zaqar | Messaging | `/v2/…` |
| 80 | http | Reverse proxy консоли (Compose + Helm gateway) | — |
| 443 | https | TLS reverse proxy (**только Compose**; в Helm TLS завершается на Ingress) | — |
Внутренний FastAPI слушает `8080` только внутри Docker (не Swift public port с хоста — хост `8080` это Swift через gateway). Postgres публикуется только как `127.0.0.1:5433` (это не порт OpenStack API).
+33
View File
@@ -0,0 +1,33 @@
**Language / Язык:** [English](../security.md) | [Русский](security.md)
# Безопасность
Этот проект — **лабораторный симулятор**, а не production OpenStack cloud.
## Граница доверия
- Пароли по умолчанию (`secret`) намеренно простые для лабораторий.
- `TICKET_SIGNING_KEY` / `secret.ticketSigningKey` нужно ротировать перед любым
общим или internet-facing развёртыванием.
- Пароли bundled Postgres в values/compose — лабораторные defaults.
## Сетевая экспозиция
| Surface | Риск |
|---|---|
| Compose ports on `0.0.0.0` | Вся поверхность API доступна на хосте |
| Helm Ingress | Публичный HTTPS к Keystone/UI; другие OS-порты требуют явной экспозиции |
| Read-only root FS (Helm) | Снижает write surface контейнера |
## TLS
- Compose: опциональный nginx TLS на `:443` с lab cert в `docker/tls/`
- Helm: terminate TLS на Ingress + cert-manager (рекомендуется)
## Что не реализовано
- Реальная federation Keystone / семантика ротации Fernet keys
- Паритет правил oslo.policy
- Multi-tenant isolation beyond project_id filters в handlers
Считайте все данные одноразовыми lab fixtures.
+30
View File
@@ -0,0 +1,30 @@
**Language / Язык:** [English](../seed-profiles.md) | [Русский](seed-profiles.md)
# Seed-профили OpenStack
| Profile | Как загрузить | Содержимое |
|---|---|---|
| `minimal` | startup / `make seed` / `python -m app.openstack.seed_cli --profile minimal` | Default domain, admin+demo users, flavors, images, небольшой IaaS sample |
| `demo` | `make seed-demo` / UI Data drawer / Helm `seed.profile=demo` / `--profile demo` | ~1000 servers, 16 hypervisors, 3 AZs, 5 projects, multi-net/SG topology, 600 volumes, ports/FIPs, Octavia/Heat/Ironic/Swift, nested pack samples |
Пароль для всех пользователей: **`secret`**. Домен: **`Default`**.
## Helm
```yaml
seed:
enabled: true
profile: demo # or minimal
```
Post-install Job запускает `python -m app.openstack.seed_cli`. Ручной reseed:
```bash
kubectl exec deploy/<release>-openstack-api-simulator -- \
python -m app.openstack.seed_cli --profile demo
```
## Поведение
Оба профиля **очищают** лабораторные таблицы OpenStack и перезагружают данные.
Предпочитайте `demo` для плотности / nested GET probes; `minimal` для быстрого CI.
+55
View File
@@ -0,0 +1,55 @@
**Language / Язык:** [English](../troubleshooting.md) | [Русский](troubleshooting.md)
# Устранение неполадок
## `/health/ready` возвращает 503
- Postgres не поднят или неверный `DATABASE_URL`
- Миграции не применены — проверьте migrate initContainer / `make db-migrate`
- Helm: `kubectl logs` на pod simulator (migrate init)
## Auth 401
- Неверный user/password/domain (`Default`)
- Отсутствует project scope для project-scoped API
- Токен от другого экземпляра simulator (reseed меняет ID)
## Пустые списки после lifecycle probe
Lifecycle DELETE может удалить demo-scoped строки. Перезагрузите:
```bash
make seed-demo
# or Helm:
kubectl exec deploy/… -- python -m app.openstack.seed_cli --profile demo
```
## Неверный сервис отвечает на порту
Проверьте gateway headers:
```bash
curl -sI http://127.0.0.1:8774/ | grep -i openstack
```
Ожидайте `X-OpenStack-Service: nova`. Если обращаетесь к simulator `:8080` напрямую,
задайте `X-OpenStack-Route-Service` / `X-OpenStack-Service` сами.
## Helm port-forward на 5000 не работает
Forward **gateway** Service, а не simulator Service:
```bash
kubectl port-forward svc/<release>-openstack-api-simulator-gateway 5000:5000
```
## Pack activate 404 / пустые ops
Убедитесь, что `contracts/openstack/<series>/` есть в образе и
`OPENSTACK_SERIES` — известное имя серии.
## Порты catalog недоступны клиенту
Catalog рекламирует per-service порты. При только Ingress на `:443→5000` Nova
`:8774` не публикуется автоматически. Используйте port-forward или expose gateway
Service (см. [kubernetes.md](kubernetes.md)).
+31
View File
@@ -0,0 +1,31 @@
**Language / Язык:** [English](../web-ui.md) | [Русский](web-ui.md)
# Web UI
Консоль обслуживается с Keystone/UI порта (**5000** на gateway).
| URL | Назначение |
|---|---|
| `/` или `/console` | Интерактивная консоль |
| `/docs` | OpenAPI (simulator) |
| `/ui/api/…` | UI JSON APIs |
## Environment drawer
- **OpenStack API pack** — список серий, активация пакета, переопределения microversion
- Apply немедленно перемонтирует schema-маршруты
## Data drawer
- **Load demo cloud** — `POST /ui/api/demo/load``seed_openstack_demo`
- **Unload / minimal** — сброс к minimal seed
## Брендинг
OpenStack red `#ED1C24`, console wordmark. Темы следуют общему chrome консоли
(light/dark).
## Health
- `/health/live` — процесс работает
- `/health/ready` — миграции применены + БД доступна
+33
View File
@@ -0,0 +1,33 @@
**Language / Язык:** [English](security.md) | [Русский](ru/security.md)
# Security
This project is a **laboratory simulator**, not a production OpenStack cloud.
## Trust boundary
- Default passwords (`secret`) are intentional for labs.
- `TICKET_SIGNING_KEY` / `secret.ticketSigningKey` must be rotated before any
shared or internet-facing deployment.
- Bundled Postgres passwords in values/compose are lab defaults.
## Network exposure
| Surface | Risk |
|---|---|
| Compose ports on `0.0.0.0` | Entire API surface reachable on the host |
| Helm Ingress | Public HTTPS to Keystone/UI; other OS ports need explicit exposure |
| Read-only root FS (Helm) | Reduces container write surface |
## TLS
- Compose: optional nginx TLS on `:443` with lab cert under `docker/tls/`
- Helm: terminate TLS at Ingress + cert-manager (recommended)
## What is not implemented
- Real Keystone federation / Fernet key rotation semantics
- oslo.policy rule parity
- Multi-tenant isolation beyond project_id filters in handlers
Treat all data as disposable lab fixtures.
+30
View File
@@ -0,0 +1,30 @@
**Language / Язык:** [English](seed-profiles.md) | [Русский](ru/seed-profiles.md)
# OpenStack seed profiles
| Profile | How to load | Contents |
|---|---|---|
| `minimal` | startup / `make seed` / `python -m app.openstack.seed_cli --profile minimal` | Default domain, admin+demo users, flavors, images, small IaaS sample |
| `demo` | `make seed-demo` / UI Data drawer / Helm `seed.profile=demo` / `--profile demo` | ~1000 servers, 16 hypervisors, 3 AZs, 5 projects, multi-net/SG topology, 600 volumes, ports/FIPs, Octavia/Heat/Ironic/Swift, nested pack samples |
Password for all users: **`secret`**. Domain: **`Default`**.
## Helm
```yaml
seed:
enabled: true
profile: demo # or minimal
```
Post-install Job runs `python -m app.openstack.seed_cli`. Manual reseed:
```bash
kubectl exec deploy/<release>-openstack-api-simulator -- \
python -m app.openstack.seed_cli --profile demo
```
## Behaviour
Both profiles **truncate** OpenStack lab tables then reload. Prefer `demo` for
density / nested GET probes; `minimal` for fast CI.
+55
View File
@@ -0,0 +1,55 @@
**Language / Язык:** [English](troubleshooting.md) | [Русский](ru/troubleshooting.md)
# Troubleshooting
## `/health/ready` is 503
- Postgres not up or wrong `DATABASE_URL`
- Migrations not applied — check migrate initContainer / `make db-migrate`
- Helm: `kubectl logs` on the simulator pod (migrate init)
## Auth 401
- Wrong user/password/domain (`Default`)
- Project scope missing for project-scoped APIs
- Token from a different simulator instance (reseed rotates IDs)
## Empty lists after lifecycle probe
Lifecycle DELETE can remove demo-scoped rows. Reload:
```bash
make seed-demo
# or Helm:
kubectl exec deploy/… -- python -m app.openstack.seed_cli --profile demo
```
## Wrong service answers on a port
Confirm gateway headers:
```bash
curl -sI http://127.0.0.1:8774/ | grep -i openstack
```
Expect `X-OpenStack-Service: nova`. If you hit simulator `:8080` directly,
set `X-OpenStack-Route-Service` / `X-OpenStack-Service` yourself.
## Helm port-forward to 5000 fails
Forward the **gateway** Service, not the simulator Service:
```bash
kubectl port-forward svc/<release>-openstack-api-simulator-gateway 5000:5000
```
## Pack activate 404 / empty ops
Ensure `contracts/openstack/<series>/` exists in the image and
`OPENSTACK_SERIES` is a known series name.
## Client catalog ports unreachable
Catalog advertises per-service ports. With only Ingress on `:443→5000`, Nova
`:8774` is not automatically published. Port-forward or expose the gateway
Service (see [kubernetes.md](kubernetes.md)).
+31
View File
@@ -0,0 +1,31 @@
**Language / Язык:** [English](web-ui.md) | [Русский](ru/web-ui.md)
# Web UI
Console is served from the Keystone/UI port (**5000** on the gateway).
| URL | Purpose |
|---|---|
| `/` or `/console` | Interactive console |
| `/docs` | OpenAPI (simulator) |
| `/ui/api/…` | UI JSON APIs |
## Environment drawer
- **OpenStack API pack** — list series, activate pack, set microversion overrides
- Apply remounts schema routes immediately
## Data drawer
- **Load demo cloud** — `POST /ui/api/demo/load``seed_openstack_demo`
- **Unload / minimal** — reset to minimal seed
## Branding
OpenStack red `#ED1C24`, console wordmark. Themes follow the shared console
chrome (light/dark).
## Health
- `/health/live` — process up
- `/health/ready` — migrations applied + DB reachable