v1.2.1: fix tracker_add in executor + labelCls + descr context + script order
Opus review fixes: - executor.py: tracker_add inside executor after instance_uid, before params/run (A3, orphan protection) - executor.py: descr parameter (version/context instead of hardcoded) - api_test.py: pass client_id/stand/descr, remove duplicate tracker_add - scenario.py: pass client_id/stand/descr with scenario context - params-render.js: fix labelCls ReferenceError in renderMapFixedRow (pre-existing bug) - index.html: params-render.js already before operations.js (verified)
This commit is contained in:
+1
-1
@@ -19,7 +19,7 @@ from routes.api_scenario_run import bp_run as api_scenario_run_bp
|
|||||||
from routes.api_scenario_defs import bp_defs as api_scenario_defs_bp
|
from routes.api_scenario_defs import bp_defs as api_scenario_defs_bp
|
||||||
|
|
||||||
# Версия — меняется при КАЖДОМ изменении кода. Показывается в топбаре UI.
|
# Версия — меняется при КАЖДОМ изменении кода. Показывается в топбаре UI.
|
||||||
VERSION = "1.2.0"
|
VERSION = "1.2.1"
|
||||||
|
|
||||||
app = Flask(__name__, template_folder="templates", static_folder="static")
|
app = Flask(__name__, template_folder="templates", static_folder="static")
|
||||||
app.config["NUBES_API_ENDPOINT"] = os.getenv("NUBES_API_ENDPOINT", "https://lk-api-gateway-test.ngcloud.ru/api/v1/svc")
|
app.config["NUBES_API_ENDPOINT"] = os.getenv("NUBES_API_ENDPOINT", "https://lk-api-gateway-test.ngcloud.ru/api/v1/svc")
|
||||||
|
|||||||
@@ -2,15 +2,18 @@
|
|||||||
Единый executor операции Nubes.
|
Единый executor операции Nubes.
|
||||||
|
|
||||||
Делает всё до /run включительно. НЕ поллит.
|
Делает всё до /run включительно. НЕ поллит.
|
||||||
|
Вызывает tracker_add для create сразу после получения instance_uid (защита от сирот).
|
||||||
Используется api_test.py (ручной) и scenario.py (сценарный).
|
Используется api_test.py (ручной) и scenario.py (сценарный).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from api.utils import find_uid, uid_from_location
|
from api.utils import find_uid, uid_from_location
|
||||||
from operations.terraform import send_params_terraform
|
from operations.terraform import send_params_terraform
|
||||||
|
from operations.tracker import add as tracker_add
|
||||||
|
|
||||||
|
|
||||||
def execute_operation(client, service_id, operation, instance_uid, params,
|
def execute_operation(client, service_id, operation, instance_uid, params,
|
||||||
svc_op_id=None, display_name=None):
|
svc_op_id=None, display_name=None, descr=None,
|
||||||
|
client_id="", stand=""):
|
||||||
"""Запустить операцию и вернуть результат.
|
"""Запустить операцию и вернуть результат.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -21,6 +24,9 @@ def execute_operation(client, service_id, operation, instance_uid, params,
|
|||||||
params: dict — {numeric_param_id: value}
|
params: dict — {numeric_param_id: value}
|
||||||
svc_op_id: int|None — svcOperationId (игнорируется для create)
|
svc_op_id: int|None — svcOperationId (игнорируется для create)
|
||||||
display_name: str|None — displayName (только для create)
|
display_name: str|None — displayName (только для create)
|
||||||
|
descr: str|None — описание инстанса
|
||||||
|
client_id: str — для tracker_add
|
||||||
|
stand: str — для tracker_add
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict {ok, error, failed_step, instance_uid, op_uid, display_name}
|
dict {ok, error, failed_step, instance_uid, op_uid, display_name}
|
||||||
@@ -32,7 +38,8 @@ def execute_operation(client, service_id, operation, instance_uid, params,
|
|||||||
if is_create:
|
if is_create:
|
||||||
if not display_name:
|
if not display_name:
|
||||||
display_name = f"autotest-{service_id}"
|
display_name = f"autotest-{service_id}"
|
||||||
descr = f"created by autotest"
|
if not descr:
|
||||||
|
descr = "created by autotest"
|
||||||
payload = {"serviceId": service_id, "displayName": display_name, "descr": descr}
|
payload = {"serviceId": service_id, "displayName": display_name, "descr": descr}
|
||||||
try:
|
try:
|
||||||
resp = client.post("/instances", payload)
|
resp = client.post("/instances", payload)
|
||||||
@@ -44,6 +51,12 @@ def execute_operation(client, service_id, operation, instance_uid, params,
|
|||||||
return {"ok": False, "error": "No instanceUid in response", "failed_step": "instances",
|
return {"ok": False, "error": "No instanceUid in response", "failed_step": "instances",
|
||||||
"instance_uid": None, "op_uid": None, "display_name": display_name}
|
"instance_uid": None, "op_uid": None, "display_name": display_name}
|
||||||
|
|
||||||
|
# tracker_add СРАЗУ после instance_uid, до params/run — защита от сирот
|
||||||
|
try:
|
||||||
|
tracker_add(client_id, stand, instance_uid, service_id, display_name)
|
||||||
|
except Exception:
|
||||||
|
pass # не ронять операцию из-за трекера
|
||||||
|
|
||||||
# --- Шаг 2: POST /instanceOperations ---
|
# --- Шаг 2: POST /instanceOperations ---
|
||||||
if is_create:
|
if is_create:
|
||||||
op_payload = {"instanceUid": instance_uid, "operation": operation}
|
op_payload = {"instanceUid": instance_uid, "operation": operation}
|
||||||
|
|||||||
@@ -128,16 +128,19 @@ def run_scenario(client, steps, client_id, stand, user_email, app_version, scena
|
|||||||
if is_create:
|
if is_create:
|
||||||
instance_uid = None
|
instance_uid = None
|
||||||
display_name = f"{AUTOTEST_PREFIX}{scenario_name}-{uuid.uuid4().hex[:6]}"
|
display_name = f"{AUTOTEST_PREFIX}{scenario_name}-{uuid.uuid4().hex[:6]}"
|
||||||
|
descr = f"scenario {scenario_name} step {step_num}"
|
||||||
else:
|
else:
|
||||||
instance_uid = _resolve_instance_uid(step, bindings, instance_map)
|
instance_uid = _resolve_instance_uid(step, bindings, instance_map)
|
||||||
if not instance_uid:
|
if not instance_uid:
|
||||||
raise ValueError(f"No instance for step {step_num} — need CREATE before non-create operations")
|
raise ValueError(f"No instance for step {step_num} — need CREATE before non-create operations")
|
||||||
display_name = None
|
display_name = None
|
||||||
|
descr = None
|
||||||
|
|
||||||
# 4. Запуск через executor
|
# 4. Запуск через executor
|
||||||
result = execute_operation(
|
result = execute_operation(
|
||||||
client, svc_id, op_name, instance_uid, resolved_params,
|
client, svc_id, op_name, instance_uid, resolved_params,
|
||||||
svc_op_id=svc_op_id, display_name=display_name
|
svc_op_id=svc_op_id, display_name=display_name, descr=descr,
|
||||||
|
client_id=client_id, stand=stand
|
||||||
)
|
)
|
||||||
if not result["ok"]:
|
if not result["ok"]:
|
||||||
raise RuntimeError(f"{op_name}: {result['error']} (step: {result['failed_step']})")
|
raise RuntimeError(f"{op_name}: {result['error']} (step: {result['failed_step']})")
|
||||||
|
|||||||
@@ -193,9 +193,11 @@ def api_test():
|
|||||||
if not display_name:
|
if not display_name:
|
||||||
display_name = f"autotest-{svc_id}"
|
display_name = f"autotest-{svc_id}"
|
||||||
display_name = _unique_display_name(client, display_name)
|
display_name = _unique_display_name(client, display_name)
|
||||||
|
descr = f"created by autotest v{current_app.config.get('VERSION', '')}"
|
||||||
result = execute_operation(
|
result = execute_operation(
|
||||||
client, svc_id, op_name, None, params,
|
client, svc_id, op_name, None, params,
|
||||||
svc_op_id=svc_op_id, display_name=display_name
|
svc_op_id=svc_op_id, display_name=display_name, descr=descr,
|
||||||
|
client_id=get_client_id(), stand=get_stand()
|
||||||
)
|
)
|
||||||
if not result["ok"]:
|
if not result["ok"]:
|
||||||
return jsonify({"status": "FAIL", "error": result["error"]}), 500
|
return jsonify({"status": "FAIL", "error": result["error"]}), 500
|
||||||
@@ -203,14 +205,6 @@ def api_test():
|
|||||||
op_uid = result["op_uid"]
|
op_uid = result["op_uid"]
|
||||||
display_name = result["display_name"]
|
display_name = result["display_name"]
|
||||||
|
|
||||||
# Трекер
|
|
||||||
try:
|
|
||||||
tracker_add(get_client_id(), get_stand(), instance_uid, svc_id, display_name)
|
|
||||||
except Exception as e:
|
|
||||||
import traceback
|
|
||||||
print(f"[TRACKER ERROR] add failed: {e}", flush=True)
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
# Фоновый поллинг
|
# Фоновый поллинг
|
||||||
user_email = get_token_info().get("email", "")
|
user_email = get_token_info().get("email", "")
|
||||||
app_version = current_app.config.get("VERSION", "")
|
app_version = current_app.config.get("VERSION", "")
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ function renderParamRow(p, allInst) {
|
|||||||
|
|
||||||
function renderMapFixedRow(p, dfl) {
|
function renderMapFixedRow(p, dfl) {
|
||||||
const dd = p.dataDescriptor;
|
const dd = p.dataDescriptor;
|
||||||
|
const labelCls = p.isRequired ? (dfl ? 'req' : 'req-nodfl') : '';
|
||||||
let subHtml = '';
|
let subHtml = '';
|
||||||
let dflObj = {};
|
let dflObj = {};
|
||||||
try { dflObj = JSON.parse(dfl || '{}'); } catch (e) { }
|
try { dflObj = JSON.parse(dfl || '{}'); } catch (e) { }
|
||||||
|
|||||||
Reference in New Issue
Block a user