Files
polygon/README.md
T

175 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# polygon v0.5.18
Эмулятор REST API облачной платформы Nubes для интеграционных тестов app-autotest.
Отдельный managed-сервис на Nubes pythonk8s: `polygon.pythonk8s.dev.nubes.ru`.
Притворяется реальным Nubes API (префикс `/api/v1/svc`).
## Архитектура
```
polygon/
├── requirements.txt # Flask>=3.0, gunicorn>=21.2, PyYAML>=6.0
├── tests/
│ ├── test_converter.py # тесты from_stands.py
│ ├── test_loader.py # тесты CWD-independent loader
│ ├── test_state_machine.py # тесты state_machine.py
│ └── test_route_regressions.py # локальные регрессионные тесты API
└── site/
├── app.py # Flask: только blueprint'ы + app.run() (57 строк)
├── routes/ # blueprint-файлы по доменам
│ ├── root.py # /health, /, /swagger
│ ├── services_routes.py# /api/v1/svc/services
│ ├── instances_routes.py# /api/v1/svc/instances
│ ├── operations_routes.py# /api/v1/svc/instanceOperations/*
│ ├── run.py # /api/v1/svc/instanceOperations/<uid>/run
│ ├── mock_routes.py # /api/v1/svc/_mock/*
│ └── openapi.py # /api/v1/svc/openapi.json
├── mock_state.py # MockState: instances, operations, op_params
├── state_machine.py # apply_effect() — мутация состояния
├── config/
│ └── loader.py # загрузка YAML + SERVICES/OPS_INDEX/DELAY/VERSION
├── utils/
│ ├── now.py # now() — UTC ISO с 'Z'
│ └── pluralize.py # pluralize() — плюрализация
├── from_stands.py # конвертер STANDS YAML → polygon config
├── static/
│ └── style.css # тёмная тема
├── templates/
│ ├── index.html # главная и инструкции API
│ └── swagger.html # Swagger UI и инструкция Authorize
└── services/ # fallback YAML, также генерируются from_stands.py
```
⛔ **Ровно 1 gunicorn-воркер.** Состояние в памяти, не shared.
## Запуск
```bash
# Локально
cd site && python app.py # порт 5000
# Тесты
pytest tests/ -v # локальные тесты Polygon
```
## Откуда берутся сервисы (YAML)
Polygon эмулирует API Nubes. Чтобы знать какие сервисы, операции и параметры
существуют — он читает YAML-конфиги. Но Nubes генерит YAML в **другом формате**,
неудобном для полигона. Поэтому есть двухэтапный процесс:
```
~/TF/tf_provider/generated/{dev,test,prod}/resources_yaml/*.yaml ← источник истины
│
│ from_stands.py — конвертация формата, дедупликация, нормализация
│ Запускается ВРУЧНУЮ при изменении терраформ-репы
│
▼
polygon/site/services/{dev,test,prod}/*.yaml ← скоммичены в git-репу полигона
│
│ config/loader.py — загрузка ВСЕХ YAML в память при старте
│
▼
Память Flask-процесса (конфиги загружаются один раз при старте)
```
Если `POLYGON_STANDS` не задан, loader использует один стенд `default` из `site/services/`. Значения относительных путей в `POLYGON_STANDS` разрешаются относительно `site/`.
### Почему нельзя читать терраформ-формат напрямую?
Терраформ-формат хранит параметры **внутри** операций, с дубликатами.
Например параметр `resourceRealm` повторяется в create, modify и delete —
три копии одного и того же.
Полигону нужен плоский список **уникальных** параметров (`cfsParams`),
плюс индекс «какой параметр к какой операции» (`cfsParamsByOp`).
Плюс `stateParams` (дефолты для create), `stateOut` (subresource-ключи),
раскодированные HTML-entities (`&quot;` → `"`).
Всё это делает `from_stands.py` **один раз**, а не на лету при каждом запросе.
### Когда запускать обновление?
Когда терраформ-репа обновилась (добавили/удалили сервис, изменили параметры) —
нужно перегенерить YAML и передеплоить полигон:
```bash
cd site
python from_stands.py ~/TF/tf_provider/generated/dev/resources_yaml services/dev
python from_stands.py ~/TF/tf_provider/generated/test/resources_yaml services/test
python from_stands.py ~/TF/tf_provider/generated/prod/resources_yaml services/prod
cd ..
git add services/
git commit -m "regenerate YAML from terraform (добавлен сервис X)"
git push
# → редеплоить polygon через Nubes UI
```
После успешной конвертации генератор удаляет из целевого каталога YAML, которых больше нет в источнике. Если конвертация завершилась ошибками, устаревшие файлы не удаляются.
Если `SERVICES_DIR` не передан, генератор пишет в `site/services/` независимо от CWD. Явно переданные относительные `STANDS_DIR` и `SERVICES_DIR` остаются относительно CWD.
### Как проверить что всё загрузилось?
```bash
curl https://polygon.pythonk8s.dev.nubes.ru/dev/api/v1/svc/services | python3 -m json.tool | head -20
```
## API
| Метод | Путь | Назначение |
|-------|------|------------|
| GET | `/health` | Healthcheck |
| GET | `/` | HTML с версией |
| GET | `/swagger` | Swagger UI |
| GET | `/api/v1/svc/openapi.json` | OpenAPI JSON |
| GET | `/api/v1/svc/services` | Список сервисов |
| GET | `/api/v1/svc/services/<id>` | Операции сервиса |
| GET | `/api/v1/svc/instances` | Пагинация |
| GET | `/api/v1/svc/instances/<uid>` | Инстанс + state |
| POST | `/api/v1/svc/instances` | Создать → 201 + Location |
| GET | `/api/v1/svc/instanceOperations/default/<id>` | Шаблон операции и cfsParams |
| POST | `/api/v1/svc/instanceOperations` | Создать операцию → 201 + Location |
| GET | `/api/v1/svc/instanceOperations/<uid>` | Статус + cfsParams |
| POST | `/api/v1/svc/instanceOperationCfsParams` | param → value |
| GET | `/api/v1/svc/instanceOperations/<uid>/validate-cfs` | 200, пустое тело |
| POST | `/api/v1/svc/instanceOperations/<uid>/run` | Выполнить |
| POST | `/api/v1/svc/_mock/reset` | Сброс |
| GET | `/api/v1/svc/_mock/state` | Отладка: состояние |
| GET | `/api/v1/svc/_mock/services` | Отладка: сервисы |
| POST | `/api/v1/svc/_mock/delay/<s>` | MOCK_OP_DELAY |
| POST | `/api/v1/svc/_mock/fail-next` | Следующий run завершится ошибкой |
Основные API-маршруты не требуют авторизации. Если задан `MOCK_AUTH_TOKEN`, запросы к `/_mock/*` должны передавать заголовок `X-Mock-Auth`.
### Где взять и куда вводить токен
`MOCK_AUTH_TOKEN` задаёт администратор в переменных окружения запущенного сервиса Polygon. Приложение не генерирует и не показывает это значение. Если у вас нет доступа к настройкам сервиса, запросите токен у его администратора.
В Swagger нажмите **Authorize**, в поле `X-Mock-Auth` → **Value** вставьте выданный токен и нажмите **Authorize** в диалоге. После этого Swagger автоматически добавит заголовок к запросам `/_mock/*`. В curl передавайте его явно: `-H "X-Mock-Auth: <token>"`. Если `MOCK_AUTH_TOKEN` на сервере не задан, токен вводить не нужно.
## Переменные окружения
| Переменная | По умолчанию | Описание |
|------------|-------------|----------|
| `POLYGON_STANDS` | `default:services` | Список стендов `name:path,name:path`; относительные пути считаются от `site/` |
| `MOCK_OP_DELAY` | `0.1` | Задержка операции в секундах |
| `MOCK_AUTH_TOKEN` | пусто | Опциональный токен для `/_mock/*`; при пустом значении локальные mock endpoints открыты |
| `POLYGON_ENDPOINT` | `https://polygon.pythonk8s.dev.nubes.ru` | Базовый URL для серверов в OpenAPI |
| `WEB_CONCURRENCY` | `1` | Использовать один gunicorn-воркер, поскольку состояние хранится в памяти |
## Деплой
- Репозиторий: `https://gitea.services.ngcloud.ru/forcloud/polygon.git`
- URL: `https://polygon.pythonk8s.dev.nubes.ru/`
- Nubes pythonk8s managed service
## Связанные документы
- [DEPLOYMENT_DIAGNOSIS.md](DEPLOYMENT_DIAGNOSIS.md) — разбор `201` при создании, NXDOMAIN и риска пути к YAML
- [DOCS/polygon-plan.md](../DOCS/polygon-plan.md) — план реализации
- [polygon-docs/sonnet-code-review-prompt.md](../polygon-docs/sonnet-code-review-prompt.md) — промпт code review
- [polygon-docs/tf-provider-refs.md](../polygon-docs/tf-provider-refs.md) — ссылки на генератор YAML