refator_comm1

This commit is contained in:
Mateusz Gruszczyński
2025-10-18 22:27:39 +02:00
parent 5b0431fbec
commit fda2b721b3
3 changed files with 67 additions and 233 deletions

91
app.py
View File

@@ -512,76 +512,6 @@ def api_vm_action():
except Exception as e:
return jsonify(ok=False, error=str(e)), 500
@app.get("/api/task-status")
def api_task_status():
upid = request.args.get("upid", "").strip()
node = request.args.get("node", "").strip()
if not upid or not node:
return jsonify(ok=False, error="upid and node required"), 400
st = get_json(["pvesh", "get", f"/nodes/{node}/tasks/{upid}/status"]) or {}
return jsonify(ok=True, status=st)
@app.get("/api/task-log")
def api_task_log():
upid = request.args.get("upid", "").strip()
node = request.args.get("node", "").strip()
start = request.args.get("start", "0").strip()
try:
start_i = int(start)
except Exception:
start_i = 0
if not upid or not node:
return jsonify(ok=False, error="upid and node required"), 400
lines = get_json(["pvesh", "get", f"/nodes/{node}/tasks/{upid}/log", "-start", str(start_i)]) or []
next_start = start_i
if isinstance(lines, list) and lines:
try:
next_start = max((int(x.get("n", start_i)) for x in lines if isinstance(x, dict)), default=start_i) + 1
except Exception:
next_start = start_i
return jsonify(ok=True, lines=lines or [], next_start=next_start)
# ---------------- WebSocket: live tail zadań ----------------
@sock.route("/ws/task")
def ws_task(ws):
# query: upid, node
q = ws.environ.get("QUERY_STRING", "")
params = {}
for part in q.split("&"):
if not part: continue
k, _, v = part.partition("=")
params[k] = v
upid = params.get("upid", "").strip()
node = params.get("node", "").strip()
if not upid or not node:
ws.send(json.dumps({"type":"error","error":"upid and node are required"}))
return
start = 0
try:
while True:
st = get_json(["pvesh", "get", f"/nodes/{node}/tasks/{upid}/status"]) or {}
ws.send(json.dumps({"type":"status","status":st}))
lines = get_json(["pvesh", "get", f"/nodes/{node}/tasks/{upid}/log", "-start", str(start)]) or []
if isinstance(lines, list) and lines:
for ln in lines:
txt = (ln.get("t") if isinstance(ln, dict) else None)
if txt:
ws.send(json.dumps({"type":"log","line":txt}))
try:
start = max((int(x.get("n", start)) for x in lines if isinstance(x, dict)), default=start) + 1
except Exception:
pass
# koniec
if isinstance(st, dict) and (str(st.get("status","")).lower() == "stopped" or st.get("exitstatus")):
ok = (str(st.get("exitstatus","")).upper() == "OK")
ws.send(json.dumps({"type":"done","ok":ok,"exitstatus":st.get("exitstatus")}))
break
time.sleep(1.2)
except Exception:
try:
ws.close()
except Exception:
pass
# ---------------- WebSocket: broadcast observe per sid ----------------
@sock.route("/ws/observe")
@@ -596,8 +526,7 @@ def ws_observe(ws):
if not sid:
ws.send(json.dumps({"type":"error","error":"sid required"})); return
# Resolve tuple + node
def resolve_tuple() -> Optional[Tuple[str,int,str]]:
def resolve_tuple():
meta = cluster_vmct_meta()
return sid_to_tuple(sid, meta)
@@ -608,7 +537,6 @@ def ws_observe(ws):
if not node:
ws.send(json.dumps({"type":"error","error":"could not resolve node"})); return
last_hash = None
seen_upids = set()
prev_node = node
@@ -621,13 +549,6 @@ def ws_observe(ws):
ws.send(json.dumps({"type":"moved","old_node":node,"new_node":cur_node,"meta":{"sid":sid,"vmid":vmid,"typ":typ}}))
prev_node, node = node, cur_node
base = f"/nodes/{node}/{typ}/{vmid}"
cur = get_json(["pvesh", "get", f"{base}/status/current"]) or {}
cur_hash = json.dumps(cur, sort_keys=True)
if cur_hash != last_hash:
last_hash = cur_hash
ws.send(json.dumps({"type":"vm","current":cur,"meta":{"sid":sid,"node":node,"typ":typ,"vmid":vmid}}))
nodes_to_scan = [node] + ([prev_node] if prev_node and prev_node != node else [])
for nX in nodes_to_scan:
tasks = get_json(["pvesh","get",f"/nodes/{nX}/tasks","-limit","50"]) or []
@@ -635,23 +556,21 @@ def ws_observe(ws):
upid = t.get("upid") if isinstance(t, dict) else None
tid = (t.get("id") or "") if isinstance(t, dict) else ""
if not upid or not isinstance(upid, str): continue
# dopasuj po vmid lub ciągu qemu/<vmid>|lxc/<vmid>
if (str(vmid) in tid) or (f"{'qemu' if typ=='qemu' else 'lxc'}/{vmid}" in tid):
st = get_json(["pvesh","get",f"/nodes/{nX}/tasks/{upid}/status"]) or {}
ws.send(json.dumps({"type":"task","upid":upid,"status":st.get("status"),"exitstatus":st.get("exitstatus"),"node":nX}))
# nowy running
ws.send(json.dumps({"type":"task","upid":upid,"node":nX}))
if upid not in seen_upids and str(st.get("status","")).lower() != "stopped":
seen_upids.add(upid)
ws.send(json.dumps({"type":"task-start","upid":upid,"node":nX}))
# zakończone
if str(st.get("status","")).lower() == "stopped" or st.get("exitstatus"):
ws.send(json.dumps({"type":"done","upid":upid,"ok":str(st.get('exitstatus','')).upper()=='OK',"node":nX}))
ok = str(st.get("exitstatus","")).upper() == "OK"
ws.send(json.dumps({"type":"done","upid":upid,"ok":ok,"node":nX}))
time.sleep(1.8)
except Exception:
try: ws.close()
except Exception: pass
if __name__ == "__main__":
import argparse
p = argparse.ArgumentParser()