La profondeur d'imbrication praticable ne se déduit pas, elle se mesure. Une mesure à la main a trouvé, au quatrième étage, un invité 36 fois plus lent que le temps réel — 583 secondes d'horloge pour 16 secondes de temps invité, chaque ligne d'ACPI prenant une seconde — puis un noyau gelé au MÊME octet quelles que soient les ressources. Un chiffre obtenu une fois, sur une machine, n'est pas un chiffre. D'où trois choses. L'algorithme, en fonctions pures. Deux ressources s'épuisent en descendant : la mémoire, chaque étage gardant de quoi faire tourner ses propres démons, et le disque, celui de l'enfant vivant DANS celui du parent. Une troisième se dégrade, et elle borne le vCPU à deux au-delà du premier étage : douze ont gelé le noyau invité, les mêmes deux avançaient. La mémoire n'est PAS bornée — la même VM gelait au même octet avec 9 Go et avec 2 Go, donc la rogner ne gagnerait rien et priverait l'étage du dessous. Le plan est annoncé avant toute création, et jamais au-delà de ce qui tient. Le garde-fou dans l'écran. Il lisait la capacité de l'HÔTE et l'offrait en entier : sur un troisième étage à 14 cœurs, il a proposé 12 vCPU à une VM qui n'a jamais démarré. Le nombre n'était pas absurde pour la machine ; il l'était pour sa profondeur, que l'écran ignorait. Elle se compte maintenant sur la chaîne de ProxyJump — un rebond par étage, et c'est nous qui écrivons ces entrées. Le test long, dans LongTest/ et non dans test/ : le lanceur unitaire doit rester lançable en quelques secondes, partout, y compris sans virtualisation. La descente est uniforme — créer, attendre le ssh, installer, redémarrer et vérifier le noyau, remettre pmxcfs debout, contrôler le stockage — et s'arrête au premier étage qui échoue en NOMMANT l'étape. Il envoie notre install_proxmox.sh par scp plutôt que de laisser la VM cloner le dépôt : c'est notre code qu'on éprouve, et un correctif absent du distant a fait revenir le même défaut sur trois VM. --- EN --- The practicable nesting depth cannot be deduced, only measured. A manual measurement found, at the fourth level, a guest 36 times slower than real time — 583 seconds of wall clock for 16 seconds of guest time, each ACPI line taking a second — then a kernel frozen at the SAME byte whatever the resources. A number obtained once, on one machine, is not a number. Hence three things. The algorithm, in pure functions. Two resources run out going down: memory, each level keeping what its own daemons need, and disk, the child's living INSIDE the parent's. A third degrades, and it caps the vCPU at two beyond the first level: twelve froze the guest kernel, the same two progressed. Memory is NOT capped — the same VM froze at the same byte with 9 GB and with 2 GB, so trimming it would gain nothing and starve the level below. The plan is announced before anything is created, and never beyond what fits. The guard in the screen. It read the HOST's capacity and offered all of it: on a third level with 14 cores it proposed 12 vCPU to a VM that never booted. The number was not absurd for the machine; it was for its depth, which the screen did not know. It is now counted on the ProxyJump chain — one hop per level, and we are the ones writing those entries. The long test, in LongTest/ and not test/: the unit runner must stay runnable in seconds, anywhere, including without virtualisation. The descent is uniform — create, wait for ssh, install, reboot and check the kernel, bring pmxcfs back, check the storage — and stops at the first level that fails, NAMING the step. It sends our install_proxmox.sh over scp instead of letting the VM clone the repository: it is our code being exercised, and a fix absent from the remote made the same defect return on three VMs. Assisted-by: Claude Opus 5 (cherry picked from commit 4f70c461330cac6f46783a60e0f33052a979fa23)
125 lines
5.9 KiB
Markdown
125 lines
5.9 KiB
Markdown
<!---------------------------->
|
||
<!-- multilingual suffix: en, fr -->
|
||
<!-- no suffix: en -->
|
||
<!---------------------------->
|
||
|
||
<!-- [en] -->
|
||
# LongTest — tests that create real machines
|
||
|
||
These are not unit tests. They create virtual machines, install systems on
|
||
them, and take hours. They live here and **not** in `test/`, which the unit
|
||
runner sweeps: `./script/test/run_unit_test.sh` must stay runnable in seconds
|
||
on any machine, including one without virtualisation.
|
||
|
||
Run them from the menu — `TODO › Execute › Test › Long tests` — or directly.
|
||
|
||
## deep_proxmox.py — how deep does Proxmox-in-Proxmox go?
|
||
|
||
The practicable nesting depth cannot be deduced, only measured. A manual
|
||
measurement found, at the fourth level, a guest **36 times slower than real
|
||
time** — 583 seconds of wall clock for 16 seconds of guest time, each ACPI
|
||
line taking a second — then a guest kernel frozen at the **same byte**
|
||
whatever the resources. A number obtained once, on one machine, is not a
|
||
number: this script redoes it on demand and says exactly where it breaks.
|
||
|
||
```
|
||
./LongTest/deep_proxmox.py --depth 10 --dry-run # the plan, nothing created
|
||
./LongTest/deep_proxmox.py --depth 10 # hours
|
||
./LongTest/deep_proxmox.py --detruire # undo it
|
||
```
|
||
|
||
The descent is **uniform**. Every level, the first included, goes through the
|
||
same six steps: create, wait for ssh, install Proxmox, reboot and check the
|
||
kernel, bring pmxcfs back up, check the storage. Only creation differs —
|
||
libvirt locally, `qm` afterwards.
|
||
|
||
It sends **our** `install_proxmox.sh` over scp instead of letting the VM clone
|
||
the repository: it is our code we want to exercise, and the remote is often
|
||
behind the checkout — a fix absent from the remote made the same defect "come
|
||
back" on three VMs in a row.
|
||
|
||
### The resource algorithm
|
||
|
||
Two things run out going down, and a third degrades. What runs out is
|
||
arithmetic, and `script/proxmox/nesting.py` computes it:
|
||
|
||
* **memory** — each level keeps what its own daemons need (`pve-cluster`,
|
||
`pvestatd`, `pvedaemon`, `pveproxy`) before handing the rest down;
|
||
* **disk** — the child's disk lives *inside* the parent's, which must also
|
||
hold its own system.
|
||
|
||
What degrades is measured, not assumed: past the second level, vendors
|
||
document nothing. Hence one capped number — **2 vCPU** for every nested
|
||
level. Twelve vCPU at the fourth level froze the guest kernel in early boot;
|
||
the same two progressed. Bringing twelve processors online costs as many
|
||
round trips through the whole stack.
|
||
|
||
Memory is **not** capped: the same VM froze at the same byte with 9 GB and
|
||
with 2 GB, so trimming it would gain nothing and starve the level below.
|
||
|
||
The plan is printed **before** anything is created, and the script never
|
||
promises a depth it knows will not fit — better to announce six levels and
|
||
reach six than to promise ten and die at the seventh without knowing why.
|
||
|
||
<!-- [fr] -->
|
||
# LongTest — des tests qui créent de vraies machines
|
||
|
||
Ce ne sont pas des tests unitaires. Ils créent des machines virtuelles, y
|
||
installent des systèmes, et durent des heures. Ils vivent ici et **non** dans
|
||
`test/`, que le lanceur unitaire balaie : `./script/test/run_unit_test.sh`
|
||
doit rester lançable en quelques secondes, sur n'importe quelle machine, y
|
||
compris sans virtualisation.
|
||
|
||
Ils se lancent depuis le menu — `TODO › Execute › Test › Tests longs` — ou
|
||
directement.
|
||
|
||
## deep_proxmox.py — jusqu'à quel étage un Proxmox dans un Proxmox tient-il ?
|
||
|
||
La profondeur d'imbrication praticable ne se déduit pas, elle se mesure. Une
|
||
mesure à la main a trouvé, au quatrième étage, un invité **36 fois plus lent
|
||
que le temps réel** — 583 secondes d'horloge pour 16 secondes de temps
|
||
invité, chaque ligne d'ACPI prenant une seconde — puis un noyau invité gelé au
|
||
**même octet** quelles que soient les ressources. Un chiffre obtenu une fois,
|
||
sur une machine, n'est pas un chiffre : ce script le refait à la demande et
|
||
dit exactement où ça casse.
|
||
|
||
```
|
||
./LongTest/deep_proxmox.py --depth 10 --dry-run # le plan, rien de créé
|
||
./LongTest/deep_proxmox.py --depth 10 # des heures
|
||
./LongTest/deep_proxmox.py --detruire # défaire
|
||
```
|
||
|
||
La descente est **uniforme**. Chaque étage, le premier compris, passe par les
|
||
mêmes six étapes : créer, attendre le ssh, installer Proxmox, redémarrer et
|
||
vérifier le noyau, remettre pmxcfs debout, contrôler le stockage. Seule la
|
||
création diffère — libvirt en local, `qm` ensuite.
|
||
|
||
Il envoie **notre** `install_proxmox.sh` par scp au lieu de laisser la VM
|
||
cloner le dépôt : c'est notre code qu'on veut éprouver, et le dépôt distant
|
||
est souvent en retard sur le checkout — un correctif absent du distant a fait
|
||
« revenir » le même défaut sur trois VM de suite.
|
||
|
||
### L'algorithme de ressources
|
||
|
||
Deux choses s'épuisent en descendant, et une troisième se dégrade. Ce qui
|
||
s'épuise est de l'arithmétique, et `script/proxmox/nesting.py` la calcule :
|
||
|
||
* **la mémoire** — chaque étage garde de quoi faire tourner ses propres démons
|
||
(`pve-cluster`, `pvestatd`, `pvedaemon`, `pveproxy`) avant de céder le
|
||
reste ;
|
||
* **le disque** — le disque de l'enfant vit *dans* celui du parent, qui doit
|
||
aussi contenir son propre système.
|
||
|
||
Ce qui se dégrade est mesuré, pas supposé : au-delà du deuxième étage, les
|
||
fabricants ne documentent rien. D'où un seul nombre borné — **2 vCPU** pour
|
||
tout étage imbriqué. Douze vCPU au quatrième étage ont gelé le noyau invité en
|
||
tout début de démarrage ; les mêmes deux avançaient. Amener douze processeurs
|
||
en ligne coûte autant d'allers-retours à travers toute la pile.
|
||
|
||
La mémoire n'est **pas** bornée : la même VM gelait au même octet avec 9 Go et
|
||
avec 2 Go, donc la rogner ne gagnerait rien et priverait l'étage du dessous.
|
||
|
||
Le plan est affiché **avant** que quoi que ce soit ne soit créé, et le script
|
||
ne promet jamais une profondeur qu'il sait irréalisable — mieux vaut annoncer
|
||
six étages et en réussir six que d'en promettre dix et mourir au septième sans
|
||
savoir pourquoi.
|