feat: support configured production API endpoint

This commit is contained in:
2026-10-25 16:51:27 +03:00
parent 4203e5674c
commit 5b19094a4d
5 changed files with 89 additions and 16 deletions
+17 -8
View File
@@ -41,9 +41,17 @@ def _cached_detect(token):
if cache is None:
g._detected_endpoint = cache = {}
if token not in cache:
endpoint = current_app.config["NUBES_API_ENDPOINT"]
if endpoint in STANDS:
endpoint = detect_endpoint(token) or endpoint
endpoint = current_app.config["NUBES_API_ENDPOINT"].rstrip("/")
endpoints = [url.rstrip("/") for url in STANDS]
for configured_endpoint in (
current_app.config.get("NUBES_API_PROD_ENDPOINT", ""),
endpoint,
):
configured_endpoint = configured_endpoint.rstrip("/")
if configured_endpoint and configured_endpoint not in endpoints:
endpoints.append(configured_endpoint)
if endpoint in endpoints:
endpoint = detect_endpoint(token, endpoints=endpoints) or endpoint
cache[token] = endpoint
return cache[token]
@@ -137,11 +145,12 @@ def get_stand():
return f"polygon_{get_polygon_stand()}"
token = get_token()
endpoint = current_app.config["NUBES_API_ENDPOINT"]
if endpoint not in STANDS:
s = stand_name(endpoint)
return s if s != "?" else "mock"
return stand_name(_cached_detect(token))
endpoint = _cached_detect(token).rstrip("/")
prod_endpoint = current_app.config.get("NUBES_API_PROD_ENDPOINT", "").rstrip("/")
if prod_endpoint and endpoint == prod_endpoint:
return "prod"
s = stand_name(endpoint)
return s if s != "?" else "mock"
def get_token_info():
+7 -7
View File
@@ -10,12 +10,12 @@ HttpClient:
- raw_delete: DELETE без авторизации (для CMDB)
Функции автоопределения стенда:
- detect_endpoint(token) — пробует dev→test стенды по токену
- stand_name(endpoint) — "dev" / "test" по URL
- detect_endpoint(token) — пробует настроенные API стенды по токену
- stand_name(endpoint) — "dev" / "test" по URL
- create_client(token) — HttpClient + endpoint одним вызовом
Зачем автоопределение: пользователь вводит токен, мы не знаем dev это или test.
Пробуем оба стенда — какой ответит с results != None, тот и рабочий.
Зачем автоопределение: пользователь вводит токен, мы не знаем его стенд.
Пробуем настроенные URL — какой ответит с results != None, тот и рабочий.
"""
import requests
@@ -28,8 +28,8 @@ STANDS = [
]
def detect_endpoint(token):
"""Пробуем токен против dev и test стендов, возвращаем рабочий URL.
def detect_endpoint(token, endpoints=None):
"""Пробуем токен против заданных API стендов, возвращаем рабочий URL.
Алгоритм:
1. Для каждого стенда создаём HttpClient + делаем GET /instances?pageSize=1.
@@ -40,7 +40,7 @@ def detect_endpoint(token):
Почему results != None а не просто HTTP 200:
API может вернуть 200 с пустым списком (нет инстансов) — это норм.
results=None — признак что ответ не соответствует ожидаемой структуре."""
for ep in STANDS:
for ep in endpoints or STANDS:
try:
c = HttpClient(ep, token)
data = c.get("/instances", params={"pageSize": 1, "page": 1})
+2 -1
View File
@@ -32,7 +32,7 @@ from routes.api_scenario_defs import bp_defs as api_scenario_defs_bp
# Версия — показывается в топбаре UI. Меняется при КАЖДОМ изменении кода.
# Нужна для фильтрации истории (пользователь видит только записи своей версии).
VERSION = "1.2.48"
VERSION = "1.2.49"
# Flask-приложение с Jinja2-шаблонами из папки templates/
app = Flask(__name__, template_folder="templates", static_folder="static")
@@ -44,6 +44,7 @@ app.config["NUBES_API_ENDPOINT"] = os.getenv(
)
app.config["NUBES_API_TOKEN"] = os.getenv("NUBES_API_TOKEN", "")
app.config["POLYGON_ENDPOINT"] = os.getenv("POLYGON_ENDPOINT", "") # если задан → все запросы в polygon
app.config["NUBES_API_PROD_ENDPOINT"] = os.getenv("NUBES_API_PROD_ENDPOINT", "")
app.config["VERSION"] = VERSION
# Регистрируем blueprint'ы — каждый отвечает за свою группу маршрутов