[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
<!---------------------------->
|
|
|
|
|
|
<!-- multilingual suffix: en, fr -->
|
|
|
|
|
|
<!-- no suffix: en -->
|
|
|
|
|
|
<!---------------------------->
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
# QEMU/KVM — Linux VM deployment (Ubuntu / Debian / Fedora)
|
|
|
|
|
|
|
|
|
|
|
|
`deploy_qemu.py` deploys a Linux VM (libvirt/KVM) from an official cloud
|
|
|
|
|
|
image, using `qemu-img` + `cloud-init` + `virt-install`. Pick the
|
|
|
|
|
|
distribution with `--distro` (`ubuntu` default, `debian`, `fedora`) and the
|
|
|
|
|
|
release with `--version`; run `--list-images` to see the full catalogue with
|
|
|
|
|
|
minimum specs. It:
|
|
|
|
|
|
|
|
|
|
|
|
1. **Downloads the cloud image by itself** (cached, no double download).
|
|
|
|
|
|
2. Converts it to a dedicated qcow2 working disk and resizes it.
|
|
|
|
|
|
3. Generates `user-data` / `meta-data` and builds the `seed.iso` (cloud-init).
|
|
|
|
|
|
4. Runs `virt-install` importing the disk + the seed as a CD-ROM.
|
|
|
|
|
|
5. Waits for the DHCP lease and prints the SSH command.
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
# QEMU/KVM — Déploiement de VM Linux (Ubuntu / Debian / Fedora)
|
|
|
|
|
|
|
|
|
|
|
|
`deploy_qemu.py` déploie une VM Linux (libvirt/KVM) à partir d'une image
|
|
|
|
|
|
cloud officielle, via `qemu-img` + `cloud-init` + `virt-install`. Choisissez
|
|
|
|
|
|
la distribution avec `--distro` (`ubuntu` par défaut, `debian`, `fedora`) et
|
|
|
|
|
|
la version avec `--version` ; `--list-images` affiche tout le catalogue avec
|
|
|
|
|
|
les specs minimales. Il :
|
|
|
|
|
|
|
|
|
|
|
|
1. **Télécharge lui-même l'image cloud** (mise en cache, sans double
|
|
|
|
|
|
téléchargement).
|
|
|
|
|
|
2. La convertit en un disque de travail qcow2 dédié et le redimensionne.
|
|
|
|
|
|
3. Génère `user-data` / `meta-data` et construit le `seed.iso` (cloud-init).
|
|
|
|
|
|
4. Lance `virt-install` en important le disque + le seed en CD-ROM.
|
|
|
|
|
|
5. Attend le bail DHCP et affiche la commande SSH.
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
## Prerequisites
|
|
|
|
|
|
|
|
|
|
|
|
- A host with KVM available (bare-metal or nested virtualization enabled).
|
|
|
|
|
|
- `sudo` rights (the deployment writes to `/var/lib/libvirt/images` and drives
|
|
|
|
|
|
libvirt).
|
|
|
|
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
|
|
|
|
|
|
The script **auto-installs the missing pieces it needs**: on first run it
|
|
|
|
|
|
detects your package manager (apt / dnf / pacman / zypper / brew), lists the
|
|
|
|
|
|
missing components (the client tools, **plus the libvirt daemon and the QEMU
|
|
|
|
|
|
system emulator**), asks for confirmation, installs them with `sudo`, then
|
|
|
|
|
|
enables and starts `libvirtd`. Use `-y` to accept automatically or
|
|
|
|
|
|
`--no-install-deps` to disable this behaviour.
|
|
|
|
|
|
|
|
|
|
|
|
To install everything manually on Ubuntu/Debian (recommended full KVM stack):
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
## Prérequis
|
|
|
|
|
|
|
|
|
|
|
|
- Un hôte disposant de KVM (bare-metal ou virtualisation imbriquée activée).
|
|
|
|
|
|
- Les droits `sudo` (le déploiement écrit dans `/var/lib/libvirt/images` et
|
|
|
|
|
|
pilote libvirt).
|
|
|
|
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
|
|
|
|
|
|
Le script **installe automatiquement les composants manquants** : au premier
|
|
|
|
|
|
lancement, il détecte votre gestionnaire de paquets (apt / dnf / pacman /
|
|
|
|
|
|
zypper / brew), liste les composants absents (les outils clients, **ainsi que
|
|
|
|
|
|
le démon libvirt et l'émulateur QEMU système**), demande confirmation, les
|
|
|
|
|
|
installe avec `sudo`, puis active et démarre `libvirtd`. Utilisez `-y` pour
|
|
|
|
|
|
accepter automatiquement ou `--no-install-deps` pour désactiver ce
|
|
|
|
|
|
comportement.
|
|
|
|
|
|
|
|
|
|
|
|
Pour tout installer manuellement sur Ubuntu/Debian (pile KVM complète
|
|
|
|
|
|
recommandée) :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
sudo apt install qemu-utils virtinst libvirt-clients cloud-image-utils \
|
|
|
|
|
|
libvirt-daemon-system qemu-system-x86
|
|
|
|
|
|
sudo systemctl enable --now libvirtd
|
|
|
|
|
|
sudo usermod -aG libvirt,kvm "$USER" # re-login / reconnectez-vous
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
`libvirt-daemon-system` provides the `libvirtd` daemon (and the
|
|
|
|
|
|
`/var/run/libvirt/libvirt-sock` socket) and `qemu-system-x86` the emulator —
|
|
|
|
|
|
without them `virt-install` fails with *"Failed to connect socket to
|
|
|
|
|
|
'/var/run/libvirt/libvirt-sock'"*. The script installs and starts them for
|
|
|
|
|
|
you; this manual command is only needed if you prefer to prepare the host
|
|
|
|
|
|
yourself or run with `--no-install-deps`.
|
|
|
|
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
|
|
|
|
Simplest form — the image is downloaded automatically (path derived from
|
|
|
|
|
|
`--version`, cached in `/var/lib/libvirt/images/iso`):
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
`libvirt-daemon-system` fournit le démon `libvirtd` (et le socket
|
|
|
|
|
|
`/var/run/libvirt/libvirt-sock`) et `qemu-system-x86` l'émulateur — sans eux
|
|
|
|
|
|
`virt-install` échoue avec *« Failed to connect socket to
|
|
|
|
|
|
'/var/run/libvirt/libvirt-sock' »*. Le script les installe et les démarre pour
|
|
|
|
|
|
vous ; cette commande manuelle n'est utile que si vous préférez préparer
|
|
|
|
|
|
l'hôte vous-même ou utiliser `--no-install-deps`.
|
|
|
|
|
|
|
|
|
|
|
|
## Utilisation
|
|
|
|
|
|
|
|
|
|
|
|
Forme la plus simple — l'image est téléchargée automatiquement (chemin déduit
|
|
|
|
|
|
de `--version`, mis en cache dans `/var/lib/libvirt/images/iso`) :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --name test-vm --version 24.04 \
|
|
|
|
|
|
--ssh-key ~/.ssh/id_ed25519.pub
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
Download (and verify) an image without creating a VM:
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Télécharger (et vérifier) une image sans créer de VM :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --download-only --version 24.04 --verify
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
Deploy with an interactive password instead of an SSH key:
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Déployer avec un mot de passe interactif au lieu d'une clé SSH :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --name test-vm --version 24.04 --ask-password
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
Larger VM (8 GB RAM, 8 vCPU, 120 GB disk), overwriting an existing disk:
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
VM plus grande (8 Go RAM, 8 vCPU, disque 120 Go), en écrasant un disque
|
|
|
|
|
|
existant :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --name test-vm --version 24.04 \
|
|
|
|
|
|
--memory 8192 --vcpus 8 --disk-size 120G --ask-password --force
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
Preview what would happen, without doing anything (no sudo, no download):
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Prévisualiser ce qui serait fait, sans rien exécuter (sans sudo, sans
|
|
|
|
|
|
téléchargement) :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
./script/qemu/deploy_qemu.py --name test-vm --version 24.04 --dry-run
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
Non-interactive deployment (accept dependency install automatically):
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Déploiement non interactif (accepte automatiquement l'installation des
|
|
|
|
|
|
dépendances) :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --name test-vm --version 24.04 \
|
|
|
|
|
|
--ssh-key ~/.ssh/id_ed25519.pub -y
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
[UPD] support: drop Ubuntu 20.04/22.04, add AlmaLinux and Rocky
Ubuntu 20.04 and 22.04 leave EVERY architecture, not just s390x. pikepdf
needs qpdf 12.2, whose build requires C++20, while focal ships GCC 9 and
publishes no g++-10 for s390x at all. Python 3.8, node 10, cargo 0.67 and
OpenSSL 1.1.1 each had a workaround; the pile of them did not. 18.04
follows, already off the lists. The refusal lands before any apt, this
script also serving existing machines.
AlmaLinux 9 and 10, Rocky 9 and 10 join the catalog on all four
architectures: the twelve "latest" URLs were opened, with no index to
parse unlike Fedora. They would have booted unreachable though -- the
cloud-config forced "groups: users, sudo", but the RHEL family has no
sudo group, only wheel, and an unknown group makes useradd fail, hence no
password and no key. The very trap already known for Debian, repeated
elsewhere. Host side, EPEL and CRB are enabled: without them most -devel
packages are missing, silently.
The server / graphical choice gains Cinnamon, the Linux Mint desktop,
from the distribution's own repositories. Mint's repository is set aside:
plain HTTP, and i386/amd64 only, which would rule out arm64 and s390x.
Along the way, dnf now installs an ENVIRONMENT rather than a group --
"gnome-desktop" brings gdm and gnome-shell but not base-x, hence no X
server.
--- FR ---
Ubuntu 20.04 et 22.04 partent de TOUTES les architectures, pas seulement
de s390x. pikepdf réclame qpdf 12.2, dont la compilation exige C++20,
quand focal livre GCC 9 et ne publie même pas de g++-10 pour s390x.
Python 3.8, node 10, cargo 0.67 et OpenSSL 1.1.1 avaient chacun leur
contournement ; leur accumulation, non. 18.04 suit, déjà hors des
listes. Le refus tombe avant tout apt, ce script servant aussi les
machines existantes.
AlmaLinux 9 et 10, Rocky 9 et 10 entrent au catalogue, sur les quatre
architectures : les douze URL « latest » ont été ouvertes, aucun index à
analyser contrairement à Fedora. Elles auraient pourtant démarré
inaccessibles — le cloud-config imposait « groups: users, sudo », or la
famille RHEL n'a pas de groupe sudo mais wheel, et un groupe inconnu fait
échouer useradd, donc ni mot de passe ni clé. C'est le piège déjà connu
pour Debian, reproduit ailleurs. Côté hôte, EPEL et CRB sont activés :
sans eux la plupart des -devel manquent, en silence.
Le choix serveur / graphique gagne Cinnamon, le bureau de Linux Mint,
depuis les dépôts de la distribution. Le dépôt de Mint lui-même est
écarté : il est en HTTP nu et ne publie que i386 et amd64, ce qui
exclurait arm64 et s390x. Au passage, dnf installe désormais un
ENVIRONNEMENT et non un groupe — « gnome-desktop » apporte gdm et
gnome-shell mais pas base-x, donc pas de serveur X.
Assisted-by: Claude Opus 5
2026-08-11 18:46:11 -04:00
|
|
|
|
Catalog, per architecture (`deploy_qemu.py` is the source of truth):
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
|
[UPD] support: drop Ubuntu 20.04/22.04, add AlmaLinux and Rocky
Ubuntu 20.04 and 22.04 leave EVERY architecture, not just s390x. pikepdf
needs qpdf 12.2, whose build requires C++20, while focal ships GCC 9 and
publishes no g++-10 for s390x at all. Python 3.8, node 10, cargo 0.67 and
OpenSSL 1.1.1 each had a workaround; the pile of them did not. 18.04
follows, already off the lists. The refusal lands before any apt, this
script also serving existing machines.
AlmaLinux 9 and 10, Rocky 9 and 10 join the catalog on all four
architectures: the twelve "latest" URLs were opened, with no index to
parse unlike Fedora. They would have booted unreachable though -- the
cloud-config forced "groups: users, sudo", but the RHEL family has no
sudo group, only wheel, and an unknown group makes useradd fail, hence no
password and no key. The very trap already known for Debian, repeated
elsewhere. Host side, EPEL and CRB are enabled: without them most -devel
packages are missing, silently.
The server / graphical choice gains Cinnamon, the Linux Mint desktop,
from the distribution's own repositories. Mint's repository is set aside:
plain HTTP, and i386/amd64 only, which would rule out arm64 and s390x.
Along the way, dnf now installs an ENVIRONMENT rather than a group --
"gnome-desktop" brings gdm and gnome-shell but not base-x, hence no X
server.
--- FR ---
Ubuntu 20.04 et 22.04 partent de TOUTES les architectures, pas seulement
de s390x. pikepdf réclame qpdf 12.2, dont la compilation exige C++20,
quand focal livre GCC 9 et ne publie même pas de g++-10 pour s390x.
Python 3.8, node 10, cargo 0.67 et OpenSSL 1.1.1 avaient chacun leur
contournement ; leur accumulation, non. 18.04 suit, déjà hors des
listes. Le refus tombe avant tout apt, ce script servant aussi les
machines existantes.
AlmaLinux 9 et 10, Rocky 9 et 10 entrent au catalogue, sur les quatre
architectures : les douze URL « latest » ont été ouvertes, aucun index à
analyser contrairement à Fedora. Elles auraient pourtant démarré
inaccessibles — le cloud-config imposait « groups: users, sudo », or la
famille RHEL n'a pas de groupe sudo mais wheel, et un groupe inconnu fait
échouer useradd, donc ni mot de passe ni clé. C'est le piège déjà connu
pour Debian, reproduit ailleurs. Côté hôte, EPEL et CRB sont activés :
sans eux la plupart des -devel manquent, en silence.
Le choix serveur / graphique gagne Cinnamon, le bureau de Linux Mint,
depuis les dépôts de la distribution. Le dépôt de Mint lui-même est
écarté : il est en HTTP nu et ne publie que i386 et amd64, ce qui
exclurait arm64 et s390x. Au passage, dnf installe désormais un
ENVIRONNEMENT et non un groupe — « gnome-desktop » apporte gdm et
gnome-shell mais pas base-x, donc pas de serveur X.
Assisted-by: Claude Opus 5
2026-08-11 18:46:11 -04:00
|
|
|
|
| Distro | Versions | amd64 | arm64 | s390x |
|
|
|
|
|
|
|---|---|:-:|:-:|:-:|
|
|
|
|
|
|
| ubuntu | `24.04` (default), `25.10`, `26.04` | ✔ | ✔ | ✔ |
|
|
|
|
|
|
| debian | `11`, `12` (default), `13` | ✔ | ✔ | — |
|
[ADD] catalogue: Fedora 43 for s390x
Fedora does publish an s390x cloud image, just elsewhere: the arch is
SECONDARY there, its images live under "fedora-secondary" rather than
/pub/fedora/linux/. The catalog comment read "404" -- it was the wrong
tree.
It brings what nothing else has on this architecture: qpdf 12.2.0,
exactly the pikepdf 10 threshold. The qpdf build, half an hour under
emulation, disappears. With GCC 15, Python 3.14 and cargo 1.90, none of
the s390x workarounds fire there.
Only 43 is kept: Fedora builds s390x for the current release only. 41 and
42 return 404 on the master mirror, 44 sits on third-party mirrors only.
Hence a positive per-architecture declaration, read by both interfaces --
the catalog never offers what deployment would refuse.
--- FR ---
Fedora publie bien une image cloud s390x, mais ailleurs : l'architecture
est SECONDAIRE chez elle, ses images vivent sous « fedora-secondary » et
non sous /pub/fedora/linux/. Le commentaire du catalogue disait « 404 » —
c'était la mauvaise arborescence.
Elle apporte ce qu'aucune autre n'a sur cette architecture : qpdf 12.2.0,
soit exactement le seuil de pikepdf 10. La compilation de qpdf, une demi-
heure sous émulation, disparaît. Avec GCC 15, Python 3.14 et cargo 1.90,
aucun des contournements s390x ne s'y déclenche.
Seule la 43 est retenue : Fedora ne construit s390x que pour la version
courante. Les 41 et 42 rendent 404 sur le miroir maître, la 44 n'est que
sur certains miroirs tiers. D'où une déclaration positive par
architecture, que les deux interfaces relisent — le catalogue ne propose
pas ce que le déploiement refuserait.
Assisted-by: Claude Opus 5
2026-08-11 19:55:09 -04:00
|
|
|
|
| fedora | `41`, `42` (default), `43`, `44` | ✔ | ✔ | `43` only |
|
[UPD] support: drop Ubuntu 20.04/22.04, add AlmaLinux and Rocky
Ubuntu 20.04 and 22.04 leave EVERY architecture, not just s390x. pikepdf
needs qpdf 12.2, whose build requires C++20, while focal ships GCC 9 and
publishes no g++-10 for s390x at all. Python 3.8, node 10, cargo 0.67 and
OpenSSL 1.1.1 each had a workaround; the pile of them did not. 18.04
follows, already off the lists. The refusal lands before any apt, this
script also serving existing machines.
AlmaLinux 9 and 10, Rocky 9 and 10 join the catalog on all four
architectures: the twelve "latest" URLs were opened, with no index to
parse unlike Fedora. They would have booted unreachable though -- the
cloud-config forced "groups: users, sudo", but the RHEL family has no
sudo group, only wheel, and an unknown group makes useradd fail, hence no
password and no key. The very trap already known for Debian, repeated
elsewhere. Host side, EPEL and CRB are enabled: without them most -devel
packages are missing, silently.
The server / graphical choice gains Cinnamon, the Linux Mint desktop,
from the distribution's own repositories. Mint's repository is set aside:
plain HTTP, and i386/amd64 only, which would rule out arm64 and s390x.
Along the way, dnf now installs an ENVIRONMENT rather than a group --
"gnome-desktop" brings gdm and gnome-shell but not base-x, hence no X
server.
--- FR ---
Ubuntu 20.04 et 22.04 partent de TOUTES les architectures, pas seulement
de s390x. pikepdf réclame qpdf 12.2, dont la compilation exige C++20,
quand focal livre GCC 9 et ne publie même pas de g++-10 pour s390x.
Python 3.8, node 10, cargo 0.67 et OpenSSL 1.1.1 avaient chacun leur
contournement ; leur accumulation, non. 18.04 suit, déjà hors des
listes. Le refus tombe avant tout apt, ce script servant aussi les
machines existantes.
AlmaLinux 9 et 10, Rocky 9 et 10 entrent au catalogue, sur les quatre
architectures : les douze URL « latest » ont été ouvertes, aucun index à
analyser contrairement à Fedora. Elles auraient pourtant démarré
inaccessibles — le cloud-config imposait « groups: users, sudo », or la
famille RHEL n'a pas de groupe sudo mais wheel, et un groupe inconnu fait
échouer useradd, donc ni mot de passe ni clé. C'est le piège déjà connu
pour Debian, reproduit ailleurs. Côté hôte, EPEL et CRB sont activés :
sans eux la plupart des -devel manquent, en silence.
Le choix serveur / graphique gagne Cinnamon, le bureau de Linux Mint,
depuis les dépôts de la distribution. Le dépôt de Mint lui-même est
écarté : il est en HTTP nu et ne publie que i386 et amd64, ce qui
exclurait arm64 et s390x. Au passage, dnf installe désormais un
ENVIRONNEMENT et non un groupe — « gnome-desktop » apporte gdm et
gnome-shell mais pas base-x, donc pas de serveur X.
Assisted-by: Claude Opus 5
2026-08-11 18:46:11 -04:00
|
|
|
|
| almalinux | `9` (default), `10` | ✔ | ✔ | ✔ |
|
|
|
|
|
|
| rocky | `9`, `10` (default) | ✔ | ✔ | ✔ |
|
[ADD] qemu: openSUSE Leap 16.0, numbered, as the default
The catalogue only offered openSUSE Tumbleweed, a rolling release with
no version number. Nearly every openSUSE incident in this series came
from that: the cloud image is a snapshot lagging behind its own repos,
hence the mandatory "zypper dup", and two VMs deployed the same day saw
git-daemon 2.54 on s390x against 2.55 on amd64. For an ERP platform,
that is not what should be offered by default.
Leap 16.0 is numbered, stable, and publishes the three architectures
that matter -- verified, x86_64, aarch64 and s390x all 200. It also
unifies its tree: no separate /ports/, unlike Tumbleweed, whose
equivalent paths 404 for Leap.
Tumbleweed stays on offer, as a bellwether for breakage to come. Two
things separate them in the scripts: the repository path, and "dup" --
which on Leap means CHANGING version, not updating.
--- FR ---
Le catalogue n'offrait qu'openSUSE Tumbleweed, une rolling sans numéro
de version. Presque tous les incidents openSUSE de la série venaient de
là : l'image cloud est un instantané en retard sur ses dépôts, d'où le
« zypper dup » obligatoire, et deux VM déployées le même jour ont vu
git-daemon 2.54 sur s390x contre 2.55 sur amd64. Pour une plateforme
ERP, ce n'est pas ce qu'on veut proposer par défaut.
Leap 16.0 est numérotée, stable, et publie les trois architectures qui
comptent — vérifié, x86_64, aarch64 et s390x en 200. Elle unifie de plus
son arbre : pas de /ports/ séparé, contrairement à Tumbleweed, dont les
chemins équivalents rendent 404 pour Leap.
Tumbleweed reste offerte, comme banc d'essai des ruptures à venir.
Deux points les séparent dans les scripts : le chemin des dépôts, et
« dup » — qui sur Leap sert à CHANGER de version, pas à mettre à jour.
Assisted-by: Claude Opus 5
2026-08-12 01:16:17 -04:00
|
|
|
|
| opensuse | `16.0` (default), `tumbleweed` | ✔ | ✔ | ✔ |
|
[UPD] support: drop Ubuntu 20.04/22.04, add AlmaLinux and Rocky
Ubuntu 20.04 and 22.04 leave EVERY architecture, not just s390x. pikepdf
needs qpdf 12.2, whose build requires C++20, while focal ships GCC 9 and
publishes no g++-10 for s390x at all. Python 3.8, node 10, cargo 0.67 and
OpenSSL 1.1.1 each had a workaround; the pile of them did not. 18.04
follows, already off the lists. The refusal lands before any apt, this
script also serving existing machines.
AlmaLinux 9 and 10, Rocky 9 and 10 join the catalog on all four
architectures: the twelve "latest" URLs were opened, with no index to
parse unlike Fedora. They would have booted unreachable though -- the
cloud-config forced "groups: users, sudo", but the RHEL family has no
sudo group, only wheel, and an unknown group makes useradd fail, hence no
password and no key. The very trap already known for Debian, repeated
elsewhere. Host side, EPEL and CRB are enabled: without them most -devel
packages are missing, silently.
The server / graphical choice gains Cinnamon, the Linux Mint desktop,
from the distribution's own repositories. Mint's repository is set aside:
plain HTTP, and i386/amd64 only, which would rule out arm64 and s390x.
Along the way, dnf now installs an ENVIRONMENT rather than a group --
"gnome-desktop" brings gdm and gnome-shell but not base-x, hence no X
server.
--- FR ---
Ubuntu 20.04 et 22.04 partent de TOUTES les architectures, pas seulement
de s390x. pikepdf réclame qpdf 12.2, dont la compilation exige C++20,
quand focal livre GCC 9 et ne publie même pas de g++-10 pour s390x.
Python 3.8, node 10, cargo 0.67 et OpenSSL 1.1.1 avaient chacun leur
contournement ; leur accumulation, non. 18.04 suit, déjà hors des
listes. Le refus tombe avant tout apt, ce script servant aussi les
machines existantes.
AlmaLinux 9 et 10, Rocky 9 et 10 entrent au catalogue, sur les quatre
architectures : les douze URL « latest » ont été ouvertes, aucun index à
analyser contrairement à Fedora. Elles auraient pourtant démarré
inaccessibles — le cloud-config imposait « groups: users, sudo », or la
famille RHEL n'a pas de groupe sudo mais wheel, et un groupe inconnu fait
échouer useradd, donc ni mot de passe ni clé. C'est le piège déjà connu
pour Debian, reproduit ailleurs. Côté hôte, EPEL et CRB sont activés :
sans eux la plupart des -devel manquent, en silence.
Le choix serveur / graphique gagne Cinnamon, le bureau de Linux Mint,
depuis les dépôts de la distribution. Le dépôt de Mint lui-même est
écarté : il est en HTTP nu et ne publie que i386 et amd64, ce qui
exclurait arm64 et s390x. Au passage, dnf installe désormais un
ENVIRONNEMENT et non un groupe — « gnome-desktop » apporte gdm et
gnome-shell mais pas base-x, donc pas de serveur X.
Assisted-by: Claude Opus 5
2026-08-11 18:46:11 -04:00
|
|
|
|
| arch | `latest` | ✔ | — | — |
|
|
|
|
|
|
|
[ADD] catalogue: Fedora 43 for s390x
Fedora does publish an s390x cloud image, just elsewhere: the arch is
SECONDARY there, its images live under "fedora-secondary" rather than
/pub/fedora/linux/. The catalog comment read "404" -- it was the wrong
tree.
It brings what nothing else has on this architecture: qpdf 12.2.0,
exactly the pikepdf 10 threshold. The qpdf build, half an hour under
emulation, disappears. With GCC 15, Python 3.14 and cargo 1.90, none of
the s390x workarounds fire there.
Only 43 is kept: Fedora builds s390x for the current release only. 41 and
42 return 404 on the master mirror, 44 sits on third-party mirrors only.
Hence a positive per-architecture declaration, read by both interfaces --
the catalog never offers what deployment would refuse.
--- FR ---
Fedora publie bien une image cloud s390x, mais ailleurs : l'architecture
est SECONDAIRE chez elle, ses images vivent sous « fedora-secondary » et
non sous /pub/fedora/linux/. Le commentaire du catalogue disait « 404 » —
c'était la mauvaise arborescence.
Elle apporte ce qu'aucune autre n'a sur cette architecture : qpdf 12.2.0,
soit exactement le seuil de pikepdf 10. La compilation de qpdf, une demi-
heure sous émulation, disparaît. Avec GCC 15, Python 3.14 et cargo 1.90,
aucun des contournements s390x ne s'y déclenche.
Seule la 43 est retenue : Fedora ne construit s390x que pour la version
courante. Les 41 et 42 rendent 404 sur le miroir maître, la 44 n'est que
sur certains miroirs tiers. D'où une déclaration positive par
architecture, que les deux interfaces relisent — le catalogue ne propose
pas ce que le déploiement refuserait.
Assisted-by: Claude Opus 5
2026-08-11 19:55:09 -04:00
|
|
|
|
Fedora builds s390x only for the current release, and on a separate tree
|
|
|
|
|
|
(`fedora-secondary`) — hence the single version there.
|
|
|
|
|
|
|
[ADD] qemu: openSUSE Leap 16.0, numbered, as the default
The catalogue only offered openSUSE Tumbleweed, a rolling release with
no version number. Nearly every openSUSE incident in this series came
from that: the cloud image is a snapshot lagging behind its own repos,
hence the mandatory "zypper dup", and two VMs deployed the same day saw
git-daemon 2.54 on s390x against 2.55 on amd64. For an ERP platform,
that is not what should be offered by default.
Leap 16.0 is numbered, stable, and publishes the three architectures
that matter -- verified, x86_64, aarch64 and s390x all 200. It also
unifies its tree: no separate /ports/, unlike Tumbleweed, whose
equivalent paths 404 for Leap.
Tumbleweed stays on offer, as a bellwether for breakage to come. Two
things separate them in the scripts: the repository path, and "dup" --
which on Leap means CHANGING version, not updating.
--- FR ---
Le catalogue n'offrait qu'openSUSE Tumbleweed, une rolling sans numéro
de version. Presque tous les incidents openSUSE de la série venaient de
là : l'image cloud est un instantané en retard sur ses dépôts, d'où le
« zypper dup » obligatoire, et deux VM déployées le même jour ont vu
git-daemon 2.54 sur s390x contre 2.55 sur amd64. Pour une plateforme
ERP, ce n'est pas ce qu'on veut proposer par défaut.
Leap 16.0 est numérotée, stable, et publie les trois architectures qui
comptent — vérifié, x86_64, aarch64 et s390x en 200. Elle unifie de plus
son arbre : pas de /ports/ séparé, contrairement à Tumbleweed, dont les
chemins équivalents rendent 404 pour Leap.
Tumbleweed reste offerte, comme banc d'essai des ruptures à venir.
Deux points les séparent dans les scripts : le chemin des dépôts, et
« dup » — qui sur Leap sert à CHANGER de version, pas à mettre à jour.
Assisted-by: Claude Opus 5
2026-08-12 01:16:17 -04:00
|
|
|
|
`opensuse` covers two distinct products, not two versions of one. Leap `16.0`
|
|
|
|
|
|
is numbered and stable (SLE base) and is the default. `tumbleweed` is the
|
|
|
|
|
|
rolling one, kept as a bellwether for breakage to come: its snapshot drift is
|
|
|
|
|
|
real, and it demands a full `zypper dup` before anything can be installed.
|
|
|
|
|
|
|
|
|
|
|
|
Both ship a qpdf above the pikepdf threshold, so the half-hour qpdf build
|
|
|
|
|
|
never runs there — which matters under s390x emulation.
|
[ADD] install: openSUSE support, mirrors and packages
Tumbleweed is the only catalog entry whose qpdf already clears the pikepdf
threshold: 12.3.2 against 12.2 required, so the half-hour qpdf build under
s390x emulation never runs there. It is also the only family foreign to
both RHEL and Debian, and it brings zypper, absent from the repository:
wired into the install_dev.sh dispatch, a dependency script, the remote
bootstrap and the desktop block.
Four SUSE traps, all met on real machines. Global options precede the
subcommand, and misplaced ones abort the call; without
"--auto-agree-with-licenses" zypper waits for an answer nobody gives in a
detached install. A compat package that PROVIDES another under a different
name makes zypper raise a conflict and drop the whole batch, so only what
nothing already provides is requested. pkg-config no longer exists as an
RPM, only as a capability. And a single mirror, unreachable one day, sent
everyone back to Europe -- three are probed in order now.
CentOS Stream is dropped again: it served as a canary but 10 duplicates
what Alma and Rocky already cover.
--- FR ---
Tumbleweed est la seule entrée du catalogue dont qpdf franchit déjà le
seuil de pikepdf : 12.3.2 contre 12.2 exigé, si bien que la demi-heure de
compilation de qpdf sous émulation s390x ne s'y déclenche jamais. C'est
aussi la seule famille étrangère à RHEL comme à Debian, et elle apporte
zypper, absent du dépôt : câblé dans l'aiguillage d'install_dev.sh, un
script de dépendances, l'amorçage distant et le bloc bureau.
Quatre pièges SUSE, tous rencontrés sur machine réelle. Les options
globales précèdent la sous-commande, mal placées elles arrêtent l'appel ;
sans « --auto-agree-with-licenses » zypper attend une réponse que personne
ne donne dans une installation détachée. Un paquet compat qui FOURNIT un
autre sous un nom différent fait lever un conflit à zypper, qui abandonne
le lot entier : on ne demande donc que ce que rien ne fournit déjà.
pkg-config n'existe plus comme RPM, seulement comme capacité. Et un miroir
unique, injoignable un jour, renvoyait tout le monde en Europe — trois
sont désormais sondés dans l'ordre.
CentOS Stream repart : il servait de canari, mais 10 double ce qu'Alma et
Rocky couvrent déjà.
Assisted-by: Claude Opus 5
2026-08-11 20:38:12 -04:00
|
|
|
|
|
[UPD] support: drop Ubuntu 20.04/22.04, add AlmaLinux and Rocky
Ubuntu 20.04 and 22.04 leave EVERY architecture, not just s390x. pikepdf
needs qpdf 12.2, whose build requires C++20, while focal ships GCC 9 and
publishes no g++-10 for s390x at all. Python 3.8, node 10, cargo 0.67 and
OpenSSL 1.1.1 each had a workaround; the pile of them did not. 18.04
follows, already off the lists. The refusal lands before any apt, this
script also serving existing machines.
AlmaLinux 9 and 10, Rocky 9 and 10 join the catalog on all four
architectures: the twelve "latest" URLs were opened, with no index to
parse unlike Fedora. They would have booted unreachable though -- the
cloud-config forced "groups: users, sudo", but the RHEL family has no
sudo group, only wheel, and an unknown group makes useradd fail, hence no
password and no key. The very trap already known for Debian, repeated
elsewhere. Host side, EPEL and CRB are enabled: without them most -devel
packages are missing, silently.
The server / graphical choice gains Cinnamon, the Linux Mint desktop,
from the distribution's own repositories. Mint's repository is set aside:
plain HTTP, and i386/amd64 only, which would rule out arm64 and s390x.
Along the way, dnf now installs an ENVIRONMENT rather than a group --
"gnome-desktop" brings gdm and gnome-shell but not base-x, hence no X
server.
--- FR ---
Ubuntu 20.04 et 22.04 partent de TOUTES les architectures, pas seulement
de s390x. pikepdf réclame qpdf 12.2, dont la compilation exige C++20,
quand focal livre GCC 9 et ne publie même pas de g++-10 pour s390x.
Python 3.8, node 10, cargo 0.67 et OpenSSL 1.1.1 avaient chacun leur
contournement ; leur accumulation, non. 18.04 suit, déjà hors des
listes. Le refus tombe avant tout apt, ce script servant aussi les
machines existantes.
AlmaLinux 9 et 10, Rocky 9 et 10 entrent au catalogue, sur les quatre
architectures : les douze URL « latest » ont été ouvertes, aucun index à
analyser contrairement à Fedora. Elles auraient pourtant démarré
inaccessibles — le cloud-config imposait « groups: users, sudo », or la
famille RHEL n'a pas de groupe sudo mais wheel, et un groupe inconnu fait
échouer useradd, donc ni mot de passe ni clé. C'est le piège déjà connu
pour Debian, reproduit ailleurs. Côté hôte, EPEL et CRB sont activés :
sans eux la plupart des -devel manquent, en silence.
Le choix serveur / graphique gagne Cinnamon, le bureau de Linux Mint,
depuis les dépôts de la distribution. Le dépôt de Mint lui-même est
écarté : il est en HTTP nu et ne publie que i386 et amd64, ce qui
exclurait arm64 et s390x. Au passage, dnf installe désormais un
ENVIRONNEMENT et non un groupe — « gnome-desktop » apporte gdm et
gnome-shell mais pas base-x, donc pas de serveur X.
Assisted-by: Claude Opus 5
2026-08-11 18:46:11 -04:00
|
|
|
|
Provide an explicit image path as a positional argument to override the
|
|
|
|
|
|
automatic download location.
|
|
|
|
|
|
|
|
|
|
|
|
Ubuntu `20.04` and `22.04` were **dropped on every architecture**: pikepdf
|
|
|
|
|
|
needs qpdf 12.2, whose build requires C++20, and focal ships GCC 9 — it does
|
|
|
|
|
|
not even publish `g++-10` for s390x. Python 3.8, node 10, cargo 0.67 and
|
|
|
|
|
|
OpenSSL 1.1.1 each had a workaround; the pile of them did not.
|
[REM] install: drop Ubuntu 20.04 and 22.04
Two blockers on 20.04, neither worth carrying. "TypeError: unsupported
operand type(s) for |" fired before the install even started:
update_env_version.py imports erplibre_state as the very first thing
"make install_os" does, hence before pyenv, on the system Python 3.8,
where a "str | None" annotation is evaluated at import. And cryptography
now demands OpenSSL 3, while focal ships 1.1.1.
Annotations are therefore deferred, a contract the bootstrap file already
stated in a comment and now holds across script/version and
script/install. But the releases themselves go: pikepdf requires
qpdf >= 12.2, compiled in C++20, when focal ships GCC 9.
--- FR ---
Deux blocages sur 20.04, aucun ne méritant d'être porté. « TypeError:
unsupported operand type(s) for | » se déclenchait avant même le début de
l'installation : update_env_version.py importe erplibre_state en tout
premier lieu de « make install_os », donc avant pyenv, sur le Python 3.8
du système, où une annotation « str | None » est évaluée à l'import. Et
cryptography exige désormais OpenSSL 3, quand focal livre 1.1.1.
Les annotations sont donc différées, contrat que le fichier d'amorçage
énonçait déjà en commentaire et qui tient maintenant sur script/version et
script/install. Mais les versions elles-mêmes partent : pikepdf réclame
qpdf >= 12.2, compilé en C++20, quand focal livre GCC 9.
Assisted-by: Claude Opus 5
2026-08-11 08:03:32 -04:00
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
## After deployment
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
[UPD] support: drop Ubuntu 20.04/22.04, add AlmaLinux and Rocky
Ubuntu 20.04 and 22.04 leave EVERY architecture, not just s390x. pikepdf
needs qpdf 12.2, whose build requires C++20, while focal ships GCC 9 and
publishes no g++-10 for s390x at all. Python 3.8, node 10, cargo 0.67 and
OpenSSL 1.1.1 each had a workaround; the pile of them did not. 18.04
follows, already off the lists. The refusal lands before any apt, this
script also serving existing machines.
AlmaLinux 9 and 10, Rocky 9 and 10 join the catalog on all four
architectures: the twelve "latest" URLs were opened, with no index to
parse unlike Fedora. They would have booted unreachable though -- the
cloud-config forced "groups: users, sudo", but the RHEL family has no
sudo group, only wheel, and an unknown group makes useradd fail, hence no
password and no key. The very trap already known for Debian, repeated
elsewhere. Host side, EPEL and CRB are enabled: without them most -devel
packages are missing, silently.
The server / graphical choice gains Cinnamon, the Linux Mint desktop,
from the distribution's own repositories. Mint's repository is set aside:
plain HTTP, and i386/amd64 only, which would rule out arm64 and s390x.
Along the way, dnf now installs an ENVIRONMENT rather than a group --
"gnome-desktop" brings gdm and gnome-shell but not base-x, hence no X
server.
--- FR ---
Ubuntu 20.04 et 22.04 partent de TOUTES les architectures, pas seulement
de s390x. pikepdf réclame qpdf 12.2, dont la compilation exige C++20,
quand focal livre GCC 9 et ne publie même pas de g++-10 pour s390x.
Python 3.8, node 10, cargo 0.67 et OpenSSL 1.1.1 avaient chacun leur
contournement ; leur accumulation, non. 18.04 suit, déjà hors des
listes. Le refus tombe avant tout apt, ce script servant aussi les
machines existantes.
AlmaLinux 9 et 10, Rocky 9 et 10 entrent au catalogue, sur les quatre
architectures : les douze URL « latest » ont été ouvertes, aucun index à
analyser contrairement à Fedora. Elles auraient pourtant démarré
inaccessibles — le cloud-config imposait « groups: users, sudo », or la
famille RHEL n'a pas de groupe sudo mais wheel, et un groupe inconnu fait
échouer useradd, donc ni mot de passe ni clé. C'est le piège déjà connu
pour Debian, reproduit ailleurs. Côté hôte, EPEL et CRB sont activés :
sans eux la plupart des -devel manquent, en silence.
Le choix serveur / graphique gagne Cinnamon, le bureau de Linux Mint,
depuis les dépôts de la distribution. Le dépôt de Mint lui-même est
écarté : il est en HTTP nu et ne publie que i386 et amd64, ce qui
exclurait arm64 et s390x. Au passage, dnf installe désormais un
ENVIRONNEMENT et non un groupe — « gnome-desktop » apporte gdm et
gnome-shell mais pas base-x, donc pas de serveur X.
Assisted-by: Claude Opus 5
2026-08-11 18:46:11 -04:00
|
|
|
|
Catalogue, par architecture (`deploy_qemu.py` fait autorité) :
|
|
|
|
|
|
|
|
|
|
|
|
| Distro | Versions | amd64 | arm64 | s390x |
|
|
|
|
|
|
|---|---|:-:|:-:|:-:|
|
|
|
|
|
|
| ubuntu | `24.04` (défaut), `25.10`, `26.04` | ✔ | ✔ | ✔ |
|
|
|
|
|
|
| debian | `11`, `12` (défaut), `13` | ✔ | ✔ | — |
|
[ADD] catalogue: Fedora 43 for s390x
Fedora does publish an s390x cloud image, just elsewhere: the arch is
SECONDARY there, its images live under "fedora-secondary" rather than
/pub/fedora/linux/. The catalog comment read "404" -- it was the wrong
tree.
It brings what nothing else has on this architecture: qpdf 12.2.0,
exactly the pikepdf 10 threshold. The qpdf build, half an hour under
emulation, disappears. With GCC 15, Python 3.14 and cargo 1.90, none of
the s390x workarounds fire there.
Only 43 is kept: Fedora builds s390x for the current release only. 41 and
42 return 404 on the master mirror, 44 sits on third-party mirrors only.
Hence a positive per-architecture declaration, read by both interfaces --
the catalog never offers what deployment would refuse.
--- FR ---
Fedora publie bien une image cloud s390x, mais ailleurs : l'architecture
est SECONDAIRE chez elle, ses images vivent sous « fedora-secondary » et
non sous /pub/fedora/linux/. Le commentaire du catalogue disait « 404 » —
c'était la mauvaise arborescence.
Elle apporte ce qu'aucune autre n'a sur cette architecture : qpdf 12.2.0,
soit exactement le seuil de pikepdf 10. La compilation de qpdf, une demi-
heure sous émulation, disparaît. Avec GCC 15, Python 3.14 et cargo 1.90,
aucun des contournements s390x ne s'y déclenche.
Seule la 43 est retenue : Fedora ne construit s390x que pour la version
courante. Les 41 et 42 rendent 404 sur le miroir maître, la 44 n'est que
sur certains miroirs tiers. D'où une déclaration positive par
architecture, que les deux interfaces relisent — le catalogue ne propose
pas ce que le déploiement refuserait.
Assisted-by: Claude Opus 5
2026-08-11 19:55:09 -04:00
|
|
|
|
| fedora | `41`, `42` (défaut), `43`, `44` | ✔ | ✔ | `43` seule |
|
[UPD] support: drop Ubuntu 20.04/22.04, add AlmaLinux and Rocky
Ubuntu 20.04 and 22.04 leave EVERY architecture, not just s390x. pikepdf
needs qpdf 12.2, whose build requires C++20, while focal ships GCC 9 and
publishes no g++-10 for s390x at all. Python 3.8, node 10, cargo 0.67 and
OpenSSL 1.1.1 each had a workaround; the pile of them did not. 18.04
follows, already off the lists. The refusal lands before any apt, this
script also serving existing machines.
AlmaLinux 9 and 10, Rocky 9 and 10 join the catalog on all four
architectures: the twelve "latest" URLs were opened, with no index to
parse unlike Fedora. They would have booted unreachable though -- the
cloud-config forced "groups: users, sudo", but the RHEL family has no
sudo group, only wheel, and an unknown group makes useradd fail, hence no
password and no key. The very trap already known for Debian, repeated
elsewhere. Host side, EPEL and CRB are enabled: without them most -devel
packages are missing, silently.
The server / graphical choice gains Cinnamon, the Linux Mint desktop,
from the distribution's own repositories. Mint's repository is set aside:
plain HTTP, and i386/amd64 only, which would rule out arm64 and s390x.
Along the way, dnf now installs an ENVIRONMENT rather than a group --
"gnome-desktop" brings gdm and gnome-shell but not base-x, hence no X
server.
--- FR ---
Ubuntu 20.04 et 22.04 partent de TOUTES les architectures, pas seulement
de s390x. pikepdf réclame qpdf 12.2, dont la compilation exige C++20,
quand focal livre GCC 9 et ne publie même pas de g++-10 pour s390x.
Python 3.8, node 10, cargo 0.67 et OpenSSL 1.1.1 avaient chacun leur
contournement ; leur accumulation, non. 18.04 suit, déjà hors des
listes. Le refus tombe avant tout apt, ce script servant aussi les
machines existantes.
AlmaLinux 9 et 10, Rocky 9 et 10 entrent au catalogue, sur les quatre
architectures : les douze URL « latest » ont été ouvertes, aucun index à
analyser contrairement à Fedora. Elles auraient pourtant démarré
inaccessibles — le cloud-config imposait « groups: users, sudo », or la
famille RHEL n'a pas de groupe sudo mais wheel, et un groupe inconnu fait
échouer useradd, donc ni mot de passe ni clé. C'est le piège déjà connu
pour Debian, reproduit ailleurs. Côté hôte, EPEL et CRB sont activés :
sans eux la plupart des -devel manquent, en silence.
Le choix serveur / graphique gagne Cinnamon, le bureau de Linux Mint,
depuis les dépôts de la distribution. Le dépôt de Mint lui-même est
écarté : il est en HTTP nu et ne publie que i386 et amd64, ce qui
exclurait arm64 et s390x. Au passage, dnf installe désormais un
ENVIRONNEMENT et non un groupe — « gnome-desktop » apporte gdm et
gnome-shell mais pas base-x, donc pas de serveur X.
Assisted-by: Claude Opus 5
2026-08-11 18:46:11 -04:00
|
|
|
|
| almalinux | `9` (défaut), `10` | ✔ | ✔ | ✔ |
|
|
|
|
|
|
| rocky | `9`, `10` (défaut) | ✔ | ✔ | ✔ |
|
[ADD] qemu: openSUSE Leap 16.0, numbered, as the default
The catalogue only offered openSUSE Tumbleweed, a rolling release with
no version number. Nearly every openSUSE incident in this series came
from that: the cloud image is a snapshot lagging behind its own repos,
hence the mandatory "zypper dup", and two VMs deployed the same day saw
git-daemon 2.54 on s390x against 2.55 on amd64. For an ERP platform,
that is not what should be offered by default.
Leap 16.0 is numbered, stable, and publishes the three architectures
that matter -- verified, x86_64, aarch64 and s390x all 200. It also
unifies its tree: no separate /ports/, unlike Tumbleweed, whose
equivalent paths 404 for Leap.
Tumbleweed stays on offer, as a bellwether for breakage to come. Two
things separate them in the scripts: the repository path, and "dup" --
which on Leap means CHANGING version, not updating.
--- FR ---
Le catalogue n'offrait qu'openSUSE Tumbleweed, une rolling sans numéro
de version. Presque tous les incidents openSUSE de la série venaient de
là : l'image cloud est un instantané en retard sur ses dépôts, d'où le
« zypper dup » obligatoire, et deux VM déployées le même jour ont vu
git-daemon 2.54 sur s390x contre 2.55 sur amd64. Pour une plateforme
ERP, ce n'est pas ce qu'on veut proposer par défaut.
Leap 16.0 est numérotée, stable, et publie les trois architectures qui
comptent — vérifié, x86_64, aarch64 et s390x en 200. Elle unifie de plus
son arbre : pas de /ports/ séparé, contrairement à Tumbleweed, dont les
chemins équivalents rendent 404 pour Leap.
Tumbleweed reste offerte, comme banc d'essai des ruptures à venir.
Deux points les séparent dans les scripts : le chemin des dépôts, et
« dup » — qui sur Leap sert à CHANGER de version, pas à mettre à jour.
Assisted-by: Claude Opus 5
2026-08-12 01:16:17 -04:00
|
|
|
|
| opensuse | `16.0` (défaut), `tumbleweed` | ✔ | ✔ | ✔ |
|
[UPD] support: drop Ubuntu 20.04/22.04, add AlmaLinux and Rocky
Ubuntu 20.04 and 22.04 leave EVERY architecture, not just s390x. pikepdf
needs qpdf 12.2, whose build requires C++20, while focal ships GCC 9 and
publishes no g++-10 for s390x at all. Python 3.8, node 10, cargo 0.67 and
OpenSSL 1.1.1 each had a workaround; the pile of them did not. 18.04
follows, already off the lists. The refusal lands before any apt, this
script also serving existing machines.
AlmaLinux 9 and 10, Rocky 9 and 10 join the catalog on all four
architectures: the twelve "latest" URLs were opened, with no index to
parse unlike Fedora. They would have booted unreachable though -- the
cloud-config forced "groups: users, sudo", but the RHEL family has no
sudo group, only wheel, and an unknown group makes useradd fail, hence no
password and no key. The very trap already known for Debian, repeated
elsewhere. Host side, EPEL and CRB are enabled: without them most -devel
packages are missing, silently.
The server / graphical choice gains Cinnamon, the Linux Mint desktop,
from the distribution's own repositories. Mint's repository is set aside:
plain HTTP, and i386/amd64 only, which would rule out arm64 and s390x.
Along the way, dnf now installs an ENVIRONMENT rather than a group --
"gnome-desktop" brings gdm and gnome-shell but not base-x, hence no X
server.
--- FR ---
Ubuntu 20.04 et 22.04 partent de TOUTES les architectures, pas seulement
de s390x. pikepdf réclame qpdf 12.2, dont la compilation exige C++20,
quand focal livre GCC 9 et ne publie même pas de g++-10 pour s390x.
Python 3.8, node 10, cargo 0.67 et OpenSSL 1.1.1 avaient chacun leur
contournement ; leur accumulation, non. 18.04 suit, déjà hors des
listes. Le refus tombe avant tout apt, ce script servant aussi les
machines existantes.
AlmaLinux 9 et 10, Rocky 9 et 10 entrent au catalogue, sur les quatre
architectures : les douze URL « latest » ont été ouvertes, aucun index à
analyser contrairement à Fedora. Elles auraient pourtant démarré
inaccessibles — le cloud-config imposait « groups: users, sudo », or la
famille RHEL n'a pas de groupe sudo mais wheel, et un groupe inconnu fait
échouer useradd, donc ni mot de passe ni clé. C'est le piège déjà connu
pour Debian, reproduit ailleurs. Côté hôte, EPEL et CRB sont activés :
sans eux la plupart des -devel manquent, en silence.
Le choix serveur / graphique gagne Cinnamon, le bureau de Linux Mint,
depuis les dépôts de la distribution. Le dépôt de Mint lui-même est
écarté : il est en HTTP nu et ne publie que i386 et amd64, ce qui
exclurait arm64 et s390x. Au passage, dnf installe désormais un
ENVIRONNEMENT et non un groupe — « gnome-desktop » apporte gdm et
gnome-shell mais pas base-x, donc pas de serveur X.
Assisted-by: Claude Opus 5
2026-08-11 18:46:11 -04:00
|
|
|
|
| arch | `latest` | ✔ | — | — |
|
|
|
|
|
|
|
[ADD] catalogue: Fedora 43 for s390x
Fedora does publish an s390x cloud image, just elsewhere: the arch is
SECONDARY there, its images live under "fedora-secondary" rather than
/pub/fedora/linux/. The catalog comment read "404" -- it was the wrong
tree.
It brings what nothing else has on this architecture: qpdf 12.2.0,
exactly the pikepdf 10 threshold. The qpdf build, half an hour under
emulation, disappears. With GCC 15, Python 3.14 and cargo 1.90, none of
the s390x workarounds fire there.
Only 43 is kept: Fedora builds s390x for the current release only. 41 and
42 return 404 on the master mirror, 44 sits on third-party mirrors only.
Hence a positive per-architecture declaration, read by both interfaces --
the catalog never offers what deployment would refuse.
--- FR ---
Fedora publie bien une image cloud s390x, mais ailleurs : l'architecture
est SECONDAIRE chez elle, ses images vivent sous « fedora-secondary » et
non sous /pub/fedora/linux/. Le commentaire du catalogue disait « 404 » —
c'était la mauvaise arborescence.
Elle apporte ce qu'aucune autre n'a sur cette architecture : qpdf 12.2.0,
soit exactement le seuil de pikepdf 10. La compilation de qpdf, une demi-
heure sous émulation, disparaît. Avec GCC 15, Python 3.14 et cargo 1.90,
aucun des contournements s390x ne s'y déclenche.
Seule la 43 est retenue : Fedora ne construit s390x que pour la version
courante. Les 41 et 42 rendent 404 sur le miroir maître, la 44 n'est que
sur certains miroirs tiers. D'où une déclaration positive par
architecture, que les deux interfaces relisent — le catalogue ne propose
pas ce que le déploiement refuserait.
Assisted-by: Claude Opus 5
2026-08-11 19:55:09 -04:00
|
|
|
|
Fedora ne construit s390x que pour la version courante, et sur une
|
|
|
|
|
|
arborescence à part (`fedora-secondary`) — d'où la version unique.
|
|
|
|
|
|
|
[ADD] qemu: openSUSE Leap 16.0, numbered, as the default
The catalogue only offered openSUSE Tumbleweed, a rolling release with
no version number. Nearly every openSUSE incident in this series came
from that: the cloud image is a snapshot lagging behind its own repos,
hence the mandatory "zypper dup", and two VMs deployed the same day saw
git-daemon 2.54 on s390x against 2.55 on amd64. For an ERP platform,
that is not what should be offered by default.
Leap 16.0 is numbered, stable, and publishes the three architectures
that matter -- verified, x86_64, aarch64 and s390x all 200. It also
unifies its tree: no separate /ports/, unlike Tumbleweed, whose
equivalent paths 404 for Leap.
Tumbleweed stays on offer, as a bellwether for breakage to come. Two
things separate them in the scripts: the repository path, and "dup" --
which on Leap means CHANGING version, not updating.
--- FR ---
Le catalogue n'offrait qu'openSUSE Tumbleweed, une rolling sans numéro
de version. Presque tous les incidents openSUSE de la série venaient de
là : l'image cloud est un instantané en retard sur ses dépôts, d'où le
« zypper dup » obligatoire, et deux VM déployées le même jour ont vu
git-daemon 2.54 sur s390x contre 2.55 sur amd64. Pour une plateforme
ERP, ce n'est pas ce qu'on veut proposer par défaut.
Leap 16.0 est numérotée, stable, et publie les trois architectures qui
comptent — vérifié, x86_64, aarch64 et s390x en 200. Elle unifie de plus
son arbre : pas de /ports/ séparé, contrairement à Tumbleweed, dont les
chemins équivalents rendent 404 pour Leap.
Tumbleweed reste offerte, comme banc d'essai des ruptures à venir.
Deux points les séparent dans les scripts : le chemin des dépôts, et
« dup » — qui sur Leap sert à CHANGER de version, pas à mettre à jour.
Assisted-by: Claude Opus 5
2026-08-12 01:16:17 -04:00
|
|
|
|
`opensuse` recouvre deux produits distincts, pas deux versions du même. Leap
|
|
|
|
|
|
`16.0` est numérotée et stable (base SLE) : c'est le défaut. `tumbleweed` est
|
|
|
|
|
|
la rolling, gardée comme banc d'essai des ruptures à venir — sa dérive
|
|
|
|
|
|
d'instantanés est réelle, et elle impose un `zypper dup` complet avant toute
|
|
|
|
|
|
installation.
|
|
|
|
|
|
|
|
|
|
|
|
Les deux livrent un qpdf au-dessus du seuil de pikepdf : la compilation de
|
|
|
|
|
|
qpdf, une demi-heure, ne s'y déclenche jamais — ce qui compte sous émulation
|
|
|
|
|
|
s390x.
|
[ADD] install: openSUSE support, mirrors and packages
Tumbleweed is the only catalog entry whose qpdf already clears the pikepdf
threshold: 12.3.2 against 12.2 required, so the half-hour qpdf build under
s390x emulation never runs there. It is also the only family foreign to
both RHEL and Debian, and it brings zypper, absent from the repository:
wired into the install_dev.sh dispatch, a dependency script, the remote
bootstrap and the desktop block.
Four SUSE traps, all met on real machines. Global options precede the
subcommand, and misplaced ones abort the call; without
"--auto-agree-with-licenses" zypper waits for an answer nobody gives in a
detached install. A compat package that PROVIDES another under a different
name makes zypper raise a conflict and drop the whole batch, so only what
nothing already provides is requested. pkg-config no longer exists as an
RPM, only as a capability. And a single mirror, unreachable one day, sent
everyone back to Europe -- three are probed in order now.
CentOS Stream is dropped again: it served as a canary but 10 duplicates
what Alma and Rocky already cover.
--- FR ---
Tumbleweed est la seule entrée du catalogue dont qpdf franchit déjà le
seuil de pikepdf : 12.3.2 contre 12.2 exigé, si bien que la demi-heure de
compilation de qpdf sous émulation s390x ne s'y déclenche jamais. C'est
aussi la seule famille étrangère à RHEL comme à Debian, et elle apporte
zypper, absent du dépôt : câblé dans l'aiguillage d'install_dev.sh, un
script de dépendances, l'amorçage distant et le bloc bureau.
Quatre pièges SUSE, tous rencontrés sur machine réelle. Les options
globales précèdent la sous-commande, mal placées elles arrêtent l'appel ;
sans « --auto-agree-with-licenses » zypper attend une réponse que personne
ne donne dans une installation détachée. Un paquet compat qui FOURNIT un
autre sous un nom différent fait lever un conflit à zypper, qui abandonne
le lot entier : on ne demande donc que ce que rien ne fournit déjà.
pkg-config n'existe plus comme RPM, seulement comme capacité. Et un miroir
unique, injoignable un jour, renvoyait tout le monde en Europe — trois
sont désormais sondés dans l'ordre.
CentOS Stream repart : il servait de canari, mais 10 double ce qu'Alma et
Rocky couvrent déjà.
Assisted-by: Claude Opus 5
2026-08-11 20:38:12 -04:00
|
|
|
|
|
[UPD] support: drop Ubuntu 20.04/22.04, add AlmaLinux and Rocky
Ubuntu 20.04 and 22.04 leave EVERY architecture, not just s390x. pikepdf
needs qpdf 12.2, whose build requires C++20, while focal ships GCC 9 and
publishes no g++-10 for s390x at all. Python 3.8, node 10, cargo 0.67 and
OpenSSL 1.1.1 each had a workaround; the pile of them did not. 18.04
follows, already off the lists. The refusal lands before any apt, this
script also serving existing machines.
AlmaLinux 9 and 10, Rocky 9 and 10 join the catalog on all four
architectures: the twelve "latest" URLs were opened, with no index to
parse unlike Fedora. They would have booted unreachable though -- the
cloud-config forced "groups: users, sudo", but the RHEL family has no
sudo group, only wheel, and an unknown group makes useradd fail, hence no
password and no key. The very trap already known for Debian, repeated
elsewhere. Host side, EPEL and CRB are enabled: without them most -devel
packages are missing, silently.
The server / graphical choice gains Cinnamon, the Linux Mint desktop,
from the distribution's own repositories. Mint's repository is set aside:
plain HTTP, and i386/amd64 only, which would rule out arm64 and s390x.
Along the way, dnf now installs an ENVIRONMENT rather than a group --
"gnome-desktop" brings gdm and gnome-shell but not base-x, hence no X
server.
--- FR ---
Ubuntu 20.04 et 22.04 partent de TOUTES les architectures, pas seulement
de s390x. pikepdf réclame qpdf 12.2, dont la compilation exige C++20,
quand focal livre GCC 9 et ne publie même pas de g++-10 pour s390x.
Python 3.8, node 10, cargo 0.67 et OpenSSL 1.1.1 avaient chacun leur
contournement ; leur accumulation, non. 18.04 suit, déjà hors des
listes. Le refus tombe avant tout apt, ce script servant aussi les
machines existantes.
AlmaLinux 9 et 10, Rocky 9 et 10 entrent au catalogue, sur les quatre
architectures : les douze URL « latest » ont été ouvertes, aucun index à
analyser contrairement à Fedora. Elles auraient pourtant démarré
inaccessibles — le cloud-config imposait « groups: users, sudo », or la
famille RHEL n'a pas de groupe sudo mais wheel, et un groupe inconnu fait
échouer useradd, donc ni mot de passe ni clé. C'est le piège déjà connu
pour Debian, reproduit ailleurs. Côté hôte, EPEL et CRB sont activés :
sans eux la plupart des -devel manquent, en silence.
Le choix serveur / graphique gagne Cinnamon, le bureau de Linux Mint,
depuis les dépôts de la distribution. Le dépôt de Mint lui-même est
écarté : il est en HTTP nu et ne publie que i386 et amd64, ce qui
exclurait arm64 et s390x. Au passage, dnf installe désormais un
ENVIRONNEMENT et non un groupe — « gnome-desktop » apporte gdm et
gnome-shell mais pas base-x, donc pas de serveur X.
Assisted-by: Claude Opus 5
2026-08-11 18:46:11 -04:00
|
|
|
|
Fournissez un chemin d'image en argument positionnel pour surcharger
|
|
|
|
|
|
l'emplacement de téléchargement automatique.
|
|
|
|
|
|
|
|
|
|
|
|
Les Ubuntu `20.04` et `22.04` sont **abandonnées sur toutes les
|
|
|
|
|
|
architectures** : pikepdf réclame qpdf 12.2, dont la compilation exige C++20,
|
|
|
|
|
|
et focal livre GCC 9 — elle ne publie même pas de `g++-10` pour s390x. Python
|
|
|
|
|
|
3.8, node 10, cargo 0.67 et OpenSSL 1.1.1 avaient chacun leur contournement ;
|
|
|
|
|
|
leur accumulation, non.
|
[REM] install: drop Ubuntu 20.04 and 22.04
Two blockers on 20.04, neither worth carrying. "TypeError: unsupported
operand type(s) for |" fired before the install even started:
update_env_version.py imports erplibre_state as the very first thing
"make install_os" does, hence before pyenv, on the system Python 3.8,
where a "str | None" annotation is evaluated at import. And cryptography
now demands OpenSSL 3, while focal ships 1.1.1.
Annotations are therefore deferred, a contract the bootstrap file already
stated in a comment and now holds across script/version and
script/install. But the releases themselves go: pikepdf requires
qpdf >= 12.2, compiled in C++20, when focal ships GCC 9.
--- FR ---
Deux blocages sur 20.04, aucun ne méritant d'être porté. « TypeError:
unsupported operand type(s) for | » se déclenchait avant même le début de
l'installation : update_env_version.py importe erplibre_state en tout
premier lieu de « make install_os », donc avant pyenv, sur le Python 3.8
du système, où une annotation « str | None » est évaluée à l'import. Et
cryptography exige désormais OpenSSL 3, quand focal livre 1.1.1.
Les annotations sont donc différées, contrat que le fichier d'amorçage
énonçait déjà en commentaire et qui tient maintenant sur script/version et
script/install. Mais les versions elles-mêmes partent : pikepdf réclame
qpdf >= 12.2, compilé en C++20, quand focal livre GCC 9.
Assisted-by: Claude Opus 5
2026-08-11 08:03:32 -04:00
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
## Après le déploiement
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
virsh list --all
|
|
|
|
|
|
virsh console test-vm # Ctrl+] to quit / pour quitter
|
|
|
|
|
|
virsh domifaddr test-vm --source lease # find the IP / trouver l'IP
|
|
|
|
|
|
ssh erplibre@<IP>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
The default user is `erplibre` (change it with `--user`).
|
|
|
|
|
|
|
|
|
|
|
|
## Via the TODO menu
|
|
|
|
|
|
|
|
|
|
|
|
The script is integrated into the interactive assistant. Run `make todo` (or
|
|
|
|
|
|
`./script/todo/todo.py`), then go to **Execute → Deploy → QEMU/KVM - Deploy an
|
|
|
|
|
|
Ubuntu VM (libvirt)**. From there you can deploy a VM, preview a dry-run,
|
|
|
|
|
|
download an image, list VMs and show a VM IP address — the menu asks for the
|
|
|
|
|
|
parameters and builds the command for you.
|
|
|
|
|
|
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
When a VM is graphical, the menu also offers a **check list of development
|
[FIX] todo qemu: open the PyCharm project without a screen, and unlicensed
Two measurements, one after the other. The unified PyCharm that
code=PCC&latest now serves stops on its licence: the log says
NoValidIdeLicense then "Get licenses: request requires authentication", and
no project is ever opened — so no .idea, so nothing for the install to
configure. The Community line asks for no account and is still patched
(2025.2.6.2 on 2026-07-29); it is resolved from the release feed, so no
version is frozen here.
That build then froze 1.3 s after startup: the trust dialog, invisible under
Xvfb and waiting for a click. idea.trust.all.projects unblocks it. Checked
on an Ubuntu 26.04 VM: .idea complete in 195 s, and pycharm_configuration.py
writes its exclusions into erplibre.iml.
--- FR ---
Deux mesures, l'une après l'autre. Le PyCharm unifié que sert désormais
code=PCC&latest s'arrête sur sa licence : le journal dit NoValidIdeLicense
puis « Get licenses: request requires authentication », et aucun projet ne
s'ouvre — donc pas de .idea, donc rien à configurer pour l'installation. La
ligne Community ne demande aucun compte et reste corrigée (2025.2.6.2 le
2026-07-29) ; elle est résolue depuis le flux des versions, sans qu'aucun
numéro ne soit figé ici.
Ce build se figeait ensuite 1,3 s après le démarrage : la fenêtre de
confiance, invisible sous Xvfb et attendant un clic.
idea.trust.all.projects la lève. Vérifié sur une VM Ubuntu 26.04 : .idea
complet en 195 s, et pycharm_configuration.py écrit ses exclusions dans
erplibre.iml.
Assisted-by: Claude Opus 5
2026-08-17 23:22:38 -04:00
|
|
|
|
tools**: PyCharm Community (installed from the official
|
|
|
|
|
|
JetBrains archive into `/opt/pycharm`, its launcher opening the ERPLibre
|
|
|
|
|
|
checkout — the Community line, because the unified 2025.3 build stops on a
|
|
|
|
|
|
licence screen and never opens a project), Android
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
Studio (`/opt/android-studio`, command `studio` or `android-studio`; x86_64
|
|
|
|
|
|
only — Google publishes no Linux aarch64 build) and a set of suggested GNOME extensions.
|
|
|
|
|
|
|
|
|
|
|
|
The extension packages of the distribution are installed but left disabled —
|
|
|
|
|
|
their UUID is not reliably known, and the Extension Manager is there to pick
|
|
|
|
|
|
from. Three extensions named by UUID are installed **and enabled**, straight
|
|
|
|
|
|
from extensions.gnome.org: **gTile**, **Freon** and **Tracker**. The archive
|
|
|
|
|
|
is fetched for the GNOME Shell version actually running in the VM — the same
|
|
|
|
|
|
endpoint serves gTile v59 for GNOME 46 and v62 for GNOME 48, so a frozen URL
|
|
|
|
|
|
would install a build made for another release. A mismatched build is never
|
|
|
|
|
|
loaded by GNOME anyway: it compares `metadata.json` with its own version and
|
|
|
|
|
|
shows the extension as outdated rather than breaking the session.
|
|
|
|
|
|
|
|
|
|
|
|
The tools are installed **before** the clone and the ERPLibre install, and
|
|
|
|
|
|
the order matters: PyCharm writes the repository's `.idea/` the first time it
|
|
|
|
|
|
opens the project, and the install that follows runs
|
|
|
|
|
|
`pycharm_configuration.py` on it (`update_env_version.pycharm_update()`,
|
[FIX] todo qemu: open the PyCharm project without a screen, and unlicensed
Two measurements, one after the other. The unified PyCharm that
code=PCC&latest now serves stops on its licence: the log says
NoValidIdeLicense then "Get licenses: request requires authentication", and
no project is ever opened — so no .idea, so nothing for the install to
configure. The Community line asks for no account and is still patched
(2025.2.6.2 on 2026-07-29); it is resolved from the release feed, so no
version is frozen here.
That build then froze 1.3 s after startup: the trust dialog, invisible under
Xvfb and waiting for a click. idea.trust.all.projects unblocks it. Checked
on an Ubuntu 26.04 VM: .idea complete in 195 s, and pycharm_configuration.py
writes its exclusions into erplibre.iml.
--- FR ---
Deux mesures, l'une après l'autre. Le PyCharm unifié que sert désormais
code=PCC&latest s'arrête sur sa licence : le journal dit NoValidIdeLicense
puis « Get licenses: request requires authentication », et aucun projet ne
s'ouvre — donc pas de .idea, donc rien à configurer pour l'installation. La
ligne Community ne demande aucun compte et reste corrigée (2025.2.6.2 le
2026-07-29) ; elle est résolue depuis le flux des versions, sans qu'aucun
numéro ne soit figé ici.
Ce build se figeait ensuite 1,3 s après le démarrage : la fenêtre de
confiance, invisible sous Xvfb et attendant un clic.
idea.trust.all.projects la lève. Vérifié sur une VM Ubuntu 26.04 : .idea
complet en 195 s, et pycharm_configuration.py écrit ses exclusions dans
erplibre.iml.
Assisted-by: Claude Opus 5
2026-08-17 23:22:38 -04:00
|
|
|
|
which skips silently when there is no `.idea` yet). That first open is automated: PyCharm runs once under
|
|
|
|
|
|
Xvfb — a virtual framebuffer inside the guest, so the orchestrating host
|
|
|
|
|
|
needs no graphics at all — with the trust, privacy and data-sharing dialogs
|
|
|
|
|
|
answered in advance. Measured on an Ubuntu 26.04 VM with 16 GB: `.idea/` is
|
|
|
|
|
|
written in 195 s, and the install then adds its exclusions to the `.iml`.
|
|
|
|
|
|
When Xvfb is unavailable or the IDE does not get there in five minutes, the
|
|
|
|
|
|
log says so and the install carries on.
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
|
[ADD] todo qemu: build and test the mobile app, and fail the VM if it breaks
A VM was declared ready without anything proving it. The mobile option now
adds the repository to the manifest (additive, so it rides along an Odoo 18
install), runs the mobile repository's own install-android.sh — licences
accepted included — then npm ci, vite build, cap sync, gradlew assembleDebug
and npm test. A failure fails the VM: the exit code reaches the dashboard.
Two gaps in that upstream installer had to be filled: unzip and wget, which
no cloud image ships, and the SDK platform — it installs android-34 while
variables.gradle asks for compileSdk 36, so the number is read from the file
rather than frozen. Gradle writes tens of megabytes and hundreds of harmless
lines carrying the word error: that output goes to a file of its own, and the
log gets the named cause instead.
--- FR ---
Une VM était déclarée prête sans que rien ne le prouve. L'option mobile ajoute
maintenant le dépôt au manifeste (additif, donc il accompagne une installation
Odoo 18), lance l'install-android.sh du dépôt mobile lui-même — licences
acceptées comprises —, puis npm ci, vite build, cap sync, gradlew
assembleDebug et npm test. Un échec fait échouer la VM : le code de sortie
remonte au tableau de bord.
Deux manques de cet installateur amont ont dû être comblés : unzip et wget,
qu'aucune image cloud ne livre, et la plateforme SDK — il pose android-34
quand variables.gradle réclame compileSdk 36, d'où le chiffre lu dans le
fichier plutôt que figé. Gradle écrit des dizaines de mégaoctets et des
centaines de lignes anodines portant le mot error : cette sortie part dans un
fichier à part, et le journal reçoit la cause nommée.
Assisted-by: Claude Opus 5
2026-08-18 00:50:08 -04:00
|
|
|
|
A fourth one needs no desktop at all: **ERPLibre mobile (build)**. It adds
|
|
|
|
|
|
the mobile repository to the manifest (which is additive, so it coexists with
|
|
|
|
|
|
an Odoo 18 install), runs the repository's own `install-android.sh` — JDK 17,
|
|
|
|
|
|
command-line tools, SDK licences accepted, NDK, whisper.cpp and sentencepiece
|
|
|
|
|
|
— then builds: `npm ci`, `vite build`, `cap sync`, `gradlew assembleDebug`,
|
|
|
|
|
|
and finally `npm test`. **A failed build fails the VM**: the exit code reaches
|
2026-08-19 05:38:57 -04:00
|
|
|
|
the dashboard, and the log names the probable cause instead of leaving a
|
|
|
|
|
|
40 MB Gradle log to read: disk full, missing SDK platform, JDK/Gradle
|
|
|
|
|
|
mismatch, unaccepted licences, a Gradle daemon killed by the kernel (with the
|
|
|
|
|
|
machine's RAM, swap and oom-kill count, because a memory cause is proven and
|
[FIX] script todo: ne plus empaqueter les dépôts du manifeste dans l'APK
La compilation butait sur « Too many zip entries 123678 (MAX=65535) » : un APK
est un ZIP, et le dépôt mobile verse 122 684 fichiers d'assets pour 337 qui
sont l'application. Le levier existe et il est documenté chez lui
(doc/SERVICES.md) : ERPLIBRE_MANIFEST_PATH, ici pointé sur un manifeste vide —
« ces dépôts-là : aucun ». Le plugin l'annonce, « 0 repos ».
Mesuré sur erplibre-ubuntu-2604-gnome : dist passe de 123 019 fichiers à 336,
l'APK sort à 59 Mo et 2 472 entrées, et la phase mobile entière rend 0, tests
Vitest compris — 75 fichiers, 1938 tests. Qui veut les dépôts pose la variable
lui-même : elle est respectée. Mesure d'attente, à retirer quand ils tiendront
sous le plafond du ZIP.
--- EN ---
The build hit "Too many zip entries 123678 (MAX=65535)": an APK is a ZIP, and
the mobile repo pours 122,684 asset files in for 337 that are the application.
The lever exists and that repo documents it (doc/SERVICES.md):
ERPLIBRE_MANIFEST_PATH, pointed here at an empty manifest — "those repos:
none". The plugin says so itself, "0 repos".
Measured on erplibre-ubuntu-2604-gnome: dist drops from 123,019 files to 336,
the APK comes out at 59 MB with 2,472 entries, and the whole mobile phase
returns 0, Vitest included — 75 files, 1938 tests. Set the variable yourself
and the repos come back. A stopgap, to drop once they fit under the ZIP
ceiling.
Assisted-by: Claude Opus 5
2026-08-19 05:57:22 -04:00
|
|
|
|
not assumed), or too many asset files for one APK. The heavy output goes to
|
|
|
|
|
|
`~/erplibre-mobile-build.log` inside the VM so the install log stays readable.
|
|
|
|
|
|
|
[FIX] script mobile: transférer les dépôts ERPLibre dans l'APK, et le vérifier
Le contournement a vécu : les dépôts n'étaient plus embarqués du tout, l'APK
était refusé pour ses 123 678 entrées quand un ZIP en tient 65 535. Ils entrent
désormais en packs — tranches de 4 Mo et un index par dépôt disant où trouver
chaque fichier — ce qui ramène le compte à 391 entrées sans rien perdre du
contenu. Le côté application est dans le dépôt mobile ; ce commit porte la
vérification et retire le contournement.
Mesuré sur une VM : 139 dépôts, 116 156 fichiers, APK de 282 Mo à 3 002 entrées,
et 20 fichiers relus depuis les packs identiques octet pour octet à leur source.
L'installation le vérifie et échoue sinon : une application qui ne porte pas le
code qu'elle doit montrer n'est pas celle demandée.
--- EN ---
The stopgap has served its time: the repositories were not embedded at all, and
the APK was refused for its 123,678 entries where a ZIP holds 65,535. They now
enter as packs — 4 MB slices and one index per repository saying where each file
lives — which brings the count to 391 entries without losing any content. The
app side lives in the mobile repository; this commit carries the verification
and drops the workaround.
Measured on a VM: 139 repositories, 116,156 files, a 282 MB APK with 3,002
entries, and 20 files read back from the packs identical byte for byte to their
source. The install verifies it and fails otherwise: an app that does not carry
the code it must show is not the one that was asked for.
Assisted-by: Claude Opus 5
2026-08-20 03:51:14 -04:00
|
|
|
|
That last cause is fixed rather than avoided. The app carries the manifest
|
|
|
|
|
|
repositories so their code can be browsed offline, and an APK is a ZIP capped at
|
|
|
|
|
|
65535 entries — one file per source asked for 123 678 and the build stopped
|
|
|
|
|
|
there. Those files now enter as **packs**: 4 MB slices, plus an `index.json` per
|
|
|
|
|
|
repository saying which slice holds a file, at which offset and length. The
|
|
|
|
|
|
reader asks for a byte range, and falls back to the whole slice when the WebView
|
|
|
|
|
|
server ignores `Range` — 4 MB at worst, which is why the slices are bounded.
|
|
|
|
|
|
Raster images are left out: addon screenshots, in a browser that shows text.
|
|
|
|
|
|
|
[UPD] qemu doc: chiffrer le transfert tel qu'il est maintenant
Les images sont revenues dans les packs, les catalogues gettext en sont sortis :
80 841 fichiers en 233 tranches au lieu de 116 156 en 391, et un APK de 354 Mo
à 2 844 entrées. La doc portait les chiffres d'avant.
Elle dit aussi ce qui n'allait pas de soi : l'APK ne suit pas la charge. Le
texte se compresse, le PNG non — 857 Mo de .po coûtaient 152 Mo d'APK, quand
218 Mo d'images en coûtent 218. D'où les deux leviers, nommés.
--- EN ---
Images came back into the packs and gettext catalogues left: 80,841 files in 233
slices instead of 116,156 in 391, and a 354 MB APK with 2,844 entries. The doc
still carried the earlier figures.
It also states what was not obvious: the APK does not follow the payload. Text
compresses, PNG does not — 857 MB of .po cost 152 MB of APK, where 218 MB of
images cost 218. Hence the two knobs, named.
Assisted-by: Claude Opus 5
2026-08-21 20:53:53 -04:00
|
|
|
|
Images are packed too, and a packed file has no URL of its own: the reader turns
|
|
|
|
|
|
its bytes into a blob URL. Gettext catalogues, on the other hand, are dropped —
|
|
|
|
|
|
41 594 `.po`/`.pot` files weighing 857 MB, 72 % of the payload for content that
|
|
|
|
|
|
Weblate maintains and nobody reads on a phone. `BUNDLE_KEEP_PO=1` brings them
|
|
|
|
|
|
back, `BUNDLE_SKIP_IMG=1` drops the images.
|
|
|
|
|
|
|
|
|
|
|
|
Measured on a VM: 139 repositories, 80 841 files in 233 slices, an APK of 354 MB
|
|
|
|
|
|
with **2 844 entries**, and 20 files read back from the packs identical byte for
|
|
|
|
|
|
byte to their source. The APK does not follow the payload — text compresses,
|
|
|
|
|
|
PNG does not: the code alone is 331 MB of assets for about 130 MB of APK. The
|
|
|
|
|
|
install verifies the transfer with `script/mobile/check_bundle_transfer.py`,
|
|
|
|
|
|
which also runs on its own, and a failed transfer fails the VM — an app that
|
|
|
|
|
|
does not carry the code it is meant to show is not the app that was asked for.
|
[ADD] todo qemu: build and test the mobile app, and fail the VM if it breaks
A VM was declared ready without anything proving it. The mobile option now
adds the repository to the manifest (additive, so it rides along an Odoo 18
install), runs the mobile repository's own install-android.sh — licences
accepted included — then npm ci, vite build, cap sync, gradlew assembleDebug
and npm test. A failure fails the VM: the exit code reaches the dashboard.
Two gaps in that upstream installer had to be filled: unzip and wget, which
no cloud image ships, and the SDK platform — it installs android-34 while
variables.gradle asks for compileSdk 36, so the number is read from the file
rather than frozen. Gradle writes tens of megabytes and hundreds of harmless
lines carrying the word error: that output goes to a file of its own, and the
log gets the named cause instead.
--- FR ---
Une VM était déclarée prête sans que rien ne le prouve. L'option mobile ajoute
maintenant le dépôt au manifeste (additif, donc il accompagne une installation
Odoo 18), lance l'install-android.sh du dépôt mobile lui-même — licences
acceptées comprises —, puis npm ci, vite build, cap sync, gradlew
assembleDebug et npm test. Un échec fait échouer la VM : le code de sortie
remonte au tableau de bord.
Deux manques de cet installateur amont ont dû être comblés : unzip et wget,
qu'aucune image cloud ne livre, et la plateforme SDK — il pose android-34
quand variables.gradle réclame compileSdk 36, d'où le chiffre lu dans le
fichier plutôt que figé. Gradle écrit des dizaines de mégaoctets et des
centaines de lignes anodines portant le mot error : cette sortie part dans un
fichier à part, et le journal reçoit la cause nommée.
Assisted-by: Claude Opus 5
2026-08-18 00:50:08 -04:00
|
|
|
|
|
|
|
|
|
|
It is bounded to apt-based distributions, because that upstream installer
|
|
|
|
|
|
starts with `sudo apt install openjdk-17-jdk`. It requires no Android Studio
|
|
|
|
|
|
— a plain server VM builds the APK — and when Android Studio is also ticked
|
|
|
|
|
|
they share one SDK through `ANDROID_HOME`. Without Android, the same app runs
|
|
|
|
|
|
in a browser: `npm start`.
|
|
|
|
|
|
|
[FIX] qemu doc: donner une commande d'émulateur qui fonctionne
Les deux commandes documentées échouent. « emulator » sans chemin absolu rend
« command not found », parce qu'un `ssh hôte 'commande'` ne lit ni ~/.profile
ni ~/.bashrc — l'erreur a été rencontrée telle quelle. Et le rendu annoncé,
« swiftshader_indirect », n'existe plus : l'émulateur répond « Selected GPU
option is not valid » et le code pose « swangle » depuis un moment.
La doc pointe maintenant d'abord le menu de todo.py, qui démarre l'émulateur
sans fenêtre et donne le tunnel adb : scrcpy reçoit du H.264 encodé par
l'appareil, là où `ssh -X` fait traverser chaque image en pixels bruts.
--- EN ---
Both documented commands fail. Bare `emulator` gives "command not found",
because `ssh host 'command'` reads neither ~/.profile nor ~/.bashrc — the
error was hit exactly like that. And the advertised renderer,
`swiftshader_indirect`, no longer exists: the emulator answers "Selected GPU
option is not valid", and the code has been setting `swangle` for a while.
The doc now points at todo.py's menu first, which starts the emulator without
a window and hands over the adb tunnel: scrcpy receives H.264 encoded by the
device, where `ssh -X` ships every frame as raw pixels.
Assisted-by: Claude Opus 5
2026-08-19 03:37:31 -04:00
|
|
|
|
A fifth, **Android emulator (Pixel)**, creates an AVD. Drive it from the
|
|
|
|
|
|
QEMU menu, *Android emulator (start, tunnel, scrcpy)*: it starts the emulator
|
|
|
|
|
|
without a window and hands you the adb tunnel and the scrcpy command. Prefer
|
|
|
|
|
|
that to a window over X11 — scrcpy receives H.264 encoded by the device, where
|
|
|
|
|
|
`ssh -X` ships every frame as raw pixels in software rendering. If you do want
|
|
|
|
|
|
the window, the path must be absolute, because `ssh host 'command'` reads
|
|
|
|
|
|
neither `~/.profile` nor `~/.bashrc`:
|
|
|
|
|
|
`ssh -XC erplibre@<ip> '$HOME/android/emulator/emulator -avd erplibre -no-audio'`.
|
|
|
|
|
|
|
|
|
|
|
|
It needs no desktop in the VM, but it does need KVM inside the guest, so
|
|
|
|
|
|
nested virtualisation on the host; the log says so when `/dev/kvm` is missing.
|
|
|
|
|
|
The device is not frozen: the SDK is asked for its profiles and the newest
|
|
|
|
|
|
plain Pixel with the smallest screen wins (no Pro, XL, Fold or tablet).
|
|
|
|
|
|
Rendering is `swangle` in the AVD's own `config.ini` — `auto` would open a
|
|
|
|
|
|
black screen, and `swiftshader_indirect` no longer exists, the emulator
|
|
|
|
|
|
answering `Selected GPU option ... is not valid`.
|
[ADD] todo qemu: add an Android emulator, and fix what the real run exposed
Running it on a VM was the only way to find these. install_os never installed
python3-venv, so .venv.erplibre was born crippled — bin/python but no pip, no
activate — and everything downstream failed on "No module named git"; one line
of dependency fixes it. Capacitor 8 needs a JDK 21 where the mobile
repository's installer puts 17, and Gradle must RUN on it. That installer is
not idempotent either, so it is replayed only when something is missing.
The new emulator option creates an AVD from the SDK's own device list — the
newest plain Pixel, smallest screen — with software rendering written into its
config so ssh -X does not open a black screen, and adds the user to the kvm
group, without which it refuses to start. Checked on a VM: boot completed in
10 s, adb sees emulator-5554, Android 16 x86_64, no KVM refusal. Vitest: 1938
tests pass. The APK still fails, upstream: sentencepiece builds protoc for the
target then runs it on the host.
--- FR ---
Seule l'exécution sur une VM pouvait trouver ceci. install_os n'installait pas
python3-venv, si bien que .venv.erplibre naissait infirme — bin/python mais ni
pip ni activate — et tout ce qui en dépend tombait sur « No module named
git » ; une ligne de dépendance suffit. Capacitor 8 réclame un JDK 21 là où
l'installateur du dépôt mobile pose un 17, et Gradle doit TOURNER dessus. Cet
installateur n'est pas idempotent non plus : il n'est rejoué que s'il manque
quelque chose.
La nouvelle option crée un AVD depuis la liste de profils du SDK — le Pixel
simple le plus récent, plus petit écran —, écrit le rendu logiciel dans sa
configuration pour qu'ssh -X n'ouvre pas un écran noir, et ajoute
l'utilisateur au groupe kvm, sans quoi il refuse de démarrer. Vérifié sur une
VM : boot en 10 s, adb voit emulator-5554, Android 16 x86_64, aucun refus de
KVM. Vitest : 1938 tests passent. L'APK échoue encore, en amont :
sentencepiece bâtit protoc pour la cible puis l'exécute sur l'hôte.
Assisted-by: Claude Opus 5
2026-08-18 02:17:08 -04:00
|
|
|
|
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
|
A sixth, **Forgejo**, installs a self-hosted git forge — the software behind
|
|
|
|
|
|
Codeberg — from the project's official static binary, and leaves it serving on
|
|
|
|
|
|
port 3000 with git-over-SSH on 2222. Like the mobile build it needs no desktop,
|
|
|
|
|
|
and unlike it no package family is excluded: the binary is static, so the same
|
|
|
|
|
|
file serves apt, dnf, pacman and zypper. That is what makes it portable across
|
|
|
|
|
|
the ERPLibre platforms without a branch per distribution. Architectures follow
|
|
|
|
|
|
upstream, which publishes amd64, arm64 and arm-6 — the checkbox greys out on
|
|
|
|
|
|
s390x rather than dropping a binary that cannot run.
|
|
|
|
|
|
|
|
|
|
|
|
The work lives in `script/forgejo/install_forgejo.sh`, callable on its own for
|
|
|
|
|
|
an existing machine: `./script/forgejo/install_forgejo.sh`. It verifies the
|
|
|
|
|
|
published checksum, writes all four secrets itself so the service never needs
|
|
|
|
|
|
to rewrite its own configuration, and stores its data in SQLite so it does not
|
|
|
|
|
|
dispute PostgreSQL with Odoo on the same VM. Replaying it is cheap and safe —
|
|
|
|
|
|
1.5 s measured with everything in place: it skips a binary already at the right
|
|
|
|
|
|
version, never overwrites an existing `app.ini`, and does not recreate the
|
|
|
|
|
|
administrator. `FORGEJO_VERSION`, `FORGEJO_HTTP_PORT`, `FORGEJO_ADMIN_USER` and
|
|
|
|
|
|
a few others tune it; `--help` lists them.
|
|
|
|
|
|
|
[ADD] todo qemu: build and test the mobile app, and fail the VM if it breaks
A VM was declared ready without anything proving it. The mobile option now
adds the repository to the manifest (additive, so it rides along an Odoo 18
install), runs the mobile repository's own install-android.sh — licences
accepted included — then npm ci, vite build, cap sync, gradlew assembleDebug
and npm test. A failure fails the VM: the exit code reaches the dashboard.
Two gaps in that upstream installer had to be filled: unzip and wget, which
no cloud image ships, and the SDK platform — it installs android-34 while
variables.gradle asks for compileSdk 36, so the number is read from the file
rather than frozen. Gradle writes tens of megabytes and hundreds of harmless
lines carrying the word error: that output goes to a file of its own, and the
log gets the named cause instead.
--- FR ---
Une VM était déclarée prête sans que rien ne le prouve. L'option mobile ajoute
maintenant le dépôt au manifeste (additif, donc il accompagne une installation
Odoo 18), lance l'install-android.sh du dépôt mobile lui-même — licences
acceptées comprises —, puis npm ci, vite build, cap sync, gradlew
assembleDebug et npm test. Un échec fait échouer la VM : le code de sortie
remonte au tableau de bord.
Deux manques de cet installateur amont ont dû être comblés : unzip et wget,
qu'aucune image cloud ne livre, et la plateforme SDK — il pose android-34
quand variables.gradle réclame compileSdk 36, d'où le chiffre lu dans le
fichier plutôt que figé. Gradle écrit des dizaines de mégaoctets et des
centaines de lignes anodines portant le mot error : cette sortie part dans un
fichier à part, et le journal reçoit la cause nommée.
Assisted-by: Claude Opus 5
2026-08-18 00:50:08 -04:00
|
|
|
|
Each tool is filtered per VM — by architecture, desktop flavour and package
|
|
|
|
|
|
family — and its disk cost is added to the plan before anything is created.
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
## Main options
|
|
|
|
|
|
|
|
|
|
|
|
- `--distro` — `ubuntu` (default), `debian` or `fedora`.
|
|
|
|
|
|
- `--version` — release for the distro (default: the distro's default).
|
|
|
|
|
|
- `--list-images` — print all distros/versions and their specs, then exit.
|
|
|
|
|
|
- `--image-dir` — image cache directory (default `/var/lib/libvirt/images/iso`).
|
|
|
|
|
|
- `--download-only` — download the image then exit (no VM).
|
|
|
|
|
|
- `--name` — VM name (required for deployment).
|
|
|
|
|
|
- `--memory`, `--vcpus`, `--disk-size` — VM sizing. When omitted, `--memory`
|
|
|
|
|
|
and `--disk-size` default to the **minimum required by the chosen version**
|
|
|
|
|
|
(libosinfo values, see `--list-images`: Ubuntu 24.04+ → 3072 MB/20G, Debian
|
|
|
|
|
|
→ 1024 MB/10G, Fedora → 2048 MB/15G); `--vcpus` defaults to 2.
|
|
|
|
|
|
- `--ssh-key`, `--ask-password`, `--password-hash` — authentication.
|
|
|
|
|
|
- `-y` / `--assume-yes` — auto-accept dependency installation.
|
|
|
|
|
|
- `--no-install-deps` — never auto-install dependencies.
|
|
|
|
|
|
- `--dry-run` — show the commands without executing anything.
|
|
|
|
|
|
- `--force` — overwrite the existing working qcow2 disk.
|
[ADD] qemu : prendre le GPU de l'hôte, et régler le matériel des VM
Une VM graphique sans accélération rend tout par le processeur : le bureau,
et l'émulateur Android qui tourne dedans — 32 % d'images en retard, mesuré.
Le déploiement prend donc le GPU de l'hôte dès qu'un nœud de rendu existe.
Une VM déjà installée n'avait aucune voie : ni vCPU, ni RAM, ni 3D. Le menu
d'état les règle maintenant, pendant qu'elle est éteinte — le seul moment où
libvirt les lit.
Trois pièges du terrain : « --memory N » ne touche que le ballon, l'ajout
d'egl-headless n'est pas idempotent, et son retrait sans cible emporte la
console VNC. Vérifié sur un domaine jetable, 459 tests verts.
--- EN ---
A graphical VM without acceleration renders everything on the CPU: the
desktop, and the Android emulator inside it — 32 % janky frames, measured.
The deployment now takes the host GPU as soon as a render node exists.
An installed VM had no path at all: no vCPU, no RAM, no 3D. The state menu
now sets them while the VM is shut off — the only moment libvirt reads them.
Three field traps: "--memory N" only moves the balloon, adding egl-headless
is not idempotent, and removing it untargeted takes the VNC console with it.
Verified on a throwaway domain, 459 tests green.
Assisted-by: Claude Opus 5
2026-08-21 22:32:56 -04:00
|
|
|
|
- `--gpu` — 3D acceleration by the host GPU: `auto` (default, on when the
|
|
|
|
|
|
host has a render node), `on` (force), `off` (software rendering).
|
|
|
|
|
|
- `--gpu-node` — which render node to use, on a multi-GPU host.
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
- `--lang` — language of the SSH login guide, `fr` (default) or `en`. The
|
|
|
|
|
|
TODO menu passes its own language.
|
|
|
|
|
|
- `--erplibre-dir` — where ERPLibre will live in the VM
|
|
|
|
|
|
(`~/git/erplibre`, or `/opt/erplibre` in production). Adds the ERPLibre
|
|
|
|
|
|
section to the login guide; omitted, that section is left out.
|
|
|
|
|
|
- `--erplibre-make` — the make target that installed the VM
|
|
|
|
|
|
(e.g. `install_odoo_18`), shown in the guide as the way to update it.
|
|
|
|
|
|
- `--no-git-identity` — do not copy the host's `user.name`, `user.email`
|
|
|
|
|
|
and `core.editor` into the VM's `~/.gitconfig`.
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
|
|
|
|
|
|
Run `./script/qemu/deploy_qemu.py --help` for the full list.
|
|
|
|
|
|
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
## Login guide (`/etc/motd`)
|
|
|
|
|
|
|
|
|
|
|
|
Every VM greets you, at each interactive SSH login, with the commands of
|
|
|
|
|
|
**its own** distribution — `apt`, `dnf`, `zypper` or `pacman` — plus the
|
|
|
|
|
|
ERPLibre ones (edit the server, restart it, update modules, update Odoo,
|
|
|
|
|
|
inspect the instance, open the TODO menu). It is written by cloud-init, so
|
|
|
|
|
|
it is there from the first boot: before ERPLibre is installed, and still
|
|
|
|
|
|
there if that installation fails, which is exactly when you log in by hand.
|
|
|
|
|
|
|
|
|
|
|
|
`--dry-run` prints the generated guide along with the rest of the user-data.
|
|
|
|
|
|
The guide is not shown to `ssh host 'command'`, so it never pollutes an
|
|
|
|
|
|
installation log.
|
|
|
|
|
|
|
|
|
|
|
|
The host's git identity travels with it, into the VM's `~/.gitconfig`: a
|
|
|
|
|
|
commit made in the VM then carries your name instead of
|
|
|
|
|
|
`erplibre@<vm-name>`. The editor follows the same route — `core.editor`, the
|
|
|
|
|
|
`config.conf` line of the guide, and the package installed in the VM all
|
|
|
|
|
|
come from one table, so the guide never names a command the VM does not
|
|
|
|
|
|
have.
|
|
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
L'utilisateur par défaut est `erplibre` (modifiable avec `--user`).
|
|
|
|
|
|
|
|
|
|
|
|
## Via le menu TODO
|
|
|
|
|
|
|
|
|
|
|
|
Le script est intégré à l'assistant interactif. Lancez `make todo` (ou
|
|
|
|
|
|
`./script/todo/todo.py`), puis allez dans **Execute → Deploy → QEMU/KVM -
|
|
|
|
|
|
Deploy an Ubuntu VM (libvirt)**. De là, vous pouvez déployer une VM,
|
|
|
|
|
|
prévisualiser un dry-run, télécharger une image, lister les VM et afficher
|
|
|
|
|
|
l'IP d'une VM — le menu demande les paramètres et construit la commande pour
|
|
|
|
|
|
vous.
|
|
|
|
|
|
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
Quand une VM est graphique, le menu propose en plus une **liste à cocher
|
[FIX] todo qemu: open the PyCharm project without a screen, and unlicensed
Two measurements, one after the other. The unified PyCharm that
code=PCC&latest now serves stops on its licence: the log says
NoValidIdeLicense then "Get licenses: request requires authentication", and
no project is ever opened — so no .idea, so nothing for the install to
configure. The Community line asks for no account and is still patched
(2025.2.6.2 on 2026-07-29); it is resolved from the release feed, so no
version is frozen here.
That build then froze 1.3 s after startup: the trust dialog, invisible under
Xvfb and waiting for a click. idea.trust.all.projects unblocks it. Checked
on an Ubuntu 26.04 VM: .idea complete in 195 s, and pycharm_configuration.py
writes its exclusions into erplibre.iml.
--- FR ---
Deux mesures, l'une après l'autre. Le PyCharm unifié que sert désormais
code=PCC&latest s'arrête sur sa licence : le journal dit NoValidIdeLicense
puis « Get licenses: request requires authentication », et aucun projet ne
s'ouvre — donc pas de .idea, donc rien à configurer pour l'installation. La
ligne Community ne demande aucun compte et reste corrigée (2025.2.6.2 le
2026-07-29) ; elle est résolue depuis le flux des versions, sans qu'aucun
numéro ne soit figé ici.
Ce build se figeait ensuite 1,3 s après le démarrage : la fenêtre de
confiance, invisible sous Xvfb et attendant un clic.
idea.trust.all.projects la lève. Vérifié sur une VM Ubuntu 26.04 : .idea
complet en 195 s, et pycharm_configuration.py écrit ses exclusions dans
erplibre.iml.
Assisted-by: Claude Opus 5
2026-08-17 23:22:38 -04:00
|
|
|
|
d'outils de développement** : PyCharm Community (posé depuis l'archive
|
|
|
|
|
|
officielle JetBrains dans `/opt/pycharm`, son lanceur ouvrant le dépôt
|
|
|
|
|
|
ERPLibre — la ligne Community, car le build unifié 2025.3 s'arrête sur un
|
|
|
|
|
|
écran de licence et n'ouvre jamais de projet),
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
Android Studio (`/opt/android-studio`, commande `studio` ou
|
|
|
|
|
|
`android-studio` ; x86_64 seulement — Google ne publie aucune archive Linux
|
|
|
|
|
|
aarch64) et un jeu
|
|
|
|
|
|
d'extensions GNOME suggérées.
|
|
|
|
|
|
|
|
|
|
|
|
Les extensions empaquetées par la distribution sont installées sans être
|
|
|
|
|
|
activées — leur UUID n'est pas connu de façon fiable, et le gestionnaire
|
|
|
|
|
|
d'extensions est là pour choisir. Trois extensions nommées par leur UUID sont,
|
|
|
|
|
|
elles, installées **et activées**, directement depuis extensions.gnome.org :
|
|
|
|
|
|
**gTile**, **Freon** et **Tracker**. L'archive est prise pour la version de
|
|
|
|
|
|
GNOME Shell qui tourne vraiment dans la VM — le même point d'entrée sert gTile
|
|
|
|
|
|
v59 en GNOME 46 et v62 en GNOME 48, si bien qu'une URL figée poserait une
|
|
|
|
|
|
version faite pour une autre release. Une archive mal appariée n'est de toute
|
|
|
|
|
|
façon jamais chargée par GNOME : il compare `metadata.json` à sa propre
|
|
|
|
|
|
version et affiche l'extension comme obsolète plutôt que de casser la session.
|
|
|
|
|
|
|
|
|
|
|
|
Les outils sont posés **avant** le clone et l'installation d'ERPLibre, et
|
|
|
|
|
|
l'ordre compte : PyCharm écrit le `.idea/` du dépôt à la première ouverture du
|
|
|
|
|
|
projet, et l'installation qui suit y lance `pycharm_configuration.py`
|
|
|
|
|
|
(`update_env_version.pycharm_update()`, qui se tait tant qu'il n'y a pas de
|
[FIX] todo qemu: open the PyCharm project without a screen, and unlicensed
Two measurements, one after the other. The unified PyCharm that
code=PCC&latest now serves stops on its licence: the log says
NoValidIdeLicense then "Get licenses: request requires authentication", and
no project is ever opened — so no .idea, so nothing for the install to
configure. The Community line asks for no account and is still patched
(2025.2.6.2 on 2026-07-29); it is resolved from the release feed, so no
version is frozen here.
That build then froze 1.3 s after startup: the trust dialog, invisible under
Xvfb and waiting for a click. idea.trust.all.projects unblocks it. Checked
on an Ubuntu 26.04 VM: .idea complete in 195 s, and pycharm_configuration.py
writes its exclusions into erplibre.iml.
--- FR ---
Deux mesures, l'une après l'autre. Le PyCharm unifié que sert désormais
code=PCC&latest s'arrête sur sa licence : le journal dit NoValidIdeLicense
puis « Get licenses: request requires authentication », et aucun projet ne
s'ouvre — donc pas de .idea, donc rien à configurer pour l'installation. La
ligne Community ne demande aucun compte et reste corrigée (2025.2.6.2 le
2026-07-29) ; elle est résolue depuis le flux des versions, sans qu'aucun
numéro ne soit figé ici.
Ce build se figeait ensuite 1,3 s après le démarrage : la fenêtre de
confiance, invisible sous Xvfb et attendant un clic.
idea.trust.all.projects la lève. Vérifié sur une VM Ubuntu 26.04 : .idea
complet en 195 s, et pycharm_configuration.py écrit ses exclusions dans
erplibre.iml.
Assisted-by: Claude Opus 5
2026-08-17 23:22:38 -04:00
|
|
|
|
`.idea`). Cette première ouverture est automatisée : PyCharm est lancé une fois sous
|
|
|
|
|
|
Xvfb — un serveur d'affichage virtuel DANS la VM invitée, si bien que l'hôte
|
|
|
|
|
|
qui orchestre n'a besoin d'aucune bibliothèque graphique — avec les fenêtres
|
|
|
|
|
|
de confiance, de confidentialité et de partage de données répondues d'avance.
|
|
|
|
|
|
Mesuré sur une VM Ubuntu 26.04 à 16 Go : le `.idea/` est écrit en 195 s, et
|
|
|
|
|
|
l'installation y ajoute ensuite ses exclusions dans le `.iml`. Sans Xvfb, ou
|
|
|
|
|
|
si l'IDE n'y arrive pas en cinq minutes, le journal le dit et l'installation
|
|
|
|
|
|
continue.
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
|
[ADD] todo qemu: build and test the mobile app, and fail the VM if it breaks
A VM was declared ready without anything proving it. The mobile option now
adds the repository to the manifest (additive, so it rides along an Odoo 18
install), runs the mobile repository's own install-android.sh — licences
accepted included — then npm ci, vite build, cap sync, gradlew assembleDebug
and npm test. A failure fails the VM: the exit code reaches the dashboard.
Two gaps in that upstream installer had to be filled: unzip and wget, which
no cloud image ships, and the SDK platform — it installs android-34 while
variables.gradle asks for compileSdk 36, so the number is read from the file
rather than frozen. Gradle writes tens of megabytes and hundreds of harmless
lines carrying the word error: that output goes to a file of its own, and the
log gets the named cause instead.
--- FR ---
Une VM était déclarée prête sans que rien ne le prouve. L'option mobile ajoute
maintenant le dépôt au manifeste (additif, donc il accompagne une installation
Odoo 18), lance l'install-android.sh du dépôt mobile lui-même — licences
acceptées comprises —, puis npm ci, vite build, cap sync, gradlew
assembleDebug et npm test. Un échec fait échouer la VM : le code de sortie
remonte au tableau de bord.
Deux manques de cet installateur amont ont dû être comblés : unzip et wget,
qu'aucune image cloud ne livre, et la plateforme SDK — il pose android-34
quand variables.gradle réclame compileSdk 36, d'où le chiffre lu dans le
fichier plutôt que figé. Gradle écrit des dizaines de mégaoctets et des
centaines de lignes anodines portant le mot error : cette sortie part dans un
fichier à part, et le journal reçoit la cause nommée.
Assisted-by: Claude Opus 5
2026-08-18 00:50:08 -04:00
|
|
|
|
Un quatrième ne demande aucun bureau : **ERPLibre mobile (compilation)**. Il
|
|
|
|
|
|
ajoute le dépôt mobile au manifeste — additif, donc il cohabite avec une
|
|
|
|
|
|
installation Odoo 18 —, lance l'`install-android.sh` du dépôt lui-même (JDK 17,
|
|
|
|
|
|
outils en ligne de commande, licences SDK acceptées, NDK, whisper.cpp et
|
|
|
|
|
|
sentencepiece), puis compile : `npm ci`, `vite build`, `cap sync`,
|
|
|
|
|
|
`gradlew assembleDebug`, et enfin `npm test`. **Une compilation en échec fait
|
|
|
|
|
|
échouer la VM** : le code de sortie remonte au tableau de bord, et le journal
|
2026-08-19 05:38:57 -04:00
|
|
|
|
NOMME la cause probable au lieu de laisser 40 Mo de journal Gradle à relire :
|
|
|
|
|
|
disque plein, plateforme SDK absente, JDK et Gradle incompatibles, licences non
|
|
|
|
|
|
acceptées, démon Gradle tué par le noyau (avec la RAM, le swap et le compte de
|
|
|
|
|
|
l'oom-killer, parce qu'une cause « mémoire » se prouve au lieu de s'affirmer),
|
[FIX] script todo: ne plus empaqueter les dépôts du manifeste dans l'APK
La compilation butait sur « Too many zip entries 123678 (MAX=65535) » : un APK
est un ZIP, et le dépôt mobile verse 122 684 fichiers d'assets pour 337 qui
sont l'application. Le levier existe et il est documenté chez lui
(doc/SERVICES.md) : ERPLIBRE_MANIFEST_PATH, ici pointé sur un manifeste vide —
« ces dépôts-là : aucun ». Le plugin l'annonce, « 0 repos ».
Mesuré sur erplibre-ubuntu-2604-gnome : dist passe de 123 019 fichiers à 336,
l'APK sort à 59 Mo et 2 472 entrées, et la phase mobile entière rend 0, tests
Vitest compris — 75 fichiers, 1938 tests. Qui veut les dépôts pose la variable
lui-même : elle est respectée. Mesure d'attente, à retirer quand ils tiendront
sous le plafond du ZIP.
--- EN ---
The build hit "Too many zip entries 123678 (MAX=65535)": an APK is a ZIP, and
the mobile repo pours 122,684 asset files in for 337 that are the application.
The lever exists and that repo documents it (doc/SERVICES.md):
ERPLIBRE_MANIFEST_PATH, pointed here at an empty manifest — "those repos:
none". The plugin says so itself, "0 repos".
Measured on erplibre-ubuntu-2604-gnome: dist drops from 123,019 files to 336,
the APK comes out at 59 MB with 2,472 entries, and the whole mobile phase
returns 0, Vitest included — 75 files, 1938 tests. Set the variable yourself
and the repos come back. A stopgap, to drop once they fit under the ZIP
ceiling.
Assisted-by: Claude Opus 5
2026-08-19 05:57:22 -04:00
|
|
|
|
ou trop de fichiers d'assets pour un APK. Le détail va dans
|
|
|
|
|
|
`~/erplibre-mobile-build.log`, dans la VM, pour que le journal d'installation
|
|
|
|
|
|
reste lisible.
|
|
|
|
|
|
|
[FIX] script mobile: transférer les dépôts ERPLibre dans l'APK, et le vérifier
Le contournement a vécu : les dépôts n'étaient plus embarqués du tout, l'APK
était refusé pour ses 123 678 entrées quand un ZIP en tient 65 535. Ils entrent
désormais en packs — tranches de 4 Mo et un index par dépôt disant où trouver
chaque fichier — ce qui ramène le compte à 391 entrées sans rien perdre du
contenu. Le côté application est dans le dépôt mobile ; ce commit porte la
vérification et retire le contournement.
Mesuré sur une VM : 139 dépôts, 116 156 fichiers, APK de 282 Mo à 3 002 entrées,
et 20 fichiers relus depuis les packs identiques octet pour octet à leur source.
L'installation le vérifie et échoue sinon : une application qui ne porte pas le
code qu'elle doit montrer n'est pas celle demandée.
--- EN ---
The stopgap has served its time: the repositories were not embedded at all, and
the APK was refused for its 123,678 entries where a ZIP holds 65,535. They now
enter as packs — 4 MB slices and one index per repository saying where each file
lives — which brings the count to 391 entries without losing any content. The
app side lives in the mobile repository; this commit carries the verification
and drops the workaround.
Measured on a VM: 139 repositories, 116,156 files, a 282 MB APK with 3,002
entries, and 20 files read back from the packs identical byte for byte to their
source. The install verifies it and fails otherwise: an app that does not carry
the code it must show is not the one that was asked for.
Assisted-by: Claude Opus 5
2026-08-20 03:51:14 -04:00
|
|
|
|
Cette dernière cause est corrigée, et non contournée. L'application embarque les
|
|
|
|
|
|
dépôts du manifeste pour en parcourir le code hors ligne, et un APK est un ZIP
|
|
|
|
|
|
borné à 65535 entrées — un fichier par source en réclamait 123 678, et la
|
|
|
|
|
|
compilation s'arrêtait là. Ces fichiers y entrent désormais en **packs** :
|
|
|
|
|
|
des tranches de 4 Mo, plus un `index.json` par dépôt qui dit dans quelle tranche
|
|
|
|
|
|
se trouve un fichier, à quel offset et sur quelle longueur. La lecture demande
|
|
|
|
|
|
un intervalle d'octets, et retombe sur la tranche entière quand le serveur du
|
|
|
|
|
|
WebView ignore `Range` — 4 Mo au pire, et c'est pour cela que les tranches sont
|
|
|
|
|
|
bornées. Les images matricielles restent dehors : des captures d'écran
|
|
|
|
|
|
d'addons, dans un navigateur qui montre du texte.
|
|
|
|
|
|
|
[UPD] qemu doc: chiffrer le transfert tel qu'il est maintenant
Les images sont revenues dans les packs, les catalogues gettext en sont sortis :
80 841 fichiers en 233 tranches au lieu de 116 156 en 391, et un APK de 354 Mo
à 2 844 entrées. La doc portait les chiffres d'avant.
Elle dit aussi ce qui n'allait pas de soi : l'APK ne suit pas la charge. Le
texte se compresse, le PNG non — 857 Mo de .po coûtaient 152 Mo d'APK, quand
218 Mo d'images en coûtent 218. D'où les deux leviers, nommés.
--- EN ---
Images came back into the packs and gettext catalogues left: 80,841 files in 233
slices instead of 116,156 in 391, and a 354 MB APK with 2,844 entries. The doc
still carried the earlier figures.
It also states what was not obvious: the APK does not follow the payload. Text
compresses, PNG does not — 857 MB of .po cost 152 MB of APK, where 218 MB of
images cost 218. Hence the two knobs, named.
Assisted-by: Claude Opus 5
2026-08-21 20:53:53 -04:00
|
|
|
|
Les images sont empaquetées aussi, et un fichier empaqueté n'a pas d'URL propre :
|
|
|
|
|
|
le lecteur fait un blob de ses octets. Les catalogues gettext, en revanche, sont
|
|
|
|
|
|
écartés — 41 594 fichiers `.po`/`.pot` pour 857 Mo, soit 72 % du poids, d'un
|
|
|
|
|
|
contenu que Weblate maintient et que personne ne lit sur un téléphone.
|
|
|
|
|
|
`BUNDLE_KEEP_PO=1` les ramène, `BUNDLE_SKIP_IMG=1` retire les images.
|
|
|
|
|
|
|
|
|
|
|
|
Mesuré sur une VM : 139 dépôts, 80 841 fichiers en 233 tranches, un APK de
|
|
|
|
|
|
354 Mo à **2 844 entrées**, et 20 fichiers relus depuis les packs identiques
|
|
|
|
|
|
octet pour octet à leur source. L'APK ne suit pas la charge — le texte se
|
|
|
|
|
|
compresse, le PNG non : le code seul fait 331 Mo d'assets pour environ 130 Mo
|
|
|
|
|
|
d'APK. L'installation vérifie le transfert avec
|
[FIX] script mobile: transférer les dépôts ERPLibre dans l'APK, et le vérifier
Le contournement a vécu : les dépôts n'étaient plus embarqués du tout, l'APK
était refusé pour ses 123 678 entrées quand un ZIP en tient 65 535. Ils entrent
désormais en packs — tranches de 4 Mo et un index par dépôt disant où trouver
chaque fichier — ce qui ramène le compte à 391 entrées sans rien perdre du
contenu. Le côté application est dans le dépôt mobile ; ce commit porte la
vérification et retire le contournement.
Mesuré sur une VM : 139 dépôts, 116 156 fichiers, APK de 282 Mo à 3 002 entrées,
et 20 fichiers relus depuis les packs identiques octet pour octet à leur source.
L'installation le vérifie et échoue sinon : une application qui ne porte pas le
code qu'elle doit montrer n'est pas celle demandée.
--- EN ---
The stopgap has served its time: the repositories were not embedded at all, and
the APK was refused for its 123,678 entries where a ZIP holds 65,535. They now
enter as packs — 4 MB slices and one index per repository saying where each file
lives — which brings the count to 391 entries without losing any content. The
app side lives in the mobile repository; this commit carries the verification
and drops the workaround.
Measured on a VM: 139 repositories, 116,156 files, a 282 MB APK with 3,002
entries, and 20 files read back from the packs identical byte for byte to their
source. The install verifies it and fails otherwise: an app that does not carry
the code it must show is not the one that was asked for.
Assisted-by: Claude Opus 5
2026-08-20 03:51:14 -04:00
|
|
|
|
`script/mobile/check_bundle_transfer.py`, qui s'exécute aussi seul, et un
|
|
|
|
|
|
transfert manqué fait échouer la VM — une application qui ne porte pas le code
|
|
|
|
|
|
qu'elle est censée montrer n'est pas l'application demandée.
|
[ADD] todo qemu: build and test the mobile app, and fail the VM if it breaks
A VM was declared ready without anything proving it. The mobile option now
adds the repository to the manifest (additive, so it rides along an Odoo 18
install), runs the mobile repository's own install-android.sh — licences
accepted included — then npm ci, vite build, cap sync, gradlew assembleDebug
and npm test. A failure fails the VM: the exit code reaches the dashboard.
Two gaps in that upstream installer had to be filled: unzip and wget, which
no cloud image ships, and the SDK platform — it installs android-34 while
variables.gradle asks for compileSdk 36, so the number is read from the file
rather than frozen. Gradle writes tens of megabytes and hundreds of harmless
lines carrying the word error: that output goes to a file of its own, and the
log gets the named cause instead.
--- FR ---
Une VM était déclarée prête sans que rien ne le prouve. L'option mobile ajoute
maintenant le dépôt au manifeste (additif, donc il accompagne une installation
Odoo 18), lance l'install-android.sh du dépôt mobile lui-même — licences
acceptées comprises —, puis npm ci, vite build, cap sync, gradlew
assembleDebug et npm test. Un échec fait échouer la VM : le code de sortie
remonte au tableau de bord.
Deux manques de cet installateur amont ont dû être comblés : unzip et wget,
qu'aucune image cloud ne livre, et la plateforme SDK — il pose android-34
quand variables.gradle réclame compileSdk 36, d'où le chiffre lu dans le
fichier plutôt que figé. Gradle écrit des dizaines de mégaoctets et des
centaines de lignes anodines portant le mot error : cette sortie part dans un
fichier à part, et le journal reçoit la cause nommée.
Assisted-by: Claude Opus 5
2026-08-18 00:50:08 -04:00
|
|
|
|
|
|
|
|
|
|
Il est borné aux distributions apt, parce que cet installateur amont commence
|
|
|
|
|
|
par `sudo apt install openjdk-17-jdk`. Il n'exige PAS Android Studio — une
|
|
|
|
|
|
simple VM serveur produit l'APK — et quand Android Studio est aussi coché, les
|
|
|
|
|
|
deux partagent un seul SDK via `ANDROID_HOME`. Sans Android, la même
|
|
|
|
|
|
application tourne dans un navigateur : `npm start`.
|
|
|
|
|
|
|
[FIX] qemu doc: donner une commande d'émulateur qui fonctionne
Les deux commandes documentées échouent. « emulator » sans chemin absolu rend
« command not found », parce qu'un `ssh hôte 'commande'` ne lit ni ~/.profile
ni ~/.bashrc — l'erreur a été rencontrée telle quelle. Et le rendu annoncé,
« swiftshader_indirect », n'existe plus : l'émulateur répond « Selected GPU
option is not valid » et le code pose « swangle » depuis un moment.
La doc pointe maintenant d'abord le menu de todo.py, qui démarre l'émulateur
sans fenêtre et donne le tunnel adb : scrcpy reçoit du H.264 encodé par
l'appareil, là où `ssh -X` fait traverser chaque image en pixels bruts.
--- EN ---
Both documented commands fail. Bare `emulator` gives "command not found",
because `ssh host 'command'` reads neither ~/.profile nor ~/.bashrc — the
error was hit exactly like that. And the advertised renderer,
`swiftshader_indirect`, no longer exists: the emulator answers "Selected GPU
option is not valid", and the code has been setting `swangle` for a while.
The doc now points at todo.py's menu first, which starts the emulator without
a window and hands over the adb tunnel: scrcpy receives H.264 encoded by the
device, where `ssh -X` ships every frame as raw pixels.
Assisted-by: Claude Opus 5
2026-08-19 03:37:31 -04:00
|
|
|
|
Un cinquième, **Émulateur Android (Pixel)**, crée un AVD. Conduisez-le depuis
|
|
|
|
|
|
le menu QEMU, *Émulateur Android (démarrage, tunnel, scrcpy)* : il démarre
|
|
|
|
|
|
l'émulateur sans fenêtre, puis donne le tunnel adb et la commande scrcpy.
|
|
|
|
|
|
Préférez cette voie à une fenêtre par X11 — scrcpy reçoit du H.264 encodé PAR
|
|
|
|
|
|
l'appareil, là où `ssh -X` fait traverser chaque image en pixels bruts, en
|
|
|
|
|
|
rendu logiciel. Si vous voulez la fenêtre, le chemin doit être ABSOLU, car
|
|
|
|
|
|
`ssh hôte 'commande'` ne lit ni `~/.profile` ni `~/.bashrc` :
|
|
|
|
|
|
`ssh -XC erplibre@<ip> '$HOME/android/emulator/emulator -avd erplibre -no-audio'`.
|
|
|
|
|
|
|
|
|
|
|
|
Il ne demande aucun bureau dans la VM, mais il exige KVM dans l'invitée, donc
|
|
|
|
|
|
la virtualisation imbriquée sur l'hôte ; le journal le dit quand `/dev/kvm`
|
[ADD] todo qemu: add an Android emulator, and fix what the real run exposed
Running it on a VM was the only way to find these. install_os never installed
python3-venv, so .venv.erplibre was born crippled — bin/python but no pip, no
activate — and everything downstream failed on "No module named git"; one line
of dependency fixes it. Capacitor 8 needs a JDK 21 where the mobile
repository's installer puts 17, and Gradle must RUN on it. That installer is
not idempotent either, so it is replayed only when something is missing.
The new emulator option creates an AVD from the SDK's own device list — the
newest plain Pixel, smallest screen — with software rendering written into its
config so ssh -X does not open a black screen, and adds the user to the kvm
group, without which it refuses to start. Checked on a VM: boot completed in
10 s, adb sees emulator-5554, Android 16 x86_64, no KVM refusal. Vitest: 1938
tests pass. The APK still fails, upstream: sentencepiece builds protoc for the
target then runs it on the host.
--- FR ---
Seule l'exécution sur une VM pouvait trouver ceci. install_os n'installait pas
python3-venv, si bien que .venv.erplibre naissait infirme — bin/python mais ni
pip ni activate — et tout ce qui en dépend tombait sur « No module named
git » ; une ligne de dépendance suffit. Capacitor 8 réclame un JDK 21 là où
l'installateur du dépôt mobile pose un 17, et Gradle doit TOURNER dessus. Cet
installateur n'est pas idempotent non plus : il n'est rejoué que s'il manque
quelque chose.
La nouvelle option crée un AVD depuis la liste de profils du SDK — le Pixel
simple le plus récent, plus petit écran —, écrit le rendu logiciel dans sa
configuration pour qu'ssh -X n'ouvre pas un écran noir, et ajoute
l'utilisateur au groupe kvm, sans quoi il refuse de démarrer. Vérifié sur une
VM : boot en 10 s, adb voit emulator-5554, Android 16 x86_64, aucun refus de
KVM. Vitest : 1938 tests passent. L'APK échoue encore, en amont :
sentencepiece bâtit protoc pour la cible puis l'exécute sur l'hôte.
Assisted-by: Claude Opus 5
2026-08-18 02:17:08 -04:00
|
|
|
|
manque. Le modèle n'est pas figé : on demande au SDK ses profils et le Pixel le
|
[FIX] qemu doc: donner une commande d'émulateur qui fonctionne
Les deux commandes documentées échouent. « emulator » sans chemin absolu rend
« command not found », parce qu'un `ssh hôte 'commande'` ne lit ni ~/.profile
ni ~/.bashrc — l'erreur a été rencontrée telle quelle. Et le rendu annoncé,
« swiftshader_indirect », n'existe plus : l'émulateur répond « Selected GPU
option is not valid » et le code pose « swangle » depuis un moment.
La doc pointe maintenant d'abord le menu de todo.py, qui démarre l'émulateur
sans fenêtre et donne le tunnel adb : scrcpy reçoit du H.264 encodé par
l'appareil, là où `ssh -X` fait traverser chaque image en pixels bruts.
--- EN ---
Both documented commands fail. Bare `emulator` gives "command not found",
because `ssh host 'command'` reads neither ~/.profile nor ~/.bashrc — the
error was hit exactly like that. And the advertised renderer,
`swiftshader_indirect`, no longer exists: the emulator answers "Selected GPU
option is not valid", and the code has been setting `swangle` for a while.
The doc now points at todo.py's menu first, which starts the emulator without
a window and hands over the adb tunnel: scrcpy receives H.264 encoded by the
device, where `ssh -X` ships every frame as raw pixels.
Assisted-by: Claude Opus 5
2026-08-19 03:37:31 -04:00
|
|
|
|
plus récent au plus petit écran gagne (ni Pro, ni XL, ni pliant, ni tablette).
|
|
|
|
|
|
Le rendu est « swangle » dans le `config.ini` de l'AVD — « auto » ouvrirait un
|
|
|
|
|
|
écran noir, et « swiftshader_indirect » n'existe plus, l'émulateur répondant
|
|
|
|
|
|
`Selected GPU option ... is not valid`.
|
[ADD] todo qemu: add an Android emulator, and fix what the real run exposed
Running it on a VM was the only way to find these. install_os never installed
python3-venv, so .venv.erplibre was born crippled — bin/python but no pip, no
activate — and everything downstream failed on "No module named git"; one line
of dependency fixes it. Capacitor 8 needs a JDK 21 where the mobile
repository's installer puts 17, and Gradle must RUN on it. That installer is
not idempotent either, so it is replayed only when something is missing.
The new emulator option creates an AVD from the SDK's own device list — the
newest plain Pixel, smallest screen — with software rendering written into its
config so ssh -X does not open a black screen, and adds the user to the kvm
group, without which it refuses to start. Checked on a VM: boot completed in
10 s, adb sees emulator-5554, Android 16 x86_64, no KVM refusal. Vitest: 1938
tests pass. The APK still fails, upstream: sentencepiece builds protoc for the
target then runs it on the host.
--- FR ---
Seule l'exécution sur une VM pouvait trouver ceci. install_os n'installait pas
python3-venv, si bien que .venv.erplibre naissait infirme — bin/python mais ni
pip ni activate — et tout ce qui en dépend tombait sur « No module named
git » ; une ligne de dépendance suffit. Capacitor 8 réclame un JDK 21 là où
l'installateur du dépôt mobile pose un 17, et Gradle doit TOURNER dessus. Cet
installateur n'est pas idempotent non plus : il n'est rejoué que s'il manque
quelque chose.
La nouvelle option crée un AVD depuis la liste de profils du SDK — le Pixel
simple le plus récent, plus petit écran —, écrit le rendu logiciel dans sa
configuration pour qu'ssh -X n'ouvre pas un écran noir, et ajoute
l'utilisateur au groupe kvm, sans quoi il refuse de démarrer. Vérifié sur une
VM : boot en 10 s, adb voit emulator-5554, Android 16 x86_64, aucun refus de
KVM. Vitest : 1938 tests passent. L'APK échoue encore, en amont :
sentencepiece bâtit protoc pour la cible puis l'exécute sur l'hôte.
Assisted-by: Claude Opus 5
2026-08-18 02:17:08 -04:00
|
|
|
|
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
|
Un sixième, **Forgejo**, installe une forge git auto-hébergée — le logiciel
|
|
|
|
|
|
derrière Codeberg — depuis le binaire statique officiel du projet, et la laisse
|
|
|
|
|
|
en service sur le port 3000, avec git par SSH sur 2222. Comme la compilation
|
|
|
|
|
|
mobile, elle n'a besoin d'aucun bureau ; contrairement à elle, aucune famille de
|
|
|
|
|
|
paquets n'est exclue : le binaire est statique, donc le même fichier sert apt,
|
|
|
|
|
|
dnf, pacman et zypper. C'est ce qui la rend portable sur les plateformes
|
|
|
|
|
|
ERPLibre sans une branche par distribution. Les architectures suivent l'amont,
|
|
|
|
|
|
qui publie amd64, arm64 et arm-6 — la case se grise sur s390x plutôt que de
|
|
|
|
|
|
poser un binaire qui ne s'exécutera pas.
|
|
|
|
|
|
|
|
|
|
|
|
Le travail vit dans `script/forgejo/install_forgejo.sh`, appelable seul sur une
|
|
|
|
|
|
machine existante : `./script/forgejo/install_forgejo.sh`. Il vérifie la somme
|
|
|
|
|
|
de contrôle publiée, écrit lui-même les quatre secrets pour que le service n'ait
|
|
|
|
|
|
jamais à réécrire sa propre configuration, et garde ses données en SQLite pour
|
|
|
|
|
|
ne pas disputer PostgreSQL à Odoo sur la même VM. Le rejouer est sans risque et
|
|
|
|
|
|
bon marché — 1,5 s mesuré, tout étant en place : il saute un binaire déjà à la
|
|
|
|
|
|
bonne version, ne réécrit jamais un `app.ini` existant et ne recrée pas
|
|
|
|
|
|
l'administrateur. `FORGEJO_VERSION`, `FORGEJO_HTTP_PORT`, `FORGEJO_ADMIN_USER`
|
|
|
|
|
|
et quelques autres le règlent ; `--help` les énumère.
|
|
|
|
|
|
|
[ADD] todo qemu: build and test the mobile app, and fail the VM if it breaks
A VM was declared ready without anything proving it. The mobile option now
adds the repository to the manifest (additive, so it rides along an Odoo 18
install), runs the mobile repository's own install-android.sh — licences
accepted included — then npm ci, vite build, cap sync, gradlew assembleDebug
and npm test. A failure fails the VM: the exit code reaches the dashboard.
Two gaps in that upstream installer had to be filled: unzip and wget, which
no cloud image ships, and the SDK platform — it installs android-34 while
variables.gradle asks for compileSdk 36, so the number is read from the file
rather than frozen. Gradle writes tens of megabytes and hundreds of harmless
lines carrying the word error: that output goes to a file of its own, and the
log gets the named cause instead.
--- FR ---
Une VM était déclarée prête sans que rien ne le prouve. L'option mobile ajoute
maintenant le dépôt au manifeste (additif, donc il accompagne une installation
Odoo 18), lance l'install-android.sh du dépôt mobile lui-même — licences
acceptées comprises —, puis npm ci, vite build, cap sync, gradlew
assembleDebug et npm test. Un échec fait échouer la VM : le code de sortie
remonte au tableau de bord.
Deux manques de cet installateur amont ont dû être comblés : unzip et wget,
qu'aucune image cloud ne livre, et la plateforme SDK — il pose android-34
quand variables.gradle réclame compileSdk 36, d'où le chiffre lu dans le
fichier plutôt que figé. Gradle écrit des dizaines de mégaoctets et des
centaines de lignes anodines portant le mot error : cette sortie part dans un
fichier à part, et le journal reçoit la cause nommée.
Assisted-by: Claude Opus 5
2026-08-18 00:50:08 -04:00
|
|
|
|
Chaque outil est filtré VM par VM — architecture, saveur de bureau et famille
|
|
|
|
|
|
de paquets — et sa place disque s'ajoute au plan avant que rien ne soit créé.
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
## Principales options
|
|
|
|
|
|
|
|
|
|
|
|
- `--distro` — `ubuntu` (défaut), `debian` ou `fedora`.
|
|
|
|
|
|
- `--version` — version de la distro (défaut : celle par défaut de la distro).
|
|
|
|
|
|
- `--list-images` — affiche toutes les distros/versions et leurs specs.
|
|
|
|
|
|
- `--image-dir` — répertoire de cache des images (défaut
|
|
|
|
|
|
`/var/lib/libvirt/images/iso`).
|
|
|
|
|
|
- `--download-only` — télécharge l'image puis quitte (sans VM).
|
|
|
|
|
|
- `--name` — nom de la VM (requis pour le déploiement).
|
|
|
|
|
|
- `--memory`, `--vcpus`, `--disk-size` — dimensionnement de la VM. Omis,
|
|
|
|
|
|
`--memory` et `--disk-size` prennent le **minimum requis par la version**
|
|
|
|
|
|
choisie (valeurs libosinfo, voir `--list-images` : Ubuntu 24.04+ →
|
|
|
|
|
|
3072 Mo/20G, Debian → 1024 Mo/10G, Fedora → 2048 Mo/15G) ; `--vcpus`
|
|
|
|
|
|
vaut 2 par défaut.
|
|
|
|
|
|
- `--ssh-key`, `--ask-password`, `--password-hash` — authentification.
|
|
|
|
|
|
- `-y` / `--assume-yes` — accepte automatiquement l'installation des
|
|
|
|
|
|
dépendances.
|
|
|
|
|
|
- `--no-install-deps` — n'installe jamais les dépendances automatiquement.
|
|
|
|
|
|
- `--dry-run` — affiche les commandes sans rien exécuter.
|
|
|
|
|
|
- `--force` — écrase le disque de travail qcow2 existant.
|
[ADD] qemu : prendre le GPU de l'hôte, et régler le matériel des VM
Une VM graphique sans accélération rend tout par le processeur : le bureau,
et l'émulateur Android qui tourne dedans — 32 % d'images en retard, mesuré.
Le déploiement prend donc le GPU de l'hôte dès qu'un nœud de rendu existe.
Une VM déjà installée n'avait aucune voie : ni vCPU, ni RAM, ni 3D. Le menu
d'état les règle maintenant, pendant qu'elle est éteinte — le seul moment où
libvirt les lit.
Trois pièges du terrain : « --memory N » ne touche que le ballon, l'ajout
d'egl-headless n'est pas idempotent, et son retrait sans cible emporte la
console VNC. Vérifié sur un domaine jetable, 459 tests verts.
--- EN ---
A graphical VM without acceleration renders everything on the CPU: the
desktop, and the Android emulator inside it — 32 % janky frames, measured.
The deployment now takes the host GPU as soon as a render node exists.
An installed VM had no path at all: no vCPU, no RAM, no 3D. The state menu
now sets them while the VM is shut off — the only moment libvirt reads them.
Three field traps: "--memory N" only moves the balloon, adding egl-headless
is not idempotent, and removing it untargeted takes the VNC console with it.
Verified on a throwaway domain, 459 tests green.
Assisted-by: Claude Opus 5
2026-08-21 22:32:56 -04:00
|
|
|
|
- `--gpu` — accélération 3D par le GPU de l'hôte : `auto` (défaut, activée si
|
|
|
|
|
|
l'hôte a un nœud de rendu), `on` (forcer), `off` (rendu logiciel).
|
|
|
|
|
|
- `--gpu-node` — quel nœud de rendu utiliser, sur un hôte à plusieurs cartes.
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
- `--lang` — langue du guide affiché à la connexion SSH, `fr` (défaut) ou
|
|
|
|
|
|
`en`. Le menu TODO passe la sienne.
|
|
|
|
|
|
- `--erplibre-dir` — où ERPLibre sera installé dans la VM
|
|
|
|
|
|
(`~/git/erplibre`, ou `/opt/erplibre` en production). Ajoute la section
|
|
|
|
|
|
ERPLibre au guide de connexion ; omis, cette section est laissée de côté.
|
|
|
|
|
|
- `--erplibre-make` — la cible make qui a installé la VM
|
|
|
|
|
|
(ex. `install_odoo_18`), reprise dans le guide pour la mettre à jour.
|
|
|
|
|
|
- `--no-git-identity` — ne recopie pas les `user.name`, `user.email` et
|
|
|
|
|
|
`core.editor` de l'hôte dans le `~/.gitconfig` de la VM.
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
|
|
|
|
|
|
Lancez `./script/qemu/deploy_qemu.py --help` pour la liste complète.
|
|
|
|
|
|
|
[ADD] todo qemu: offer PyCharm, Android Studio and GNOME extensions
A graphical VM was a desktop and nothing else: every developer tool had to
be installed by hand afterwards. A check list now carries them, filtered
per machine — Android Studio is x86_64 only, Google publishes no Linux
aarch64 build — and their disk cost reaches the plan before any qcow2 is
created. They are installed BEFORE the clone: PyCharm writes the .idea/ of
the repository, and the install that follows is what runs
pycharm_configuration.py, through update_env_version.pycharm_update().
Its launcher is named studio, which is enough to conclude the install
failed; it now answers to android-studio too. GNOME extensions come from
the site by UUID, per running Shell: the same endpoint serves gTile v59
for GNOME 46 and v62 for 48. Checked with stubs: every tool can fail and
the install's exit code still wins, 45 tests.
--- FR ---
Une VM graphique n'était qu'un bureau : chaque outil de développement
restait à poser à la main. Une liste à cocher les porte, filtrés machine
par machine — Android Studio n'existe qu'en x86_64, Google ne publiant
aucune archive Linux aarch64 — et leur place disque atteint le plan avant
qu'un seul qcow2 ne soit créé. Ils sont posés AVANT le clone : PyCharm
écrit le .idea/ du dépôt, et c'est l'installation qui suit qui lance
pycharm_configuration.py, via update_env_version.pycharm_update().
Son lanceur s'appelle studio, ce qui suffit à conclure à un échec ; il
répond désormais aussi à android-studio. Les extensions GNOME viennent du
site par UUID, selon le Shell qui tourne : le même point d'entrée sert
gTile v59 pour GNOME 46 et v62 pour 48. Vérifié avec des leurres : chaque
outil peut échouer sans que le code de sortie de l'installation ne change,
45 tests.
Assisted-by: Claude Opus 5
2026-08-17 22:57:56 -04:00
|
|
|
|
## Guide de connexion (`/etc/motd`)
|
|
|
|
|
|
|
|
|
|
|
|
Chaque VM accueille celui qui s'y connecte en SSH avec les commandes de **sa**
|
|
|
|
|
|
distribution — `apt`, `dnf`, `zypper` ou `pacman` — et celles d'ERPLibre :
|
|
|
|
|
|
éditer le serveur, le redémarrer, mettre à jour des modules, mettre à jour
|
|
|
|
|
|
Odoo, inspecter l'instance, ouvrir le menu TODO. Il est écrit par cloud-init,
|
|
|
|
|
|
donc présent dès le premier démarrage : avant l'installation d'ERPLibre, et
|
|
|
|
|
|
encore là si elle échoue — le moment où l'on se connecte justement à la main.
|
|
|
|
|
|
|
|
|
|
|
|
`--dry-run` affiche le guide généré avec le reste du user-data. Il ne
|
|
|
|
|
|
s'affiche PAS pour un `ssh hôte 'commande'` : les journaux d'installation
|
|
|
|
|
|
restent nets.
|
|
|
|
|
|
|
|
|
|
|
|
L'identité git de l'hôte voyage avec lui, dans le `~/.gitconfig` de la VM :
|
|
|
|
|
|
un commit fait dans la VM porte alors votre nom plutôt que
|
|
|
|
|
|
`erplibre@<nom-de-vm>`. L'éditeur suit le même chemin — `core.editor`, la
|
|
|
|
|
|
ligne `config.conf` du guide et le paquet installé dans la VM viennent d'une
|
|
|
|
|
|
seule table, de sorte que le guide ne nomme jamais une commande absente.
|
|
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
## Managing VMs
|
|
|
|
|
|
|
|
|
|
|
|
List, stop and remove VMs (the qcow2 disk under `/var/lib/libvirt/images`
|
|
|
|
|
|
is kept unless you delete it):
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
## Gestion des VM
|
|
|
|
|
|
|
|
|
|
|
|
Lister, arrêter et supprimer les VM (le disque qcow2 sous
|
|
|
|
|
|
`/var/lib/libvirt/images` est conservé tant que vous ne le supprimez pas) :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
sudo virsh list --all # toutes les VM et leur état / all VMs and state
|
|
|
|
|
|
sudo virsh shutdown <nom-vm> # arrêt propre ACPI / graceful shutdown
|
|
|
|
|
|
sudo virsh destroy <nom-vm> # arrêt forcé / force off (pull the plug)
|
|
|
|
|
|
sudo virsh undefine <nom-vm> # supprime la définition / remove definition
|
|
|
|
|
|
sudo virsh domifaddr <nom-vm> # adresse IP de la VM / VM IP address
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
`destroy` only powers the VM off (disk kept); `undefine` removes its
|
|
|
|
|
|
definition. To fully recreate a VM with the same name, `destroy` + `undefine`
|
|
|
|
|
|
it first, or redeploy with `--force`.
|
|
|
|
|
|
|
|
|
|
|
|
## SSH access from another machine (ProxyJump)
|
|
|
|
|
|
|
|
|
|
|
|
With the default NAT network the VM is reachable **only from the KVM host**.
|
|
|
|
|
|
To reach it from another machine **without changing the network**, use the
|
|
|
|
|
|
host as a jump host (it already reaches the VM). Get the VM IP with
|
|
|
|
|
|
`sudo virsh domifaddr <nom-vm>`, then from the other machine:
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
`destroy` ne fait qu'éteindre la VM (disque conservé) ; `undefine` supprime sa
|
|
|
|
|
|
définition. Pour recréer proprement une VM du même nom, faites `destroy` +
|
|
|
|
|
|
`undefine` d'abord, ou redéployez avec `--force`.
|
|
|
|
|
|
|
|
|
|
|
|
## Accès SSH depuis une autre machine (ProxyJump)
|
|
|
|
|
|
|
|
|
|
|
|
Avec le réseau NAT par défaut, la VM n'est joignable que **depuis l'hôte
|
|
|
|
|
|
KVM**. Pour l'atteindre depuis une autre machine **sans toucher au réseau**,
|
|
|
|
|
|
utilisez l'hôte comme rebond (il joint déjà la VM). Récupérez l'IP de la VM
|
|
|
|
|
|
avec `sudo virsh domifaddr <nom-vm>`, puis depuis l'autre machine :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Rebond SSH vers la VM / jump through the KVM host
|
|
|
|
|
|
ssh -J user@<ip-hote> erplibre@<ip-vm>
|
|
|
|
|
|
|
|
|
|
|
|
# Tunnel d'un service, ex. Odoo 8069 / tunnel a service, then http://localhost:8069
|
|
|
|
|
|
ssh -L 8069:<ip-vm>:8069 user@<ip-hote>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
To make it permanent, add this to `~/.ssh/config` on the other machine (then
|
|
|
|
|
|
just `ssh myvm`):
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Pour le rendre permanent, ajoutez ceci à `~/.ssh/config` sur l'autre machine
|
|
|
|
|
|
(ensuite `ssh myvm` suffit) :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```text
|
|
|
|
|
|
Host myvm
|
|
|
|
|
|
HostName <ip-vm> # ex. 192.168.122.50 (reseau NAT)
|
|
|
|
|
|
User erplibre
|
|
|
|
|
|
ProxyJump user@<ip-hote> # IP LAN de l'hote KVM
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
This works over Wi-Fi and needs no VM shutdown — the simplest option for
|
|
|
|
|
|
personal access. Prefer a bridge (below) if the VM must be a full server
|
|
|
|
|
|
exposed on the LAN.
|
|
|
|
|
|
|
[ADD] qemu : prendre le GPU de l'hôte, et régler le matériel des VM
Une VM graphique sans accélération rend tout par le processeur : le bureau,
et l'émulateur Android qui tourne dedans — 32 % d'images en retard, mesuré.
Le déploiement prend donc le GPU de l'hôte dès qu'un nœud de rendu existe.
Une VM déjà installée n'avait aucune voie : ni vCPU, ni RAM, ni 3D. Le menu
d'état les règle maintenant, pendant qu'elle est éteinte — le seul moment où
libvirt les lit.
Trois pièges du terrain : « --memory N » ne touche que le ballon, l'ajout
d'egl-headless n'est pas idempotent, et son retrait sans cible emporte la
console VNC. Vérifié sur un domaine jetable, 459 tests verts.
--- EN ---
A graphical VM without acceleration renders everything on the CPU: the
desktop, and the Android emulator inside it — 32 % janky frames, measured.
The deployment now takes the host GPU as soon as a render node exists.
An installed VM had no path at all: no vCPU, no RAM, no 3D. The state menu
now sets them while the VM is shut off — the only moment libvirt reads them.
Three field traps: "--memory N" only moves the balloon, adding egl-headless
is not idempotent, and removing it untargeted takes the VNC console with it.
Verified on a throwaway domain, 459 tests green.
Assisted-by: Claude Opus 5
2026-08-21 22:32:56 -04:00
|
|
|
|
## 3D acceleration (host GPU)
|
|
|
|
|
|
|
|
|
|
|
|
A graphical VM without acceleration renders everything on the CPU — the
|
|
|
|
|
|
desktop, and the Android emulator running inside it. The deployment therefore
|
|
|
|
|
|
takes the host GPU **by default** (`--gpu auto`): when the host exposes a
|
|
|
|
|
|
render node, the VM gets a virtio-GPU with `accel3d` plus an `egl-headless`
|
|
|
|
|
|
display that carries the OpenGL context **beside** the VNC console — it opens
|
|
|
|
|
|
no port and replaces nothing. No render node, no 3D, and the deployment says
|
|
|
|
|
|
why instead of quietly falling back.
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
ls /dev/dri/renderD* # the GPU QEMU can use — empty means no 3D
|
|
|
|
|
|
sudo virsh dumpxml <vm-name> | grep -A2 -E "accel3d|egl-headless"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
An existing VM is adjusted from the TODO menu **while it is shut off**:
|
|
|
|
|
|
libvirt only reads these settings when QEMU starts. `QEMU/KVM › List VMs ›
|
|
|
|
|
|
[2] Change the state`, then either accept *Adjust hardware before starting*,
|
|
|
|
|
|
or take `[3] Adjust hardware only`. vCPU, RAM, 3D and autostart are set
|
|
|
|
|
|
there — in a form when Textual is available, in prompts otherwise.
|
|
|
|
|
|
|
|
|
|
|
|
Two things worth knowing:
|
|
|
|
|
|
|
|
|
|
|
|
- A host that is **itself a VM** has no render node unless a GPU was handed
|
|
|
|
|
|
down to it. Nested without passthrough, 3D is out of reach: the Android
|
|
|
|
|
|
emulator then runs on SwiftShader, and no option changes that.
|
|
|
|
|
|
- Once the VM does have 3D, the emulator can be tried with `-gpu host`
|
|
|
|
|
|
instead of its default `-gpu swangle`: `EL_EMULATOR_GPU=host ./todo.sh`.
|
|
|
|
|
|
It stays a manual test — an emulator whose GL context fails hangs instead
|
|
|
|
|
|
of falling back, so `swangle` remains the default.
|
|
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
## QEMU inside QEMU (nested) & exposing the VM via a bridge
|
|
|
|
|
|
|
|
|
|
|
|
If the KVM host is **itself a VM** (QEMU-in-QEMU), the deployment works only
|
|
|
|
|
|
when **nested virtualization** is enabled on the outer/physical host and the
|
|
|
|
|
|
middle VM uses CPU mode `host-passthrough`. Check from inside the KVM host
|
|
|
|
|
|
(the first command must be non-empty):
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Ça marche en Wi-Fi et sans arrêter la VM — l'option la plus simple pour un
|
|
|
|
|
|
accès personnel. Préférez un pont (ci-dessous) si la VM doit être un serveur
|
|
|
|
|
|
à part entière exposé sur le LAN.
|
|
|
|
|
|
|
[ADD] qemu : prendre le GPU de l'hôte, et régler le matériel des VM
Une VM graphique sans accélération rend tout par le processeur : le bureau,
et l'émulateur Android qui tourne dedans — 32 % d'images en retard, mesuré.
Le déploiement prend donc le GPU de l'hôte dès qu'un nœud de rendu existe.
Une VM déjà installée n'avait aucune voie : ni vCPU, ni RAM, ni 3D. Le menu
d'état les règle maintenant, pendant qu'elle est éteinte — le seul moment où
libvirt les lit.
Trois pièges du terrain : « --memory N » ne touche que le ballon, l'ajout
d'egl-headless n'est pas idempotent, et son retrait sans cible emporte la
console VNC. Vérifié sur un domaine jetable, 459 tests verts.
--- EN ---
A graphical VM without acceleration renders everything on the CPU: the
desktop, and the Android emulator inside it — 32 % janky frames, measured.
The deployment now takes the host GPU as soon as a render node exists.
An installed VM had no path at all: no vCPU, no RAM, no 3D. The state menu
now sets them while the VM is shut off — the only moment libvirt reads them.
Three field traps: "--memory N" only moves the balloon, adding egl-headless
is not idempotent, and removing it untargeted takes the VNC console with it.
Verified on a throwaway domain, 459 tests green.
Assisted-by: Claude Opus 5
2026-08-21 22:32:56 -04:00
|
|
|
|
## Accélération 3D (GPU de l'hôte)
|
|
|
|
|
|
|
|
|
|
|
|
Une VM graphique sans accélération rend tout par le processeur — le bureau
|
|
|
|
|
|
comme l'émulateur Android qui tourne dedans. Le déploiement prend donc le GPU
|
|
|
|
|
|
de l'hôte **par défaut** (`--gpu auto`) : si l'hôte expose un nœud de rendu,
|
|
|
|
|
|
la VM reçoit un virtio-GPU avec `accel3d` et un affichage `egl-headless` qui
|
|
|
|
|
|
porte le contexte OpenGL **à côté** de la console VNC — il n'ouvre aucun port
|
|
|
|
|
|
et ne remplace rien. Pas de nœud de rendu, pas de 3D, et le déploiement dit
|
|
|
|
|
|
pourquoi au lieu de retomber en silence.
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
ls /dev/dri/renderD* # le GPU utilisable par QEMU — vide : pas de 3D
|
|
|
|
|
|
sudo virsh dumpxml <nom-vm> | grep -A2 -E "accel3d|egl-headless"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Une VM déjà installée se règle depuis le menu TODO **pendant qu'elle est
|
|
|
|
|
|
éteinte** : libvirt ne lit ces réglages qu'au démarrage de QEMU. `QEMU/KVM ›
|
|
|
|
|
|
Liste des VM › [2] Changer l'état`, puis acceptez *Régler le matériel avant de
|
|
|
|
|
|
démarrer*, ou prenez `[3] Régler le matériel seulement`. vCPU, RAM, 3D et
|
|
|
|
|
|
démarrage automatique s'y règlent — en formulaire si Textual est présent, en
|
|
|
|
|
|
invites sinon.
|
|
|
|
|
|
|
|
|
|
|
|
Deux choses à savoir :
|
|
|
|
|
|
|
|
|
|
|
|
- Un hôte qui est **lui-même une VM** n'a aucun nœud de rendu, sauf si un GPU
|
|
|
|
|
|
lui a été transmis. Imbriqué sans passthrough, la 3D est hors d'atteinte :
|
|
|
|
|
|
l'émulateur Android tourne alors sur SwiftShader, et aucune option n'y
|
|
|
|
|
|
change rien.
|
|
|
|
|
|
- Quand la VM a la 3D, l'émulateur peut être essayé en `-gpu host` plutôt
|
|
|
|
|
|
qu'en `-gpu swangle`, son défaut : `EL_EMULATOR_GPU=host ./todo.sh`. Ça
|
|
|
|
|
|
reste un essai manuel — un émulateur dont le contexte GL échoue reste pendu
|
|
|
|
|
|
au lieu de retomber, d'où `swangle` par défaut.
|
|
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
## QEMU dans QEMU (imbriqué) & exposer la VM via un pont
|
|
|
|
|
|
|
|
|
|
|
|
Si l'hôte KVM est **lui-même une VM** (QEMU dans QEMU), le déploiement ne
|
|
|
|
|
|
fonctionne que si la **virtualisation imbriquée** est activée sur l'hôte
|
|
|
|
|
|
physique et que la VM intermédiaire utilise le mode CPU `host-passthrough`.
|
|
|
|
|
|
Vérifiez depuis l'hôte KVM (la première commande doit être non vide) :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
grep -E -o '(vmx|svm)' /proc/cpuinfo | sort -u # extensions visibles / visible
|
|
|
|
|
|
# Sur l'hote PHYSIQUE / on the PHYSICAL host:
|
|
|
|
|
|
cat /sys/module/kvm_intel/parameters/nested # Intel -> Y/1
|
|
|
|
|
|
cat /sys/module/kvm_amd/parameters/nested # AMD -> Y/1
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
To enable nesting on the physical host (Intel shown; use `kvm_amd` on AMD),
|
|
|
|
|
|
then recreate the middle VM with `host-passthrough`:
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Pour activer l'imbrication sur l'hôte physique (Intel montré ; `kvm_amd` sur
|
|
|
|
|
|
AMD), puis recréer la VM intermédiaire en `host-passthrough` :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
echo "options kvm_intel nested=1" | sudo tee /etc/modprobe.d/kvm-nested.conf
|
|
|
|
|
|
sudo modprobe -r kvm_intel && sudo modprobe kvm_intel # ou / or reboot
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
[IMP] qemu: a VM one can reach, and a first boot that does not stall
The monitor froze the address given at launch, so it lost the VM as soon as
cloud-init renamed the host and DHCP handed out another lease. It now
re-resolves at each attempt, in the views too, and reads virsh without sudo
— « sudo -n » fails in a detached session with no tty.
First boot also stopped paying for what it does not need: the guest agent
leaves cloud-init, snapd and locale-gen go, apt takes the fastest mirror.
The timezone follows the host. And when KVM is missing, the deployment says
so before the wait instead of being mysteriously fifteen times slower.
--- FR ---
Le suivi figeait l'adresse connue au lancement : il perdait donc la VM dès
que cloud-init posait le vrai nom d'hôte et que DHCP donnait un autre bail.
Il la ré-résout désormais à chaque tentative, dans les vues aussi, et lit
virsh sans sudo — « sudo -n » échoue dans une session détachée, sans tty.
Le premier démarrage cesse aussi de payer l'inutile : l'agent invité sort
de cloud-init, snapd et locale-gen disparaissent, apt prend le miroir le
plus rapide. Le fuseau suit l'hôte. Et faute de KVM, le déploiement le dit
avant l'attente, au lieu d'être quinze fois plus lent sans raison visible.
Assisted-by: Claude Opus 5
2026-08-10 03:10:50 -04:00
|
|
|
|
On **s390x and arm64** the parameter lives on the `kvm` module itself, not on
|
|
|
|
|
|
`kvm_intel` / `kvm_amd` — and `/sys/module/kvm/parameters/nested` does not even
|
|
|
|
|
|
exist on x86. Reading the wrong file returns a reassuring `0` that commands
|
|
|
|
|
|
nothing:
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Sur **s390x et arm64**, le paramètre vit sur le module `kvm` lui-même, et non
|
|
|
|
|
|
sur `kvm_intel` / `kvm_amd` — et `/sys/module/kvm/parameters/nested` n'existe
|
|
|
|
|
|
même pas sur x86. Lire le mauvais fichier renvoie un `0` rassurant qui ne
|
|
|
|
|
|
commande rien :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
echo "options kvm nested=1" | sudo tee /etc/modprobe.d/kvm-nested.conf
|
|
|
|
|
|
sudo modprobe -r kvm && sudo modprobe kvm # ou / or reboot
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
`nested` on a machine means « let MY guests run VMs ». To accelerate a VM
|
|
|
|
|
|
created on host H, the setting belongs to the hypervisor **above** H, not to H
|
|
|
|
|
|
itself. The one command that settles it, run on H:
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
`nested` sur une machine signifie « j'autorise MES invités à faire tourner des
|
|
|
|
|
|
VM ». Pour accélérer une VM créée sur l'hôte H, le réglage appartient à
|
|
|
|
|
|
l'hyperviseur **au-dessus** de H, pas à H. La commande qui tranche, sur H :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
ls -l /dev/kvm # absent -> pas d'imbrication, tout sera émulé
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
Measured on an s390x host that was itself a KVM guest without nesting:
|
|
|
|
|
|
`/dev/kvm` absent, `virsh dumpxml` showing `<domain type='qemu'>`, and a
|
|
|
|
|
|
7 min 30 boot instead of well under a minute. `systemd-detect-virt` inside the
|
|
|
|
|
|
VM is **not** proof of acceleration — on s390x, QEMU fabricates the STSI answer
|
|
|
|
|
|
and reports `kvm` even under TCG. Only `<domain type=…>` on the host is
|
|
|
|
|
|
conclusive.
|
|
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
If nesting is unavailable, QEMU still runs via software emulation (TCG) — it
|
|
|
|
|
|
works but is slow.
|
|
|
|
|
|
|
[IMP] qemu: a VM one can reach, and a first boot that does not stall
The monitor froze the address given at launch, so it lost the VM as soon as
cloud-init renamed the host and DHCP handed out another lease. It now
re-resolves at each attempt, in the views too, and reads virsh without sudo
— « sudo -n » fails in a detached session with no tty.
First boot also stopped paying for what it does not need: the guest agent
leaves cloud-init, snapd and locale-gen go, apt takes the fastest mirror.
The timezone follows the host. And when KVM is missing, the deployment says
so before the wait instead of being mysteriously fifteen times slower.
--- FR ---
Le suivi figeait l'adresse connue au lancement : il perdait donc la VM dès
que cloud-init posait le vrai nom d'hôte et que DHCP donnait un autre bail.
Il la ré-résout désormais à chaque tentative, dans les vues aussi, et lit
virsh sans sudo — « sudo -n » échoue dans une session détachée, sans tty.
Le premier démarrage cesse aussi de payer l'inutile : l'agent invité sort
de cloud-init, snapd et locale-gen disparaissent, apt prend le miroir le
plus rapide. Le fuseau suit l'hôte. Et faute de KVM, le déploiement le dit
avant l'attente, au lieu d'être quinze fois plus lent sans raison visible.
Assisted-by: Claude Opus 5
2026-08-10 03:10:50 -04:00
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Mesuré sur un hôte s390x lui-même invité KVM sans imbrication : `/dev/kvm`
|
|
|
|
|
|
absent, `virsh dumpxml` affichant `<domain type='qemu'>`, et un démarrage de
|
|
|
|
|
|
7 min 30 au lieu de bien moins d'une minute. `systemd-detect-virt` dans la VM
|
|
|
|
|
|
ne prouve **pas** l'accélération — sur s390x, QEMU fabrique la réponse STSI et
|
|
|
|
|
|
annonce `kvm` même en TCG. Seul `<domain type=…>` sur l'hôte fait foi.
|
|
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
|
### Bridge for external access
|
|
|
|
|
|
|
|
|
|
|
|
A NAT VM is isolated; a **bridged** VM gets an IP directly on the LAN,
|
|
|
|
|
|
reachable by any machine. On the KVM host, create a bridge `br0` over the
|
|
|
|
|
|
physical NIC (**wired only** — Wi-Fi cannot be bridged). netplan (Ubuntu
|
|
|
|
|
|
server) — replace `enp3s0` with your interface:
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Si l'imbrication est indisponible, QEMU tourne quand même en émulation
|
|
|
|
|
|
logicielle (TCG) — ça marche mais c'est lent.
|
|
|
|
|
|
|
|
|
|
|
|
### Pont pour l'accès externe
|
|
|
|
|
|
|
|
|
|
|
|
Une VM en NAT est isolée ; une VM **pontée** obtient une IP directement sur le
|
|
|
|
|
|
LAN, joignable par n'importe quelle machine. Sur l'hôte KVM, créez un pont
|
|
|
|
|
|
`br0` sur la carte physique (**filaire uniquement** — le Wi-Fi ne se ponte
|
|
|
|
|
|
pas). netplan (Ubuntu serveur) — remplacez `enp3s0` par votre interface :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
# /etc/netplan/01-br0.yaml
|
|
|
|
|
|
network:
|
|
|
|
|
|
version: 2
|
|
|
|
|
|
renderer: networkd
|
|
|
|
|
|
ethernets:
|
|
|
|
|
|
enp3s0: {dhcp4: no, dhcp6: no}
|
|
|
|
|
|
bridges:
|
|
|
|
|
|
br0:
|
|
|
|
|
|
interfaces: [enp3s0]
|
|
|
|
|
|
dhcp4: yes
|
|
|
|
|
|
parameters: {stp: false, forward-delay: 0}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
Apply safely (auto-reverts if you lose the connection) and verify — or use
|
|
|
|
|
|
NetworkManager (Ubuntu desktop):
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Appliquez avec filet de sécurité (annulation auto en cas de coupure) et
|
|
|
|
|
|
vérifiez — ou via NetworkManager (Ubuntu bureau) :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# netplan
|
|
|
|
|
|
sudo netplan try && sudo netplan apply
|
|
|
|
|
|
ip addr show br0 # br0 porte l'IP du LAN / br0 holds the LAN IP
|
|
|
|
|
|
|
|
|
|
|
|
# NetworkManager (alternative)
|
|
|
|
|
|
nmcli con add type bridge ifname br0 con-name br0
|
|
|
|
|
|
nmcli con add type ethernet ifname enp3s0 master br0 con-name br0-port
|
|
|
|
|
|
nmcli con modify br0 ipv4.method auto
|
|
|
|
|
|
nmcli con down "Wired connection 1" ; nmcli con up br0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
Then attach the VM to the bridge — **either at creation**:
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
Rattachez ensuite la VM au pont — **soit à la création** :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --name <nom-vm> --version 24.04 \
|
|
|
|
|
|
--ssh-key ~/.ssh/id_ed25519.pub --network bridge=br0,model=virtio -y --force
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
**or by editing a VM already created**: stop it, replace its `<interface>`
|
|
|
|
|
|
block (`type='network'` / `<source network='default'/>` → `type='bridge'` /
|
|
|
|
|
|
`<source bridge='br0'/>`), then start it again:
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
**soit par édition d'une VM déjà créée** : arrêtez-la, remplacez son bloc
|
|
|
|
|
|
`<interface>` (`type='network'` / `<source network='default'/>` →
|
|
|
|
|
|
`type='bridge'` / `<source bridge='br0'/>`), puis redémarrez-la :
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
|
```bash
|
|
|
|
|
|
sudo virsh shutdown <nom-vm>
|
|
|
|
|
|
sudo virsh edit <nom-vm> # mettre l'interface en bridge=br0
|
|
|
|
|
|
sudo virsh start <nom-vm>
|
|
|
|
|
|
sudo virsh domifaddr <nom-vm> # nouvelle IP LAN / new LAN IP
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
|
The VM now gets a LAN IP from your router, reachable by other machines. From
|
|
|
|
|
|
the Internet you additionally need a port-forward on your router (or a VPN);
|
|
|
|
|
|
in a nested setup the outer host must also forward/expose the middle VM.
|
|
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
|
La VM obtient maintenant une IP LAN de votre routeur, joignable par les autres
|
|
|
|
|
|
machines. Depuis Internet, il faut en plus une redirection de port sur votre
|
|
|
|
|
|
routeur (ou un VPN) ; en configuration imbriquée, l'hôte externe doit aussi
|
|
|
|
|
|
rediriger/exposer la VM intermédiaire.
|