[IMP] script todo: fil d'Ariane télémétrie + arrêt VM par signal (compte à rebours)
Deux points : - Fil d'Ariane depuis la télémétrie : une commande lancée DEPUIS le TUI de télémétrie ne passait par aucun menu, donc son chemin n'était jamais affiché. On imprime désormais « 📍 TODO › … › <commande> » (dernier segment traduit + icône) avant l'exécution, et on enregistre le chemin. - Arrêt de VM (réduction disque) par SIGNAL : virsh shutdown --mode acpi,agent (bouton ACPI puis agent invité) au lieu d'un arrêt implicite. Pendant l'attente, on affiche un compte à rebours du timeout (« ⏳ arrêt en cours… NNN s restantes ») et le délai max au départ. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ec88b5f1f0
commit
a0c560b15f
2 changed files with 42 additions and 6 deletions
|
|
@ -596,6 +596,20 @@ class TODO:
|
||||||
if not action:
|
if not action:
|
||||||
return # quitté sans choisir de commande
|
return # quitté sans choisir de commande
|
||||||
method, kwargs = action
|
method, kwargs = action
|
||||||
|
# Fil d'Ariane : la commande étant lancée DEPUIS la télémétrie (et
|
||||||
|
# non via la navigation), aucun menu n'a affiché le chemin. On le
|
||||||
|
# montre ici (dernier segment traduit + icône) et on l'enregistre.
|
||||||
|
path = state.get("path") if isinstance(state, dict) else None
|
||||||
|
if path:
|
||||||
|
segs = path.split(" › ")
|
||||||
|
segs[-1] = t(segs[-1])
|
||||||
|
print(f"\n📍 {' › '.join(segs)}")
|
||||||
|
try:
|
||||||
|
from script.todo import todo_telemetry
|
||||||
|
|
||||||
|
todo_telemetry.record(path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
fn = getattr(self, method, None)
|
fn = getattr(self, method, None)
|
||||||
if not callable(fn):
|
if not callable(fn):
|
||||||
print(f"{t('Command not found !')} ({method})")
|
print(f"{t('Command not found !')} ({method})")
|
||||||
|
|
@ -1359,22 +1373,32 @@ class TODO:
|
||||||
return out if res.returncode == 0 and out else name
|
return out if res.returncode == 0 and out else name
|
||||||
|
|
||||||
def _qemu_shutdown_wait(self, name, timeout=120):
|
def _qemu_shutdown_wait(self, name, timeout=120):
|
||||||
"""Arrête la VM proprement (ACPI) et attend qu'elle soit « shut off ».
|
"""Arrête la VM par SIGNAL (ACPI power-button, puis agent invité) et
|
||||||
Si l'arrêt gracieux traîne, propose un arrêt forcé (destroy).
|
attend qu'elle soit « shut off » en affichant le temps restant du
|
||||||
|
timeout. Si l'arrêt gracieux traîne, propose un arrêt forcé (destroy).
|
||||||
Renvoie True si la VM est bien éteinte."""
|
Renvoie True si la VM est bien éteinte."""
|
||||||
name = self._qemu_domname(name)
|
name = self._qemu_domname(name)
|
||||||
if self._qemu_domstate(name) == "shut off":
|
if self._qemu_domstate(name) == "shut off":
|
||||||
return True
|
return True
|
||||||
cmd = f"sudo virsh shutdown {shlex.quote(name)}"
|
# --mode acpi,agent : envoie le SIGNAL d'extinction (bouton ACPI) puis
|
||||||
|
# tente l'agent invité si présent — plus fiable qu'un arrêt brutal.
|
||||||
|
cmd = f"sudo virsh shutdown {shlex.quote(name)} --mode acpi,agent"
|
||||||
print(f"{t('Will execute:')} {cmd}")
|
print(f"{t('Will execute:')} {cmd}")
|
||||||
self.execute.exec_command_live(cmd, source_erplibre=False)
|
self.execute.exec_command_live(cmd, source_erplibre=False)
|
||||||
print(t("Waiting for the VM to shut down..."))
|
print(f"{t('Waiting for the VM to shut down...')} "
|
||||||
|
f"({t('timeout')}: {timeout} s)")
|
||||||
deadline = time.time() + timeout
|
deadline = time.time() + timeout
|
||||||
while time.time() < deadline:
|
while time.time() < deadline:
|
||||||
if self._qemu_domstate(name) == "shut off":
|
if self._qemu_domstate(name) == "shut off":
|
||||||
print(f"✅ {name}: {t('VM is off.')}")
|
# Efface la ligne de compte à rebours puis confirme.
|
||||||
|
print(f"\r{' ' * 40}\r✅ {name}: {t('VM is off.')}")
|
||||||
return True
|
return True
|
||||||
time.sleep(3)
|
remaining = int(deadline - time.time())
|
||||||
|
print(f"\r ⏳ {t('shutting down')}… "
|
||||||
|
f"{remaining:>3d} s {t('remaining')}",
|
||||||
|
end="", flush=True)
|
||||||
|
time.sleep(2)
|
||||||
|
print() # newline après le compte à rebours
|
||||||
# Arrêt gracieux trop long : proposer un arrêt forcé.
|
# Arrêt gracieux trop long : proposer un arrêt forcé.
|
||||||
if self._is_yes(
|
if self._is_yes(
|
||||||
input(t("Graceful shutdown timed out. Force off (destroy)? "
|
input(t("Graceful shutdown timed out. Force off (destroy)? "
|
||||||
|
|
|
||||||
|
|
@ -1432,6 +1432,18 @@ TRANSLATIONS = {
|
||||||
"fr": "Attente de l'arrêt de la VM…",
|
"fr": "Attente de l'arrêt de la VM…",
|
||||||
"en": "Waiting for the VM to shut down...",
|
"en": "Waiting for the VM to shut down...",
|
||||||
},
|
},
|
||||||
|
"timeout": {
|
||||||
|
"fr": "délai max",
|
||||||
|
"en": "timeout",
|
||||||
|
},
|
||||||
|
"shutting down": {
|
||||||
|
"fr": "arrêt en cours",
|
||||||
|
"en": "shutting down",
|
||||||
|
},
|
||||||
|
"remaining": {
|
||||||
|
"fr": "restantes",
|
||||||
|
"en": "remaining",
|
||||||
|
},
|
||||||
"VM is off.": {
|
"VM is off.": {
|
||||||
"fr": "VM éteinte.",
|
"fr": "VM éteinte.",
|
||||||
"en": "VM is off.",
|
"en": "VM is off.",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue