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.
Запуск
# Локально
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 (" → ").
Всё это делает from_stands.py один раз, а не на лету при каждом запросе.
Когда запускать обновление?
Когда терраформ-репа обновилась (добавили/удалили сервис, изменили параметры) — нужно перегенерить YAML и передеплоить полигон:
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.
Как проверить что всё загрузилось?
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 — разбор
201при создании, NXDOMAIN и риска пути к YAML - DOCS/polygon-plan.md — план реализации
- polygon-docs/sonnet-code-review-prompt.md — промпт code review
- polygon-docs/tf-provider-refs.md — ссылки на генератор YAML