[ADD] qemu guide: dire comment démarrer le bureau, sur les VM qui en ont un

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
This commit is contained in:
Mathieu Benoit 2026-08-20 03:32:49 -04:00
parent 49bc354d25
commit 75dbeb3258
2 changed files with 83 additions and 0 deletions

View file

@ -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),
),
"",
)

View file

@ -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()