From 4c04145c314057afa481cd6f0ff801808b34dd9e Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Wed, 29 Jul 2026 10:42:02 +0000 Subject: [PATCH] [IMP] script todo: choix du profil d'installation ERPLibre sur une VM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quand on installe ERPLibre sur une/des VM, on choisit désormais CE qu'on installe (au lieu de forcer install_odoo_18) : ERPLibre + Odoo 18/17/16/15/14/13/12 (make install_os && make install_odoo_X) ERPLibre + toutes les versions Odoo (make install_odoo_all_version) ERPLibre seulement (sans Odoo) (./script/install/install_erplibre.sh) ERPLibre mobile (home) (./mobile/install_and_run.sh) ERPLibre Déploiement (+ QEMU + dev) (install_dev + qemu/libvirt/virtinst) _qemu_pick_install_profile renvoie la commande finale ; _qemu_erplibre_remote_cmd l'exécute dans ~/git/erplibre ; le profil est threadé aux installeurs (monitoré + streamé). Cibles make vérifiées dans les Makefiles. Co-Authored-By: Claude Opus 4.8 (1M context) --- script/todo/todo.py | 93 +++++++++++++++++++++++++++++++++------- script/todo/todo_i18n.py | 24 +++++++++++ 2 files changed, 102 insertions(+), 15 deletions(-) diff --git a/script/todo/todo.py b/script/todo/todo.py index 60b2477..8dd97cc 100755 --- a/script/todo/todo.py +++ b/script/todo/todo.py @@ -2092,9 +2092,62 @@ class TODO: # sshd répondait au moins (mieux qu'un abandon silencieux). return ssh_up - def _qemu_erplibre_remote_cmd(self, branch): + # Paquets QEMU/libvirt pour le profil « Déploiement » (nos 3 gestionnaires). + _QEMU_QEMU_PKGS = ( + "(sudo apt-get install -y qemu-kvm libvirt-daemon-system virtinst " + "cloud-image-utils 2>/dev/null || sudo dnf install -y qemu-kvm " + "libvirt virt-install cloud-utils 2>/dev/null || sudo pacman -S " + "--needed --noconfirm qemu-desktop libvirt virt-install 2>/dev/null " + "|| true)" + ) + + def _qemu_pick_install_profile(self): + """Choix de CE QU'ON installe sur la VM. Renvoie (label, commande + finale exécutée dans ~/git/erplibre).""" + profiles = [ + ( + f"ERPLibre + Odoo {v}", + f"make install_os && make install_odoo_{v}", + ) + for v in ("18", "17", "16", "15", "14", "13", "12") + ] + profiles += [ + ( + t("ERPLibre + all Odoo versions"), + "make install_os && make install_odoo_all_version", + ), + ( + t("ERPLibre only (no Odoo)"), + "make install_os && ./script/install/install_erplibre.sh", + ), + ( + t("ERPLibre mobile (home)"), + "make install_os && ./mobile/install_and_run.sh", + ), + ( + t("ERPLibre Deployment (+ QEMU + dev)"), + "make install_os && make install_dev && " + + self._QEMU_QEMU_PKGS, + ), + ] + print(f"\n{t('What to install on the VM(s)?')}") + for i, (label, _cmd) in enumerate(profiles, 1): + print(f" [{i}] {label}{' *' if i == 1 else ''}") + sel = input(t("Choice (number, blank = Odoo 18): ")).strip() + try: + idx = int(sel) - 1 + if 0 <= idx < len(profiles): + return profiles[idx] + except ValueError: + pass + return profiles[0] # défaut : ERPLibre + Odoo 18 + + def _qemu_erplibre_remote_cmd(self, branch, final_cmd=None): """Script d'installation ERPLibre exécuté DANS la VM (curl/git/make - puis clone + make install_os + make install_odoo_18).""" + puis clone + `final_cmd` dans ~/git/erplibre). `final_cmd` par défaut : + install_os + install_odoo_18.""" + if not final_cmd: + final_cmd = f"make install_os && make {self.ERPLIBRE_ODOO_TARGET}" return ( "set -e; " # Attendre la FIN de cloud-init : pendant sa phase « paquets » il @@ -2150,21 +2203,23 @@ class TODO: "if [ ! -d ~/git/erplibre/.git ]; then " f"git clone --branch {shlex.quote(branch)} " f"{self.ERPLIBRE_GIT_URL} ~/git/erplibre; fi; " - # Installation : dépendances système puis Odoo. - "cd ~/git/erplibre && make install_os && " - f"make {self.ERPLIBRE_ODOO_TARGET}" + # Installation : commande finale selon le profil choisi. + f"cd ~/git/erplibre && {final_cmd}" ) - def _qemu_install_erplibre_monitored(self, names, branch, ip_map=None): + def _qemu_install_erplibre_monitored( + self, names, branch, ip_map=None, final_cmd=None + ): """Lance l'install ERPLibre en parallèle DÉTACHÉE sur les VM et ouvre le dashboard Textual. Quitter le dashboard n'arrête pas les installs. - `ip_map` : IP déjà résolues (sinon on résout ici, EN PARALLÈLE).""" + `ip_map` : IP déjà résolues (sinon on résout ici, EN PARALLÈLE). + `final_cmd` : commande d'install selon le profil choisi.""" from script.todo.qemu_install_monitor import ( launch_installs, run_monitor, ) - remote = self._qemu_erplibre_remote_cmd(branch) + remote = self._qemu_erplibre_remote_cmd(branch, final_cmd) try: mod = self._qemu_import_module() except Exception: @@ -2216,10 +2271,12 @@ class TODO: # Commande prête à copier pour relire/partager tous les logs. print(f" {t('Read the logs:')} tail -n +1 {logdir}/*.log") - def _qemu_install_erplibre_vm(self, name, ssh_key, branch, ip=None): + def _qemu_install_erplibre_vm( + self, name, ssh_key, branch, ip=None, final_cmd=None + ): """Clone ERPLibre (branche donnée) dans ~/git/erplibre de la VM puis - exécute « make install_os » et « make install_odoo_18 » (streamé). - `ip` : IP déjà résolue (sinon on la résout ici).""" + exécute la commande d'install du profil choisi (streamé). `ip` : IP + déjà résolue ; `final_cmd` : commande d'install.""" if ip is None: ip = self._qemu_vm_ip(name) if not ip: @@ -2236,7 +2293,7 @@ class TODO: f"{t('SSH not reachable, ERPLibre install skipped.')}" ) return - remote = self._qemu_erplibre_remote_cmd(branch) + remote = self._qemu_erplibre_remote_cmd(branch, final_cmd) ssh_opts = ( "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null " "-o ConnectTimeout=15" @@ -2244,7 +2301,7 @@ class TODO: cmd = f"ssh {ssh_opts} erplibre@{ip} {shlex.quote(remote)}" print( f"\n 📦 {name} ({ip}): {t('installing ERPLibre')} " - f"({branch}, make install_os + {self.ERPLIBRE_ODOO_TARGET})" + f"({branch})" ) print(f" {t('Will execute:')} {cmd}") self.execute.exec_command_live(cmd, source_erplibre=False) @@ -2545,11 +2602,13 @@ class TODO: # 4) Option : installer ERPLibre dans ~/git/erplibre de chaque VM. install_branch = None install_monitor = False + install_cmd = None # commande finale selon le profil choisi ans = input( t("Install ERPLibre into ~/git/erplibre on each VM? (y/N): ") ) if self._is_yes(ans): install_branch = self._qemu_pick_branch() + _label, install_cmd = self._qemu_pick_install_profile() install_monitor = self._is_yes( input(t("Interactive monitoring dashboard? (y/N): ")) ) @@ -2667,7 +2726,7 @@ class TODO: if install_monitor: # Installs détachées en parallèle + dashboard Textual. self._qemu_install_erplibre_monitored( - deployed, install_branch, ip_map + deployed, install_branch, ip_map, install_cmd ) else: print( @@ -2676,7 +2735,11 @@ class TODO: ) for name in deployed: self._qemu_install_erplibre_vm( - name, ssh_key, install_branch, ip_map.get(name) + name, + ssh_key, + install_branch, + ip_map.get(name), + install_cmd, ) # Sommaire TOTAL (déploiement + résolution IP + ssh_config + install diff --git a/script/todo/todo_i18n.py b/script/todo/todo_i18n.py index eb9d5a6..2eef0aa 100644 --- a/script/todo/todo_i18n.py +++ b/script/todo/todo_i18n.py @@ -1790,6 +1790,30 @@ TRANSLATIONS = { "fr": "SSH injoignable, installation ERPLibre ignorée.", "en": "SSH not reachable, ERPLibre install skipped.", }, + "What to install on the VM(s)?": { + "fr": "Que veut-on installer sur la/les VM ?", + "en": "What to install on the VM(s)?", + }, + "Choice (number, blank = Odoo 18): ": { + "fr": "Choix (numéro, vide = Odoo 18) : ", + "en": "Choice (number, blank = Odoo 18): ", + }, + "ERPLibre + all Odoo versions": { + "fr": "ERPLibre + toutes les versions Odoo", + "en": "ERPLibre + all Odoo versions", + }, + "ERPLibre only (no Odoo)": { + "fr": "ERPLibre seulement (sans Odoo)", + "en": "ERPLibre only (no Odoo)", + }, + "ERPLibre mobile (home)": { + "fr": "ERPLibre mobile (home)", + "en": "ERPLibre mobile (home)", + }, + "ERPLibre Deployment (+ QEMU + dev)": { + "fr": "ERPLibre Déploiement (+ QEMU + dev)", + "en": "ERPLibre Deployment (+ QEMU + dev)", + }, "Interactive monitoring dashboard? (y/N): ": { "fr": "Suivi interactif (dashboard) ? (o/N, défaut : non) : ", "en": "Interactive monitoring dashboard? (y/N, default: no): ",