From 75dbeb325813cbc9a0f6ca567a7c4c693254fb8b Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Thu, 20 Aug 2026 03:32:49 -0400 Subject: [PATCH] =?UTF-8?q?[ADD]=20qemu=20guide:=20dire=20comment=20d?= =?UTF-8?q?=C3=A9marrer=20le=20bureau,=20sur=20les=20VM=20qui=20en=20ont?= =?UTF-8?q?=20un?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Une VM graphique peut arriver sur une console texte — graphical.target est atteinte avant que le paquet du bureau soit là, et « systemctl enable gdm » rend 0 sans rien faire sur Debian et Ubuntu, où l'unité n'a pas de WantedBy. La commande qui répare tient sur une ligne ; encore faut-il la lire quelque part. Le guide de connexion porte donc un bloc « Bureau », avec l'état et le « enable --now ». Il n'apparaît que si la VM a été déployée avec un bureau : sur un serveur, ces commandes ne mèneraient à aucune unité. Le drapeau existait déjà côté déploiement, il n'y avait qu'à le passer. --- EN --- A graphical VM can land on a text console — graphical.target is reached before the desktop package exists, and "systemctl enable gdm" returns 0 doing nothing on Debian and Ubuntu, where the unit has no WantedBy. The command that repairs it is one line; it still has to be readable somewhere. The login guide therefore carries a "Desktop" block, with the state and the "enable --now". It only shows when the VM was deployed with a desktop: on a server those commands would point at no unit. The flag already existed on the deploy side; it only had to be passed along. Assisted-by: Claude Opus 5 --- script/qemu/deploy_qemu.py | 32 ++++++++++++++++++++++++ test/test_qemu_motd.py | 51 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/script/qemu/deploy_qemu.py b/script/qemu/deploy_qemu.py index 491fc47..45e23aa 100755 --- a/script/qemu/deploy_qemu.py +++ b/script/qemu/deploy_qemu.py @@ -1660,6 +1660,26 @@ SERVICE_GUIDE: tuple[tuple[str, str, str], ...] = ( ) +# N'apparaît que sur une VM déployée AVEC un bureau. Vécu : GNOME installé, +# gdm3 installé, cible graphique par défaut… et la console restait en mode texte. +# graphical.target était déjà atteinte quand le paquet est arrivé, et une cible +# active ne rattrape pas un service ajouté après coup. « enable » seul n'y change +# rien sur Debian et Ubuntu — l'unité n'a pas de WantedBy, seulement un alias — +# d'où le « --now », qui démarre. +DESKTOP_GUIDE: tuple[tuple[str, str, str], ...] = ( + ( + "systemctl status display-manager", + "état du bureau graphique", + "graphical desktop state", + ), + ( + "sudo systemctl enable --now gdm", + "le démarrer (« --now » : enable seul ne suffit pas)", + 'start it ("--now": enable alone does nothing)', + ), +) + + def erplibre_guide( el_dir: str, el_make: str = "", editor: str = "" ) -> tuple[tuple[str, str, str], ...]: @@ -1770,11 +1790,14 @@ def build_motd( el_dir: str = "", el_make: str = "", editor: str = "", + desktop: bool = False, ) -> str: """Texte du /etc/motd de la VM. Fonction PURE : aucun I/O, donc testable. La section ERPLibre n'apparaît qu'avec `el_dir` : une VM déployée sans installation ne doit pas annoncer un dépôt et un service qui n'existent pas. + Le bloc « Bureau » suit la même règle avec `desktop` : sur un serveur, ces + deux commandes ne mèneraient à aucune unité. """ body: list[str] = [] mgr = DISTRO_PKG.get(distro, "") @@ -1795,6 +1818,14 @@ def build_motd( body.append("") el_rows = erplibre_guide(el_dir, el_make, editor) body += motd_block("ERPLibre", el_rows, lang, gloss_col(el_rows)) + if desktop: + body.append("") + body += motd_block( + _pick(("Bureau", "Desktop"), lang), + DESKTOP_GUIDE, + lang, + gloss_col(DESKTOP_GUIDE), + ) body.append("") body += motd_block( _pick(("Système", "System"), lang), sys_rows, lang, narrow @@ -2016,6 +2047,7 @@ def guide_files(args: argparse.Namespace) -> list[tuple[str, str, str, str]]: args.erplibre_dir, args.erplibre_make, editor, + bool(args.desktop), ), "", ) diff --git a/test/test_qemu_motd.py b/test/test_qemu_motd.py index 1fde3ff..8156cd9 100644 --- a/test/test_qemu_motd.py +++ b/test/test_qemu_motd.py @@ -352,5 +352,56 @@ class TestInstallerGuideNames(unittest.TestCase): ) +class TestDesktopBlock(unittest.TestCase): + """Le bloc « Bureau » : présent seulement là où un bureau existe. + + Vécu : une VM graphique restait sur une console texte, GNOME installé et + gdm3 installé — graphical.target était déjà atteinte quand le paquet est + arrivé. La commande qui répare tient sur une ligne, encore faut-il la lire + quelque part. Sur un serveur, elle ne mènerait à aucune unité : le bloc + n'y apparaît pas. + """ + + def _motd(self, desktop): + return dq.build_motd( + "ubuntu", + "26.04", + "amd64", + "fr", + "~/git/erplibre", + "install_odoo_18", + "vim", + desktop, + ) + + def test_a_server_gets_no_desktop_block(self): + self.assertNotIn("Bureau", self._motd(False)) + + def test_a_graphical_vm_gets_it(self): + self.assertIn("Bureau", self._motd(True)) + + def test_it_carries_the_command_that_repairs(self): + """« --now » et non « enable » seul : sur Debian et Ubuntu, l'unité n'a + pas de WantedBy, et « enable » rend 0 sans rien faire.""" + motd = self._motd(True) + self.assertIn("systemctl enable --now gdm", motd) + self.assertIn("systemctl status display-manager", motd) + + def test_it_says_why_now_matters(self): + self.assertIn("--now", self._motd(True)) + + def test_it_stays_inside_the_frame(self): + """Le guide est encadré : une ligne trop longue casse la boîte.""" + lines = self._motd(True).splitlines() + width = max(len(line) for line in lines) + border = [line for line in lines if line.startswith("╭")][0] + self.assertEqual(len(border), width) + + def test_the_default_is_no_block(self): + """Un appelant qui n'en sait rien n'annonce pas un bureau.""" + motd = dq.build_motd("ubuntu", "26.04", "amd64", "fr") + self.assertNotIn("Bureau", motd) + + if __name__ == "__main__": unittest.main()