[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:
parent
49bc354d25
commit
75dbeb3258
2 changed files with 83 additions and 0 deletions
|
|
@ -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(
|
def erplibre_guide(
|
||||||
el_dir: str, el_make: str = "", editor: str = ""
|
el_dir: str, el_make: str = "", editor: str = ""
|
||||||
) -> tuple[tuple[str, str, str], ...]:
|
) -> tuple[tuple[str, str, str], ...]:
|
||||||
|
|
@ -1770,11 +1790,14 @@ def build_motd(
|
||||||
el_dir: str = "",
|
el_dir: str = "",
|
||||||
el_make: str = "",
|
el_make: str = "",
|
||||||
editor: str = "",
|
editor: str = "",
|
||||||
|
desktop: bool = False,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Texte du /etc/motd de la VM. Fonction PURE : aucun I/O, donc testable.
|
"""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
|
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.
|
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] = []
|
body: list[str] = []
|
||||||
mgr = DISTRO_PKG.get(distro, "")
|
mgr = DISTRO_PKG.get(distro, "")
|
||||||
|
|
@ -1795,6 +1818,14 @@ def build_motd(
|
||||||
body.append("")
|
body.append("")
|
||||||
el_rows = erplibre_guide(el_dir, el_make, editor)
|
el_rows = erplibre_guide(el_dir, el_make, editor)
|
||||||
body += motd_block("ERPLibre", el_rows, lang, gloss_col(el_rows))
|
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.append("")
|
||||||
body += motd_block(
|
body += motd_block(
|
||||||
_pick(("Système", "System"), lang), sys_rows, lang, narrow
|
_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_dir,
|
||||||
args.erplibre_make,
|
args.erplibre_make,
|
||||||
editor,
|
editor,
|
||||||
|
bool(args.desktop),
|
||||||
),
|
),
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue