[IMP] script todo: dashboard — états Pause / Effacée (check virsh lent)
Pendant le suivi, une VM pouvait « stagner » sans qu'on sache pourquoi (mise en pause, ou effacée à côté). Le dashboard interroge désormais l'état libvirt (« virsh list --all ») à INTERVALLE LENT (toutes les 10 s, un seul appel pour tout le parc ; le tableau applique le cache à chaque tick de 2 s) : - VM en pause (virsh suspend) -> État « ⏸ pause » (non terminal, peut reprendre). - VM absente de virsh (effacée pendant l'attente) -> État « ❌ effacée », terminal (on cesse de lire son log). Sinon on garde le statut basé sur le log (⏳ / ✅ / ❌). Validé headless : running -> ⏳, paused -> ⏸ pause, absente -> ❌ effacée. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1fd98e6ab6
commit
62ea6ebb7f
2 changed files with 62 additions and 0 deletions
|
|
@ -265,6 +265,30 @@ def cli_browser() -> str | None:
|
|||
return None
|
||||
|
||||
|
||||
def virsh_domstates() -> dict:
|
||||
"""{nom: état} de tous les domaines libvirt (« virsh list --all »). Sert à
|
||||
détecter une VM EN PAUSE ou EFFACÉE pendant le suivi. Un seul appel virsh
|
||||
pour tout le parc (à interroger à intervalle LENT)."""
|
||||
try:
|
||||
res = subprocess.run(
|
||||
["sudo", "virsh", "list", "--all"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=15,
|
||||
)
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
return {}
|
||||
states = {}
|
||||
for line in res.stdout.splitlines():
|
||||
parts = line.split()
|
||||
# Ignore l'en-tête (« Id Name State ») et le séparateur (« ---- »,
|
||||
# un seul token). Une VM éteinte a « - » en Id : à NE PAS ignorer.
|
||||
if len(parts) < 3 or parts[0] == "Id":
|
||||
continue
|
||||
states[parts[1]] = " ".join(parts[2:])
|
||||
return states
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Dashboard Textual
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
|
@ -316,6 +340,8 @@ def run_monitor(manifest_path: str, run_app: bool = True):
|
|||
# Historique de durées (ETA) + dossier disque à surveiller.
|
||||
self._stats = load_stats()
|
||||
self._disk_dir = os.path.dirname(vm_disk_path(vms[0])) if vms else "/"
|
||||
# État libvirt (running/paused/gone), rafraîchi à intervalle LENT.
|
||||
self._domstate = {}
|
||||
|
||||
@staticmethod
|
||||
def _fmt(secs):
|
||||
|
|
@ -362,6 +388,10 @@ def run_monitor(manifest_path: str, run_app: bool = True):
|
|||
# sélectionné toutes les 1 s (une seule lecture incrémentale).
|
||||
self.set_interval(2.0, self._tick_table)
|
||||
self.set_interval(1.0, self._tick_log)
|
||||
# État libvirt (pause / effacée) : check LENT (appel virsh) toutes
|
||||
# les 10 s ; le tableau applique le cache à chaque tick (2 s).
|
||||
self.set_interval(10.0, self._tick_domstate)
|
||||
self._tick_domstate() # premier relevé immédiat
|
||||
|
||||
# -- helpers -------------------------------------------------------- #
|
||||
def _vm_by_name(self, name):
|
||||
|
|
@ -415,6 +445,14 @@ def run_monitor(manifest_path: str, run_app: bool = True):
|
|||
)
|
||||
if name in self._final:
|
||||
continue # déjà terminé -> plus de lecture de statut
|
||||
# VM EFFACÉE pendant le suivi -> état terminal « effacé ».
|
||||
ds = self._domstate.get(name)
|
||||
if ds == "gone":
|
||||
self._final[name] = ("deleted", None, now - started)
|
||||
self._set_cell(
|
||||
table, name, "state", f"❌ {t('deleted')}"
|
||||
)
|
||||
continue
|
||||
state, code = read_status(vm["log"])
|
||||
if state in ("done", "failed"):
|
||||
# Fige la durée + MÉMORISE pour l'ETA des prochaines.
|
||||
|
|
@ -428,6 +466,12 @@ def run_monitor(manifest_path: str, run_app: bool = True):
|
|||
self._set_cell(
|
||||
table, name, "elapsed", self._fmt(elapsed)
|
||||
)
|
||||
elif ds == "paused":
|
||||
# VM EN PAUSE (virsh suspend) : l'install ne progresse
|
||||
# pas -> on l'indique (non terminal, peut reprendre).
|
||||
self._set_cell(
|
||||
table, name, "state", f"⏸ {t('paused')}"
|
||||
)
|
||||
else:
|
||||
# running/pending : icône stable -> pas de churn. ETA
|
||||
# = référence historique (par arch) - temps écoulé.
|
||||
|
|
@ -475,6 +519,16 @@ def run_monitor(manifest_path: str, run_app: bool = True):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
def _tick_domstate(self):
|
||||
# Relevé LENT de l'état libvirt : une VM absente de « virsh list »
|
||||
# est EFFACÉE (« gone ») ; sinon on garde son état (paused, …).
|
||||
try:
|
||||
states = virsh_domstates()
|
||||
for vm in vms:
|
||||
self._domstate[vm["name"]] = states.get(vm["name"], "gone")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# -- events --------------------------------------------------------- #
|
||||
def on_data_table_row_highlighted(self, event) -> None:
|
||||
name = event.row_key.value
|
||||
|
|
|
|||
|
|
@ -1373,6 +1373,14 @@ TRANSLATIONS = {
|
|||
"fr": "terminées",
|
||||
"en": "completed",
|
||||
},
|
||||
"deleted": {
|
||||
"fr": "effacée",
|
||||
"en": "deleted",
|
||||
},
|
||||
"paused": {
|
||||
"fr": "pause",
|
||||
"en": "paused",
|
||||
},
|
||||
"Waiting for the VM to start (boot + cloud-init)": {
|
||||
"fr": "En attente du démarrage de la VM (boot + cloud-init)",
|
||||
"en": "Waiting for the VM to start (boot + cloud-init)",
|
||||
|
|
|
|||
Loading…
Reference in a new issue