v1.1.37: params for all ops + polling try/catch + refresh always + tracker CMDB + firstServiceId
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.1.36"
|
VERSION = "1.1.37"
|
||||||
|
|
||||||
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")
|
||||||
|
|||||||
@@ -220,6 +220,10 @@ def api_test():
|
|||||||
cmdb_ok, cmdb_code = client.raw_delete(cmdb_url)
|
cmdb_ok, cmdb_code = client.raw_delete(cmdb_url)
|
||||||
_log(f"[CMDB] DELETE {instance_uid} → ok={cmdb_ok} code={cmdb_code}")
|
_log(f"[CMDB] DELETE {instance_uid} → ok={cmdb_ok} code={cmdb_code}")
|
||||||
if cmdb_ok:
|
if cmdb_ok:
|
||||||
|
try:
|
||||||
|
tracker_remove(get_client_id(), get_stand(), instance_uid)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
return jsonify({"status": "OK", "opUid": "cmdb-"+instance_uid[:8], "instanceUid": instance_uid, "displayName": display_name})
|
return jsonify({"status": "OK", "opUid": "cmdb-"+instance_uid[:8], "instanceUid": instance_uid, "displayName": display_name})
|
||||||
|
|
||||||
if op_name == "redeploy":
|
if op_name == "redeploy":
|
||||||
|
|||||||
+20
-18
@@ -26,7 +26,7 @@
|
|||||||
* showStages() — отрисовка этапов выполнения операции (⏳/✅/❌)
|
* showStages() — отрисовка этапов выполнения операции (⏳/✅/❌)
|
||||||
*/
|
*/
|
||||||
let svcInstances=[], selectedInst=null, selectedOp=null, pollTimer=null;
|
let svcInstances=[], selectedInst=null, selectedOp=null, pollTimer=null;
|
||||||
let currentSvcId=1; // динамический — обновляется при selectService()
|
let currentSvcId=(window.APP&&window.APP.firstServiceId)||1; // динамический — обновляется при selectService()
|
||||||
let currentSvcName=''; // имя текущего сервиса (колонка «тип инстанса»)
|
let currentSvcName=''; // имя текущего сервиса (колонка «тип инстанса»)
|
||||||
let currentSvcShort=''; // краткое имя (redis, postgres) для displayName
|
let currentSvcShort=''; // краткое имя (redis, postgres) для displayName
|
||||||
let busy=false; // блокировка: запрет операций пока идёт другая
|
let busy=false; // блокировка: запрет операций пока идёт другая
|
||||||
@@ -127,14 +127,7 @@ function makeCreateDisplayName(){
|
|||||||
function runOp(opName,opId){
|
function runOp(opName,opId){
|
||||||
if(busy) return;
|
if(busy) return;
|
||||||
stopPoll();
|
stopPoll();
|
||||||
selectedOp={opId,opName,svcId:currentSvcId};
|
showParams(opId,opName);
|
||||||
if(opName==='modify'){
|
|
||||||
showParams(opId,opName);
|
|
||||||
}else{
|
|
||||||
// confirm and execute immediately
|
|
||||||
if(!confirm(`Запустить ${opName} для ${findInstName()}?`)) return;
|
|
||||||
executeOp({});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function findInstName(){
|
function findInstName(){
|
||||||
@@ -167,7 +160,8 @@ function showParams(opId,opName){
|
|||||||
const form=document.getElementById('params-form');
|
const form=document.getElementById('params-form');
|
||||||
const displayNameValue=isCreate?makeCreateDisplayName():'';
|
const displayNameValue=isCreate?makeCreateDisplayName():'';
|
||||||
const createHeader=isCreate?`<div style="font-weight:600;font-size:13px;margin-bottom:8px;color:var(--brand-primary);">Создание: ${currentSvcName}</div>`:'';
|
const createHeader=isCreate?`<div style="font-weight:600;font-size:13px;margin-bottom:8px;color:var(--brand-primary);">Создание: ${currentSvcName}</div>`:'';
|
||||||
form.innerHTML=createHeader+(opName==='create'?`<div class="param-row"><label class="req">displayName</label><span style="font-size:12px;color:var(--muted);white-space:nowrap;">${AUTOTEST_PREFIX}</span><input type="text" id="param-displayname" value="${_esc(displayNameValue)}" autocomplete="off"></div>`:'')
|
const emptyOpHeader=(!isCreate&¶ms.length===0)?`<div style="font-size:13px;margin-bottom:8px;color:var(--muted);">Операция: <b>${_esc(opName)}</b> → <b>${_esc(findInstName())}</b></div>`:'';
|
||||||
|
form.innerHTML=createHeader+emptyOpHeader+(opName==='create'?`<div class="param-row"><label class="req">displayName</label><span style="font-size:12px;color:var(--muted);white-space:nowrap;">${AUTOTEST_PREFIX}</span><input type="text" id="param-displayname" value="${_esc(displayNameValue)}" autocomplete="off"></div>`:'')
|
||||||
+ params.map(p=>{
|
+ params.map(p=>{
|
||||||
const req=p.isRequired;
|
const req=p.isRequired;
|
||||||
const hasDfl=p.defaultValue!==null&&p.defaultValue!==undefined&&p.defaultValue!=='';
|
const hasDfl=p.defaultValue!==null&&p.defaultValue!==undefined&&p.defaultValue!=='';
|
||||||
@@ -350,17 +344,25 @@ async function executeOp(params){
|
|||||||
// start polling
|
// start polling
|
||||||
const opUid=d.opUid;
|
const opUid=d.opUid;
|
||||||
const instanceName=d.displayName||displayName||findInstName();
|
const instanceName=d.displayName||displayName||findInstName();
|
||||||
|
let _pollErrors=0;
|
||||||
pollTimer=setInterval(async()=>{
|
pollTimer=setInterval(async()=>{
|
||||||
const sr=await fetch('/api/test/status/'+opUid);
|
try{
|
||||||
const sd=await sr.json();
|
const sr=await fetch('/api/test/status/'+opUid);
|
||||||
showStages(sd.stages||[]);
|
const sd=await sr.json();
|
||||||
if(sd.status!=='RUNNING'){
|
_pollErrors=0;
|
||||||
stopPoll();
|
showStages(sd.stages||[]);
|
||||||
setFinishedState(sd.status, sd.status==='OK'?'badge-success':'badge', sd.error||sd.errorLog, sd.duration, sd.displayName||instanceName);
|
if(sd.status!=='RUNNING'){
|
||||||
if(sd.status==='OK'){
|
stopPoll();
|
||||||
|
setFinishedState(sd.status, sd.status==='OK'?'badge-success':'badge', sd.error||sd.errorLog, sd.duration, sd.displayName||instanceName);
|
||||||
await refreshInstances();
|
await refreshInstances();
|
||||||
|
if(historyOpen) await loadHistory();
|
||||||
|
}
|
||||||
|
}catch(e){
|
||||||
|
_pollErrors++;
|
||||||
|
if(_pollErrors>=5){
|
||||||
|
stopPoll();
|
||||||
|
setFinishedState('TIMEOUT','','Связь потеряна',0,instanceName);
|
||||||
}
|
}
|
||||||
if(historyOpen) await loadHistory();
|
|
||||||
}
|
}
|
||||||
},2000);
|
},2000);
|
||||||
}catch(e){
|
}catch(e){
|
||||||
|
|||||||
@@ -138,7 +138,8 @@
|
|||||||
window.APP = {
|
window.APP = {
|
||||||
version: "{{ config.VERSION | tojson }}",
|
version: "{{ config.VERSION | tojson }}",
|
||||||
stand: "{{ stand | tojson }}",
|
stand: "{{ stand | tojson }}",
|
||||||
hasUserToken: {{ has_user_token | tojson }}
|
hasUserToken: {{ has_user_token | tojson }},
|
||||||
|
firstServiceId: {{ (config.service_ids[0] if config.service_ids else 1) | tojson }}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<script src="{{ url_for('static', filename='app.js') }}"></script>
|
<script src="{{ url_for('static', filename='app.js') }}"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user