Compare commits
5 commits
59bf857558
...
c9b51998a4
| Author | SHA1 | Date | |
|---|---|---|---|
| c9b51998a4 | |||
| 6ce56629f4 | |||
| c140b418d5 | |||
| 14fa807221 | |||
| babe69dbf7 |
3 changed files with 163 additions and 3 deletions
|
|
@ -92,12 +92,19 @@ sudo su - postgres -c "createuser -s ${EL_USER}" 2>/dev/null || true
|
||||||
# Install Dependencies
|
# Install Dependencies
|
||||||
#--------------------------------------------------
|
#--------------------------------------------------
|
||||||
echo -e "\n--- Installing debian dependency --"
|
echo -e "\n--- Installing debian dependency --"
|
||||||
${APT_GET} install git build-essential wget libxslt-dev libzip-dev libldap2-dev libsasl2-dev gdebi-core libffi-dev libbz2-dev parallel pysassc swig cmake portaudio19-dev libcups2-dev shfmt xmlsec1 -y
|
${APT_GET} install git build-essential wget libxslt-dev libzip-dev libldap2-dev libsasl2-dev gdebi-core libffi-dev libbz2-dev parallel pysassc swig cmake portaudio19-dev libcups2-dev xmlsec1 -y
|
||||||
retVal=$?
|
retVal=$?
|
||||||
if [[ $retVal -ne 0 ]]; then
|
if [[ $retVal -ne 0 ]]; then
|
||||||
echo "apt-get debian tool installation error."
|
echo "apt-get debian tool installation error."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
# shfmt : ABSENT des dépôts Ubuntu < 22.04. Il était dans le lot critique
|
||||||
|
# ci-dessus -> un seul paquet introuvable faisait échouer TOUT l'apt-get
|
||||||
|
# (donc pas de build-essential/gcc -> pyenv ne pouvait plus compiler Python).
|
||||||
|
# C'est un simple formateur shell (dev), non requis pour exécuter ERPLibre :
|
||||||
|
# on l'installe SÉPARÉMENT et en best-effort (jamais fatal).
|
||||||
|
${APT_GET} install shfmt -y \
|
||||||
|
|| echo "shfmt indisponible dans les dépôts (Ubuntu < 22.04 ?) — ignoré."
|
||||||
${APT_GET} install libmariadbd-dev freetds-dev -y
|
${APT_GET} install libmariadbd-dev freetds-dev -y
|
||||||
retVal=$?
|
retVal=$?
|
||||||
if [[ $retVal -ne 0 ]]; then
|
if [[ $retVal -ne 0 ]]; then
|
||||||
|
|
|
||||||
|
|
@ -1082,6 +1082,11 @@ class TODO:
|
||||||
{"prompt_description": t("Resize a VM disk")},
|
{"prompt_description": t("Resize a VM disk")},
|
||||||
{"prompt_description": t("Delete VM(s)")},
|
{"prompt_description": t("Delete VM(s)")},
|
||||||
{"prompt_description": t("Clean up QEMU (orphan files)")},
|
{"prompt_description": t("Clean up QEMU (orphan files)")},
|
||||||
|
{
|
||||||
|
"prompt_description": t(
|
||||||
|
"Test a VM (open Odoo in a CLI browser)"
|
||||||
|
)
|
||||||
|
},
|
||||||
{"section": t("Catalog")},
|
{"section": t("Catalog")},
|
||||||
{"prompt_description": t("List available images and specs")},
|
{"prompt_description": t("List available images and specs")},
|
||||||
]
|
]
|
||||||
|
|
@ -1114,6 +1119,8 @@ class TODO:
|
||||||
elif status == "9":
|
elif status == "9":
|
||||||
self._qemu_cleanup()
|
self._qemu_cleanup()
|
||||||
elif status == "10":
|
elif status == "10":
|
||||||
|
self._qemu_test_vm()
|
||||||
|
elif status == "11":
|
||||||
self._qemu_list_images()
|
self._qemu_list_images()
|
||||||
else:
|
else:
|
||||||
cmd_no_found = True
|
cmd_no_found = True
|
||||||
|
|
@ -1342,6 +1349,96 @@ class TODO:
|
||||||
print(f"{t('Will execute:')} {cmd}")
|
print(f"{t('Will execute:')} {cmd}")
|
||||||
self.execute.exec_command_live(cmd, source_erplibre=False)
|
self.execute.exec_command_live(cmd, source_erplibre=False)
|
||||||
|
|
||||||
|
def _qemu_test_vm(self):
|
||||||
|
"""Teste une VM : résout son IP puis ouvre Odoo (:8069) dans un
|
||||||
|
navigateur web EN LIGNE DE COMMANDE choisi par l'utilisateur."""
|
||||||
|
self._qemu_list_vms()
|
||||||
|
print()
|
||||||
|
name = input(t("VM name or ID: ")).strip()
|
||||||
|
if not name:
|
||||||
|
print(t("VM name is required!"))
|
||||||
|
return
|
||||||
|
real = self._qemu_domname(name)
|
||||||
|
if not self._qemu_domain_exists(real):
|
||||||
|
print(f"{real}: {t('VM not found.')}")
|
||||||
|
return
|
||||||
|
print(f"\n{t('Resolving VM IP...')}")
|
||||||
|
ip = self._qemu_vm_ip(real, timeout=120)
|
||||||
|
if not ip:
|
||||||
|
print(t("No IP found for this VM."))
|
||||||
|
return
|
||||||
|
browser = self._qemu_choose_cli_browser()
|
||||||
|
if not browser:
|
||||||
|
return
|
||||||
|
url = f"http://{ip}:8069"
|
||||||
|
print(f"→ {browser} {url}")
|
||||||
|
# os.system (et NON exec_command_live) : un navigateur texte a besoin
|
||||||
|
# du VRAI TTY interactif. exec_command_live redirige la sortie dans un
|
||||||
|
# tube -> le navigateur ne fait qu'imprimer sans réagir au clavier.
|
||||||
|
rc = os.system(f"{browser} {shlex.quote(url)}")
|
||||||
|
if rc != 0:
|
||||||
|
msg = t(
|
||||||
|
"Page may not have loaded: Odoo not started on :8069, "
|
||||||
|
"or network/firewall."
|
||||||
|
)
|
||||||
|
print(f"⚠ {msg}")
|
||||||
|
|
||||||
|
def _qemu_choose_cli_browser(self):
|
||||||
|
"""Offre la LISTE des navigateurs CLI installés, plus une option pour
|
||||||
|
en INSTALLER un autre, et renvoie celui choisi, sinon None."""
|
||||||
|
from script.todo.qemu_install_monitor import CLI_BROWSERS
|
||||||
|
|
||||||
|
available = [b for b in CLI_BROWSERS if shutil.which(b)]
|
||||||
|
if not available:
|
||||||
|
return self._qemu_install_cli_browser()
|
||||||
|
print(f"\n{t('Which browser to view the page?')}")
|
||||||
|
for i, b in enumerate(available, 1):
|
||||||
|
print(f" [{i}] {b}{' *' if i == 1 else ''}")
|
||||||
|
print(f" [i] {t('Install another browser')}")
|
||||||
|
sel = input(t("Choice (number, blank = first): ")).strip().lower()
|
||||||
|
if sel == "i":
|
||||||
|
return self._qemu_install_cli_browser()
|
||||||
|
if not sel:
|
||||||
|
return available[0]
|
||||||
|
try:
|
||||||
|
idx = int(sel) - 1
|
||||||
|
if 0 <= idx < len(available):
|
||||||
|
return available[idx]
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return available[0]
|
||||||
|
|
||||||
|
def _qemu_install_cli_browser(self):
|
||||||
|
"""Demande QUEL navigateur CLI installer, affiche la commande adaptée
|
||||||
|
à l'OS, l'exécute après validation. Renvoie le binaire installé ou
|
||||||
|
None."""
|
||||||
|
from script.todo.qemu_install_monitor import (
|
||||||
|
INSTALLABLE_BROWSERS,
|
||||||
|
browser_install_command,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"\n{t('Which browser to install?')}")
|
||||||
|
for i, (b, desc) in enumerate(INSTALLABLE_BROWSERS, 1):
|
||||||
|
print(f" [{i}] {desc}{' *' if i == 1 else ''}")
|
||||||
|
sel = input(t("Choice (number, blank = w3m): ")).strip()
|
||||||
|
browser = INSTALLABLE_BROWSERS[0][0]
|
||||||
|
try:
|
||||||
|
idx = int(sel) - 1
|
||||||
|
if 0 <= idx < len(INSTALLABLE_BROWSERS):
|
||||||
|
browser = INSTALLABLE_BROWSERS[idx][0]
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
cmd = browser_install_command(browser)
|
||||||
|
if not cmd:
|
||||||
|
print(t("Unknown package manager; install it manually."))
|
||||||
|
return None
|
||||||
|
printable = " ".join(cmd)
|
||||||
|
print(f"{t('Command:')} {printable}")
|
||||||
|
if not self._is_yes(input(t("Install now? (y/N): "))):
|
||||||
|
return None
|
||||||
|
os.system(printable)
|
||||||
|
return browser if shutil.which(browser) else None
|
||||||
|
|
||||||
# ------------------------------------------------------------------ #
|
# ------------------------------------------------------------------ #
|
||||||
# Redimensionnement du disque d'une VM
|
# Redimensionnement du disque d'une VM
|
||||||
# ------------------------------------------------------------------ #
|
# ------------------------------------------------------------------ #
|
||||||
|
|
@ -1472,6 +1569,10 @@ class TODO:
|
||||||
if not self._qemu_domain_exists(name):
|
if not self._qemu_domain_exists(name):
|
||||||
print(f"{name}: {t('VM not found.')}")
|
print(f"{name}: {t('VM not found.')}")
|
||||||
return
|
return
|
||||||
|
# Résout tout de suite le NOM canonique (VM encore allumée -> l'ID est
|
||||||
|
# résoluble). Après extinction, un ID numérique disparaît : « virsh
|
||||||
|
# start 32 » échouerait. On travaille désormais avec le nom.
|
||||||
|
name = self._qemu_domname(name)
|
||||||
disk = self._qemu_main_disk(name)
|
disk = self._qemu_main_disk(name)
|
||||||
if not disk:
|
if not disk:
|
||||||
print(t("Main disk not found for this VM."))
|
print(t("Main disk not found for this VM."))
|
||||||
|
|
@ -1583,8 +1684,9 @@ class TODO:
|
||||||
if self._is_yes(
|
if self._is_yes(
|
||||||
input(t("Start the VM now? (y/N): "))
|
input(t("Start the VM now? (y/N): "))
|
||||||
):
|
):
|
||||||
real = self._qemu_domname(name)
|
# `name` est déjà le nom canonique (résolu au début) : un
|
||||||
cmd = f"sudo virsh start {shlex.quote(real)}"
|
# « virsh start <id> » échouerait car l'ID a disparu.
|
||||||
|
cmd = f"sudo virsh start {shlex.quote(name)}"
|
||||||
print(f"{t('Will execute:')} {cmd}")
|
print(f"{t('Will execute:')} {cmd}")
|
||||||
self.execute.exec_command_live(cmd, source_erplibre=False)
|
self.execute.exec_command_live(cmd, source_erplibre=False)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1432,6 +1432,57 @@ TRANSLATIONS = {
|
||||||
"fr": "Aucune erreur détectée.",
|
"fr": "Aucune erreur détectée.",
|
||||||
"en": "No error detected.",
|
"en": "No error detected.",
|
||||||
},
|
},
|
||||||
|
"Test a VM (open Odoo in a CLI browser)": {
|
||||||
|
"fr": "🧪 Tester une VM (ouvrir Odoo dans un navigateur CLI)",
|
||||||
|
"en": "🧪 Test a VM (open Odoo in a CLI browser)",
|
||||||
|
},
|
||||||
|
"Resolving VM IP...": {
|
||||||
|
"fr": "Résolution de l'IP de la VM…",
|
||||||
|
"en": "Resolving VM IP...",
|
||||||
|
},
|
||||||
|
"No IP found for this VM.": {
|
||||||
|
"fr": "Aucune IP trouvée pour cette VM.",
|
||||||
|
"en": "No IP found for this VM.",
|
||||||
|
},
|
||||||
|
"No CLI browser installed. Which to install?": {
|
||||||
|
"fr": "Aucun navigateur CLI installé. Lequel installer ?",
|
||||||
|
"en": "No CLI browser installed. Which to install?",
|
||||||
|
},
|
||||||
|
"Which browser to install?": {
|
||||||
|
"fr": "Quel navigateur installer ?",
|
||||||
|
"en": "Which browser to install?",
|
||||||
|
},
|
||||||
|
"Install another browser": {
|
||||||
|
"fr": "Installer un autre navigateur",
|
||||||
|
"en": "Install another browser",
|
||||||
|
},
|
||||||
|
"Choice (number, blank = w3m): ": {
|
||||||
|
"fr": "Choix (numéro, vide = w3m) : ",
|
||||||
|
"en": "Choice (number, blank = w3m): ",
|
||||||
|
},
|
||||||
|
"Unknown package manager; install it manually.": {
|
||||||
|
"fr": "Gestionnaire de paquets inconnu ; installez-le manuellement.",
|
||||||
|
"en": "Unknown package manager; install it manually.",
|
||||||
|
},
|
||||||
|
"Install now? (y/N): ": {
|
||||||
|
"fr": "Installer maintenant ? (o/N) : ",
|
||||||
|
"en": "Install now? (y/N): ",
|
||||||
|
},
|
||||||
|
"Which browser to view the page?": {
|
||||||
|
"fr": "Quel navigateur pour voir la page ?",
|
||||||
|
"en": "Which browser to view the page?",
|
||||||
|
},
|
||||||
|
"Choice (number, blank = first): ": {
|
||||||
|
"fr": "Choix (numéro, vide = le premier) : ",
|
||||||
|
"en": "Choice (number, blank = first): ",
|
||||||
|
},
|
||||||
|
"Page may not have loaded: Odoo not started on :8069, "
|
||||||
|
"or network/firewall.": {
|
||||||
|
"fr": "La page ne s'est peut-être pas affichée : Odoo n'est pas "
|
||||||
|
"démarré sur :8069, ou réseau/pare-feu.",
|
||||||
|
"en": "Page may not have loaded: Odoo not started on :8069, "
|
||||||
|
"or network/firewall.",
|
||||||
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"fr": "erreurs",
|
"fr": "erreurs",
|
||||||
"en": "errors",
|
"en": "errors",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue