- Ticks ASYNCHRONES : les I/O bloquantes (lecture des logs, stat disque,
subprocess « virsh list », /proc) sont déportées en THREAD via
asyncio.to_thread ; seules les mises à jour d'UI restent sur la boucle
d'événements Textual -> plus de gel, même sous forte charge ou disque lent.
_collect_table (thread) rassemble statut+disque+télémétrie, l'application
au tableau se fait ensuite sur la boucle. _tick_log/_tick_domstate idem.
Helper _read_new (lecture incrémentale) réutilisé.
- Touche « w » : si aucun navigateur CLI n'est présent, on PROPOSE de
l'installer selon l'OS (apt Ubuntu/Debian, dnf Fedora, pacman Arch — nos 4
systèmes) : la commande est AFFICHÉE puis exécutée après validation (o/N).
Validé headless : ticks async mettent l'UI à jour ; browser_install_command
renvoie la bonne commande selon l'OS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pendant le suivi, une VM pouvait « stagner » sans qu'on sache pourquoi
(mise en pause, ou effacée à côté). Le dashboard interroge désormais l'état
libvirt (« virsh list --all ») à INTERVALLE LENT (toutes les 10 s, un seul
appel pour tout le parc ; le tableau applique le cache à chaque tick de 2 s) :
- VM en pause (virsh suspend) -> État « ⏸ pause » (non terminal, peut
reprendre).
- VM absente de virsh (effacée pendant l'attente) -> État « ❌ effacée »,
terminal (on cesse de lire son log).
Sinon on garde le statut basé sur le log (⏳ / ✅ / ❌).
Validé headless : running -> ⏳, paused -> ⏸ pause, absente -> ❌ effacée.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ajouts au suivi d'installation (dashboard Textual) :
- Télémétrie hôte (barre dédiée, MAJ 2 s) : CPU % = charge / nb CPU, et
disque du dossier des images (utilisé/total/libre) — utile pour anticiper
le remplissage du disque (cas vécu).
- Colonne « Disque » par VM : taille RÉELLE du qcow2 (st_blocks) -> on voit
quelle VM grossit.
- ETA « hypothèse » : les durées d'install sont MÉMORISÉES par architecture
dans ~/.erplibre/qemu-install/stats.json ; l'ETA du parc = médiane
historique (par arch, repli global) - temps écoulé, affichée au sous-titre.
- Touche « w » : ouvre l'UI web de la VM (Odoo :8069) dans un navigateur CLI
(browsh/carbonyl/w3m/links/elinks/lynx, le 1er trouvé ; sinon notifie quoi
installer). Surtout utile quand l'install est terminée.
Helpers module : load_stats/record_duration/eta_reference, _fmt_size/_fmt_secs,
vm_disk_path/disk_actual_size, cli_browser. run_monitor(run_app=False) expose
l'app pour test headless.
Validé headless (run_test) : montage, ticks, enregistrement des durées, ETA,
télémétrie, touches f/w — sans crash.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Encore du lag à 16 VM : update_cell était appelé pour CHAQUE ligne à chaque
tick (état + « Durée »), or la Durée — dérivée d'un `started` global — est
identique sur toutes les lignes et se réécrivait sans cesse -> re-render
permanent de la DataTable.
- _set_cell : n'appelle update_cell (donc ne re-render) que si la valeur
CHANGE. Mesuré : 312 -> 18 update_cell sur 10 ticks × 16 VM.
- La durée « live » passe dans le SOUS-TITRE (une seule mise à jour) ; la
colonne Durée n'est écrite qu'à la complétion (durée finale figée).
- Le NOMBRE de VM est affiché : titre « … (N VM) », sous-titre
« k/N terminées · mm:ss ».
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le TUI de suivi laggait à 30 VM et se figeait quand l'I/O ralentissait
(disque plein / logs effacés). Cause : à chaque tick (1 s) on lisait le
fichier log ENTIER de CHAQUE VM pour le statut + on relisait tout le log
sélectionné, en synchrone sur la boucle d'événements Textual.
Corrections :
- read_status ne lit que les 4 derniers Ko (le marqueur de sortie est sur
la dernière ligne) : un log de 2 Mo passe de « tout lire » à 0,1 ms.
- _load_selected_log lit de façon INCRÉMENTALE (seek à l'offset) au lieu de
relire tout le fichier.
- Les VM TERMINÉES ne sont plus relues (cache _final).
- _tick_table (2 s) et _tick_log (1 s) séparés et PROTÉGÉS par try/except :
une erreur I/O transitoire (disque plein, log supprimé) ne tue plus la
boucle -> l'interface reste réactive aux touches.
- RichLog borné (max_lines=5000).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le log d'installation commence désormais par un en-tête identifiant
l'installation : date, VM, distribution + version, architecture, branche, IP.
Écrit dès la création du log (plus jamais vide au démarrage).
_qemu_install_erplibre_monitored déduit distro/version/arch de chaque VM
(nom via _qemu_infra_name + arch via virsh dumpxml) et les passe à
launch_installs, qui écrit l'en-tête et les stocke dans le manifeste.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1) Nommage : _qemu_infra_name ajoute un suffixe d'architecture quand elle
diffère de la native de l'hôte -> déployer un s390x sur un hôte amd64
donne « erplibre-ubuntu-2604-s390x » (au lieu de « erplibre-ubuntu-2604 »).
Évite les collisions de noms entre archis et rend l'archi visible. Passé
dans les 3 appelants (VM unique + plan + jobs de l'infra).
2) Log d'installation vide : sur une archi ÉMULÉE (s390x/arm64 sur x86) le
boot prend plusieurs minutes ; pendant ce temps l'attente n'écrivait rien
-> le log restait VIDE et paraissait « bloqué ». _launch_one écrit
désormais un en-tête d'attente immédiat + un battement toutes les ~30 s,
et l'attente sshd/cloud-init passe de ~12 à ~20 min (boot émulé lent).
_qemu_wait_ssh (chemin streamé) : timeout porté à 20 min également.
Validé : nommage (amd64/natif sans suffixe, s390x/arm64 suffixés) ; le log
se remplit dès le départ (en-tête + « ... 30s »).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deux échecs d'install ERPLibre sur VM constatés dans les logs :
Arch — install_arch_linux.sh utilisait « yay » (helper AUR ABSENT d'une
image cloud et qui refuse de tourner en root) et n'installait JAMAIS
base-devel : sur une image cloud fraîche rien ne s'installait, donc pas de
compilateur C -> pyenv : « no acceptable C compiler found » -> build de
Python 3.12 échoué -> pas de venv -> pip/poetry/repo absents. Réécrit avec
pacman (dépôts officiels) : base-devel (gcc/make), deps de build pyenv
(openssl/zlib/xz/tk/…), PostgreSQL (+ initdb, Arch ne l'initialise pas),
Node/npm, deps Odoo en best-effort paquet par paquet (pacman refuse toute
la transaction sur un seul nom inconnu). wkhtmltopdf (AUR) : ignoré
proprement.
Fedora — « Connection closed by remote host » (exit 255) dès le début :
« cloud-init status --wait » tournait dans une session SSH UNIQUE tuée
quand cloud-init régénère les clés d'hôte et REDÉMARRE sshd au 1er boot.
On attend désormais la FIN de cloud-init via des connexions COURTES
successives (chaque tentative survit à un redémarrage de sshd), AVANT de
lancer l'install — dans les deux chemins : _qemu_wait_ssh (streamé) et
_launch_one (détaché/monitoré). On matche sur le TEXTE de « cloud-init
status » (done/disabled/error/degraded) car son code de sortie n'est pas
fiable selon la version.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dashboard: the info bar under the log now shows the selected VM's log
file path (in addition to its ssh command), so it can be opened/shared.
Install bootstrap: each package-manager branch first refreshes the repos
so the VM is as fast as possible, and Arch (pacman) is now supported:
- apt: apt-get update
- dnf: dnf makecache (dnf5 picks the fastest mirrors)
- pacman (Arch): reflector selects the 20 fastest HTTPS mirrors ->
pacman -Syy -> install curl/git/make (Arch was previously unsupported
by the bootstrap and would abort with "no package manager").
Validated live on the Arch VM: reflector + refresh + install all OK.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Root cause of "git/make: command not found": the bootstrap ran
"apt-get update -qq && apt-get install -y $PKGS". Inside an && list,
set -e does NOT abort on failure, so when apt-get update failed (flaky
VM network) the install was silently skipped and the script marched on
without git/make. Now: "apt-get update || true; apt-get install -y
$PKGS" (update best-effort, install mandatory), followed by an explicit
"command -v curl git make" check that exits with a clear message
("Outil manquant ... (reseau de la VM ?)") instead of a cryptic failure
later. Shared by the streamed and the monitored install paths.
Dashboard: add "c" to copy the selected VM's full log to the clipboard
(OSC 52, works over SSH) with a notification; the ssh bar documents
Shift+drag for native terminal selection; on close, print a ready-to-
copy "tail -n +1 <logdir>/*.log" to share the logs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deploying ERPLibre (single VM [1] and infra [4]) now asks "Interactive
monitoring dashboard?". When yes, the installs run DETACHED (setsid, one
log file + exit marker per VM) and a Textual dashboard opens:
- left: a table of VMs with live status (⏳ running / ✅ done / ❌ failed
with exit code) and elapsed time;
- right: the selected VM's log, tailed live (f toggles follow);
- footer: the VM's ssh command; s suspends the dashboard and SSHes in;
- q quits back to the menu — the installs keep running detached, so you
can leave before they finish and reopen later on the same log dir.
New module qemu_install_monitor.py holds the detached launcher and the
Textual app. The remote install script is factored into
_qemu_erplibre_remote_cmd. Falls back gracefully if textual is missing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>