210b4f5f16
Postmortem of the Linux template deploy/prepare 'no IP' investigation: separates the three distinct causes (apt index stale from --skip-update, deploy --force snapshot-chain, wedged host vmnet-dhcpd) and documents the recovery (restart vmware-networks). Changelog entry summarising the toolchain, xvfb, --force cleanup and cloud-init seal changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
183 lines
8.0 KiB
Markdown
183 lines
8.0 KiB
Markdown
# Postmortem — Template Linux: deploy/prepare "no IP" (2026-06-06)
|
|
|
|
## Sintesi
|
|
|
|
Durante l'aggiunta di dipendenze GUI al toolchain del template Linux
|
|
(`python3-gi gir1.2-gtk-4.0 xvfb`), una serie di fallimenti ha aperto una lunga
|
|
sessione di debug. Sono emersi **due problemi distinti**, più una causa
|
|
ambientale che ha confuso la diagnosi:
|
|
|
|
1. **Origine reale della sessione** — `prepare-linux` falliva allo Step 4a con
|
|
`Unable to locate package gir1.2-gtk-4.0`. Causa: `--skip-update` saltava
|
|
anche `apt-get update`, lasciando l'indice apt vecchio. **Non c'entrava la
|
|
rete.** Fix banale, applicato.
|
|
|
|
2. **Bug `deploy-linux --force`** — il resize allo Step 4 falliva con
|
|
*"disk is part of a snapshot chain"* perché `--force` riusava la directory
|
|
senza rimuovere la snapshot chain precedente. Bug deterministico, colpito
|
|
due volte. Fix applicato.
|
|
|
|
3. **Saga "no IP" (ambientale)** — il rilevamento IP via open-vm-tools andava in
|
|
timeout in modo **intermittente**. Causa finale: il servizio DHCP/NAT di
|
|
vmnet8 sull'host si era **inceppato** a causa della churn di debug (decine di
|
|
`vmrun start/stop`, `tcpdump` promiscuo, DISCOVER ripetuti del guest).
|
|
Risolto con un **restart di `vmware-networks`**. Non è un bug del codice né
|
|
del CI normale.
|
|
|
|
Stato finale: template `BaseClean-Linux` ricostruito da powered-off, con gtk/xvfb
|
|
e cloud-init sigillato. Tutti i test passano (coverage 94.4%).
|
|
|
|
---
|
|
|
|
## Cronologia
|
|
|
|
| Ora (host) | Evento |
|
|
|-----------|--------|
|
|
| ~10:50 | `prepare-linux --skip-update` → fallisce allo Step 4a (`gir1.2-gtk-4.0` non trovato) per indice apt stale |
|
|
| ~11:00 | Dopo fix apt + revert snapshot: `prepare-linux` riesce, guest ottiene IP `.153`, snapshot ripreso |
|
|
| ~11:03+ | I boot successivi dello snapshot non ottengono IP utile → inizio debug rete |
|
|
| 11:20 | Cattura sul filo: DHCP OFFER/ACK presenti, ma il guest non applica l'IPv4 |
|
|
| 12:06 | Deploy fresco: il guest **ottiene** `.143` (cloud-init), ma deploy Step 7 va in timeout sui tools |
|
|
| 12:26 | Reboot: stesso guest **non** ottiene IP (intermittenza) |
|
|
| ~12:30 | `vmware-networks --stop/--start` → l'IP torna stabile. Sblocco confermato |
|
|
| dopo | Implementati e testati i fix; template rigenerato |
|
|
|
|
---
|
|
|
|
## Analisi cause
|
|
|
|
### 2.1 Step 4a apt (origine della sessione)
|
|
|
|
`Install-CIToolchain-Linux2404.sh` faceva `apt-get update` **solo** se non era
|
|
passato `--skip-update`. Ma `--skip-update` dovrebbe saltare il solo *upgrade*
|
|
(lento), non il refresh dell'indice. Con indice vecchio, i pacchetti nuovi
|
|
(`gir1.2-gtk-4.0`, `xvfb`) non venivano trovati.
|
|
|
|
A riprova che a quel punto la rete funzionava: quel `prepare-linux` era entrato
|
|
in SSH nel guest senza problemi.
|
|
|
|
### 2.2 deploy-linux --force e la snapshot chain
|
|
|
|
`deploy-linux --force` riusa la directory della VM ma non rimuoveva gli artefatti
|
|
di un'eventuale snapshot precedente (`-NNNNNN.vmdk`, `.vmsn`, `.vmsd`). Con la
|
|
chain presente, `vmware-vdiskmanager` rifiuta il resize dello Step 4:
|
|
|
|
```
|
|
This disk is part of a snapshot chain in '.../LinuxBuild2404.vmx'.
|
|
The selected operation can only be executed on a disk with no snapshots.
|
|
```
|
|
|
|
### 2.3 La saga "no IP" — vmnet8 DHCP inceppato
|
|
|
|
Sintomo: `vmrun getGuestIPAddress` → *"VMware Tools are not running"* /
|
|
*"Unable to get the IP address"*, **in modo intermittente**. Il guest in realtà:
|
|
|
|
- bootava correttamente (login prompt),
|
|
- aveva open-vm-tools installato e attivo,
|
|
- ma `systemd-networkd` a volte **non applicava** un lease DHCPv4 (link up,
|
|
solo IPv6LL, `networkd-wait-online` in timeout).
|
|
|
|
Sul filo il DHCP a volte completava (`.143` applicato e raggiungibile), a volte
|
|
no. Il server rispondeva (altre VM ottenevano lease). La causa finale: il demone
|
|
`vmnet-dhcpd`/`vmnet-natd` di vmnet8 era andato in uno stato degradato dopo la
|
|
churn di debug. Il **restart** `vmware-networks --stop/--start` lo ha sbloccato
|
|
e l'IP è tornato stabile e immediato.
|
|
|
|
#### Ipotesi scartate (vicoli ciechi)
|
|
- **Controller pvscsi vs lsilogic** — il boot funzionava con pvscsi; irrilevante.
|
|
- **Naming NIC `ens192` vs `ens160`** — cloud-init si adattava; l'IP arrivava lo
|
|
stesso quando la rete funzionava.
|
|
- **Saturazione del pool DHCP** — il pool era di fatto libero (0 lease attivi);
|
|
i MAC multipli per IP nel lease DB sono storia normale di ISC dhcpd.
|
|
- **Seal cloud-init / machine-id** — difensivi ma non erano la causa del no-IP.
|
|
|
|
---
|
|
|
|
## Fix applicati (branch `fix/linux-template-toolchain-deploy`)
|
|
|
|
### Commit 1 — toolchain
|
|
`template/Install-CIToolchain-Linux2404.sh`
|
|
- **Step 4a**: installa `python3-gi gir1.2-gtk-4.0 xvfb` con assert su
|
|
`import gi` e `Xvfb` (richiesta originale).
|
|
- **Step 1**: `apt-get update` ora gira **sempre**; `--skip-update` salta solo
|
|
l'upgrade. Risolve il fallimento Step 4a.
|
|
|
|
### Commit 2 — robustezza deploy/prepare
|
|
`src/ci_orchestrator/commands/template.py` (+ test)
|
|
- **`_clean_force_artifacts`**: con `--force` rimuove snapshot delta, `.vmsn`,
|
|
`.vmsd` e `.lck` prima del resize → niente più errore snapshot-chain.
|
|
Coperto da 3 unit test.
|
|
- **prepare-linux Step 7d (seal cloud-init)**: rimuove la `50-cloud-init.yaml`
|
|
stale, rigenera netplan (resta solo il `99-ci-dhcp-allnics` MAC-agnostic),
|
|
disabilita cloud-init (`/etc/cloud/cloud-init.disabled`) così non rigira sui
|
|
cloni.
|
|
- **deploy user-data**: `package_update/upgrade: false` per non tenere il lock
|
|
dpkg al primo boot e non ritardare open-vm-tools oltre il poll dello Step 7.
|
|
- **Step 7 timeout**: `300s → 600s` come rete di sicurezza per primi boot lenti.
|
|
|
|
Verifica: `ruff` ✅, `mypy --strict` (23 file) ✅, suite completa ✅,
|
|
coverage **94.4%** (gate 90%). Prod venv reinstallato (non-editable).
|
|
|
|
---
|
|
|
|
## Procedura di recovery: deploy/prepare non ottiene IP
|
|
|
|
Quando `deploy-linux` (Step 7) o `prepare-linux` non riescono a rilevare l'IP
|
|
**ma il guest sembra sano** (booting, tools attivi), prima di sospettare
|
|
immagine o codice, riavvia il networking VMware sull'host:
|
|
|
|
```bash
|
|
sudo /usr/bin/vmware-networks --stop
|
|
sudo /usr/bin/vmware-networks --start
|
|
```
|
|
|
|
Flush opzionale dei lease (backup prima), **solo se nessuna VM è accesa**:
|
|
|
|
```bash
|
|
sudo cp /etc/vmware/vmnet8/dhcpd/dhcpd.leases /tmp/dhcpd.leases.bak
|
|
sudo sh -c ': > /etc/vmware/vmnet8/dhcpd/dhcpd.leases'
|
|
```
|
|
|
|
Distinto da:
|
|
- **Tools-not-running sul template** → revert a `BaseClean-Linux`
|
|
(vedi `template-live-state-recovery`).
|
|
- **vmmon/vmnet non compilati dopo bump kernel** → il guard systemd ricostruisce
|
|
i moduli al boot (vedi `vmware-modules-kernel-upgrade`).
|
|
|
|
---
|
|
|
|
## Raccomandazioni (NON applicate di proposito)
|
|
|
|
### Cosa NON fare
|
|
- **Restart/flush automatico ad ogni clone/deploy/prepare.** `vmware-networks`
|
|
è globale (bridge + hostonly + NAT insieme): un restart sotto un job in corso
|
|
rompe la rete di **tutte** le VM in esecuzione → job concorrenti falliti. Il
|
|
flush dei lease con VM attive causa conflitti IP al rinnovo. Sproporzionato
|
|
rispetto a un problema non dimostrato ricorrente.
|
|
|
|
### Cosa fare
|
|
- **Monitorare.** L'inceppamento è nato dalla churn anomala di debug, non dal CI
|
|
normale. Tenere la recovery manuale e agire solo se ricapita con dati reali.
|
|
|
|
### Se servisse hardening preventivo (a freddo, con cautela)
|
|
- Abbassare `max-lease-time` (i cloni vivono minuti → IP liberati in fretta; i
|
|
job lunghi rinnovano da soli via networkd).
|
|
- Allargare il range DHCP per più margine.
|
|
- **Caveat**: `/etc/vmware/vmnet8/dhcpd/dhcpd.conf` è **auto-generato da VMware**
|
|
("DO NOT MODIFY", validato con `CFG_HASH` in `/etc/vmware/networking`). Edit a
|
|
mano fragili: rischio rigenerazione al prossimo `--configure`/update. Da fare
|
|
solo se il problema si dimostra ricorrente.
|
|
|
|
---
|
|
|
|
## Lezioni
|
|
|
|
- L'attività di debug intensa sulla rete host (start/stop ripetuti, sniffing
|
|
promiscuo) può degradare `vmnet-dhcpd`: in futuro, minimizzare la churn e
|
|
preferire osservazione mirata.
|
|
- Tre cause distinte si sono sovrapposte; separarle prima ha richiesto tempo. Il
|
|
guest era fondamentalmente sano per quasi tutta la sessione — l'errore di
|
|
rilevamento IP non implicava un guest rotto.
|
|
- Non sovrastimare: i fix committati coprono i bug **veri e provati**; il DHCP è
|
|
stato lasciato invariato per evitare over-engineering.
|