v1.0.71: finished status shows instance name
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Архитектура app-autotest — полный документ
|
# Архитектура app-autotest — полный документ
|
||||||
|
|
||||||
v1.0.69, 27.07.2026
|
v1.0.71, 27.07.2026
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+19
-1
@@ -1,6 +1,24 @@
|
|||||||
# История разработки app-autotest
|
# История разработки app-autotest
|
||||||
|
|
||||||
# v1.0.69 (27.07.2026) — autotest prefix fixed in CREATE field
|
# v1.0.71 (27.07.2026) — finished status shows instance name
|
||||||
|
|
||||||
|
### Что изменилось
|
||||||
|
- В `site/templates/index.html` финальная строка после `OK/FAIL` теперь показывает имя инстанса.
|
||||||
|
- Имя операции и длительность остаются рядом, отдельно от имени инстанса.
|
||||||
|
|
||||||
|
### Что это чинит
|
||||||
|
- Ситуацию, когда после завершения delete/modify было видно только название операции, но не ясно, над каким инстансом она выполнялась.
|
||||||
|
|
||||||
|
# v1.0.70 (27.07.2026) — dedupe autotest instances by displayName
|
||||||
|
|
||||||
|
### Что изменилось
|
||||||
|
- В `site/routes/main.py` сервисный список теперь склеивает записи по `displayName`.
|
||||||
|
- Если cloud уже отдал `running`, он выигрывает у tracker-fallback `creating`.
|
||||||
|
|
||||||
|
### Что это чинит
|
||||||
|
- Дубли одной и той же autotest-записи после CREATE, когда в списке появлялись и `running`, и `creating`.
|
||||||
|
|
||||||
|
## v1.0.69 (27.07.2026) — autotest prefix fixed in CREATE field
|
||||||
|
|
||||||
### Что изменилось
|
### Что изменилось
|
||||||
- В `site/templates/index.html` префикс `autotest-` отображается отдельным фиксированным текстом.
|
- В `site/templates/index.html` префикс `autotest-` отображается отдельным фиксированным текстом.
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ from routes.main import bp as main_bp
|
|||||||
from routes.api import bp as api_bp
|
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
|
||||||
|
|
||||||
VERSION = "1.0.69"
|
VERSION = "1.0.71"
|
||||||
|
|
||||||
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-dev.ngcloud.ru/api/v1/svc")
|
app.config["NUBES_API_ENDPOINT"] = os.getenv("NUBES_API_ENDPOINT", "https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc")
|
||||||
|
|||||||
+16
-3
@@ -156,7 +156,19 @@ def api_operations(svc_id):
|
|||||||
tracked_by_uid = {t["instanceUid"]: t for t in tracked if t["svcId"] == svc_id}
|
tracked_by_uid = {t["instanceUid"]: t for t in tracked if t["svcId"] == svc_id}
|
||||||
instances = get_instances(client)
|
instances = get_instances(client)
|
||||||
nubes_uids = {i["instanceUid"] for i in instances}
|
nubes_uids = {i["instanceUid"] for i in instances}
|
||||||
svc_instances = []
|
svc_instances_by_name = {}
|
||||||
|
|
||||||
|
def _store_instance(item):
|
||||||
|
display_name = str(item.get("displayName", "") or "")
|
||||||
|
if not display_name.startswith(AUTOTEST_PREFIX):
|
||||||
|
return
|
||||||
|
existing = svc_instances_by_name.get(display_name)
|
||||||
|
if existing is None:
|
||||||
|
svc_instances_by_name[display_name] = item
|
||||||
|
return
|
||||||
|
if existing.get("status") == "creating" and item.get("status") != "creating":
|
||||||
|
svc_instances_by_name[display_name] = item
|
||||||
|
|
||||||
for i in instances:
|
for i in instances:
|
||||||
if not str(i.get("displayName", "")).startswith(AUTOTEST_PREFIX):
|
if not str(i.get("displayName", "")).startswith(AUTOTEST_PREFIX):
|
||||||
continue
|
continue
|
||||||
@@ -164,11 +176,11 @@ def api_operations(svc_id):
|
|||||||
continue
|
continue
|
||||||
item = dict(i)
|
item = dict(i)
|
||||||
item["status"] = _resolve_instance_status(item, tracked_by_uid.get(i.get("instanceUid")))
|
item["status"] = _resolve_instance_status(item, tracked_by_uid.get(i.get("instanceUid")))
|
||||||
svc_instances.append(item)
|
_store_instance(item)
|
||||||
# Если Nubes ещё не отдаёт только что созданный autotest-инстанс, добавляем его из трекера.
|
# Если Nubes ещё не отдаёт только что созданный autotest-инстанс, добавляем его из трекера.
|
||||||
for uid, t in tracked_by_uid.items():
|
for uid, t in tracked_by_uid.items():
|
||||||
if uid not in nubes_uids:
|
if uid not in nubes_uids:
|
||||||
svc_instances.append({
|
_store_instance({
|
||||||
"instanceUid": uid,
|
"instanceUid": uid,
|
||||||
"displayName": t["displayName"],
|
"displayName": t["displayName"],
|
||||||
"serviceId": svc_id,
|
"serviceId": svc_id,
|
||||||
@@ -176,6 +188,7 @@ def api_operations(svc_id):
|
|||||||
"explainedStatus": "",
|
"explainedStatus": "",
|
||||||
"status": "creating",
|
"status": "creating",
|
||||||
})
|
})
|
||||||
|
svc_instances = list(svc_instances_by_name.values())
|
||||||
return jsonify({"svc": detail.get("svc", ""), "operations": ops, "instances": svc_instances})
|
return jsonify({"svc": detail.get("svc", ""), "operations": ops, "instances": svc_instances})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({"error": str(e)}), 500
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ function showParams(opId,opName){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFinishedState(statusText, statusClass, statusError, statusDuration){
|
function setFinishedState(statusText, statusClass, statusError, statusDuration, instanceName){
|
||||||
const btn=document.getElementById('btn-test');
|
const btn=document.getElementById('btn-test');
|
||||||
btn.disabled=false;
|
btn.disabled=false;
|
||||||
btn.textContent='Готово';
|
btn.textContent='Готово';
|
||||||
@@ -250,7 +250,8 @@ function setFinishedState(statusText, statusClass, statusError, statusDuration){
|
|||||||
const opName=selectedOp?.opName||'операция';
|
const opName=selectedOp?.opName||'операция';
|
||||||
const durationText=statusDuration!==undefined&&statusDuration!==null?`${statusDuration}s`:'0s';
|
const durationText=statusDuration!==undefined&&statusDuration!==null?`${statusDuration}s`:'0s';
|
||||||
const extra=statusError||'';
|
const extra=statusError||'';
|
||||||
document.getElementById('test-status').innerHTML=` <span class="badge ${statusClass}">${statusText}</span> <span style="color:var(--muted);">${opName}</span> <span style="color:var(--muted);">${durationText}</span> ${extra}`;
|
const instName=instanceName||findInstName()||selectedInst||'';
|
||||||
|
document.getElementById('test-status').innerHTML=` <span class="badge ${statusClass}">${statusText}</span> <span style="color:var(--muted);">${opName}</span> <span style="color:var(--muted);">${durationText}</span> <span style="color:var(--muted);">${instName}</span> ${extra}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setRunningState(opName, displayName){
|
function setRunningState(opName, displayName){
|
||||||
@@ -289,13 +290,14 @@ async function executeOp(params){
|
|||||||
if(d.status==='FAIL'){document.getElementById('test-status').innerHTML=` <span class="badge">FAIL</span> ${d.error||''}`;btn.disabled=false;return;}
|
if(d.status==='FAIL'){document.getElementById('test-status').innerHTML=` <span class="badge">FAIL</span> ${d.error||''}`;btn.disabled=false;return;}
|
||||||
// start polling
|
// start polling
|
||||||
const opUid=d.opUid;
|
const opUid=d.opUid;
|
||||||
|
const instanceName=d.displayName||displayName;
|
||||||
pollTimer=setInterval(async()=>{
|
pollTimer=setInterval(async()=>{
|
||||||
const sr=await fetch('/api/test/status/'+opUid);
|
const sr=await fetch('/api/test/status/'+opUid);
|
||||||
const sd=await sr.json();
|
const sd=await sr.json();
|
||||||
showStages(sd.stages||[]);
|
showStages(sd.stages||[]);
|
||||||
if(sd.status!=='RUNNING'){
|
if(sd.status!=='RUNNING'){
|
||||||
stopPoll();
|
stopPoll();
|
||||||
setFinishedState(sd.status, sd.status==='OK'?'badge-success':'badge', sd.error, sd.duration);
|
setFinishedState(sd.status, sd.status==='OK'?'badge-success':'badge', sd.error, sd.duration, instanceName);
|
||||||
if(sd.status==='OK'){
|
if(sd.status==='OK'){
|
||||||
await refreshInstances();
|
await refreshInstances();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user