polygon v0.2.2

Эмулятор 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     # 10 юнит-тестов from_stands.py
│   └── test_state_machine.py # 9 юнит-тестов state_machine.py
└── site/
    ├── app.py                # Flask: только blueprint'ы + app.run() (57 строк)
    ├── routes/               # 6 blueprint-файлов по доменам
    │   ├── root.py           #   /health, /
    │   ├── 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/*
    ├── 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        # Jinja2-шаблон
    └── services/             # YAML-конфиги (сгенерированы from_stands.py)

Ровно 1 gunicorn-воркер. Состояние в памяти, не shared.

Запуск

# Локально
cd site && python app.py                          # порт 5000

# Тесты
pytest tests/ -v                                  # 19 тестов

Откуда берутся сервисы (YAML)

Polygon эмулирует API Nubes. Чтобы знать какие сервисы, операции и параметры существуют — он читает YAML-конфиги. Но Nubes генерит YAML в другом формате, неудобном для полигона. Поэтому есть двухэтапный процесс:

~/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-процесса  (~0.7 MB на 3 стенда)

Почему нельзя читать терраформ-формат напрямую?

Терраформ-формат хранит параметры внутри операций, с дубликатами. Например параметр resourceRealm повторяется в create, modify и delete — три копии одного и того же.

Полигону нужен плоский список уникальных параметров (cfsParams), плюс индекс «какой параметр к какой операции» (cfsParamsByOp). Плюс stateParams (дефолты для create), stateOut (subresource-ключи), раскодированные HTML-entities (&quot;").

Всё это делает from_stands.py один раз, а не на лету при каждом запросе.

Когда запускать обновление?

Когда терраформ-репа обновилась (добавили/удалили сервис, изменили параметры) — нужно перегенерить YAML и передеплоить полигон:

cd site
python from_stands.py ~/tf_provider/generated/dev/resources_yaml  services/dev
python from_stands.py ~/tf_provider/generated/test/resources_yaml services/test
python from_stands.py ~/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

Как проверить что всё загрузилось?

curl https://polygon.pythonk8s.dev.nubes.ru/dev/api/v1/svc/services | python3 -m json.tool | head -20

API (17 эндпоинтов)

Метод Путь Назначение
GET /health Healthcheck
GET / HTML с версией
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

Переменные окружения

Переменная По умолчанию Описание
MOCK_OP_DELAY 0.1 Задержка операции в секундах
WEB_CONCURRENCY 1 Не менять — ровно 1 воркер

Деплой

  • Репозиторий: https://gitea.services.ngcloud.ru/forcloud/polygon.git
  • URL: https://polygon.pythonk8s.dev.nubes.ru/
  • Nubes pythonk8s managed service

Связанные документы

S
Description
No description provided
Readme
519 KiB
Languages
Python 87.7%
HTML 8.4%
CSS 3.9%