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/... → стенд по умолчанию
This commit is contained in:
@@ -13,11 +13,16 @@ Blueprint "operations" с префиксом /api/v1/svc.
|
||||
выше для ясности.
|
||||
"""
|
||||
|
||||
from flask import Blueprint, jsonify, make_response, request
|
||||
from flask import Blueprint, g, jsonify, make_response, request
|
||||
from werkzeug.local import LocalProxy
|
||||
|
||||
import mock_state
|
||||
import state_machine
|
||||
from config.loader import SERVICES, OPS_INDEX
|
||||
import config.loader as _cfg
|
||||
|
||||
state = LocalProxy(lambda: mock_state.get_state(g.stand_id))
|
||||
SERVICES = LocalProxy(lambda: _cfg.get_services(g.stand_id))
|
||||
OPS_INDEX = LocalProxy(lambda: _cfg.get_ops_index(g.stand_id))
|
||||
|
||||
bp = Blueprint("operations", __name__, url_prefix="/api/v1/svc")
|
||||
|
||||
@@ -135,7 +140,7 @@ def create_operation():
|
||||
return jsonify({"error": "instanceUid is required"}), 400
|
||||
|
||||
# Проверка что инстанс существует
|
||||
inst = mock_state.state.get_instance(instance_uid)
|
||||
inst = state.get_instance(instance_uid)
|
||||
if not inst:
|
||||
return jsonify({"error": "instance not found"}), 404
|
||||
|
||||
@@ -165,7 +170,7 @@ def create_operation():
|
||||
break
|
||||
|
||||
# Создать операцию в MockState (dtFinish=None — ещё не выполнена)
|
||||
op_uid = mock_state.state.create_operation(instance_uid, svc_op_id, operation, kind, action)
|
||||
op_uid = state.create_operation(instance_uid, svc_op_id, operation, kind, action)
|
||||
|
||||
# ⛔ Location ОБЯЗАТЕЛЕН — без него executor не получит opUid
|
||||
resp = make_response(jsonify({"instanceOperationUid": op_uid}), 201)
|
||||
@@ -192,7 +197,7 @@ def get_operation(uid):
|
||||
app-autotest использует ?fields=dtFinish,isSuccessful для поллинга —
|
||||
ждёт пока dtFinish != None.
|
||||
"""
|
||||
op = mock_state.state.get_operation(uid)
|
||||
op = state.get_operation(uid)
|
||||
if not op:
|
||||
return jsonify({"error": "operation not found"}), 404
|
||||
|
||||
@@ -203,7 +208,7 @@ def get_operation(uid):
|
||||
if "cfsParams" in fields:
|
||||
svc_op_id = op.get("svcOperationId")
|
||||
svc_def = OPS_INDEX.get(svc_op_id, {})
|
||||
op_params = mock_state.state.get_params(uid)
|
||||
op_params = state.get_params(uid)
|
||||
result["cfsParams"] = _build_cfs_list(svc_def, svc_op_id, op_params)
|
||||
|
||||
return jsonify({"instanceOperation": result})
|
||||
@@ -233,11 +238,11 @@ def set_operation_param():
|
||||
return jsonify({"error": "instanceOperationUid and svcOperationCfsParamId required"}), 400
|
||||
|
||||
# Проверка что операция существует
|
||||
if not mock_state.state.get_operation(op_uid):
|
||||
if not state.get_operation(op_uid):
|
||||
return jsonify({"error": "operation not found"}), 404
|
||||
|
||||
# Сохранить параметр (param_id — int, value — str)
|
||||
mock_state.state.set_param(op_uid, param_id, value)
|
||||
state.set_param(op_uid, param_id, value)
|
||||
return jsonify({})
|
||||
|
||||
|
||||
@@ -256,7 +261,7 @@ def validate_cfs(uid):
|
||||
Если вернуть jsonify({}), app-autotest распарсит но логика та же.
|
||||
Пустое тело — канонический ответ реального Nubes API для validate-cfs.
|
||||
"""
|
||||
if not mock_state.state.get_operation(uid):
|
||||
if not state.get_operation(uid):
|
||||
return jsonify({"error": "operation not found"}), 404
|
||||
|
||||
return "", 200
|
||||
|
||||
Reference in New Issue
Block a user