Files
polygon/site/routes/root.py
T
naeel 58d54f2a95 v0.5.0: 3 стенда — изоляция состояния, WSGI middleware, OpenAPI server selector, POLYGON_STANDS env
- loader.py: STANDS dict, get_services/get_ops_index per stand, POLYGON_STANDS env
- mock_state.py: get_state(stand_id) — ленивая инициализация
- app.py: StandMiddleware — перезапись PATH_INFO до Flask-роутинга
- Все роуты: LocalProxy(state), LocalProxy(SERVICES/OPS_INDEX) через g.stand_id
- openapi.py: _build_servers() — по одному серверу на стенд
- services/stand{1,2,3}/ — 37 YAML на стенд из STANDS/dev и STANDS/test
- tests/test_api.py: +4 multi-stand теста (изоляция, fail-next, OpenAPI servers)
- Обратная совместимость: /api/v1/svc/... → стенд по умолчанию
2026-08-01 20:10:19 +04:00

89 lines
3.2 KiB
Python

"""
routes/root.py — корневые эндпоинты (/health, /, /swagger).
Blueprint "root" регистрируется в app.py БЕЗ url_prefix.
Отвечает за healthcheck (для Nubes), HTML-страницу с информацией о сервисе,
и страницу Swagger UI.
"""
import os
from flask import Blueprint, g, render_template
from werkzeug.local import LocalProxy
import mock_state
import config.loader as _cfg
state = LocalProxy(lambda: mock_state.get_state(g.stand_id))
SERVICES = LocalProxy(lambda: _cfg.get_services(g.stand_id))
VERSION = _cfg.VERSION
# Токен для авторизации в Swagger UI (предзаполняется)
_MOCK_AUTH_TOKEN = os.getenv("MOCK_AUTH_TOKEN", "test-token-123")
# URL для OpenAPI-спеке (сервер)
_POLYGON_ENDPOINT = os.getenv("POLYGON_ENDPOINT", "https://polygon.pythonk8s.dev.nubes.ru")
# Blueprint без префикса — роуты /health и / будут на корне домена
bp = Blueprint("root", __name__)
@bp.route("/health")
def health():
"""Healthcheck для Nubes.
Платформа периодически дёргает этот эндпоинт. Если вернёт не 200 —
контейнер будет перезапущен. Возвращаем просто "OK", без JSON.
"""
return "OK"
@bp.route("/")
def index():
"""Корневая HTML-страница с информацией о сервисе.
Показывает: версию, количество загруженных сервисов, количество инстансов,
текущую задержку операций, список сервисов с операциями.
Использует Jinja2-шаблон templates/index.html и внешний CSS из static/style.css.
"""
svc_count = len(_cfg.SERVICES)
inst_count = len(state.instances)
# Список сервисов для таблицы: name, id, кол-во операций
svc_list = []
for sid, svc in sorted(_cfg.SERVICES.items(), key=lambda x: x[1].get("name", x[0])):
svc_list.append({
"id": sid,
"name": svc.get("name", sid),
"display_name": svc.get("service_display_name", svc.get("name", "")),
"op_count": len(svc.get("operations", [])),
"has_cfs": bool(svc.get("cfsParams")),
"has_state": bool(svc.get("stateParams")),
"has_out": bool(svc.get("stateOut")),
})
return render_template(
"index.html",
version=_cfg.VERSION,
svc_count=svc_count,
inst_count=inst_count,
delay=_cfg.DELAY,
svc_list=svc_list,
endpoint=_POLYGON_ENDPOINT,
)
@bp.route("/swagger")
def swagger():
"""Swagger UI — интерактивная документация API.
Загружает Swagger UI с CDN, указывает на /api/v1/svc/openapi.json.
Токен авторизации предзаполняется автоматически (MOCK_AUTH_TOKEN).
"""
return render_template(
"swagger.html",
version=_cfg.VERSION,
openapi_url="/api/v1/svc/openapi.json",
auth_token=_MOCK_AUTH_TOKEN,
)