fix: code review #2 — _cfg.DELAY + VERSION в config/loader + мёртвые импорты
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# polygon v0.2.0
|
# polygon v0.2.2
|
||||||
|
|
||||||
Эмулятор REST API облачной платформы Nubes для интеграционных тестов app-autotest.
|
Эмулятор REST API облачной платформы Nubes для интеграционных тестов app-autotest.
|
||||||
|
|
||||||
@@ -14,12 +14,27 @@ polygon/
|
|||||||
│ ├── test_converter.py # 10 юнит-тестов from_stands.py
|
│ ├── test_converter.py # 10 юнит-тестов from_stands.py
|
||||||
│ └── test_state_machine.py # 9 юнит-тестов state_machine.py
|
│ └── test_state_machine.py # 9 юнит-тестов state_machine.py
|
||||||
└── site/
|
└── site/
|
||||||
├── app.py # Flask (17 эндпоинтов)
|
├── 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
|
├── mock_state.py # MockState: instances, operations, op_params
|
||||||
├── state_machine.py # apply_effect() — мутация состояния
|
├── state_machine.py # apply_effect() — мутация состояния
|
||||||
├── config_loader.py # загрузка services/*.yaml
|
├── 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
|
├── from_stands.py # конвертер STANDS YAML → polygon config
|
||||||
└── services/ # 37 YAML-конфигов (сгенерированы)
|
├── static/
|
||||||
|
│ └── style.css # тёмная тема
|
||||||
|
├── templates/
|
||||||
|
│ └── index.html # Jinja2-шаблон
|
||||||
|
└── services/ # YAML-конфиги (сгенерированы from_stands.py)
|
||||||
```
|
```
|
||||||
|
|
||||||
⛔ **Ровно 1 gunicorn-воркер.** Состояние в памяти, не shared.
|
⛔ **Ровно 1 gunicorn-воркер.** Состояние в памяти, не shared.
|
||||||
|
|||||||
+3
-2
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
polygon v0.2.1 — Mock Nubes API.
|
polygon v0.2.2 — Mock Nubes API.
|
||||||
Эмулятор REST API облачной платформы Nubes для интеграционных тестов.
|
Эмулятор REST API облачной платформы Nubes для интеграционных тестов.
|
||||||
|
|
||||||
Blueprint'ы (каждый — отдельный файл в routes/):
|
Blueprint'ы (каждый — отдельный файл в routes/):
|
||||||
@@ -35,7 +35,8 @@ from routes.operations_routes import bp as operations_bp
|
|||||||
from routes.run import bp as run_bp
|
from routes.run import bp as run_bp
|
||||||
from routes.mock_routes import bp as mock_bp
|
from routes.mock_routes import bp as mock_bp
|
||||||
|
|
||||||
VERSION = "0.2.2"
|
# Версия — единый источник правды в config/loader.py
|
||||||
|
from config.loader import VERSION
|
||||||
|
|
||||||
# Flask-приложение с Jinja2-шаблонами и статикой
|
# Flask-приложение с Jinja2-шаблонами и статикой
|
||||||
app = Flask(__name__, template_folder="templates", static_folder="static")
|
app = Flask(__name__, template_folder="templates", static_folder="static")
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
config/loader.py — загрузка сервисов и глобальные конфигурационные переменные.
|
config/loader.py — загрузка сервисов и глобальные конфигурационные переменные.
|
||||||
|
|
||||||
Этот модуль загружает все YAML-конфиги сервисов при первом импорте и хранит их
|
Этот модуль загружает все YAML-конфиги сервисов при первом импорте и хранит их
|
||||||
как модульные переменные. Все routes/*.py импортируют SERVICES, OPS_INDEX, DELAY
|
как модульные переменные. Все routes/*.py импортируют SERVICES, OPS_INDEX, DELAY,
|
||||||
отсюда — без дублирования загрузки и без циклических импортов.
|
VERSION отсюда — без дублирования загрузки и без циклических импортов.
|
||||||
|
|
||||||
Переменные модуля (вычисляются ОДИН раз при старте):
|
Переменные модуля (вычисляются ОДИН раз при старте):
|
||||||
|
VERSION — str, версия полигона (единая для app.py и root.py)
|
||||||
SERVICES — {service_id: service_def} все сервисы
|
SERVICES — {service_id: service_def} все сервисы
|
||||||
OPS_INDEX — {svcOperationId: service_def} поиск сервиса по ID операции
|
OPS_INDEX — {svcOperationId: service_def} поиск сервиса по ID операции
|
||||||
DELAY — float, задержка операции из MOCK_OP_DELAY (по умолчанию 0.1)
|
DELAY — float, задержка операции из MOCK_OP_DELAY (по умолчанию 0.1)
|
||||||
@@ -64,4 +65,10 @@ SERVICES, OPS_INDEX = _load_all()
|
|||||||
|
|
||||||
# Задержка операции в секундах (для синхронного sleep в /run).
|
# Задержка операции в секундах (для синхронного sleep в /run).
|
||||||
# Меняется на лету через POST /_mock/delay/<s> — см. mock_routes.py.
|
# Меняется на лету через POST /_mock/delay/<s> — см. mock_routes.py.
|
||||||
|
# ⛔ Импортировать ТОЛЬКО через `import config.loader as _cfg` и читать `_cfg.DELAY` —
|
||||||
|
# иначе float копируется по значению и не реагирует на изменение.
|
||||||
DELAY = float(os.getenv("MOCK_OP_DELAY", "0.1"))
|
DELAY = float(os.getenv("MOCK_OP_DELAY", "0.1"))
|
||||||
|
|
||||||
|
# Версия полигона — единый источник правды для app.py и routes/root.py.
|
||||||
|
# Меняется при КАЖДОМ изменении кода.
|
||||||
|
VERSION = "0.2.2"
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ Blueprint "mock" с префиксом /api/v1/svc/_mock.
|
|||||||
from flask import Blueprint, jsonify
|
from flask import Blueprint, jsonify
|
||||||
|
|
||||||
import mock_state
|
import mock_state
|
||||||
from config.loader import SERVICES, DELAY as _DELAY
|
import config.loader as _cfg # для чтения/записи модульных переменных DELAY, SERVICES
|
||||||
import config.loader as _cfg # для модификации модульной переменной DELAY
|
|
||||||
|
|
||||||
bp = Blueprint("mock", __name__, url_prefix="/api/v1/svc/_mock")
|
bp = Blueprint("mock", __name__, url_prefix="/api/v1/svc/_mock")
|
||||||
|
|
||||||
@@ -73,7 +72,7 @@ def mock_services():
|
|||||||
не дёргая реальный /api/v1/svc/services.
|
не дёргая реальный /api/v1/svc/services.
|
||||||
"""
|
"""
|
||||||
result = {}
|
result = {}
|
||||||
for svc_id, svc_def in SERVICES.items():
|
for svc_id, svc_def in _cfg.SERVICES.items():
|
||||||
result[str(svc_id)] = {
|
result[str(svc_id)] = {
|
||||||
"name": svc_def.get("name", ""),
|
"name": svc_def.get("name", ""),
|
||||||
"displayName": svc_def.get("service_display_name", ""),
|
"displayName": svc_def.get("service_display_name", ""),
|
||||||
|
|||||||
@@ -8,10 +8,9 @@ Blueprint "operations" с префиксом /api/v1/svc.
|
|||||||
POST /instanceOperationCfsParams — установить параметр
|
POST /instanceOperationCfsParams — установить параметр
|
||||||
GET /instanceOperations/<uid>/validate-cfs — пустое тело, 200
|
GET /instanceOperations/<uid>/validate-cfs — пустое тело, 200
|
||||||
|
|
||||||
ВАЖНО: порядок маршрутов в蓝图 критичен.
|
Порядок маршрутов: default/<int:op_id> (целое число) и <uid> (строка UUID)
|
||||||
/instanceOperations/default/<int:op_id> ДОЛЖЕН быть выше
|
различаются Flask/Werkzeug автоматически — конфликта нет, но default размещён
|
||||||
/instanceOperations/<uid>
|
выше для ясности.
|
||||||
Иначе Flask распарсит "default" как uid и уйдёт не в тот обработчик.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from flask import Blueprint, jsonify, make_response, request
|
from flask import Blueprint, jsonify, make_response, request
|
||||||
|
|||||||
+6
-7
@@ -8,11 +8,10 @@ Blueprint "root" регистрируется в app.py БЕЗ url_prefix.
|
|||||||
from flask import Blueprint, render_template
|
from flask import Blueprint, render_template
|
||||||
|
|
||||||
import mock_state
|
import mock_state
|
||||||
from config.loader import SERVICES, DELAY
|
import config.loader as _cfg
|
||||||
from utils.now import now as _now
|
|
||||||
|
|
||||||
# Версия — показывается на HTML-странице и в healthcheck (опционально)
|
# Версия — из config/loader.py (единый источник правды)
|
||||||
VERSION = "0.2.2"
|
VERSION = _cfg.VERSION
|
||||||
|
|
||||||
# Blueprint без префикса — роуты /health и / будут на корне домена
|
# Blueprint без префикса — роуты /health и / будут на корне домена
|
||||||
bp = Blueprint("root", __name__)
|
bp = Blueprint("root", __name__)
|
||||||
@@ -36,12 +35,12 @@ def index():
|
|||||||
текущую задержку операций. Использует Jinja2-шаблон templates/index.html
|
текущую задержку операций. Использует Jinja2-шаблон templates/index.html
|
||||||
и внешний CSS из static/style.css.
|
и внешний CSS из static/style.css.
|
||||||
"""
|
"""
|
||||||
svc_count = len(SERVICES)
|
svc_count = len(_cfg.SERVICES)
|
||||||
inst_count = len(mock_state.state.instances)
|
inst_count = len(mock_state.state.instances)
|
||||||
return render_template(
|
return render_template(
|
||||||
"index.html",
|
"index.html",
|
||||||
version=VERSION,
|
version=_cfg.VERSION,
|
||||||
svc_count=svc_count,
|
svc_count=svc_count,
|
||||||
inst_count=inst_count,
|
inst_count=inst_count,
|
||||||
delay=DELAY,
|
delay=_cfg.DELAY,
|
||||||
)
|
)
|
||||||
|
|||||||
+5
-4
@@ -14,7 +14,7 @@ from flask import Blueprint, jsonify
|
|||||||
|
|
||||||
import mock_state
|
import mock_state
|
||||||
import state_machine
|
import state_machine
|
||||||
from config.loader import SERVICES, DELAY
|
import config.loader as _cfg
|
||||||
from utils.now import now as _now
|
from utils.now import now as _now
|
||||||
|
|
||||||
bp = Blueprint("run", __name__, url_prefix="/api/v1/svc")
|
bp = Blueprint("run", __name__, url_prefix="/api/v1/svc")
|
||||||
@@ -48,12 +48,13 @@ def run_operation(uid):
|
|||||||
op["dtStart"] = _now()
|
op["dtStart"] = _now()
|
||||||
|
|
||||||
# Эмулируем задержку выполнения (по умолчанию 0.1с)
|
# Эмулируем задержку выполнения (по умолчанию 0.1с)
|
||||||
if DELAY > 0:
|
# ⛔ _cfg.DELAY — модульная переменная, может меняться через /_mock/delay
|
||||||
time.sleep(DELAY)
|
if _cfg.DELAY > 0:
|
||||||
|
time.sleep(_cfg.DELAY)
|
||||||
|
|
||||||
# Применить эффект операции к состоянию инстанса
|
# Применить эффект операции к состоянию инстанса
|
||||||
# (create → running+params, delete → удалить, modify → мерж params, ...)
|
# (create → running+params, delete → удалить, modify → мерж params, ...)
|
||||||
state_machine.apply_effect(uid, mock_state.state, SERVICES)
|
state_machine.apply_effect(uid, mock_state.state, _cfg.SERVICES)
|
||||||
|
|
||||||
# Фиксируем время завершения — операция выполнена успешно
|
# Фиксируем время завершения — операция выполнена успешно
|
||||||
op["dtFinish"] = _now()
|
op["dtFinish"] = _now()
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ def apply_effect(op_uid, mock_state, services):
|
|||||||
Args:
|
Args:
|
||||||
op_uid — UUID операции
|
op_uid — UUID операции
|
||||||
mock_state — экземпляр MockState
|
mock_state — экземпляр MockState
|
||||||
services — {service_id: service_def} из config_loader
|
services — {service_id: service_def} из config/loader.py
|
||||||
"""
|
"""
|
||||||
op = mock_state.operations.get(op_uid)
|
op = mock_state.operations.get(op_uid)
|
||||||
if not op:
|
if not op:
|
||||||
|
|||||||
Reference in New Issue
Block a user