v1.0.95: full test data — op_uid, user_email, app_version, params saved to runs
This commit is contained in:
+1
-1
@@ -18,7 +18,7 @@ from routes.api import bp as api_bp
|
|||||||
from routes.api_test import bp as api_test_bp
|
from routes.api_test import bp as api_test_bp
|
||||||
|
|
||||||
# Версия — меняется при КАЖДОМ изменении кода. Показывается в топбаре UI.
|
# Версия — меняется при КАЖДОМ изменении кода. Показывается в топбаре UI.
|
||||||
VERSION = "1.0.93"
|
VERSION = "1.0.95"
|
||||||
|
|
||||||
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")
|
||||||
|
|||||||
+16
-3
@@ -8,10 +8,12 @@
|
|||||||
Таблица runs — история запусков операций:
|
Таблица runs — история запусков операций:
|
||||||
- id, created_at
|
- id, created_at
|
||||||
- client_id, stand (изоляция по пользователю и стенду)
|
- client_id, stand (изоляция по пользователю и стенду)
|
||||||
|
- user_email (кто запустил)
|
||||||
- svc_id, svc_name, op_name, svc_op_id
|
- svc_id, svc_name, op_name, svc_op_id
|
||||||
- instance_uid, display_name
|
- instance_uid, display_name, op_uid
|
||||||
- status (OK/FAIL/TIMEOUT), duration_sec, error_log
|
- status (OK/FAIL/TIMEOUT), duration_sec, error_log
|
||||||
- params (JSONB), stages (JSONB)
|
- params (JSONB), stages (JSONB)
|
||||||
|
- app_version (версия приложения)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -23,17 +25,20 @@ CREATE TABLE IF NOT EXISTS runs (
|
|||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
client_id VARCHAR(64) NOT NULL,
|
client_id VARCHAR(64) NOT NULL,
|
||||||
stand VARCHAR(16) NOT NULL,
|
stand VARCHAR(16) NOT NULL,
|
||||||
|
user_email VARCHAR(128),
|
||||||
svc_id INTEGER NOT NULL,
|
svc_id INTEGER NOT NULL,
|
||||||
svc_name VARCHAR(128),
|
svc_name VARCHAR(128),
|
||||||
op_name VARCHAR(32) NOT NULL,
|
op_name VARCHAR(32) NOT NULL,
|
||||||
svc_op_id INTEGER,
|
svc_op_id INTEGER,
|
||||||
|
op_uid VARCHAR(64),
|
||||||
instance_uid VARCHAR(64),
|
instance_uid VARCHAR(64),
|
||||||
display_name VARCHAR(255),
|
display_name VARCHAR(255),
|
||||||
status VARCHAR(16) NOT NULL,
|
status VARCHAR(16) NOT NULL,
|
||||||
duration_sec DOUBLE PRECISION,
|
duration_sec DOUBLE PRECISION,
|
||||||
error_log TEXT,
|
error_log TEXT,
|
||||||
params JSONB,
|
params JSONB,
|
||||||
stages JSONB
|
stages JSONB,
|
||||||
|
app_version VARCHAR(16)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_runs_client_stand
|
CREATE INDEX IF NOT EXISTS idx_runs_client_stand
|
||||||
@@ -46,9 +51,16 @@ CREATE INDEX IF NOT EXISTS idx_runs_created
|
|||||||
ON runs (created_at);
|
ON runs (created_at);
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Миграция для существующих таблиц (добавляем колонки если их нет)
|
||||||
|
MIGRATION_SQL = """
|
||||||
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS op_uid VARCHAR(64);
|
||||||
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS user_email VARCHAR(128);
|
||||||
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS app_version VARCHAR(16);
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def init_db():
|
def init_db():
|
||||||
"""Применить схему — идемпотентно, безопасно для конкурентного вызова."""
|
"""Применить схему + миграции — идемпотентно, безопасно для конкурентного вызова."""
|
||||||
if not os.getenv("DB_USER"):
|
if not os.getenv("DB_USER"):
|
||||||
print("[DB] DB_USER not set — skipping init", flush=True)
|
print("[DB] DB_USER not set — skipping init", flush=True)
|
||||||
return
|
return
|
||||||
@@ -61,6 +73,7 @@ def init_db():
|
|||||||
try:
|
try:
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
cur.execute(SCHEMA_SQL)
|
cur.execute(SCHEMA_SQL)
|
||||||
|
cur.execute(MIGRATION_SQL)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
cur.close()
|
cur.close()
|
||||||
print("[DB] Schema initialized", flush=True)
|
print("[DB] Schema initialized", flush=True)
|
||||||
|
|||||||
+10
-9
@@ -6,9 +6,9 @@ import json
|
|||||||
from db.pool import get_conn, put_conn
|
from db.pool import get_conn, put_conn
|
||||||
|
|
||||||
|
|
||||||
def save_run(client_id, stand, svc_id, svc_name, op_name, svc_op_id,
|
def save_run(client_id, stand, user_email, svc_id, svc_name, op_name, svc_op_id,
|
||||||
instance_uid, display_name, status, duration_sec,
|
op_uid, instance_uid, display_name, status, duration_sec,
|
||||||
error_log, params, stages):
|
error_log, params, stages, app_version):
|
||||||
"""Сохранить один запуск в таблицу runs."""
|
"""Сохранить один запуск в таблицу runs."""
|
||||||
conn = get_conn()
|
conn = get_conn()
|
||||||
if not conn:
|
if not conn:
|
||||||
@@ -17,16 +17,17 @@ def save_run(client_id, stand, svc_id, svc_name, op_name, svc_op_id,
|
|||||||
try:
|
try:
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
INSERT INTO runs (client_id, stand, svc_id, svc_name, op_name, svc_op_id,
|
INSERT INTO runs (client_id, stand, user_email, svc_id, svc_name,
|
||||||
instance_uid, display_name, status, duration_sec,
|
op_name, svc_op_id, op_uid, instance_uid, display_name,
|
||||||
error_log, params, stages)
|
status, duration_sec, error_log, params, stages, app_version)
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
""", (
|
""", (
|
||||||
client_id, stand, svc_id, svc_name, op_name, svc_op_id,
|
client_id, stand, user_email, svc_id, svc_name, op_name, svc_op_id,
|
||||||
instance_uid, display_name, status, duration_sec,
|
op_uid, instance_uid, display_name, status, duration_sec,
|
||||||
error_log,
|
error_log,
|
||||||
json.dumps(params) if params else None,
|
json.dumps(params) if params else None,
|
||||||
json.dumps(stages) if stages else None,
|
json.dumps(stages) if stages else None,
|
||||||
|
app_version,
|
||||||
))
|
))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
cur.close()
|
cur.close()
|
||||||
|
|||||||
+16
-9
@@ -234,7 +234,7 @@ def api_test():
|
|||||||
client.post(f"/instanceOperations/{op_uid}/run")
|
client.post(f"/instanceOperations/{op_uid}/run")
|
||||||
|
|
||||||
# фоном ждать завершения
|
# фоном ждать завершения
|
||||||
threading.Thread(target=_finish_op, args=(client, op_uid, instance_uid, svc_id, display_name, op_name, svc_op_id, True, get_client_id(), get_stand()), daemon=True).start()
|
threading.Thread(target=_finish_op, args=(client, op_uid, instance_uid, svc_id, display_name, op_name, svc_op_id, True, get_client_id(), get_stand(), params), daemon=True).start()
|
||||||
return jsonify({"status": "RUNNING", "opUid": op_uid, "instanceUid": instance_uid, "displayName": display_name})
|
return jsonify({"status": "RUNNING", "opUid": op_uid, "instanceUid": instance_uid, "displayName": display_name})
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -264,7 +264,7 @@ def api_test():
|
|||||||
# Получить реальное имя инстанса из API (не UUID!)
|
# Получить реальное имя инстанса из API (не UUID!)
|
||||||
if not display_name:
|
if not display_name:
|
||||||
display_name = _get_instance_display_name(client, instance_uid)
|
display_name = _get_instance_display_name(client, instance_uid)
|
||||||
threading.Thread(target=_finish_op, args=(client, op_uid, instance_uid, svc_id, display_name, op_name, svc_op_id, False, get_client_id(), get_stand(), is_delete), daemon=True).start()
|
threading.Thread(target=_finish_op, args=(client, op_uid, instance_uid, svc_id, display_name, op_name, svc_op_id, False, get_client_id(), get_stand(), is_delete, params), daemon=True).start()
|
||||||
return jsonify({"status": "RUNNING", "opUid": op_uid, "instanceUid": instance_uid, "displayName": display_name})
|
return jsonify({"status": "RUNNING", "opUid": op_uid, "instanceUid": instance_uid, "displayName": display_name})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -303,7 +303,7 @@ def _get_instance_display_name(client, instance_uid):
|
|||||||
return instance_uid
|
return instance_uid
|
||||||
|
|
||||||
|
|
||||||
def _finish_op(client, op_uid, instance_uid, svc_id, display_name, op_name, svc_op_id, is_create, client_id, stand, is_delete=False):
|
def _finish_op(client, op_uid, instance_uid, svc_id, display_name, op_name, svc_op_id, is_create, client_id, stand, is_delete=False, params=None):
|
||||||
"""Фоном ждать dtFinish и сохранить результат."""
|
"""Фоном ждать dtFinish и сохранить результат."""
|
||||||
import time
|
import time
|
||||||
_cleanup_op_results() # очистить старые записи перед добавлением новой
|
_cleanup_op_results() # очистить старые записи перед добавлением новой
|
||||||
@@ -344,13 +344,18 @@ def _finish_op(client, op_uid, instance_uid, svc_id, display_name, op_name, svc_
|
|||||||
# Сохранить в БД историю
|
# Сохранить в БД историю
|
||||||
try:
|
try:
|
||||||
from db.save_run import save_run
|
from db.save_run import save_run
|
||||||
save_run(client_id, stand, svc_id, op.get("svc", ""), op_name, svc_op_id,
|
from api.auth import get_token_info
|
||||||
instance_uid, display_name,
|
user = get_token_info()
|
||||||
|
save_run(client_id, stand,
|
||||||
|
user.get("email", ""),
|
||||||
|
svc_id, op.get("svc", ""), op_name, svc_op_id,
|
||||||
|
op_uid, instance_uid, display_name,
|
||||||
"OK" if is_ok else "FAIL",
|
"OK" if is_ok else "FAIL",
|
||||||
round(time.time() - t0, 1),
|
round(time.time() - t0, 1),
|
||||||
str(err) if err else "",
|
str(err) if err else "",
|
||||||
{}, # params недоступны в _finish_op — будут при следующем улучшении
|
params or {},
|
||||||
op.get("stages", []))
|
op.get("stages", []),
|
||||||
|
current_app.config.get("VERSION", ""))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # не ронять фоновый поток из-за БД
|
pass # не ронять фоновый поток из-за БД
|
||||||
return
|
return
|
||||||
@@ -413,8 +418,10 @@ def api_history():
|
|||||||
return jsonify([])
|
return jsonify([])
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT id, created_at, client_id, stand, svc_id, svc_name,
|
SELECT id, created_at, client_id, stand, user_email,
|
||||||
op_name, instance_uid, display_name, status, duration_sec, error_log
|
svc_id, svc_name, op_name, svc_op_id, op_uid,
|
||||||
|
instance_uid, display_name,
|
||||||
|
status, duration_sec, error_log, app_version
|
||||||
FROM runs
|
FROM runs
|
||||||
WHERE client_id = %s AND stand = %s
|
WHERE client_id = %s AND stand = %s
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
|
|||||||
Reference in New Issue
Block a user