Prepare 0.1.0 for lab release: durable handlers, HTTP Compose, CI, and pulumi-tests.
- Harden DB-backed handlers and seed profiles; align client wire shapes for cluster resources, QEMU config, and node SSL fields - Serve plain HTTP on Compose :8006; keep TLS optional (--profile tls) and terminate HTTPS at Kubernetes Ingress - Add pulumi-tests (full contract surface majors 6–9 + BPG lifecycle) and make pulumi-tests - Ship bilingual docs, CHANGELOG, SECURITY, CONTRIBUTING, and GitHub Actions (make ci + Compose/Helm validation)
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
**Language / Язык:** [English](../README.md) | [Русский](README.md)
|
||||
|
||||
# Документация
|
||||
|
||||
Руководства по симулятору Proxmox VE API. Переключайте язык с помощью заголовка на
|
||||
каждой странице. Русские версии находятся в каталоге [`ru/`](README.md).
|
||||
|
||||
| Руководство | Описание |
|
||||
|---|---|
|
||||
| [Быстрый старт](getting-started.md) | Первая успешная лабораторная сессия |
|
||||
| [Конфигурация](configuration.md) | Переменные окружения и Compose |
|
||||
| [Аутентификация](authentication.md) | Тикеты, CSRF, API-токены, ACL |
|
||||
| [Версии API](api-versions.md) | Контракты 6–9 и горячая замена |
|
||||
| [Клиенты и примеры](clients.md) | Python, Go, Java, Perl, Ansible, Terraform, Pulumi |
|
||||
| [Профили seed](seed-profiles.md) | Детерминированные фикстуры кластера |
|
||||
| [Поверхность API](api-surface.md) | Маршрутизация, обработчики, fallback |
|
||||
| [Домены](domains/README.md) | QEMU, LXC, storage, HA, SDN, … |
|
||||
| [Web UI](web-ui.md) | Интерактивная консоль и каталоги |
|
||||
| [Эксплуатация](operations.md) | Миграция, reseed, обновление, публикация в Hub |
|
||||
| [Обзор Docker Hub](../docker-hub-overview.md) | Готовый текст описания репозитория Hub (EN) |
|
||||
| [Kubernetes / Helm](kubernetes.md) | Образ Hub + Ingress + Let's Encrypt |
|
||||
| [Безопасность](security.md) | Модель угроз лаборатории и учётные данные |
|
||||
| [Наблюдаемость](observability.md) | Эндпоинты health и логирование |
|
||||
| [Устранение неполадок](troubleshooting.md) | Типичные сбои |
|
||||
| [FAQ](faq.md) | Краткие ответы |
|
||||
| [Архитектура](architecture.md) | Границы компонентов |
|
||||
| [Совместимость](compatibility.md) | Модель evidence и матрица релизов |
|
||||
|
||||
Исполняемые cookbook'и: [`examples/`](../../examples/README.ru.md).
|
||||
Интеграционные наборы: [`pulumi-tests/`](../../pulumi-tests/README.ru.md).
|
||||
@@ -0,0 +1,86 @@
|
||||
**Language / Язык:** [English](../api-surface.md) | [Русский](api-surface.md)
|
||||
|
||||
# Поверхность API
|
||||
|
||||
## Путь запроса
|
||||
|
||||
1. Middleware назначает или пробрасывает request ID.
|
||||
2. Активный снимок контракта выбирает объявленные пути и схемы.
|
||||
3. Аутентификация разрешает принципала (тикет или API-токен).
|
||||
4. Проверки ACL / привилегий выполняются до раскрытия или изменения ресурсов.
|
||||
5. Path, query и body валидируются по схемам, производным от контракта.
|
||||
6. Семантический обработчик выполняется против состояния в PostgreSQL.
|
||||
7. Долгие операции создают durable-задачу (+ lock при необходимости) и возвращают UPID.
|
||||
8. Ответы используют Proxmox-конверт под `/api2/json` или `/api2/extjs`.
|
||||
|
||||
## Два рендерера
|
||||
|
||||
Каждый метод контракта регистрируется под обоими:
|
||||
|
||||
- `/api2/json/...`
|
||||
- `/api2/extjs/...`
|
||||
|
||||
Клиенты и Web UI обычно используют JSON-рендерер.
|
||||
|
||||
## Обработчики vs контракты
|
||||
|
||||
- **Declared** — присутствует во импортированном снимке API Viewer для мажора.
|
||||
- **Implemented** — для этого verb + path зарегистрирован семантический обработчик.
|
||||
- Мажорные версии **6–9** имеют **100%** implemented-покрытие для объявленных методов.
|
||||
|
||||
Обработчики должны сохранять эффекты create/update/delete. Пустые no-op мутации не
|
||||
входят в продуктовый контракт. См. workspace durable-simulator rule.
|
||||
|
||||
## OpenAPI и исследование
|
||||
|
||||
- Интерактивная документация FastAPI: `/docs`
|
||||
- Инспектор методов Web UI: `/` → catalog → method
|
||||
- UI API: `/ui/api/versions`, `/ui/api/catalog`, `/ui/api/method`,
|
||||
`/ui/api/compatibility`, `/ui/api/contract/apply`, `/ui/api/demo/*`
|
||||
|
||||
## Эндпоинты совместимости
|
||||
|
||||
| Путь | Формат |
|
||||
|---|---|
|
||||
| `/admin/compatibility` | JSON |
|
||||
| `/admin/compatibility.md` | Markdown |
|
||||
| `/admin/compatibility.html` | HTML |
|
||||
|
||||
Отчёты следуют активному runtime-контракту после горячей замены.
|
||||
|
||||
## Задачи (UPID)
|
||||
|
||||
Асинхронная работа (power гостя, clone, migrate, многие delete, backup, …)
|
||||
возвращает UPID. Опрашивайте:
|
||||
|
||||
```text
|
||||
GET /nodes/{node}/tasks/{upid}/status
|
||||
GET /nodes/{node}/tasks/{upid}/log
|
||||
```
|
||||
|
||||
Workers забирают задачи через `FOR UPDATE SKIP LOCKED`, продлевают аренды и
|
||||
восстанавливаются после перезапуска процесса. HTTP 200 на запрос мутации означает
|
||||
«принято», а не «гость уже в финальном состоянии».
|
||||
|
||||
## Ошибки (типичные)
|
||||
|
||||
| Статус | Типичная причина |
|
||||
|---|---|
|
||||
| 401 | Отсутствует/невалидный тикет или токен |
|
||||
| 403 | Отказ ACL или отсутствует CSRF при мутации по тикету |
|
||||
| 409 | Конфликт VMID, недопустимый переход состояния, contention lock |
|
||||
| 501 | Обработчик отсутствует (не должно появляться для объявленных методов на 6–9) |
|
||||
| 503 | Сбой готовности (database / migrations) |
|
||||
|
||||
## Импорт контрактов
|
||||
|
||||
```bash
|
||||
make shell
|
||||
proxmox-api-contract validate path/to/source.json
|
||||
proxmox-api-contract --store contracts import --file path/to/source.json --version 9.2.3
|
||||
proxmox-api-contract --store contracts list
|
||||
proxmox-api-contract diff old.json new.json --format markdown
|
||||
```
|
||||
|
||||
Удалённый импорт требует HTTPS, allowlist официальных хостов, лимиты
|
||||
size/redirect/timeout и неизменяемые ревизии с checksum.
|
||||
@@ -0,0 +1,79 @@
|
||||
**Language / Язык:** [English](../api-versions.md) | [Русский](api-versions.md)
|
||||
|
||||
# Версии API (PVE 6–9)
|
||||
|
||||
Симулятор поставляет авторитетные импортированные контракты для четырёх мажорных
|
||||
версий Proxmox VE. Покрытие реестра обработчиков **100% проверено** для каждой:
|
||||
|
||||
| Мажор | Исходная версия | Объявленных методов | Покрытие обработчиками |
|
||||
|---|---|---:|---:|
|
||||
| 6 | 6.4-15 | 504 | 100% |
|
||||
| 7 | 7.4-16 | 540 | 100% |
|
||||
| 8 | 8.4.5 | 605 | 100% |
|
||||
| 9 | 9.2.3 | 675 | 100% |
|
||||
|
||||
Более старые мажорные версии переиспользуют текущие семантические обработчики плюс
|
||||
синонимы путей, зарегистрированные в `app/handlers/legacy_aliases.py` (например,
|
||||
исторические написания путей Ceph и backup).
|
||||
|
||||
## Холодный старт
|
||||
|
||||
Задайте `CONTRACT_SNAPSHOT` путь к нормализованному снимку. Docker Compose по
|
||||
умолчанию закрепляет встроенную ревизию PVE **9.2.3**.
|
||||
|
||||
`GET /api2/json/version` возвращает поля, производные от `source_version` **активного**
|
||||
снимка.
|
||||
|
||||
## Горячая замена (runtime)
|
||||
|
||||
Просмотрите любой мажор в каталоге Web UI, затем **Apply as runtime**, или вызовите:
|
||||
|
||||
```http
|
||||
POST /ui/api/contract/apply?major=7
|
||||
```
|
||||
|
||||
Эффекты:
|
||||
|
||||
- Маршруты `/api2/json` и `/api2/extjs` в памяти заменяются под блокировкой
|
||||
приложения.
|
||||
- `/version`, OpenAPI, метаданные реализации и состояние совместимости обновляются
|
||||
для нового мажора.
|
||||
- Изменение **локально для процесса** и **не сохраняется**.
|
||||
- Перезапуск восстанавливает `CONTRACT_SNAPSHOT`.
|
||||
|
||||
Просмотр каталога (`GET /ui/api/catalog?major=N`) **сам по себе** не меняет
|
||||
runtime; меняет только apply.
|
||||
|
||||
### Рекомендации для клиентов
|
||||
|
||||
- Явно закрепляйте мажор в CI (env холодного старта **или** apply + проверка
|
||||
`/version` перед набором тестов).
|
||||
- Горячая замена на лету может инвалидировать предположения клиента о схемах и
|
||||
путях — избегайте во время длинных прогонов Terraform/Ansible, если прогон не
|
||||
владеет переключением.
|
||||
- После apply перепроверьте `/admin/compatibility` для активного runtime.
|
||||
|
||||
## Режимы fallback
|
||||
|
||||
`CONTRACT_FALLBACK` управляет поведением для необъявленных обработчиков:
|
||||
|
||||
| Значение | Поведение |
|
||||
|---|---|
|
||||
| `error` (по умолчанию) | HTTP 501 с явным сообщением в стиле pending-handler |
|
||||
| `schema-default` | Синтез возвращаемого значения из схемы контракта |
|
||||
| `fixture` | Только fixture-данные, встроенные в контракт метода |
|
||||
|
||||
При полном покрытии обработчиков активного контракта объявленные методы не должны
|
||||
попадать в fallback. Оставляйте `error`, чтобы регрессии оставались видимыми.
|
||||
|
||||
## Evidence vs реестр
|
||||
|
||||
**Покрытие реестра** означает, что у каждого объявленного метода зарегистрирован
|
||||
семантический обработчик (нет систематического 501 для этого контракта).
|
||||
|
||||
**Verified** в смысле этого проекта — мажорные версии прогоняются через наборы
|
||||
совместимости и автоматизацию на наличие обработчиков для 6–9. Многомерный evidence
|
||||
JSON может со временем расширяться для более глубоких edge-case заявлений;
|
||||
предпочитайте живой `/admin/compatibility`, когда процесс запущен.
|
||||
|
||||
См. [Совместимость](compatibility.md).
|
||||
@@ -0,0 +1,240 @@
|
||||
**Language / Язык:** [English](../architecture.md) | [Русский](architecture.md)
|
||||
|
||||
# Архитектура
|
||||
|
||||
## Цели
|
||||
|
||||
`proxmox-api-simulator` — stateful асинхронный эмулятор Proxmox VE API. Главная
|
||||
цель проектирования — измеримая совместимость с контрактом: маршруты, валидация,
|
||||
аутентификация, права доступа, формы ответов, переходы состояния и персистентные
|
||||
долгоживущие задачи проверяются независимо, а не объявляются «универсально
|
||||
совместимыми». В комплекте majors **6–9** поставляются с **100%** регистрацией
|
||||
семантических обработчиков для каждого объявленного метода контракта и поддержкой
|
||||
горячей замены между этими majors во время работы.
|
||||
|
||||
Для обычной работы симулятору не нужна живая установка Proxmox. Официальные
|
||||
артефакты API и санитизированные наблюдения импортируются заранее и хранятся как
|
||||
версионируемые снимки.
|
||||
|
||||
## Контекст системы
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Client["API clients<br/>proxmoxer / Terraform / Ansible"]
|
||||
Admin["Simulator operator"]
|
||||
Docs["Official Proxmox API Viewer"]
|
||||
API["FastAPI application"]
|
||||
Importer["Contract importer and CLI"]
|
||||
Contract["Versioned API contract"]
|
||||
Engine["Simulation engine"]
|
||||
Worker["Persistent task workers"]
|
||||
DB[(PostgreSQL)]
|
||||
Obs["Logs / Prometheus / OpenTelemetry"]
|
||||
|
||||
Client -->|"/api2/json"| API
|
||||
Admin -->|"CLI, Make/Helm, Web UI /ui/api"| API
|
||||
Docs -->|"explicit import only"| Importer
|
||||
Importer --> Contract
|
||||
Contract --> DB
|
||||
API --> Contract
|
||||
API --> Engine
|
||||
Engine --> DB
|
||||
Engine --> Worker
|
||||
Worker --> DB
|
||||
API --> Obs
|
||||
Worker --> Obs
|
||||
```
|
||||
|
||||
## Архитектура компонентов
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph ContractPlane["API contract plane"]
|
||||
Sources["Remote, local, and recorded sources"] --> Parse["Source adapters and parser"]
|
||||
Parse --> Normalize["Version-independent normalized model"]
|
||||
Normalize --> Validate["Validation, checksums, manifests"]
|
||||
Validate --> Registry["Contract registry"]
|
||||
Registry --> Diff["Semantic version diff"]
|
||||
Registry --> Routes["Dynamic route and schema factory"]
|
||||
Registry --> Reports["Compatibility reports"]
|
||||
end
|
||||
|
||||
subgraph RequestPlane["Request plane"]
|
||||
Middleware["Request ID, logging, metrics"] --> Auth["Ticket or API-token authentication"]
|
||||
Auth --> Permission["ACL and privilege evaluation"]
|
||||
Permission --> Input["Contract-driven request validation"]
|
||||
Input --> Handler["Semantic handler registry"]
|
||||
Handler --> Render["Proxmox response and error renderer"]
|
||||
end
|
||||
|
||||
subgraph SimulationPlane["Simulation plane"]
|
||||
Handler --> Services["Node, QEMU, LXC, storage services"]
|
||||
Services --> State["State machines and resource locks"]
|
||||
Services --> Tasks["Transactional persistent tasks"]
|
||||
Tasks --> Workers["asyncio workers with PostgreSQL leases"]
|
||||
Faults["Scenarios, faults, virtual clock"] --> Services
|
||||
end
|
||||
|
||||
Routes --> Input
|
||||
Registry --> Permission
|
||||
State --> PG[(PostgreSQL)]
|
||||
Workers --> PG
|
||||
Auth --> PG
|
||||
```
|
||||
|
||||
## Границы и направление зависимостей
|
||||
|
||||
Плоскость контракта владеет объявленными фактами API. Она импортирует
|
||||
исходные артефакты, сохраняет неизвестные поля источника, формирует
|
||||
детерминированный нормализованный JSON и предоставляет неизменяемые
|
||||
версионируемые контракты. Она не знает о состоянии ВМ и не выполняет операции.
|
||||
|
||||
Плоскость симуляции владеет изменяемым состоянием кластера и семантикой
|
||||
операций. Она использует доменные модели и репозитории, не зависящие от FastAPI
|
||||
и структур контракта, специфичных для источника. PostgreSQL — система записи
|
||||
для ресурсов, состояния безопасности, блокировок, сценариев и задач.
|
||||
|
||||
Долговечные задачи подтверждаются только после совместной фиксации строки задачи,
|
||||
события, ключа идемпотентности и опциональной блокировки ресурса. Воркеры
|
||||
захватывают задачи через `SKIP LOCKED`, продлевают аренды в реальном времени,
|
||||
сохраняют прогресс и append-only логи/события и позволяют повторно захватить
|
||||
просроченную работу после сбоя процесса. Lifespan владеет ограниченным набором
|
||||
asyncio-воркеров и ждёт упорядоченного завершения; PostgreSQL остаётся очередью
|
||||
и источником истины между репликами.
|
||||
|
||||
Длительности симуляции используют внедрённые часы: реальные, ускоренные или
|
||||
продвигаемые вручную. Операции ВМ — явные переходы конечного автомата, а
|
||||
засеянные правила сбоев оцениваются детерминированно. Аренды воркеров намеренно
|
||||
исключены из виртуального времени: они используют wall time PostgreSQL и
|
||||
monotonic sleep процесса, чтобы приостановленный или ускоренный сценарий не
|
||||
нарушил безопасность распределённых воркеров.
|
||||
|
||||
Секреты аутентификации хранятся как salted scrypt-хеши. Сессионные тикеты
|
||||
подписаны и имеют срок действия; мутационные запросы используют CSRF-токены,
|
||||
привязанные к тикету. Привилегии API-токена пересекаются с эффективными
|
||||
распространёнными ACL владельца-принципала, поэтому токен не может эскалировать
|
||||
права владельца. Логи редактируют распознанные представления тикетов, паролей и
|
||||
токенов перед записью.
|
||||
|
||||
API-слой — адаптер. Он аутентифицирует, авторизует, валидирует по выбранному
|
||||
контракту, диспетчеризует семантический обработчик и формирует
|
||||
версионно-совместимый ответ. Маршрут без семантического обработчика явно
|
||||
сообщается как неподдерживаемый, если оператор не включил нестандартный режим
|
||||
fallback.
|
||||
|
||||
Зависимости направлены внутрь: HTTP- и CLI-адаптеры зависят от прикладных
|
||||
сервисов; прикладные сервисы — от доменных интерфейсов; PostgreSQL, файлы
|
||||
контрактов, метрики и часы реализуют эти интерфейсы. Доменные сервисы никогда не
|
||||
импортируют FastAPI.
|
||||
|
||||
## Жизненный цикл запроса
|
||||
|
||||
1. Middleware назначает или проверяет request ID и запускает безопасную
|
||||
структурированную телеметрию.
|
||||
2. Выбранный профиль совместимости разрешает неизменяемый снимок API и
|
||||
версионно-специфичное поведение.
|
||||
3. Аутентификация определяет принципала без раскрытия учётных данных в логах.
|
||||
4. Объявленные контрактом и специфичные для обработчика права проверяются до
|
||||
раскрытия или изменения ресурсов.
|
||||
5. Значения path, query и body валидируются схемами, полученными из контракта.
|
||||
6. Семантический обработчик выполняется через прикладной сервис и явную границу
|
||||
транзакции.
|
||||
7. Долгие операции атомарно обновляют блокировку ресурса и создают
|
||||
персистентную задачу, затем возвращают её UPID.
|
||||
8. Рендерер ответа применяет Proxmox-обёртку, заголовки, cookies и
|
||||
версионно-специфичные шаблоны ошибок.
|
||||
|
||||
## Персистентность и конкурентность
|
||||
|
||||
Используется `asyncpg` напрямую. Репозитории принимают явное соединение или
|
||||
контекст транзакции; SQL параметризован и расположен рядом с репозиторием.
|
||||
Изменяемые глобальные переменные процесса не являются авторитетным состоянием.
|
||||
|
||||
Воркеры захватывают задачи через `FOR UPDATE SKIP LOCKED`, устанавливают
|
||||
продлеваемые аренды и используют метаданные идемпотентности для восстановления
|
||||
после сбоя процесса. Состояние ресурса, блокировки ресурсов и создание задачи
|
||||
изменяются в одной транзакции, когда это требуется. Оптимистичные колонки версии
|
||||
обнаруживают конкурентные обновления, а ограничения БД защищают инварианты,
|
||||
например уникальность VMID в пределах кластера.
|
||||
|
||||
Application lifespan владеет пулом соединений и ограниченным набором
|
||||
asyncio-задач воркеров. При shutdown захват прекращается, выполняемая работа
|
||||
достигает безопасной границы, отмена происходит только после настроенного grace
|
||||
period, затем пул закрывается.
|
||||
|
||||
## Получение контракта и доверие
|
||||
|
||||
Сетевой доступ ограничен явными командами import и recorder. Импортёры
|
||||
принудительно используют HTTPS, по умолчанию allowlist официальных хостов,
|
||||
лимиты размера ответа и редиректов, таймауты и ограниченные повторы. Каждый
|
||||
сырой артефакт неизменяем и имеет SHA-256 checksum. Его manifest фиксирует
|
||||
происхождение, версию, предупреждения парсера и checksum нормализованного
|
||||
снимка. Локальные снимки позволяют запуску и тестам работать офлайн.
|
||||
|
||||
Объявленная документация и санитизированное наблюдаемое поведение остаются
|
||||
разделёнными. Профиль совместимости выбирает поведение `strict-docs`, `observed`
|
||||
или `hybrid` без разброса проверок версий по сервисам.
|
||||
|
||||
## Модель безопасности
|
||||
|
||||
- Пароли и секреты API-токенов хранятся только как password hash.
|
||||
- Тикеты подписаны, краткоживущие и редактируются в телеметрии.
|
||||
- Мутации с ticket-аутентификацией требуют CSRF-валидации; запросы с API-токеном
|
||||
CSRF не требуют.
|
||||
- Интерактивный Web UI и вспомогательные `/admin/compatibility*` — лабораторные
|
||||
поверхности без отдельного admin-токена в текущей сборке; границей доверия
|
||||
является сетевая экспозиция.
|
||||
- Контейнеры в упакованных образах работают от непривилегированного пользователя.
|
||||
|
||||
## Горячая замена контракта во время работы
|
||||
|
||||
При холодном старте загружается `CONTRACT_SNAPSHOT`. Операторы могут заменить
|
||||
таблицу маршрутов в памяти для majors 6–9 через
|
||||
`POST /ui/api/contract/apply?major=N` (также доступно в Web UI). Замена
|
||||
обновляет `/version`, OpenAPI и состояние совместимости и действует только в
|
||||
пределах процесса (перезапуск восстанавливает снимок из env).
|
||||
|
||||
## Наблюдаемость
|
||||
|
||||
JSON-логи содержат request ID, шаблон маршрута, статус, длительность и
|
||||
редактированные поля идентичности. Процессные экспортёры Prometheus/OpenTelemetry
|
||||
пока не поставляются; обработчики Proxmox `/cluster/metrics*` симулируют только
|
||||
конфигурацию metrics-server PVE.
|
||||
|
||||
## Стратегия тестирования
|
||||
|
||||
Unit-тесты покрывают обработку контракта и доменные правила. Интеграционные
|
||||
тесты проверяют репозитории, транзакции, воркеров и lifespan на PostgreSQL.
|
||||
Наборы contract и compatibility нацелены на majors **6–9** с **100%** покрытием
|
||||
реестра обработчиков. Внешний proxmoxer smoke выполняется против TLS-шлюза
|
||||
Compose. Concurrency-тесты проверяют аренды задач и переходы состояния.
|
||||
|
||||
Готовность БД включает последнюю упакованную версию миграции, а не только
|
||||
успешный connectivity-запрос. Воркеры повторяют неудачные захваты, пока не
|
||||
появятся таблицы миграций. Нормализованные записи ресурсов используют
|
||||
compare-and-swap обновления версии через типизированный репозиторий, поэтому
|
||||
устаревшие писатели получают domain conflict.
|
||||
|
||||
## Модель развёртывания
|
||||
|
||||
На контейнер приходится один процесс Uvicorn. Горизонтальные реплики
|
||||
координируются через PostgreSQL, а не через локальные очереди. Миграции БД и
|
||||
операции seed — явные команды и в Kubernetes становятся отдельными job. PostgreSQL
|
||||
включён в локальный Docker Compose, но в production chart — внешняя зависимость.
|
||||
|
||||
## Архитектурные решения
|
||||
|
||||
1. Маршруты FastAPI регистрируются из нормализованных снимков при старте;
|
||||
сотни вручную поддерживаемых объявлений маршрутов не нужны.
|
||||
2. SQLAlchemy не используется. Прямые asyncpg-репозитории делают поведение
|
||||
транзакций и конкурентности явным.
|
||||
3. Задачи на PostgreSQL — граница долговечности; фоновые задачи FastAPI и
|
||||
in-memory очереди не используются для критичной работы.
|
||||
4. Совместимость capability-driven и версионирована, а не реализована через
|
||||
разбросанные условия по строкам версий.
|
||||
5. Отсутствующие обработчики честно завершаются через `CONTRACT_FALLBACK`
|
||||
(по умолчанию `error` → HTTP 501). Majors 6–9 поставляются с полной
|
||||
регистрацией обработчиков, поэтому объявленные методы не должны попадать на
|
||||
этот путь при нормальной работе.
|
||||
6. Лабораторная документация и cookbooks живут в `docs/` и `examples/`; внутренние
|
||||
research/prompt-заметки не входят в пользовательское руководство.
|
||||
@@ -0,0 +1,85 @@
|
||||
**Language / Язык:** [English](../authentication.md) | [Русский](authentication.md)
|
||||
|
||||
# Аутентификация
|
||||
|
||||
Симулятор реализует аутентификацию Proxmox-совместимыми тикетами и API-токенами
|
||||
с проверкой ACL для не-root принципалов.
|
||||
|
||||
## Вход по тикету
|
||||
|
||||
```http
|
||||
POST /api2/json/access/ticket
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
username=root@pam&password=secret
|
||||
```
|
||||
|
||||
Успешный ответ включает:
|
||||
|
||||
- `ticket` — также устанавливается как HttpOnly cookie `PVEAuthCookie` (SameSite=Strict)
|
||||
- `CSRFPreventionToken` — обязателен для мутаций с аутентификацией по тикету
|
||||
- `username` и связанные поля идентичности
|
||||
|
||||
Тикеты подписываются HMAC с `TICKET_SIGNING_KEY`, по умолчанию истекают через два часа
|
||||
и допускают небольшой сдвиг часов в будущее.
|
||||
|
||||
### Правила CSRF
|
||||
|
||||
| Запрос | Сессия по тикету | API-токен |
|
||||
|---|---|---|
|
||||
| `GET` / `HEAD` / `OPTIONS` | Достаточно cookie (или тикета) | Заголовок `Authorization` |
|
||||
| Другие методы | Cookie **и** заголовок `CSRFPreventionToken` | CSRF **не** требуется |
|
||||
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Cookie: PVEAuthCookie=$TICKET" \
|
||||
-H "CSRFPreventionToken: $CSRF" \
|
||||
-d '...' \
|
||||
http://localhost:8006/api2/json/nodes/pve01/qemu/100/status/start
|
||||
```
|
||||
|
||||
## API-токены
|
||||
|
||||
Формат заголовка:
|
||||
|
||||
```http
|
||||
Authorization: PVEAPIToken=USER@REALM!TOKENID=SECRET
|
||||
```
|
||||
|
||||
Секреты хранятся только как scrypt-хеши. Создание и явная регенерация возвращают
|
||||
plaintext-секрет **один раз**; list и read его никогда не выводят. Удаление токена
|
||||
немедленно его инвалидирует.
|
||||
|
||||
Привилегии токена — **пересечение** привилегий токена и эффективных (прямых +
|
||||
унаследованных) ACL владельца. Токен не может эскалировать права выше владельца.
|
||||
|
||||
## Seeded development-принципалы
|
||||
|
||||
Сидятся **каждым** профилем — включая `minimal` и после demo unload в Web UI.
|
||||
Unload уменьшает guests/nodes/storages; лабораторные принципалы и токены
|
||||
`apply_seed` всё равно вставляет:
|
||||
|
||||
| Принципал | Пароль | Токен | Примечания |
|
||||
|---|---|---|---|
|
||||
| `root@pam` | `secret` | `automation` / `automation-secret` | Полный доступ по тикету; токен всё равно ограничен при ограниченных привилегиях |
|
||||
| `auditor@pve` | `auditor-secret` | `readonly` / `readonly-secret` | Унаследованный auditor ACL — чтение OK, power ops запрещены |
|
||||
| `operator@pve` | `operator@pve-password` | `operator` / `operator-secret` | VM audit/power на `/vms` |
|
||||
| `storage@pve` | `storage@pve-password` | `storage` / `storage-secret` | Область datastore на `/storage` |
|
||||
|
||||
Эти учётные данные **только для лаборатории**. Смените или отключите их перед
|
||||
выходом в сеть за пределы вашей рабочей станции.
|
||||
|
||||
## Root vs ACL
|
||||
|
||||
Root-сессии по тикету обходят обычные проверки ACL в Proxmox-совместимом смысле,
|
||||
используемом этим симулятором. Отдельные API-токены остаются ограниченными. Тесты
|
||||
совместимости проверяют разделение привилегий для персон auditor/operator/storage.
|
||||
|
||||
## Связанные пути
|
||||
|
||||
- Тикет: `/access/ticket`
|
||||
- Пользователи / группы / роли / ACL / realm'ы / permissions
|
||||
- Токены: `/access/users/{userid}/token[/{tokenid}]`
|
||||
- TFA и OpenID: durable локальное состояние; **без** живых вызовов IdP
|
||||
|
||||
См. доменное руководство [Access](../domains/access.md).
|
||||
@@ -0,0 +1,42 @@
|
||||
**Language / Язык:** [English](../clients.md) | [Русский](clients.md)
|
||||
|
||||
# Клиенты
|
||||
|
||||
Используйте симулятор из обычных стеков автоматизации. Каждый cookbook стремится
|
||||
к одному лабораторному сценарию, где инструмент это позволяет:
|
||||
|
||||
1. Аутентификация (ticket + CSRF **или** API token)
|
||||
2. Чтение `version` / nodes / списка QEMU
|
||||
3. Создание VM (принять UPID)
|
||||
4. Опрос статуса задачи
|
||||
5. Start / stop
|
||||
6. Чтение статуса
|
||||
7. Delete / cleanup
|
||||
|
||||
## Матрица подключений
|
||||
|
||||
Клиенты реального Proxmox VE ходят на **HTTPS `:8006`**. Compose в этой
|
||||
лаборатории публикует plain **HTTP `:8006`** (тот же номер порта). HTTPS —
|
||||
на **Kubernetes Ingress** (cert-manager). Клиенты без HTTP (proxmoxer):
|
||||
`docker compose --profile tls` → `https://localhost:8443/` (см.
|
||||
[Порты и TLS](configuration.md#порты-и-tls)).
|
||||
|
||||
| Стек | Транспорт Compose | Заметки | Docs | Code |
|
||||
|---|---|---|---|---|
|
||||
| Python (proxmoxer) | HTTPS `:8443` (`--profile tls`) | Только HTTPS; `verify_ssl=False` для lab cert | [руководство](examples/python-proxmoxer.md) | [`examples/python`](../../examples/python) |
|
||||
| Python (requests) | HTTP `:8006` | Сырой `/api2/json` | [руководство](examples/python-requests.md) | [`examples/python`](../../examples/python) |
|
||||
| Go | HTTP `:8006` | stdlib `net/http` | [руководство](examples/go.md) | [`examples/go`](../../examples/go) |
|
||||
| Java | HTTP `:8006` | Java 11+ `HttpClient` | [руководство](examples/java.md) | [`examples/java`](../../examples/java) |
|
||||
| Perl | HTTP `:8006` | `HTTP::Tiny` + JSON | [руководство](examples/perl.md) | [`examples/perl`](../../examples/perl) |
|
||||
| Ansible | HTTP `:8006` | Cookbook модуля `uri` | [руководство](examples/ansible.md) | [`examples/ansible`](../../examples/ansible) |
|
||||
| Terraform | HTTP `:8006` (или TLS `:8443`) | Предпочитайте HTTP; `insecure` только с `--profile tls` | [руководство](examples/terraform.md) | [`examples/terraform`](../../examples/terraform) |
|
||||
| Pulumi | HTTP `:8006` | `pulumi-proxmoxve` или HTTP cookbooks | [руководство](examples/pulumi.md) | [`examples/pulumi`](../../examples/pulumi) |
|
||||
|
||||
В Kubernetes с Ingress + cert-manager направляйте клиентов на
|
||||
`https://<ваш-хост>/`.
|
||||
|
||||
## Дальше
|
||||
|
||||
- Индекс cookbook: [examples/overview.md](examples/overview.md)
|
||||
- Troubleshooting: [examples/troubleshooting-clients.md](examples/troubleshooting-clients.md)
|
||||
- Полный Pulumi suite: [`pulumi-tests/`](../../pulumi-tests/README.ru.md)
|
||||
@@ -0,0 +1,109 @@
|
||||
**Language / Язык:** [English](../compatibility-0.1.0.md) | [Русский](compatibility-0.1.0.md)
|
||||
|
||||
# Отчёт о совместимости — 0.1.0
|
||||
|
||||
Этот отчёт фиксирует evidence для релиза симулятора 0.1.0 относительно bundled
|
||||
контрактов Proxmox VE API (majors 6–9). Это матрица ограничений для измерений
|
||||
*качества / внешней интеграции*, а не заявление общей совместимости с
|
||||
гипервизором Proxmox. Покрытие реестра обработчиков относительно каждого
|
||||
contract snapshot — **100%** для majors 6–9: у каждого объявленного метода есть
|
||||
семантический обработчик.
|
||||
|
||||
Обзор для пользователя — в [compatibility.md](compatibility.md). Актуальные
|
||||
machine-readable counts всегда доступны из `/admin/compatibility` (и `.md` /
|
||||
`.html`). Предпочитайте этот endpoint, когда симулятор запущен.
|
||||
|
||||
## Сводка (основной контракт PVE 9.2.3)
|
||||
|
||||
| Уровень | Методы | Доля контракта | Evidence |
|
||||
|---|---:|---:|---|
|
||||
| Declared and dynamically routed | 675 | 100% | Bundled API Viewer snapshot |
|
||||
| Stateful semantics implemented | **675** | **100%** | Handler registry ∩ contract |
|
||||
| Observed / verified surface ledger | **675** | **100%** | `evidence/pve-9.2.3.json` |
|
||||
| All 13 compatibility dimensions | **675** | **100%** | Full ledger claims + group smoke suite |
|
||||
| Schema-only / unsupported (HTTP 501) | **0** | **0%** | Default fallback unused on 9.2.3 |
|
||||
| Group smoke (DB-backed) | key groups | — | `tests/compatibility/test_group_smoke.py` |
|
||||
| proxmoxer smoke exercised | 9 | 1.33% | Unmodified proxmoxer 2.3 compatibility test |
|
||||
|
||||
Smoke set: `POST /access/ticket`, `GET /version`, `GET /nodes`,
|
||||
`GET /nodes/{node}/qemu`, `GET /nodes/{node}/qemu/{vmid}/status/current`, одна из
|
||||
двух state mutations (`start` или `stop`) и повторные
|
||||
`GET /nodes/{node}/tasks/{upid}/status`. Обе мутации имеют независимые API- и
|
||||
worker-тесты; один smoke run выбирает переход, допустимый для текущего состояния.
|
||||
|
||||
## Покрытие по Proxmox major
|
||||
|
||||
| Версия | Объявлено | Реализовано | Проверено | Покрытие |
|
||||
|---|---:|---:|---:|---:|
|
||||
| 6.4-15 | 504 | 504 | 504 | 100.00% |
|
||||
| 7.4-16 | 540 | 540 | 540 | 100.00% |
|
||||
| 8.4.5 | 605 | 605 | 605 | 100.00% |
|
||||
| 9.2.3 | 675 | 675 | 675 | 100.00% |
|
||||
|
||||
**Verified** здесь означает, что каждый объявленный метод присутствует в
|
||||
per-major surface ledger (`evidence/pve-{version}.json`), перегенерируемом через
|
||||
`make evidence` и охраняемом `tests/compatibility/test_verified_surface.py`.
|
||||
Hot-swap (`POST /ui/api/contract/apply?major=N`) загружает ledger этого major,
|
||||
поэтому Help → Compatibility показывает полные observed/verified counts после
|
||||
Apply.
|
||||
|
||||
Каждая запись ledger заявляет все тринадцать измерений, поэтому
|
||||
`fully_compatible` совпадает с declared после Apply. Group smoke
|
||||
(`tests/compatibility/test_group_smoke.py`) проверяет репрезентативные
|
||||
мутации с PostgreSQL для access, QEMU, LXC, storage, notifications, SDN и node
|
||||
DNS/network.
|
||||
|
||||
Старые majors переиспользуют обработчики 9.2.3 плюс path synonyms из
|
||||
`app/handlers/legacy_aliases.py` (`ceph/pools` → `ceph/pool`,
|
||||
`backupinfo` → `backup-info`, `scan/glusterfs`, legacy TFA collection verbs и
|
||||
т. д.).
|
||||
|
||||
## Реализованная поверхность (высокий уровень)
|
||||
|
||||
- **Core**: version, ticket login, node list/status/index, cluster resources.
|
||||
- **Access**: users, groups, roles, ACL, password, tokens, realms, TFA, OpenID,
|
||||
permissions, VNC ticket — всё durable в PostgreSQL.
|
||||
- **QEMU / LXC**: полные contract surfaces, включая agent, cloud-init, consoles,
|
||||
RRD, firewall aliases/ipset, migrate/clone/snapshot subsets.
|
||||
- **Storage / pools / backup / HA / firewall / Ceph / SDN**: durable handlers
|
||||
(`clusters.metadata`, `nodes.metadata.ops`, normalized tables).
|
||||
- **Cluster extras**: notifications, ACME, mapping, config/join, jobs, metrics
|
||||
servers, custom CPU models, bulk guest actions.
|
||||
- **Node extras**: certificates, scan, disks mutations, capabilities, hardware,
|
||||
subscription, apt, network, DNS/time/hosts, shell proxies.
|
||||
- **Tasks**: leased workers, status, append-only logs.
|
||||
- **Auth**: ticket + CSRF для mutations; hashed API tokens.
|
||||
|
||||
## Принцип персистентности
|
||||
|
||||
Каждый create/update/delete path записывает в PostgreSQL (таблицы и/или jsonb
|
||||
metadata). Секреты могут храниться, но не должны возвращаться в GET.
|
||||
Пользовательские ошибки «not supported in the emulator» запрещены — см.
|
||||
`.cursor/rules/durable-simulator.mdc`.
|
||||
|
||||
## Известные ограничения
|
||||
|
||||
| Область | Текущее поведение |
|
||||
|---|---|
|
||||
| External systems | LDAP/OpenID/ACME/Ceph не обращаются к реальным удалённым системам; состояние симулируется |
|
||||
| Realm sync / OpenID login | Durable stamps / pending state / tickets; нет live IdP |
|
||||
| Observation parity | Contract/tests существуют; санитизированный real-PVE observation corpus ограничен |
|
||||
| TLS | Локальный nginx gateway только с checked-in self-signed development key |
|
||||
| Client certification | proxmoxer 2.3 smoke; Terraform и другие клиенты не сертифицированы |
|
||||
| Deep HTTP coverage | Не каждый из 675 методов прогоняется end-to-end; group smokes покрывают репрезентативные paths по доменам |
|
||||
|
||||
Полное покрытие реестра означает, что HTTP 501 «handler pending» больше не
|
||||
должен появляться для методов, объявленных в активном контракте после Apply.
|
||||
*Качество* совместимости (точный parity edge-case Proxmox) по-прежнему углубляется
|
||||
тестами и observation.
|
||||
|
||||
При импорте новой версии контракта Proxmox: обновите bundled snapshot, выполните
|
||||
`make evidence`, запустите `pytest tests/compatibility/test_verified_surface.py`
|
||||
и закоммитьте обновлённые ledger `evidence/pve-*.json`.
|
||||
|
||||
Отчёт также раскрывает 13 независимых измерений совместимости, требуемых project
|
||||
brief. Surface ledgers живут в `evidence/pve-{version}.json`; исторический deep
|
||||
overlay `evidence/pve-9.2.3-0.1.0.json` сливается в canon 9.2.3 при
|
||||
перегенерации. Сама динамическая регистрация маршрутов доказывает измерение
|
||||
route/method; это не означает полную семантическую совместимость для каждого
|
||||
edge case.
|
||||
@@ -0,0 +1,78 @@
|
||||
**Language / Язык:** [English](../compatibility.md) | [Русский](compatibility.md)
|
||||
|
||||
# Совместимость
|
||||
|
||||
Этот документ объясняет, как симулятор заявляет совместимость с Proxmox VE API
|
||||
majors **6–9**. Предпочитайте live-отчёты, когда процесс запущен.
|
||||
|
||||
## Live-отчёты
|
||||
|
||||
| URL | Формат |
|
||||
|---|---|
|
||||
| `/admin/compatibility` | JSON |
|
||||
| `/admin/compatibility.md` | Markdown |
|
||||
| `/admin/compatibility.html` | HTML |
|
||||
|
||||
Web UI также показывает панель совместимости через `/ui/api/compatibility?major=N`.
|
||||
|
||||
## Реестр и проверенное покрытие поверхности
|
||||
|
||||
| Версия | Объявлено | Реализовано | Проверено | Покрытие |
|
||||
|---|---:|---:|---:|---:|
|
||||
| 6.4-15 | 504 | 504 | 504 | 100% |
|
||||
| 7.4-16 | 540 | 540 | 540 | 100% |
|
||||
| 8.4.5 | 605 | 605 | 605 | 100% |
|
||||
| 9.2.3 | 675 | 675 | 675 | 100% |
|
||||
|
||||
Старые majors сопоставляют legacy path synonyms через `legacy_aliases` с общим
|
||||
набором обработчиков.
|
||||
|
||||
- **Implemented** — зарегистрирован семантический обработчик.
|
||||
- **Verified / observed** — каждый объявленный метод перечислен в
|
||||
`evidence/pve-{version}.json` (surface ledger). Перегенерируйте через
|
||||
`make evidence`. Охраняется `tests/compatibility/test_verified_surface.py`.
|
||||
|
||||
После **Apply as runtime** (`POST /ui/api/contract/apply?major=N`) live-отчёт
|
||||
загружает ledger этого major, поэтому Help → Compatibility показывает полные
|
||||
verified counts.
|
||||
|
||||
## Измерения evidence
|
||||
|
||||
Оценка совместимости использует тринадцать независимых измерений (routing,
|
||||
input shape, HTTP status, JSON structure, state semantics, long tasks,
|
||||
permissions, …). Ledger по majors в `evidence/pve-{version}.json` в настоящее
|
||||
время заявляют **все тринадцать измерений для каждого объявленного метода**
|
||||
(перегенерируются через `make evidence`), поэтому Help → Compatibility
|
||||
Dimensions показывает 100% после Apply.
|
||||
|
||||
Исполняемая основа этих заявлений:
|
||||
|
||||
| Набор | Роль |
|
||||
|---|---|
|
||||
| `tests/compatibility/test_verified_surface.py` | hot-swap + ledger drift + score gates |
|
||||
| `tests/compatibility/test_group_smoke.py` | access / qemu / lxc / storage / cluster / SDN / node ops with PostgreSQL |
|
||||
| `tests/compatibility/test_proxmoxer.py` | external proxmoxer HTTPS smoke |
|
||||
|
||||
Историческое богатое происхождение из `evidence/pve-9.2.3-0.1.0.json` по-прежнему
|
||||
сливается в `sources` ledger 9.2.3 при перегенерации.
|
||||
|
||||
## Внешний client smoke
|
||||
|
||||
`make test-compatibility` запускает неизменённый поток **proxmoxer 2.3** против
|
||||
Compose TLS gateway (`PROXMOXER_HOST` / `PROXMOXER_PORT`). Проверяются login,
|
||||
reads, CSRF-protected mutation, token/ACL behaviour и завершение UPID.
|
||||
|
||||
Дополнительные cookbooks в [`examples/`](../../examples/README.ru.md) — manual или
|
||||
CI-optional в зависимости от стека.
|
||||
|
||||
## Известные поведенческие ограничения
|
||||
|
||||
| Область | Поведение |
|
||||
|---|---|
|
||||
| External systems | LDAP / OpenID / ACME / Ceph не обращаются к реальным удалённым системам |
|
||||
| TLS | Только локальный self-signed development gateway |
|
||||
| Hypervisor | Нет реального выполнения KVM/LXC |
|
||||
| Observation corpus | Санитизированные данные наблюдений real-PVE остаются ограниченными |
|
||||
|
||||
Исторические release notes:
|
||||
[compatibility-0.1.0.md](compatibility-0.1.0.md).
|
||||
@@ -0,0 +1,107 @@
|
||||
**Language / Язык:** [English](../configuration.md) | [Русский](configuration.md)
|
||||
|
||||
# Конфигурация
|
||||
|
||||
Настройки приложения загружаются из окружения (см. `.env.example`).
|
||||
Docker Compose подставляет многие из них для сервиса `simulator`; значения,
|
||||
объявленные в `environment:` в `docker-compose.yml`, переопределяют `.env` для этого
|
||||
сервиса.
|
||||
|
||||
## Основные
|
||||
|
||||
| Переменная | По умолчанию / пример | Назначение |
|
||||
|---|---|---|
|
||||
| `APP_HOST` | `0.0.0.0` | Адрес привязки |
|
||||
| `APP_PORT` | `8006` | HTTP-порт прослушивания |
|
||||
| `DATABASE_URL` | `postgresql://proxmox:proxmox@postgres:5432/proxmox_simulator` | asyncpg DSN |
|
||||
| `DB_POOL_MIN_SIZE` | `1` | Минимум пула |
|
||||
| `DB_POOL_MAX_SIZE` | `10` | Максимум пула |
|
||||
| `DB_CONNECT_TIMEOUT_SECONDS` | `10` | Таймаут подключения |
|
||||
| `DB_COMMAND_TIMEOUT_SECONDS` | `30` | Таймаут команды |
|
||||
| `LOG_LEVEL` | `INFO` | Уровень логирования |
|
||||
| `REQUEST_ID_HEADER` | `X-Request-ID` | Заголовок корреляции запросов |
|
||||
|
||||
## Контракт и каталог
|
||||
|
||||
| Переменная | Назначение |
|
||||
|---|---|
|
||||
| `CONTRACT_SNAPSHOT` | Путь к нормализованному снимку, загружаемому при **холодном старте** |
|
||||
| `CONTRACT_FALLBACK` | `error` (по умолчанию), `schema-default` или `fixture` — поведение для методов **без** семантического обработчика |
|
||||
| `COMPATIBILITY_EVIDENCE` | Необязательный evidence JSON для отчётов совместимости |
|
||||
| `CATALOG_ARTIFACT_URL_6` … `_9` | Официальные URL API Viewer при импорте/кэшировании мажоров каталога |
|
||||
|
||||
Горячая замена в runtime (Web UI / `POST /ui/api/contract/apply`) заменяет таблицу
|
||||
маршрутов в памяти для мажоров **6–9** без перезаписи `CONTRACT_SNAPSHOT`. Перезапуск
|
||||
процесса восстанавливает снимок холодного старта. См. [Версии API](api-versions.md).
|
||||
|
||||
При **100%** покрытии обработчиков на мажорах 6–9 `CONTRACT_FALLBACK` не используется
|
||||
для объявленных методов активного контракта. В production-подобных лабораториях
|
||||
оставляйте `error`, чтобы любой случайный пробел проявлялся как HTTP 501.
|
||||
|
||||
## Безопасность и задачи
|
||||
|
||||
| Переменная | Назначение |
|
||||
|---|---|
|
||||
| `TICKET_SIGNING_KEY` | HMAC-ключ для тикетов и CSRF-токенов, привязанных к тикету (**меняйте вне игрушечных лабораторий**) |
|
||||
| `TASK_WORKER_CONCURRENCY` | Число asyncio workers с арендой (1–32) |
|
||||
| `TASK_LEASE_SECONDS` | Длительность аренды задачи в PostgreSQL |
|
||||
| `SIMULATION_TIME_SCALE` | Ускоряет симулируемые длительности задач |
|
||||
|
||||
## Seed и хуки клиентских тестов
|
||||
|
||||
| Переменная | Назначение |
|
||||
|---|---|
|
||||
| `SEED_PROFILE` | Имя профиля для seed CLI (`small`, `medium`, …) |
|
||||
| `SEED_LARGE_NODES` | Число узлов для `large` |
|
||||
| `SEED_LARGE_RESOURCES` | Число гостей для `large` (по умолчанию 10 000) |
|
||||
| `TEST_DATABASE_URL` | DSN для интеграционных тестов |
|
||||
| `PROXMOXER_HOST` / `PROXMOXER_PORT` | Цель клиента совместимости (`tls-gateway` / `8443` в Compose) |
|
||||
|
||||
## Порты и TLS
|
||||
|
||||
### Реальный Proxmox VE (справочно)
|
||||
|
||||
На физическом / production-узле PVE management API слушает **HTTPS `:8006`**
|
||||
(`/api2/json/...`). Связанные management-порты (это не отдельные REST API):
|
||||
|
||||
| Порт | Протокол | Назначение |
|
||||
|---|---|---|
|
||||
| `8006` | TCP, HTTPS | Web UI + REST API |
|
||||
| `3128` | TCP | SPICE proxy (графическая консоль) |
|
||||
| `5900–5999` | TCP (WebSocket) | VNC web-консоль |
|
||||
| `22` | TCP | SSH / кластерные операции |
|
||||
| `5405–5412` | UDP | Трафик Corosync |
|
||||
|
||||
Порт **`8007`** — **не** API PVE: обычно это management-порт Proxmox Backup
|
||||
Server (PBS). Не направляйте PVE-клиентов на `:8007` на реальном железе.
|
||||
|
||||
### Эндпоинты лабораторного симулятора
|
||||
|
||||
| Эндпоинт | Использование |
|
||||
|---|---|
|
||||
| `http://localhost:8006` | Основной URL клиентов — nginx TLS-шлюз → симулятор (curl, браузеры, proxmoxer, Terraform, …) |
|
||||
|
||||
Сам процесс симулятора говорит по **HTTP на `:8006` внутри Docker-сети**. Compose
|
||||
публикует self-signed HTTPS-фронт на хосте **`:8006`** (тот же порт, что у
|
||||
реального PVE), чтобы неизменённые TLS-клиенты вели себя как против production
|
||||
(`https://host:8006/api2/json/...`). Внутри Compose шлюз слушает `8443` и
|
||||
проксирует на `simulator:8006`. Хост **`:8007` больше не используется** для
|
||||
лабораторного API (на реальном железе этот порт обычно PBS, не PVE).
|
||||
|
||||
Встроенный сертификат в `docker/tls/` — одноразовый материал для разработки.
|
||||
Никогда не используйте его вне локальных лабораторий. См. [Безопасность](security.md).
|
||||
|
||||
## Заметки по Compose
|
||||
|
||||
- `migrate` выполняется один раз; `simulator` ждёт успешного migrate.
|
||||
- Development Compose монтирует репозиторий и включает Uvicorn reload.
|
||||
- В Compose по умолчанию `CONTRACT_SNAPSHOT` закрепляет встроенную ревизию PVE **9.2.3**
|
||||
для холодного старта.
|
||||
|
||||
## Открытые и неиспользуемые ключи в примере
|
||||
|
||||
`.env.example` может по-прежнему перечислять ключи вроде `PVE_API_VERSION`,
|
||||
`SIMULATION_SEED`, `SIMULATOR_ADMIN_ENABLED` и `SIMULATOR_ADMIN_TOKEN`, которые
|
||||
**не** потребляются текущей моделью настроек. Для мажорной версии по умолчанию
|
||||
используйте `CONTRACT_SNAPSHOT`, для runtime-переключений — Web UI / apply API. Не
|
||||
предполагайте, что сегодня существует аутентифицированный admin API `/_simulator`.
|
||||
@@ -0,0 +1,28 @@
|
||||
**Language / Язык:** [English](../../domains/README.md) | [Русский](README.md)
|
||||
|
||||
# Руководства по доменам
|
||||
|
||||
Эти страницы описывают устойчивую семантику по областям API. Для исчерпывающих
|
||||
списков методов используйте каталог Web UI или OpenAPI (`/docs`) для активной
|
||||
major-версии — заявленное покрытие составляет **100%** для PVE 6–9.
|
||||
|
||||
| Руководство | Темы |
|
||||
|---|---|
|
||||
| [Core и кластер](core-cluster.md) | version, nodes, cluster resources/options/status |
|
||||
| [Access](access.md) | users, groups, roles, ACL, realms, tokens, TFA, OpenID |
|
||||
| [QEMU](qemu.md) | guests, power, disks, snapshots, clone/migrate, agent |
|
||||
| [LXC](lxc.md) | containers and parallel lifecycle operations |
|
||||
| [Storage и backup](storage-backup.md) | storages, content, vzdump / backup jobs |
|
||||
| [Firewall](firewall.md) | cluster / node / guest firewall objects |
|
||||
| [HA](ha.md) | groups, resources, status |
|
||||
| [Ceph](ceph.md) | simulated Ceph configuration and status |
|
||||
| [Pools](pools.md) | pools and membership |
|
||||
| [SDN](sdn.md) | zones, VNets, subnets, controllers, IPAM |
|
||||
| [Cluster extras](cluster-extras.md) | notifications, ACME, mapping, metrics servers |
|
||||
| [Tasks](tasks.md) | UPID workers, status, logs |
|
||||
|
||||
## Карта персистентности
|
||||
|
||||
- Guests / HA / storage / identity → нормализованные таблицы
|
||||
- Свободная конфигурация кластера → `clusters.metadata` jsonb
|
||||
- Операции на уровне узла (network, disks, apt, …) → `nodes.metadata` под ключом `ops`
|
||||
@@ -0,0 +1,21 @@
|
||||
**Language / Язык:** [English](../../domains/access.md) | [Русский](access.md)
|
||||
|
||||
# Access
|
||||
|
||||
Устойчивая идентификация и авторизация: users, groups, roles, ACL entries,
|
||||
realms, passwords, API tokens, permissions queries, tickets, TFA, OpenID,
|
||||
VNC tickets.
|
||||
|
||||
## Основное
|
||||
|
||||
- Ticket login и CSRF — см. [Authentication](../authentication.md).
|
||||
- При создании token секрет возвращается один раз; в хранилище сохраняются только
|
||||
хеши.
|
||||
- Наследование ACL и пересечение привилегий token ∩ owner.
|
||||
- Состояние realm / TFA / OpenID **локальное**; живые вызовы каталога или IdP не
|
||||
выполняются.
|
||||
|
||||
## Предзаполненные персоны
|
||||
|
||||
`root@pam`, `auditor@pve`, `operator@pve`, `storage@pve` — пароли и tokens см. в
|
||||
руководстве по authentication.
|
||||
@@ -0,0 +1,9 @@
|
||||
**Language / Язык:** [English](../../domains/ceph.md) | [Русский](ceph.md)
|
||||
|
||||
# Ceph
|
||||
|
||||
Пути API, связанные с Ceph, сохраняют симулированное состояние кластера, pool,
|
||||
OSD и monitor. Они не обращаются к живому кластеру Ceph.
|
||||
|
||||
Устаревшие алиасы путей (например, исторические написания `ceph/pools`) мапятся
|
||||
на общие handlers, чтобы старые major-версии оставались полностью маршрутизируемыми.
|
||||
@@ -0,0 +1,13 @@
|
||||
**Language / Язык:** [English](../../domains/cluster-extras.md) | [Русский](cluster-extras.md)
|
||||
|
||||
# Cluster extras
|
||||
|
||||
Дополнительные домены на уровне кластера с устойчивыми handlers:
|
||||
|
||||
- **Notifications** — состояние конфигурации endpoints и targets
|
||||
- **ACME** — симуляция account/plugin/certificate (без реальной регистрации в CA)
|
||||
- **Mapping** — PCI / USB / resource mappings
|
||||
- **Metrics servers** — симуляция конфигурации и экспорта PVE metrics-server
|
||||
- **Custom CPU models** и массовые guest actions — как заявлено в контракте
|
||||
|
||||
Точные пути для активной major-версии смотрите в каталоге Web UI.
|
||||
@@ -0,0 +1,25 @@
|
||||
**Language / Язык:** [English](../../domains/core-cluster.md) | [Русский](core-cluster.md)
|
||||
|
||||
# Core и кластер
|
||||
|
||||
## Version
|
||||
|
||||
`GET /version` отражает `source_version` **активного** контракта (cold-start
|
||||
snapshot или hot-swapped major).
|
||||
|
||||
## Nodes
|
||||
|
||||
- Endpoints списка и статуса устойчивы и формируются из seeded / созданных nodes.
|
||||
- Имя node по умолчанию в seed-профиле `small`: **`pve01`**.
|
||||
- Операционные мутации node (network, apt, disks, services, DNS/time/hosts,
|
||||
certificates, …) сохраняются в `nodes.metadata.ops`.
|
||||
|
||||
## Cluster
|
||||
|
||||
- `/cluster/resources` и связанные inventory views читают guests и storages из
|
||||
PostgreSQL.
|
||||
- Cluster options, status, tasks, logs, replication, config/join helpers
|
||||
сохраняют cluster metadata и связанные таблицы.
|
||||
|
||||
Работает для всех заявленных методов на major 6–9 для этих путей. Используйте
|
||||
каталог Web UI, чтобы проверить различия параметров между версиями.
|
||||
@@ -0,0 +1,10 @@
|
||||
**Language / Язык:** [English](../../domains/firewall.md) | [Русский](firewall.md)
|
||||
|
||||
# Firewall
|
||||
|
||||
Конфигурация firewall на уровне cluster, node и guest — rules, aliases, IP sets,
|
||||
security groups — в основном сохраняется через cluster/node metadata и связанные
|
||||
структуры.
|
||||
|
||||
Handlers покрывают заявленную firewall-поверхность для major 6–9. Примените
|
||||
нужную major-версию перед проверкой имён полей, специфичных для версии.
|
||||
@@ -0,0 +1,10 @@
|
||||
**Language / Язык:** [English](../../domains/ha.md) | [Русский](ha.md)
|
||||
|
||||
# HA
|
||||
|
||||
High-availability groups, resources, status и rules сохраняются в cluster
|
||||
metadata / таблицах HA.
|
||||
|
||||
Используйте профиль `ha-demo` (medium + HA resource для VM 100) или demo cluster
|
||||
для более богатых fixtures. HA здесь оркестрирует **симулированное** состояние
|
||||
размещения guest — реальные nodes не изолируются (fencing не выполняется).
|
||||
@@ -0,0 +1,15 @@
|
||||
**Language / Язык:** [English](../../domains/lxc.md) | [Русский](lxc.md)
|
||||
|
||||
# LXC
|
||||
|
||||
Container API повторяют паттерны жизненного цикла QEMU там, где это заявлено
|
||||
контрактом: CRUD, power, clone/migrate, snapshots, volume operations, consoles,
|
||||
RRD и firewall objects.
|
||||
|
||||
Мутации сохраняются в нормализованные container tables и связанные metadata.
|
||||
Асинхронные пути возвращают UPID по той же модели leased-worker, что и QEMU.
|
||||
|
||||
Seed-профили:
|
||||
|
||||
- `small` — CT `200` на `pve01`
|
||||
- `medium` / `large` / `demo-cluster` — множество containers
|
||||
@@ -0,0 +1,6 @@
|
||||
**Language / Язык:** [English](../../domains/pools.md) | [Русский](pools.md)
|
||||
|
||||
# Pools
|
||||
|
||||
Pool CRUD и membership ресурсов полностью покрыты и устойчивы. Seed `medium`
|
||||
включает development pool для экспериментов с membership.
|
||||
@@ -0,0 +1,19 @@
|
||||
**Language / Язык:** [English](../../domains/qemu.md) | [Русский](qemu.md)
|
||||
|
||||
# QEMU
|
||||
|
||||
Полная contract-поверхность для QEMU guests на активной major, включая:
|
||||
|
||||
- Create / sync & async config update / delete (UPID для async)
|
||||
- Power: start, stop, shutdown, reboot, reset, suspend, resume
|
||||
- Явная state machine + per-VM PostgreSQL lock
|
||||
- Snapshots (create/delete/rollback как tasks)
|
||||
- Clone и local migration (UPID)
|
||||
- Disk resize (sync; shrink отклоняется) и disk move (task)
|
||||
- Pending config view
|
||||
- Guest agent read-only subset (info, OS/hostname, network, time, ping) при
|
||||
`agent=1` и запущенном guest
|
||||
- Cloud-init, consoles, RRD, guest firewall objects — как заявлено в контракте
|
||||
|
||||
Индексированные поля контракта, такие как `scsi[n]`, принимают конкретные имена
|
||||
(`scsi0`, …). Неизвестные version-dependent parameters сохраняются в JSONB.
|
||||
@@ -0,0 +1,10 @@
|
||||
**Language / Язык:** [English](../../domains/sdn.md) | [Русский](sdn.md)
|
||||
|
||||
# SDN
|
||||
|
||||
Handlers software-defined networking покрывают заявленные zones, VNets, subnets,
|
||||
controllers, IPAM, DNS, fabrics, locks и связанные dry-run/rollback операции для
|
||||
активной major.
|
||||
|
||||
Состояние локально в базе симулятора. Переключение major 6–9 меняет набор SDN
|
||||
methods на wire; все заявленные реализованы.
|
||||
@@ -0,0 +1,18 @@
|
||||
**Language / Язык:** [English](../../domains/storage-backup.md) | [Русский](storage-backup.md)
|
||||
|
||||
# Storage и backup
|
||||
|
||||
## Storage
|
||||
|
||||
- Cluster и node storage inventories сохраняются в нормализованных storage tables.
|
||||
- Content listings и мутации обновляют `storage_contents` (и связанные строки).
|
||||
- Seed `broken-storage` помечает `local-lvm` недоступным для тестирования сбоев.
|
||||
|
||||
## Backup
|
||||
|
||||
- Backup jobs, metadata и task-пути в стиле `vzdump` создают устойчивые task rows
|
||||
и backup records.
|
||||
- Workers выполняют leased backup tasks аналогично guest operations.
|
||||
|
||||
Реальные удалённые backup targets не вызываются; состояние объектов остаётся
|
||||
внутри PostgreSQL.
|
||||
@@ -0,0 +1,25 @@
|
||||
**Language / Язык:** [English](../../domains/tasks.md) | [Русский](tasks.md)
|
||||
|
||||
# Tasks
|
||||
|
||||
Долгие операции возвращают **UPID** в стиле Proxmox. Task rows, events,
|
||||
опциональные resource locks и idempotency metadata фиксируются вместе.
|
||||
|
||||
## Паттерн для клиента
|
||||
|
||||
1. `POST`/`DELETE` mutation → прочитать UPID из `data`
|
||||
2. Опрашивать `GET /nodes/{node}/tasks/{upid}/status` до завершения
|
||||
3. При необходимости запросить `.../log`
|
||||
|
||||
## Workers
|
||||
|
||||
- Claim через `FOR UPDATE SKIP LOCKED`
|
||||
- Возобновляемые leases (`TASK_LEASE_SECONDS`)
|
||||
- Progress + append-only logs
|
||||
- Recovery после сбоя процесса
|
||||
|
||||
Длительность симуляции учитывает `SIMULATION_TIME_SCALE`. Безопасность lease
|
||||
worker использует wall-clock time, чтобы ускоренный сценарий не нарушал
|
||||
семантику распределённого claim.
|
||||
|
||||
См. [API surface](../api-surface.md) и [Operations](../operations.md).
|
||||
@@ -0,0 +1,14 @@
|
||||
**Language / Язык:** [English](../../examples/ansible.md) | [Русский](ansible.md)
|
||||
|
||||
# Ansible
|
||||
|
||||
Playbook использует модуль `uri` для HTTP `:8006` с аутентификацией по токену, затем
|
||||
ticket+CSRF для пути мутации.
|
||||
|
||||
```bash
|
||||
cd examples/ansible
|
||||
ansible-playbook -i inventory.ini playbook.yml
|
||||
```
|
||||
|
||||
Перед использованием фиксированных VMID из предыдущего запуска выполните повторный seed
|
||||
симулятора.
|
||||
@@ -0,0 +1,13 @@
|
||||
**Language / Язык:** [English](../../examples/go.md) | [Русский](go.md)
|
||||
|
||||
# Go
|
||||
|
||||
Использует стандартную библиотеку Go для `http://localhost:8006` с аутентификацией
|
||||
по API-токену.
|
||||
|
||||
```bash
|
||||
cd examples/go
|
||||
go run .
|
||||
```
|
||||
|
||||
См. `main.go` — там cookbook-поток и вспомогательная функция опроса UPID.
|
||||
@@ -0,0 +1,13 @@
|
||||
**Language / Язык:** [English](../../examples/java.md) | [Русский](java.md)
|
||||
|
||||
# Java
|
||||
|
||||
Cookbook на Java 11+ `HttpClient` с аутентификацией по API-токену через `:8006`.
|
||||
|
||||
```bash
|
||||
cd examples/java
|
||||
javac Cookbook.java && java Cookbook
|
||||
```
|
||||
|
||||
Сторонние JSON-библиотеки не нужны — ответы разбираются простыми строковыми
|
||||
вспомогательными функциями, достаточными для лабораторного smoke-теста.
|
||||
@@ -0,0 +1,58 @@
|
||||
**Language / Язык:** [English](../../examples/overview.md) | [Русский](overview.md)
|
||||
|
||||
# Обзор примеров клиентов
|
||||
|
||||
## Чеклист запуска
|
||||
|
||||
```bash
|
||||
make up
|
||||
curl -sf http://localhost:8006/health/ready
|
||||
make seed PROFILE=small
|
||||
curl -s http://localhost:8006/api2/json/version
|
||||
```
|
||||
|
||||
Опционально — зафиксировать major 8 на время сессии:
|
||||
|
||||
```bash
|
||||
curl -s -X POST 'http://localhost:8006/ui/api/contract/apply?major=8'
|
||||
```
|
||||
|
||||
## Эндпоинты
|
||||
|
||||
| URL | Когда использовать |
|
||||
|---|---|
|
||||
| `http://localhost:8006` | curl, Go, Java, Perl, Ansible, requests |
|
||||
| `http://localhost:8006` | proxmoxer, многие TLS-клиенты Terraform/Pulumi |
|
||||
|
||||
## Краткая справка по аутентификации
|
||||
|
||||
**Ticket**
|
||||
|
||||
```bash
|
||||
RESP=$(curl -s -X POST -d 'username=root@pam&password=secret' \
|
||||
http://localhost:8006/api2/json/access/ticket)
|
||||
TICKET=$(echo "$RESP" | jq -r .data.ticket)
|
||||
CSRF=$(echo "$RESP" | jq -r .data.CSRFPreventionToken)
|
||||
```
|
||||
|
||||
**Заголовок токена**
|
||||
|
||||
```text
|
||||
Authorization: PVEAPIToken=root@pam!automation=automation-secret
|
||||
```
|
||||
|
||||
## Ожидание UPID
|
||||
|
||||
Никогда не считайте, что ВМ уже запущена, только по HTTP-ответу мутации. Опрашивайте
|
||||
`/nodes/{node}/tasks/{upid}/status`, пока `data.status` не станет терминальным (обычно
|
||||
`stopped` с кодом выхода OK для завершённых задач — используйте поля Proxmox, которые
|
||||
ваш клиент уже понимает).
|
||||
|
||||
## Предупреждение о повторном seed
|
||||
|
||||
`make seed` заменяет гостей в PostgreSQL. После этого обновите состояние
|
||||
Terraform/Pulumi/Ansible.
|
||||
|
||||
## Запускаемое дерево примеров
|
||||
|
||||
См. [`examples/README.ru.md`](../../../examples/README.ru.md).
|
||||
@@ -0,0 +1,11 @@
|
||||
**Language / Язык:** [English](../../examples/perl.md) | [Русский](perl.md)
|
||||
|
||||
# Perl
|
||||
|
||||
Cookbook на `HTTP::Tiny` + JSON с аутентификацией по API-токену.
|
||||
|
||||
```bash
|
||||
cd examples/perl
|
||||
cpanm --installdeps . # или установите HTTP::Tiny и JSON вручную
|
||||
perl cookbook.pl
|
||||
```
|
||||
@@ -0,0 +1,15 @@
|
||||
**Language / Язык:** [English](../../examples/pulumi.md) | [Русский](pulumi.md)
|
||||
|
||||
# Pulumi
|
||||
|
||||
Python-программа Pulumi, управляющая симулятором по HTTPS с аутентификацией по токену
|
||||
через паттерны Pulumi Command/provider, описанные в `examples/pulumi`.
|
||||
|
||||
```bash
|
||||
cd examples/pulumi
|
||||
pulumi stack init dev # один раз
|
||||
pulumi up
|
||||
```
|
||||
|
||||
Та же осторожность, что и с Terraform: состояние PostgreSQL симулятора и состояние Pulumi
|
||||
независимы. Зафиксируйте major API для воспроизводимого CI.
|
||||
@@ -0,0 +1,23 @@
|
||||
**Language / Язык:** [English](../../examples/python-proxmoxer.md) | [Русский](python-proxmoxer.md)
|
||||
|
||||
# Python — proxmoxer
|
||||
|
||||
Канонический путь через библиотеку к HTTPS-шлюзу.
|
||||
|
||||
## Запуск
|
||||
|
||||
```bash
|
||||
make up && make seed PROFILE=small
|
||||
pip install -r examples/python/requirements.txt
|
||||
python examples/python/proxmoxer_cookbook.py
|
||||
```
|
||||
|
||||
Переопределение через переменные окружения: `PVE_HOST` (по умолчанию `localhost`),
|
||||
`PVE_PORT` (по умолчанию `8007`), `PVE_USER`, `PVE_PASSWORD`, либо токен через
|
||||
`PVE_TOKEN_NAME` / `PVE_TOKEN_VALUE`.
|
||||
|
||||
## Заметки
|
||||
|
||||
- `verify_ssl=False` нужен только для одноразового локального сертификата.
|
||||
- Мутации по ticket, которые обрабатывает proxmoxer, автоматически включают CSRF.
|
||||
- Узел по умолчанию для профиля `small` — `pve01`.
|
||||
@@ -0,0 +1,13 @@
|
||||
**Language / Язык:** [English](../../examples/python-requests.md) | [Русский](python-requests.md)
|
||||
|
||||
# Python — requests
|
||||
|
||||
Сырой HTTP к `:8006` без proxmoxer.
|
||||
|
||||
```bash
|
||||
pip install -r examples/python/requirements.txt
|
||||
python examples/python/requests_cookbook.py
|
||||
```
|
||||
|
||||
Скрипт демонстрирует аутентификацию по токену (без CSRF) и по ticket (с CSRF) для
|
||||
общего потока create → wait → start → stop → delete.
|
||||
@@ -0,0 +1,20 @@
|
||||
**Language / Язык:** [English](../../examples/terraform.md) | [Русский](terraform.md)
|
||||
|
||||
# Terraform
|
||||
|
||||
Пример использует провайдер Proxmox, направленный на локальный HTTPS-шлюз
|
||||
(`http://localhost:8006`) с `insecure = true` для разработческого сертификата.
|
||||
|
||||
```bash
|
||||
cd examples/terraform
|
||||
terraform init
|
||||
terraform apply
|
||||
```
|
||||
|
||||
Версии плагинов провайдера меняются быстро — зафиксируйте версии в `versions.tf` на
|
||||
те, что вы протестировали. После `make seed` обновите или пересоздайте state, чтобы
|
||||
предположения о VMID и узле оставались согласованными.
|
||||
|
||||
Этот cookbook — отправная точка для лабораторного CI, а не сертификация каждого
|
||||
ресурса провайдера по всем четырём major API. Зафиксируйте major симулятора перед
|
||||
apply (`CONTRACT_SNAPSHOT` или hot-swap + проверка `/version`).
|
||||
@@ -0,0 +1,13 @@
|
||||
**Language / Язык:** [English](../../examples/troubleshooting-clients.md) | [Русский](troubleshooting-clients.md)
|
||||
|
||||
# Устранение неполадок клиентов
|
||||
|
||||
| Симптом | Решение |
|
||||
|---|---|
|
||||
| Ошибки TLS-сертификата | Используйте `http://localhost:8006` с отключённой проверкой **только** локально (`curl -sk`, `verify_ssl=False`, `insecure=true`) |
|
||||
| Ошибка CSRF | Передавайте `CSRFPreventionToken` при мутациях по ticket; в скриптах предпочитайте аутентификацию по токену |
|
||||
| Узел не найден | Профиль `small` использует `pve01` |
|
||||
| 403 на power | Возможно, используется `auditor@pve` / readonly-токен — переключитесь на root или operator |
|
||||
| Создание провайдером vs UPID | Опрашивайте задачи; многие провайдеры уже ждут — сырые HTTP-клиенты часто забывают |
|
||||
| Расхождение после reseed | Обновите/пересоздайте состояние Terraform/Pulumi/Ansible |
|
||||
| Неверные поля схемы | Hot-swap или cold-start нужного major; проверьте `/version` |
|
||||
@@ -0,0 +1,58 @@
|
||||
**Language / Язык:** [English](../faq.md) | [Русский](faq.md)
|
||||
|
||||
# FAQ
|
||||
|
||||
## Это настоящий гипервизор Proxmox?
|
||||
|
||||
Нет. Это симулятор API и состояния. Гости, storage, Ceph и HA — durable-модели в
|
||||
PostgreSQL, а не процессы KVM/LXC.
|
||||
|
||||
## Вы действительно покрываете API версий 6, 7, 8 и 9?
|
||||
|
||||
Да — **100%** объявленных методов для каждого встроенного мажора имеют
|
||||
зарегистрированные семантические обработчики. Переключайте мажорные версии через
|
||||
снимок холодного старта или runtime hot-swap. См. [Версии API](api-versions.md) и
|
||||
[Совместимость](compatibility.md).
|
||||
|
||||
## Можно использовать это в CI для Terraform / Ansible / своих клиентов?
|
||||
|
||||
Да. Это один из основных сценариев. Закрепите мажор API, загрузите профиль seed и
|
||||
направьте клиентов на **HTTP `:8006`** (Compose) или Ingress **HTTPS** в Kubernetes. См. [Клиенты](clients.md).
|
||||
Набор Pulumi surface — [`pulumi-tests/`](../../pulumi-tests/README.ru.md).
|
||||
|
||||
## Почему некоторые вызовы OpenID / LDAP / ACME / Ceph «успешны» без внешних систем?
|
||||
|
||||
Эти домены сохраняют **локальное** состояние симулятора. Они намеренно не вызывают
|
||||
реальные внешние системы.
|
||||
|
||||
## Означает ли покрытие реестра идеальный паритет с Proxmox?
|
||||
|
||||
Это означает, что у каждого объявленного маршрута есть durable-обработчик и он
|
||||
покрыт verification-наборами проекта для мажоров 6–9. Точный edge-case паритет с
|
||||
физическим кластером может отличаться; для сертификационных заявлений используйте
|
||||
evidence-эндпоинты и свои клиентские тесты.
|
||||
|
||||
## Где Web UI?
|
||||
|
||||
[http://localhost:8006/](http://localhost:8006/) после `make up`.
|
||||
|
||||
## Можно развернуть в Kubernetes?
|
||||
|
||||
Да. Используйте Helm chart в `helm/proxmox-api-simulator` с опубликованным образом
|
||||
Hub. Поддерживаются Ingress + cert-manager Let's Encrypt — см.
|
||||
[Kubernetes / Helm](kubernetes.md).
|
||||
|
||||
## Какое имя узла использует профиль small seed?
|
||||
|
||||
`pve01`. Профили `medium` и `ha-demo` используют **`pve1` / `pve2` / `pve3`**.
|
||||
|
||||
## Какие порты у реального Proxmox VE и у этого симулятора?
|
||||
|
||||
Реальный PVE отдаёт Web UI и REST API только по **HTTPS `:8006`**. Связанные
|
||||
management-порты: SPICE `:3128`, VNC `:5900–5999`, SSH `:22`, Corosync UDP
|
||||
`:5405–5412`. Порт `:8007` на реальном железе обычно принадлежит
|
||||
**Proxmox Backup Server**, а не PVE.
|
||||
|
||||
Эта лаборатория публикует plain **HTTP `:8006`** в Compose; HTTPS — на Ingress. Опционально `--profile tls` на `:8443`. Было: development TLS-шлюз (тот же
|
||||
порт, что у реального PVE). Хост **`:8007` не используется**. Подробности:
|
||||
[Порты и TLS](configuration.md#порты-и-tls).
|
||||
@@ -0,0 +1,179 @@
|
||||
**Language / Язык:** [English](../getting-started.md) | [Русский](getting-started.md)
|
||||
|
||||
# Быстрый старт
|
||||
|
||||
Поднимите локальный лабораторный кластер, пройдите аутентификацию и выполните первый
|
||||
цикл чтения/мутации против симулятора.
|
||||
|
||||
## Требования
|
||||
|
||||
- Docker и Docker Compose
|
||||
- `make` (необязательно, но используется в документированных командах)
|
||||
|
||||
Python, линтеры и тесты запускаются **внутри** контейнеров. Для повседневной работы
|
||||
локальный Python-инструментарий не нужен.
|
||||
|
||||
## Выберите путь
|
||||
|
||||
| Путь | Когда использовать |
|
||||
|---|---|
|
||||
| [Опубликованный образ](#1a-опубликованный-образ-docker-hub) | Самый быстрый старт с `inecs/proxmox-api-simulator` |
|
||||
| [Helm / Kubernetes](kubernetes.md) | Установка в кластер с Ingress + Let's Encrypt |
|
||||
| [Checkout для разработки](#1b-checkout-для-разработки) | Вклад в проект / bind-mount исходников / HTTPS-шлюз на `:8006` |
|
||||
|
||||
## 1a. Опубликованный образ (Docker Hub)
|
||||
|
||||
Используется [`docker-compose.release.yml`](../../docker-compose.release.yml) —
|
||||
PostgreSQL + runtime-симулятор из Hub + лабораторный HTTPS-шлюз. Нужен checkout
|
||||
с `docker/tls/` (self-signed материалы). Сборка исходников не требуется.
|
||||
|
||||
> Только лаборатория / CI — перед shared или сетевым демо смените
|
||||
> `TICKET_SIGNING_KEY` и пароль БД. См. [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
```bash
|
||||
# из этого репозитория (compose + docker/tls/)
|
||||
docker compose -f docker-compose.release.yml pull
|
||||
docker compose -f docker-compose.release.yml up -d
|
||||
docker compose -f docker-compose.release.yml run --rm --entrypoint python \
|
||||
simulator -m app.simulation.seed_cli
|
||||
```
|
||||
|
||||
Закрепите версию:
|
||||
|
||||
```bash
|
||||
IMAGE_TAG=0.1.0 docker compose -f docker-compose.release.yml up -d
|
||||
```
|
||||
|
||||
Make-цели (git checkout):
|
||||
|
||||
```bash
|
||||
make release-up
|
||||
make release-seed PROFILE=small
|
||||
```
|
||||
|
||||
| Порт хоста | Сервис |
|
||||
|---|---|
|
||||
| `8006` | HTTPS API + Web UI через лабораторный TLS-шлюз (как у реального PVE) |
|
||||
| `5432` | PostgreSQL (только localhost) |
|
||||
|
||||
Миграции выполняются автоматически через одноразовый сервис `migrate`.
|
||||
|
||||
Далее переходите к разделу [Дождитесь готовности](#2-дождитесь-готовности).
|
||||
|
||||
## 1b. Checkout для разработки
|
||||
|
||||
```bash
|
||||
make install
|
||||
make up
|
||||
```
|
||||
|
||||
Сервисы:
|
||||
|
||||
| Порт хоста | Сервис |
|
||||
|---|---|
|
||||
| `8006` | HTTPS API + Web UI через nginx TLS-шлюз (как у реального PVE) |
|
||||
| `5432` | PostgreSQL (только localhost) |
|
||||
|
||||
У реального Proxmox VE REST API доступен **только** как
|
||||
`https://<host>:8006/api2/json/...`. Лаборатория публикует то же: HTTPS на
|
||||
хосте `:8006` через development TLS-шлюз; см.
|
||||
[Порты и TLS](configuration.md#порты-и-tls). Хост **`:8007` не используется**
|
||||
(на железе это обычно PBS, не API PVE).
|
||||
|
||||
Миграции применяются автоматически до того, как симулятор станет готов.
|
||||
|
||||
## 2. Дождитесь готовности
|
||||
|
||||
```bash
|
||||
curl -sS http://localhost:8006/health/live
|
||||
curl -sS http://localhost:8006/health/ready
|
||||
```
|
||||
|
||||
`/health/ready` возвращает HTTP 503, пока PostgreSQL недоступен **и** не применена
|
||||
последняя упакованная миграция.
|
||||
|
||||
## 3. Загрузите профиль seed
|
||||
|
||||
```bash
|
||||
make seed PROFILE=small
|
||||
```
|
||||
|
||||
`small` создаёт узел `pve01`, две QEMU-гостевые ВМ (`100`, `101`), один LXC (`200`),
|
||||
локальные хранилища и стандартных development-принципалов. Другие размеры — в
|
||||
[Профилях seed](seed-profiles.md).
|
||||
|
||||
## 4. Проверьте версию API
|
||||
|
||||
```bash
|
||||
curl -sS http://localhost:8006/api2/json/version | jq .
|
||||
```
|
||||
|
||||
При холодном старте контракт по умолчанию — встроенный снимок PVE **9.2.3** в Docker
|
||||
Compose. Переключайте мажорные версии 6–9 из Web UI или через
|
||||
[Версии API](api-versions.md).
|
||||
|
||||
## 5. Пройдите аутентификацию
|
||||
|
||||
```bash
|
||||
curl -sk -X POST \
|
||||
-d 'username=root@pam&password=secret' \
|
||||
http://localhost:8006/api2/json/access/ticket | jq .
|
||||
```
|
||||
|
||||
Сохраните `ticket` и `CSRFPreventionToken` из `data`. Для мутаций отправляйте:
|
||||
|
||||
- Cookie: `PVEAuthCookie=<ticket>`
|
||||
- Header: `CSRFPreventionToken: <token>`
|
||||
|
||||
Подробнее: [Аутентификация](authentication.md).
|
||||
|
||||
## 6. Получите список гостей и запустите одного
|
||||
|
||||
```bash
|
||||
# замените TICKET / CSRF из предыдущего ответа
|
||||
curl -sk -H "Cookie: PVEAuthCookie=$TICKET" \
|
||||
http://localhost:8006/api2/json/nodes/pve01/qemu | jq .
|
||||
|
||||
curl -sk -X POST \
|
||||
-H "Cookie: PVEAuthCookie=$TICKET" \
|
||||
-H "CSRFPreventionToken: $CSRF" \
|
||||
http://localhost:8006/api2/json/nodes/pve01/qemu/100/status/start | jq .
|
||||
```
|
||||
|
||||
Асинхронные операции возвращают строку UPID. Опрашивайте, пока задача не завершится:
|
||||
|
||||
```bash
|
||||
curl -s -H "Cookie: PVEAuthCookie=$TICKET" \
|
||||
"http://localhost:8006/api2/json/nodes/pve01/tasks/${UPID}/status" | jq .
|
||||
```
|
||||
|
||||
## 7. Откройте Web UI
|
||||
|
||||
Перейдите на [http://localhost:8006/](http://localhost:8006/) — интерактивная
|
||||
консоль, каталог контрактов (PVE 6–9), представление совместимости, применение runtime-
|
||||
контракта и управление demo-кластером. Скриншоты светлой/тёмной темы и полный список
|
||||
возможностей — в [Web UI](web-ui.md).
|
||||
|
||||
## 8. Попробуйте клиентскую библиотеку
|
||||
|
||||
```bash
|
||||
# из корня репозитория после make up + seed
|
||||
python examples/python/proxmoxer_cookbook.py
|
||||
```
|
||||
|
||||
Другие стеки: [Клиенты](clients.md) и [`examples/`](../../examples/README.ru.md).
|
||||
|
||||
## Готово, когда…
|
||||
|
||||
- `/health/ready` возвращает `{"status":"ok"}` (или эквивалентное OK-тело)
|
||||
- `/api2/json/version` сообщает активную версию контракта
|
||||
- Вход по тикету для `root@pam` успешен
|
||||
- `nodes/pve01/qemu` перечисляет seeded ВМ
|
||||
- Хотя бы один путь power или create возвращает UPID, который успешно завершается
|
||||
|
||||
## Дальнейшие шаги
|
||||
|
||||
- [Конфигурация](configuration.md) — env vars, workers, путь к контракту
|
||||
- [Версии API](api-versions.md) — горячая замена мажоров 6–9
|
||||
- [Клиенты](clients.md) — Ansible, Terraform, Pulumi, Go, Java, Perl
|
||||
- [Эксплуатация](operations.md) — reseed, migrate, обновления
|
||||
@@ -0,0 +1,190 @@
|
||||
**Language / Язык:** [English](../kubernetes.md) | [Русский](kubernetes.md)
|
||||
|
||||
# Kubernetes / Helm
|
||||
|
||||
Разверните опубликованный runtime-образ Docker Hub с chart из
|
||||
[`helm/proxmox-api-simulator`](../../helm/proxmox-api-simulator).
|
||||
|
||||
Образ: [`inecs/proxmox-api-simulator`](https://hub.docker.com/r/inecs/proxmox-api-simulator)
|
||||
|
||||
> **Только лаборатория / CI.** В defaults чарта слабые placeholder-секреты.
|
||||
> Перед shared или Internet-facing установкой всегда переопределяйте
|
||||
> `secret.ticketSigningKey` и `postgresql.auth.password`. См.
|
||||
> [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Транспорт (Compose vs Helm)
|
||||
|
||||
| Путь | URL клиента |
|
||||
|---|---|
|
||||
| Локальный Compose (`docker-compose*.yml`) | **HTTP** `:8006` (процесс симулятора) |
|
||||
| Helm Service / `kubectl port-forward` | **HTTP** `:8006` (процесс симулятора; TLS на Ingress, если включён) |
|
||||
| Helm Ingress + cert-manager | **HTTPS** на вашем hostname |
|
||||
|
||||
## Предварительные требования
|
||||
|
||||
- Kubernetes 1.27+ (или сопоставимый)
|
||||
- Helm 3.14+
|
||||
- [Ingress NGINX](https://kubernetes.github.io/ingress-nginx/) (или другой
|
||||
IngressClass с поддержкой HTTP-01)
|
||||
- [cert-manager](https://cert-manager.io/) установлен cluster-wide
|
||||
|
||||
Пример установки cert-manager:
|
||||
|
||||
```bash
|
||||
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.yaml
|
||||
```
|
||||
|
||||
## Быстрая установка (Hub release + Ingress + Let's Encrypt)
|
||||
|
||||
Из git checkout этого репозитория:
|
||||
|
||||
```bash
|
||||
helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
|
||||
-n proxmox-sim --create-namespace \
|
||||
-f ./helm/proxmox-api-simulator/values-ingress-example.yaml \
|
||||
--set certManager.email=you@example.com \
|
||||
--set 'ingress.hosts[0].host=pve-sim.example.com' \
|
||||
--set 'ingress.tls[0].hosts[0]=pve-sim.example.com' \
|
||||
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
|
||||
--set postgresql.auth.password="$(openssl rand -hex 16)"
|
||||
```
|
||||
|
||||
Что это делает:
|
||||
|
||||
1. Подтягивает `inecs/proxmox-api-simulator:0.1.0` (см. `image.tag` в example
|
||||
file).
|
||||
2. Устанавливает bundled PostgreSQL 17 (`postgres:17.5-bookworm`, как в Compose).
|
||||
3. Запускает миграции схемы в init container (идемпотентно).
|
||||
4. Засеивает lab profile `small` (`seed.enabled=true`).
|
||||
5. Создаёт ресурсы `ClusterIssuer`:
|
||||
- `letsencrypt-prod`
|
||||
- `letsencrypt-staging`
|
||||
6. Создаёт Ingress с
|
||||
`cert-manager.io/cluster-issuer: letsencrypt-prod` и TLS secret
|
||||
`proxmox-api-simulator-tls`.
|
||||
|
||||
DNS для `pve-sim.example.com` должен указывать на ваш Ingress controller. Затем:
|
||||
|
||||
```bash
|
||||
kubectl -n proxmox-sim get certificate,ingress,pods
|
||||
# wait until Certificate READY=True
|
||||
curl -sS https://pve-sim.example.com/health/ready
|
||||
open https://pve-sim.example.com/
|
||||
```
|
||||
|
||||
Логин по умолчанию после seed: `root@pam` / `secret`.
|
||||
|
||||
### Сначала staging (рекомендуется)
|
||||
|
||||
Проверьте HTTP-01 без production rate limits:
|
||||
|
||||
```bash
|
||||
helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
|
||||
-n proxmox-sim --create-namespace \
|
||||
-f ./helm/proxmox-api-simulator/values-ingress-example.yaml \
|
||||
--set certManager.email=you@example.com \
|
||||
--set certManager.useStaging=true \
|
||||
--set 'ingress.hosts[0].host=pve-sim.example.com' \
|
||||
--set 'ingress.tls[0].hosts[0]=pve-sim.example.com' \
|
||||
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
|
||||
--set postgresql.auth.password="$(openssl rand -hex 16)"
|
||||
```
|
||||
|
||||
Браузеры не доверяют staging CA — при тестировании используйте `curl -k`.
|
||||
Переключите `certManager.useStaging=false` и пересоздайте Certificate/TLS secret
|
||||
для production.
|
||||
|
||||
## Минимальная установка (ClusterIP + port-forward)
|
||||
|
||||
```bash
|
||||
helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
|
||||
-n proxmox-sim --create-namespace \
|
||||
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
|
||||
--set seed.enabled=true
|
||||
|
||||
kubectl -n proxmox-sim port-forward svc/pve-sim-proxmox-api-simulator 8006:8006
|
||||
```
|
||||
|
||||
Откройте http://127.0.0.1:8006/ (обычный HTTP — чарт не включает TLS-шлюз из
|
||||
Compose; для HTTPS используйте Ingress).
|
||||
|
||||
## Внешний PostgreSQL
|
||||
|
||||
```bash
|
||||
helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
|
||||
-n proxmox-sim --create-namespace \
|
||||
--set postgresql.enabled=false \
|
||||
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
|
||||
--set secret.databaseUrl='postgresql://user:pass@pg.example.com:5432/proxmox_simulator'
|
||||
```
|
||||
|
||||
Или используйте `secret.existingSecret` с ключами `DATABASE_URL` и
|
||||
`TICKET_SIGNING_KEY`.
|
||||
|
||||
## Как работает выпуск TLS
|
||||
|
||||
Когда `certManager.enabled=true` и `certManager.createClusterIssuer=true`, chart
|
||||
создаёт ACME `ClusterIssuer`, решающие HTTP-01 через ваш Ingress class. Шаблон
|
||||
Ingress добавляет:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
tls:
|
||||
- secretName: proxmox-api-simulator-tls
|
||||
hosts: [pve-sim.example.com]
|
||||
```
|
||||
|
||||
cert-manager затем создаёт `Certificate`, завершает HTTP-01 и сохраняет пару
|
||||
ключей Let's Encrypt в этом TLS secret. Chart **не** устанавливает cert-manager
|
||||
и Ingress controller — только issuers и Ingress wiring.
|
||||
|
||||
Если ClusterIssuers уже существуют cluster-wide, задайте:
|
||||
|
||||
```yaml
|
||||
certManager:
|
||||
enabled: true
|
||||
createClusterIssuer: false
|
||||
issuerName: your-existing-issuer
|
||||
```
|
||||
|
||||
## Локальная проверка chart
|
||||
|
||||
Из корня репозитория (нужен Helm 3.14+):
|
||||
|
||||
```bash
|
||||
make helm-lint
|
||||
make helm-template
|
||||
```
|
||||
|
||||
`helm lint` должен завершаться без failures (информационное замечание про
|
||||
отсутствие `icon` в Chart.yaml ожидаемо). `helm template` рендерит Deployment
|
||||
(по умолчанию с migrate initContainer), Service, Secret, PostgreSQL
|
||||
StatefulSet, опциональный отдельный migrate Job (`migrate.asJob`), seed Job,
|
||||
Ingress и ClusterIssuers.
|
||||
|
||||
## Эксплуатация
|
||||
|
||||
```bash
|
||||
# logs
|
||||
kubectl -n proxmox-sim logs -l app.kubernetes.io/name=proxmox-api-simulator -c simulator -f
|
||||
|
||||
# reseed
|
||||
kubectl -n proxmox-sim exec deploy/pve-sim-proxmox-api-simulator -- \
|
||||
python -m app.simulation.seed_cli
|
||||
# SEED_PROFILE via: kubectl set env ... or --set seed.profile=medium and upgrade
|
||||
|
||||
# uninstall
|
||||
helm -n proxmox-sim uninstall pve-sim
|
||||
```
|
||||
|
||||
## Справочник values
|
||||
|
||||
См. [`helm/proxmox-api-simulator/values.yaml`](../../helm/proxmox-api-simulator/values.yaml)
|
||||
и README chart. Связанная документация:
|
||||
|
||||
- [Начало работы](getting-started.md) — пути Compose
|
||||
- [Эксплуатация](operations.md) — публикация Docker Hub / release compose
|
||||
- [Безопасность](security.md) — учётные данные лаборатории и граница доверия
|
||||
@@ -0,0 +1,43 @@
|
||||
**Language / Язык:** [English](../observability.md) | [Русский](observability.md)
|
||||
|
||||
# Наблюдаемость
|
||||
|
||||
## Health
|
||||
|
||||
| Путь | Назначение |
|
||||
|---|---|
|
||||
| `GET /health/live` | Liveness процесса |
|
||||
| `GET /health/ready` | База доступна **и** миграции актуальны; HTTP 503 при невыполнении |
|
||||
|
||||
Пример:
|
||||
|
||||
```bash
|
||||
curl -s http://localhost:8006/health/live
|
||||
curl -s http://localhost:8006/health/ready
|
||||
```
|
||||
|
||||
## Корреляция запросов
|
||||
|
||||
Входящие запросы принимают или генерируют ID через `REQUEST_ID_HEADER`
|
||||
(по умолчанию `X-Request-ID`). Структурированные логи включают поля корреляции и
|
||||
редактируют известные шаблоны секретов.
|
||||
|
||||
## Метрики / трейсинг
|
||||
|
||||
В текущем приложении **нет** scrape-эндпоинта Prometheus `/metrics` и **нет**
|
||||
встроенного экспортёра OpenTelemetry. Архитектурные заметки, где они упоминаются,
|
||||
описывают целевой дизайн, а не поставляемую телеметрию.
|
||||
|
||||
Не путайте пути Proxmox API под `/cluster/metrics` с телеметрией процесса
|
||||
симулятора — эти обработчики симулируют состояние конфигурации metrics-server PVE
|
||||
внутри PostgreSQL.
|
||||
|
||||
## Evidence совместимости
|
||||
|
||||
Операционные отчёты совместимости:
|
||||
|
||||
- `/admin/compatibility`
|
||||
- `/admin/compatibility.md`
|
||||
- `/admin/compatibility.html`
|
||||
|
||||
Также доступны через панель совместимости Web UI.
|
||||
@@ -0,0 +1,157 @@
|
||||
**Language / Язык:** [English](../operations.md) | [Русский](operations.md)
|
||||
|
||||
# Эксплуатация
|
||||
|
||||
## Команды day-2
|
||||
|
||||
```bash
|
||||
make up # start stack
|
||||
make down # stop stack
|
||||
make restart
|
||||
make logs
|
||||
make dev # foreground reload-oriented workflow
|
||||
make db-migrate # idempotent migrations
|
||||
make seed PROFILE=small # atomic reseed
|
||||
make shell # interactive tools container
|
||||
```
|
||||
|
||||
## Миграции
|
||||
|
||||
Упорядоченные SQL-файлы применяются транзакционно и записывают SHA-256
|
||||
checksum. Повторный запуск `make db-migrate` безопасен. Изменение уже
|
||||
применённой миграции отклоняется. `/health/ready` остаётся недоступным, пока
|
||||
не применена последняя упакованная миграция. Воркеры задач повторяют захват
|
||||
после того, как миграции догонят актуальное состояние.
|
||||
|
||||
## Reseed
|
||||
|
||||
```bash
|
||||
make seed PROFILE=medium
|
||||
```
|
||||
|
||||
Reseed заменяет изменяемое состояние симуляции. Внешнее состояние автоматизации
|
||||
(Terraform state files, Pulumi stacks, Ansible inventories с закодированными
|
||||
VMID) может после этого рассинхронизироваться — обновите или пересоздайте эти
|
||||
боковые каналы.
|
||||
|
||||
## Восстановление воркеров
|
||||
|
||||
Воркеры используют аренды PostgreSQL. После сбоя или перезапуска просроченные
|
||||
аренды перехватываются, а незавершённая работа может безопасно продолжиться.
|
||||
Настраиваемые параметры: `TASK_WORKER_CONCURRENCY`, `TASK_LEASE_SECONDS`,
|
||||
`SIMULATION_TIME_SCALE`.
|
||||
|
||||
## Смена API major по умолчанию
|
||||
|
||||
1. Предпочтительно задайте `CONTRACT_SNAPSHOT` на нужный bundled/normalized
|
||||
snapshot для холодного старта (Compose / k8s / OpenShift).
|
||||
2. Используйте Web UI apply или `POST /ui/api/contract/apply?major=N` для
|
||||
временных переключений в пределах процесса.
|
||||
|
||||
## Резервное копирование состояния лаборатории
|
||||
|
||||
PostgreSQL — система записи. Используйте обычное резервное копирование и
|
||||
восстановление Postgres (pg_dump / снимки томов), если нужно сохранить
|
||||
засеянную лабораторию. Контейнеры приложения одноразовые, пока сохранён том БД.
|
||||
|
||||
## Публикация в Docker Hub
|
||||
|
||||
`make release` собирает **runtime**-образ (production target — не локальный
|
||||
bind-mounted образ `dev`) и публикует его в Docker Hub:
|
||||
|
||||
```bash
|
||||
docker login # once; account must own or can push to DOCKERHUB_USER
|
||||
make release
|
||||
```
|
||||
|
||||
Значения по умолчанию:
|
||||
|
||||
| Переменная | По умолчанию | Назначение |
|
||||
|---|---|---|
|
||||
| `DOCKERHUB_USER` | `inecs` | Namespace/org в Docker Hub |
|
||||
| `IMAGE_NAME` | `proxmox-api-simulator` | Имя репозитория |
|
||||
| `VERSION` | from `pyproject.toml` | Тег образа |
|
||||
| `PUSH_LATEST` | `1` | Также тегировать/пушить `:latest` |
|
||||
|
||||
Примеры:
|
||||
|
||||
```bash
|
||||
make release
|
||||
make release VERSION=0.2.0
|
||||
make release DOCKERHUB_USER=myorg PUSH_LATEST=0
|
||||
make release-build # build/tag locally without pushing
|
||||
```
|
||||
|
||||
Опубликованные теги:
|
||||
|
||||
- `inecs/proxmox-api-simulator:<version>`
|
||||
- `inecs/proxmox-api-simulator:latest` (если не `PUSH_LATEST=0`)
|
||||
|
||||
После публикации при необходимости вставьте
|
||||
[обзор Docker Hub](../docker-hub-overview.md) в описание репозитория Hub и
|
||||
держите GitHub About в одном стиле («stateful Proxmox VE API simulator», а не
|
||||
тонкий mock).
|
||||
|
||||
CI в GitHub Actions на каждый push/PR в `main` запускает `make ci` и проверку
|
||||
Compose/Helm (см. `.github/workflows/ci.yml`).
|
||||
|
||||
## Быстрый старт с опубликованным compose-файлом
|
||||
|
||||
[`docker-compose.release.yml`](../../docker-compose.release.yml) подтягивает
|
||||
runtime-образ из Hub и запускает PostgreSQL + migrate + simulator:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.release.yml up -d
|
||||
docker compose -f docker-compose.release.yml run --rm --entrypoint python \
|
||||
simulator -m app.simulation.seed_cli
|
||||
|
||||
curl http://localhost:8006/health/ready
|
||||
open http://localhost:8006/
|
||||
```
|
||||
|
||||
Вспомогательные команды из git checkout:
|
||||
|
||||
```bash
|
||||
make release-up
|
||||
make release-seed PROFILE=small
|
||||
make release-down
|
||||
```
|
||||
|
||||
Полезные переопределения:
|
||||
|
||||
| Переменная | По умолчанию | Назначение |
|
||||
|---|---|---|
|
||||
| `DOCKER_IMAGE` | `inecs/proxmox-api-simulator` | Репозиторий образа |
|
||||
| `IMAGE_TAG` | `latest` | Тег для pull |
|
||||
| `SIMULATOR_PORT` | `8006` | HTTPS-порт на хосте (TLS-шлюз) |
|
||||
| `TICKET_SIGNING_KEY` | lab default | Меняйте вне игрушечных лаб |
|
||||
| `POSTGRES_PASSWORD` | `proxmox` | Пароль БД |
|
||||
|
||||
Development и release Compose публикуют **HTTPS `:8006`** на хосте через nginx
|
||||
TLS-шлюз (тот же порт, что у реального PVE). Процесс симулятора остаётся HTTP
|
||||
на `:8006` внутри Docker-сети. См.
|
||||
[Порты и TLS](configuration.md#порты-и-tls).
|
||||
|
||||
Для Kubernetes с публичным TLS (cert-manager / Let's Encrypt) используйте Helm
|
||||
chart — см. [Kubernetes / Helm](kubernetes.md).
|
||||
|
||||
## Обновления
|
||||
|
||||
1. Подтяните / пересоберите образы (`make install` / `make docker-build` по
|
||||
необходимости).
|
||||
2. Выполните миграции.
|
||||
3. Подтвердите `/health/ready`.
|
||||
4. Повторно проверьте `/admin/compatibility` и `/api2/json/version`.
|
||||
5. Повторно запустите `make test-compatibility`, если в CI проверяете внешних
|
||||
клиентов (засеивает профиль **medium** — `pve1`/`pve2`/`pve3` — для migration
|
||||
smoke).
|
||||
|
||||
## Сброс лаборатории
|
||||
|
||||
```bash
|
||||
make seed PROFILE=small
|
||||
# or via UI: unload demo → minimal, then seed again
|
||||
```
|
||||
|
||||
Для жёсткого сброса БД используйте `make db-reset` (разрушительно — см. help
|
||||
Makefile).
|
||||
@@ -0,0 +1,48 @@
|
||||
**Language / Язык:** [English](../security.md) | [Русский](security.md)
|
||||
|
||||
# Безопасность
|
||||
|
||||
Политика репозитория и репортинг: [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Модель угроз лаборатории
|
||||
|
||||
Этот проект — **локальный / CI лабораторный симулятор**. Он не закалён как
|
||||
multi-tenant публичный сервис Proxmox. Учётные данные по умолчанию, demo-контролы UI
|
||||
и эндпоинты совместимости удобны для разработки и намеренно открыты в стандартном
|
||||
Compose-стеке.
|
||||
|
||||
Не выставляйте порт `8006` в недоверенные сети без дополнительных мер,
|
||||
которые вы обеспечите сами. Хост `:8006` — lab HTTPS API-шлюз (у реального PVE
|
||||
на этом порту HTTPS). Хост **`:8007` этим стеком не используется** (на железе
|
||||
обычно PBS). См. [Порты и TLS](configuration.md#порты-и-tls).
|
||||
|
||||
## Учётные данные и секреты
|
||||
|
||||
- Пароли и секреты API-токенов хранятся как scrypt-хеши.
|
||||
- Значения тикетов подписываются HMAC и краткоживущие.
|
||||
- CSRF привязывает мутации к сессиям по тикету.
|
||||
- Логи редактируют распознанные представления тикетов, паролей и токенов.
|
||||
- Ответы create/regenerate токена показывают секрет один раз; GET его никогда не
|
||||
выводит.
|
||||
|
||||
Меняйте `TICKET_SIGNING_KEY` для любой общей лаборатории. Замените seeded-пароли и
|
||||
токены перед демонстрацией другим людям.
|
||||
|
||||
## TLS-материалы
|
||||
|
||||
`docker/tls/` содержит встроенный self-signed сертификат для локального шлюза. Он
|
||||
нужен, чтобы неизменённые TLS-клиенты (например, proxmoxer) могли подключаться.
|
||||
**Никогда** не переиспользуйте эти файлы в production.
|
||||
|
||||
## Администрирование симулятора
|
||||
|
||||
Сейчас **нет** отдельно аутентифицированной control plane `/_simulator`.
|
||||
Helper-маршруты Web UI под `/ui/api/*` и `/admin/compatibility*` доступны, когда
|
||||
процесс достижим. Считайте границей доверия сетевую экспозицию.
|
||||
|
||||
## Симулированные внешние системы
|
||||
|
||||
LDAP sync stamps, pending-состояние OpenID, ACME и эндпоинты Ceph сохраняют только
|
||||
локальное состояние симулятора. Они не открывают реальные подключения к внешним IdP
|
||||
или кластерам. Не полагайтесь на симулятор для тестирования защиты от утечки
|
||||
учётных данных к реальным провайдерам.
|
||||
@@ -0,0 +1,67 @@
|
||||
**Language / Язык:** [English](../seed-profiles.md) | [Русский](seed-profiles.md)
|
||||
|
||||
# Профили seed
|
||||
|
||||
Seed **атомарно** заменяет изменяемое состояние симуляции и использует
|
||||
детерминированные UUIDv5-идентификаторы для воспроизводимости лабораторий.
|
||||
|
||||
```bash
|
||||
make seed PROFILE=small
|
||||
```
|
||||
|
||||
## Профили
|
||||
|
||||
| Профиль | Содержимое (кратко) |
|
||||
|---|---|
|
||||
| `minimal` | Один узел `pve01`, storage `local` + `local-lvm`. Используется после demo unload в Web UI. |
|
||||
| `small` | Один узел, QEMU `100`/`101`, LXC `200`, storage, завершённые задачи, полный набор identity. |
|
||||
| `medium` | Узлы `pve1`/`pve2`/`pve3`, 50 QEMU, 20 LXC, per-node `local-pveN` + storage `shared`, development pool, больше задач. |
|
||||
| `large` | Настраиваемые узлы/ресурсы (`SEED_LARGE_NODES`, `SEED_LARGE_RESOURCES`, по умолчанию 10 000 гостей). |
|
||||
| `ha-demo` | `medium` плюс HA resource wiring для VM 100. |
|
||||
| `broken-storage` | `small` с offline `local-lvm` / симулированной I/O ошибкой. |
|
||||
| `demo-cluster` | Крупный enterprise-набор для UI (много узлов/гостей/Ceph/HA/history). Предпочтительно загружать через demo-контролы Web UI. |
|
||||
|
||||
Каждый профиль seed'ит только durable-состояние — обработчики читают/пишут PostgreSQL и
|
||||
**не** подмешивают catalog/template defaults на GET:
|
||||
|
||||
- `clusters.metadata`: firewall (scopes + macros), SDN, notifications (+ matcher
|
||||
catalogs), ACME (accounts/plugins/directories/schema), mappings, replication
|
||||
(+ logs), metrics (servers + export), jobs, HA (`ha` / `ha_groups` / `ha_rules`
|
||||
+ status), Ceph (+ pools/cmd_safety), QEMU CPU flags/models, cluster options/config, quorate
|
||||
- `nodes.metadata.ops`: network, disks, apt, services, hardware, scan, subscription,
|
||||
dns/time/config/status/ip, certificates, capabilities, hosts, journal/syslog/netstat,
|
||||
report/rrd/rrddata, oci_tags, cluster_status, node Ceph, aplinfo, vzdump defaults
|
||||
- guest `resources.state` (via `enrich_guest_state`): agent results/files, rrd/rrddata,
|
||||
migrate_preconditions, LXC interfaces, cloudinit dump
|
||||
- storage `storages.config` (via `enrich_storage_state`): rrd/rrddata, file_restore,
|
||||
import_metadata, identity
|
||||
|
||||
## Примеры
|
||||
|
||||
```bash
|
||||
make seed PROFILE=small
|
||||
make seed PROFILE=medium
|
||||
make seed PROFILE=ha-demo
|
||||
make seed PROFILE=broken-storage
|
||||
make seed PROFILE=large
|
||||
make seed PROFILE=minimal
|
||||
# demo-cluster большой; для интерактива предпочтительна загрузка demo в Web UI
|
||||
make seed PROFILE=demo-cluster
|
||||
```
|
||||
|
||||
## Demo-кластер через UI
|
||||
|
||||
Интерактивная консоль может загружать и выгружать demo-набор данных:
|
||||
|
||||
- `POST /ui/api/demo/load`
|
||||
- `POST /ui/api/demo/unload` — стирает состояние, созданное через API, затем загружает `minimal`
|
||||
- `GET /ui/api/demo/state`
|
||||
|
||||
Эти helper-эндпоинты UI ориентированы на разработку и сегодня не аутентифицируются
|
||||
отдельно. Считайте их только лабораторными контролами.
|
||||
|
||||
## Reseed vs состояние клиента
|
||||
|
||||
Terraform, Pulumi и Ansible могут по-прежнему хранить resource state после reseed.
|
||||
Обновите или destroy/recreate внешнее состояние после замены содержимого симуляции в
|
||||
PostgreSQL. См. [Эксплуатация](operations.md) и client cookbook'и.
|
||||
@@ -0,0 +1,66 @@
|
||||
**Language / Язык:** [English](../troubleshooting.md) | [Русский](troubleshooting.md)
|
||||
|
||||
# Устранение неполадок
|
||||
|
||||
## Ready остаётся недоступным
|
||||
|
||||
1. Проверьте Postgres: `make logs` / health в Compose.
|
||||
2. Выполните `make db-migrate`.
|
||||
3. Снова вызовите `/health/ready`.
|
||||
|
||||
Workers могут повторять попытки, пока миграции не догонят после позднего migrate.
|
||||
|
||||
## Неожиданный HTTP 501
|
||||
|
||||
У объявленных методов на мажорах **6–9** должны быть обработчики. Если видите 501:
|
||||
|
||||
- Подтвердите активный runtime (`/api2/json/version` и метка runtime в Web UI).
|
||||
- Убедитесь, что вызываете path/verb точно как объявлено для этого мажора.
|
||||
- Проверьте, что `CONTRACT_FALLBACK` в режиме fixture не маскирует другую проблему.
|
||||
- Сообщите о регрессии — ожидается полное покрытие реестра.
|
||||
|
||||
## 401 / 403
|
||||
|
||||
- Тикет истёк или cookie не отправлена.
|
||||
- Мутация без `CSRFPreventionToken` в сессии по тикету.
|
||||
- API-токен с неверным форматом (`PVEAPIToken=user@realm!id=secret`).
|
||||
- Отказ ACL (сравните `auditor@pve` и `root@pam`).
|
||||
|
||||
## Задача никогда не завершается
|
||||
|
||||
- Изучите `/nodes/{node}/tasks/{upid}/status` и `/log`.
|
||||
- Проверьте логи workers (`make logs`).
|
||||
- Убедитесь, что `TASK_WORKER_CONCURRENCY` > 0 и аренды в базе можно забрать.
|
||||
- Очень высокий `SIMULATION_TIME_SCALE` даёт необычные замедления (больше = быстрее
|
||||
симуляция); чаще виноваты неверно заданные worker leases.
|
||||
|
||||
## proxmoxer / сбои TLS
|
||||
|
||||
- Реальный PVE использует **HTTPS `:8006`**. К этой лаборатории TLS-клиенты
|
||||
ходят на порт хоста **8006** (development-шлюз) с отключённой проверкой
|
||||
локального self-signed cert.
|
||||
- Хост **`:8007` этим стеком не используется** (на железе обычно PBS).
|
||||
- `verify_ssl=False` **только** для локального self-signed cert.
|
||||
- Внутри Compose цель — `tls-gateway:8443`.
|
||||
- Seeded-имя узла для `small` — `pve01`, а не `pve1`.
|
||||
- Профили `medium` / `ha-demo` используют **`pve1` / `pve2` / `pve3`**.
|
||||
- Карта портов: [Порты и TLS](configuration.md#порты-и-tls).
|
||||
|
||||
## Drift Terraform / Pulumi после reseed
|
||||
|
||||
Reseed заменяет гостей в PostgreSQL; state-файлы инструментов — нет. Refresh, import
|
||||
или пересборка стеков после `make seed`.
|
||||
|
||||
## Hot-swap «ничего не сделал»
|
||||
|
||||
- Просмотр каталога ≠ apply. Используйте **Apply as runtime** или
|
||||
`POST /ui/api/contract/apply?major=N`.
|
||||
- Подтвердите через `/api2/json/version`.
|
||||
- Помните: apply локален для процесса; перезапуск Compose восстанавливает
|
||||
`CONTRACT_SNAPSHOT`.
|
||||
|
||||
## Demo unload удивил
|
||||
|
||||
`POST /ui/api/demo/unload` очищает состояние, созданное через API, и загружает
|
||||
`minimal`. Повторите `make seed PROFILE=small` (или снова загрузите demo), чтобы
|
||||
восстановить более богатые фикстуры.
|
||||
@@ -0,0 +1,64 @@
|
||||
**Language / Язык:** [English](../web-ui.md) | [Русский](web-ui.md)
|
||||
|
||||
# Web UI
|
||||
|
||||
Откройте [http://localhost:8006/](http://localhost:8006/) после `make up`.
|
||||
|
||||
UI — лабораторная консоль симулятора, а не полноценный интерфейс управления Proxmox VE.
|
||||
Поддерживаются светлая и тёмная темы, мажорные версии PVE **6–9**, редактирование
|
||||
запросов/ответов, история и runtime apply контракта.
|
||||
|
||||
## Скриншоты
|
||||
|
||||
Светлая тема — `GET /cluster/resources` на PVE 9.2.3:
|
||||
|
||||

|
||||
|
||||
Тёмная тема — та же консоль с переключателем темы:
|
||||
|
||||

|
||||
|
||||
## Возможности
|
||||
|
||||
- Дерево эндпоинтов и выбор метода по выбранному мажору каталога
|
||||
- Параметры и примеры payload, производные от контракта
|
||||
- Редактор запросов, просмотр ответов и история
|
||||
- Вход по паролю с обработкой cookie + CSRF
|
||||
- Сводка окружения (runtime-версия, узлы, гости, storage)
|
||||
- Превью curl / запросов
|
||||
- Каталог API PVE **6–9** с покрытием реализации
|
||||
- **Apply as runtime** — горячая замена активного контракта
|
||||
- Представления совместимости и готовности
|
||||
- Загрузка / выгрузка / обновление demo-кластера
|
||||
- Монитор задач UPID (кнопка в шапке → status / log / «From last response»;
|
||||
для опросов задач нужна аутентификация)
|
||||
- Ссылка на OpenAPI по `/docs`
|
||||
|
||||
## Backend-хелперы
|
||||
|
||||
| Method | Path | Назначение |
|
||||
|---|---|---|
|
||||
| GET | `/ui/api/versions` | Мажорные версии каталога vs runtime |
|
||||
| GET | `/ui/api/catalog?major=N` | Каталог для мажора 6–9 |
|
||||
| GET | `/ui/api/method?...` | Метаданные одного метода |
|
||||
| GET | `/ui/api/compatibility?major=N` | Payload покрытия |
|
||||
| POST | `/ui/api/contract/apply?major=N` | Горячая замена runtime-контракта |
|
||||
| GET | `/ui/api/demo/state` | Состояние demo-набора данных |
|
||||
| POST | `/ui/api/demo/load` | Загрузить `demo-cluster` |
|
||||
| POST | `/ui/api/demo/unload` | Выгрузить → `minimal` |
|
||||
|
||||
## Workflow версий
|
||||
|
||||
1. Выберите мажор **6 / 7 / 8 / 9** в каталоге.
|
||||
2. Изучите методы и покрытие.
|
||||
3. **Apply as runtime**, когда нужно, чтобы живые маршруты `/api2/*` соответствовали
|
||||
этому мажору.
|
||||
4. Подтвердите через `/api2/json/version` и `/admin/compatibility`.
|
||||
|
||||
Горячая замена только в памяти; перезапуск восстанавливает `CONTRACT_SNAPSHOT`.
|
||||
Подробнее: [Версии API](api-versions.md).
|
||||
|
||||
## Замечание по безопасности
|
||||
|
||||
UI и demo-эндпоинты предназначены для локальной разработки. В текущей сборке они не
|
||||
защищены отдельным admin-токеном. Не выставляйте порт симулятора в недоверенные сети.
|
||||
Reference in New Issue
Block a user