From 4bebf5a39770d5b3743793d2704c9a604ef9e40b Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Wed, 29 Jul 2026 11:09:40 +0000 Subject: [PATCH] =?UTF-8?q?[IMP]=20script=20todo:=20QEMU=20[4]=20=E2=80=94?= =?UTF-8?q?=20choix=20infos=20avanc=C3=A9es=20OU=20changer=20l'=C3=A9tat?= =?UTF-8?q?=20de=20VM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Après « virsh list --all », le menu propose désormais : [1] Infos avancées (vCPU, RAM, disque) [2] Changer l'état d'une ou plusieurs VM [Entrée] Rien Changement d'état (_qemu_change_state) : - Saisie d'une liste de VM séparée par des virgules (noms ou ID, résolus via _qemu_domname et validés contre les VM existantes). - Choix de l'état cible : Ouvrir (start) ou Fermer (shutdown). - DOUBLE validation (« Appliquer : … ? » puis « Confirmer pour de vrai ? ») avant d'exécuter virsh start/shutdown sur chaque VM. Co-Authored-By: Claude Opus 4.8 (1M context) --- script/todo/todo.py | 65 ++++++++++++++++++++++++++++++++++++++-- script/todo/todo_i18n.py | 64 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 3 deletions(-) diff --git a/script/todo/todo.py b/script/todo/todo.py index d487d82..6821440 100755 --- a/script/todo/todo.py +++ b/script/todo/todo.py @@ -1134,10 +1134,69 @@ class TODO: cmd = "sudo virsh list --all" print(f"{t('Will execute:')} {cmd}") self.execute.exec_command_live(cmd, source_erplibre=False) - if ask_advanced and self._is_yes( - input(t("Show advanced info (vCPU, RAM, disk)? (y/N): ")) - ): + if not ask_advanced: + return + # Menu contextuel : infos avancées, ou changer l'état de VM. + print(f"\n{t('What do you want to do?')}") + print(f" [1] {t('Advanced info (vCPU, RAM, disk)')}") + print(f" [2] {t('Change the state of one or more VMs')}") + print(f" [{t('Enter')}] {t('Nothing')}") + choice = input(t("Choice: ")).strip() + if choice == "1": self._qemu_list_vms_advanced() + elif choice == "2": + self._qemu_change_state() + + def _qemu_change_state(self): + """Démarre (« ouvrir ») ou éteint (« fermer ») une liste de VM saisie + séparée par des virgules, avec DOUBLE validation.""" + names = self._qemu_list_domains() + if not names: + print(f"\n{t('No VM found.')}") + return + print(f"\n{t('Available VMs:')} {', '.join(names)}") + raw = input(t("VMs to change (comma-separated): ")).strip() + targets = [n.strip() for n in raw.split(",") if n.strip()] + if not targets: + print(t("Nothing selected.")) + return + # Résoudre les ID -> noms et valider l'existence. + resolved, unknown = [], [] + known = set(names) + for tgt in targets: + real = self._qemu_domname(tgt) + (resolved if real in known else unknown).append(real) + if unknown: + print(f"{t('Unknown VM(s):')} {', '.join(unknown)}") + return + # Choix de l'état cible : ouvrir (démarrer) ou fermer (éteindre). + print(f"\n{t('Target state:')}") + print(f" [1] {t('Open (start)')}") + print(f" [2] {t('Close (shut down)')}") + st = input(t("Choice: ")).strip() + if st == "1": + action, verb = "start", t("start") + elif st == "2": + action, verb = "shutdown", t("shut down") + else: + print(t("Cancelled.")) + return + # DOUBLE validation avant d'appliquer. + summary = f"{verb} -> {', '.join(resolved)}" + if not self._is_yes( + input(f"{t('Apply:')} {summary} ? (o/N) : ") + ): + print(t("Cancelled.")) + return + if not self._is_yes( + input(t("Confirm for real? (y/N): ")) + ): + print(t("Cancelled.")) + return + for real in resolved: + cmd = f"sudo virsh {action} {shlex.quote(real)}" + print(f"\n{t('Will execute:')} {cmd}") + self.execute.exec_command_live(cmd, source_erplibre=False) @staticmethod def _qemu_dominfo(name): diff --git a/script/todo/todo_i18n.py b/script/todo/todo_i18n.py index c470b0b..b5ec688 100644 --- a/script/todo/todo_i18n.py +++ b/script/todo/todo_i18n.py @@ -1452,6 +1452,70 @@ TRANSLATIONS = { "fr": "Afficher les infos avancées (vCPU, RAM, disque) ? (o/N) : ", "en": "Show advanced info (vCPU, RAM, disk)? (y/N): ", }, + "What do you want to do?": { + "fr": "Que voulez-vous faire ?", + "en": "What do you want to do?", + }, + "Advanced info (vCPU, RAM, disk)": { + "fr": "Infos avancées (vCPU, RAM, disque)", + "en": "Advanced info (vCPU, RAM, disk)", + }, + "Change the state of one or more VMs": { + "fr": "Changer l'état d'une ou plusieurs VM", + "en": "Change the state of one or more VMs", + }, + "Enter": { + "fr": "Entrée", + "en": "Enter", + }, + "Nothing": { + "fr": "Rien", + "en": "Nothing", + }, + "Choice: ": { + "fr": "Choix : ", + "en": "Choice: ", + }, + "Available VMs:": { + "fr": "VM disponibles :", + "en": "Available VMs:", + }, + "VMs to change (comma-separated): ": { + "fr": "VM à modifier (séparées par des virgules) : ", + "en": "VMs to change (comma-separated): ", + }, + "Unknown VM(s):": { + "fr": "VM inconnue(s) :", + "en": "Unknown VM(s):", + }, + "Target state:": { + "fr": "État cible :", + "en": "Target state:", + }, + "Open (start)": { + "fr": "Ouvrir (démarrer)", + "en": "Open (start)", + }, + "Close (shut down)": { + "fr": "Fermer (éteindre)", + "en": "Close (shut down)", + }, + "start": { + "fr": "démarrer", + "en": "start", + }, + "shut down": { + "fr": "éteindre", + "en": "shut down", + }, + "Apply:": { + "fr": "Appliquer :", + "en": "Apply:", + }, + "Confirm for real? (y/N): ": { + "fr": "Confirmer pour de vrai ? (o/N) : ", + "en": "Confirm for real? (y/N): ", + }, "Storage": { "fr": "Stockage", "en": "Storage",