docs: record the LinuxRust2404 template, its failure modes and open decisions
- AGENTS.md: LinuxRust2404 reference, plus errors #14-#16 -- deploy --force against a powered-on VM, the three distinct causes behind the identical "VMware Tools are not running" message, and the orphan snapshot deltas --force leaves behind after deleting the .vmsd. - docs/RUNBOOK.md §16: triage for a Step 7 IP timeout, ordered cheapest check first, with a Quick Reference entry. - docs/RUNBOOK-PhaseC.md: deploy-rust/prepare-rust, the ownership and non-login shell constraints on /opt/rust, --then-prepare, and how to route a label to a template (a second runner instance, with the verification step). - TODO.md §2.9: retention run covers only artifacts, logs and IP leases, so it warned about low disk while freeing 0.0 GB two runs in a row. Mitigated by hand; the automated policy is still blind to what actually weighs. - TODO.md §6.5: act_runner v1.0.4 -> v2.x evaluated and deferred, with the trigger for reopening. v2.1.0 exposes no RUNNER_LABELS either (checked against the binary), so the two-runner design is not a stopgap.
This commit is contained in:
@@ -174,6 +174,47 @@ Variante **WinBuild2022**: path `F:\CI\Templates\WinBuild2022\WinBuild2022.vmx`,
|
||||
| Toolchain | GCC, G++, Clang, CMake, Ninja, Python 3, Git, 7-Zip |
|
||||
| CI dirs | `/opt/ci/{build,output,scripts,cache}` — owner `ci_build` |
|
||||
|
||||
### Linux Rust (LinuxRust2404)
|
||||
|
||||
Variante di `LinuxBuild2404` per workspace Rust (es. app Tauri): stessa cloud
|
||||
image e stesso layout guest, provisioning via
|
||||
`template/Install-CIToolchain-LinuxRust2404.sh` che aggiunge le librerie
|
||||
webview/GTK di Tauri v2 e una toolchain Rust system-wide sotto `/opt/rust`
|
||||
(rustup + rustfmt + clippy + binario `cargo-audit`; il DB advisory di
|
||||
cargo-audit NON e' bakato, viene fetchato a runtime).
|
||||
|
||||
| Parametro | Valore |
|
||||
| -------------- | ------------------------------------------------------------- |
|
||||
| OS | Ubuntu 24.04 LTS (cloud image) |
|
||||
| VMX | `LinuxRust2404/LinuxRust2404.vmx` (sotto la dir templates) |
|
||||
| Snapshot clone | `BaseClean-LinuxRust` |
|
||||
| Transport | SSH porta 22, utente `ci_build`, stessa chiave di LinuxBuild2404 |
|
||||
| Toolchain | quella di LinuxBuild2404 + webview/GTK Tauri + Rust in `/opt/rust` |
|
||||
| Comandi | `ci template deploy-rust` / `ci template prepare-rust` |
|
||||
|
||||
`--rust-channel` (default `stable`) controlla la toolchain bakata: pinnare una
|
||||
versione esatta (es. `1.97.1`) per uno snapshot deterministico; con `stable`
|
||||
rustup riscarica a runtime ad ogni nuova stable. Rigenerare lo snapshot quando
|
||||
cambia il pin o la baseline apt di sicurezza.
|
||||
|
||||
Due vincoli sull'albero `/opt/rust`, entrambi regressioni gia' occorse:
|
||||
|
||||
1. **`chown` DOPO l'installazione.** Lo script gira come root, quindi tutto
|
||||
cio' che rustup/cargo creano nasce root-owned: un `chown` fatto solo prima
|
||||
copre le due directory vuote e nient'altro. Senza il `chown` finale
|
||||
`ci_build` non puo' scrivere ne' in `RUSTUP_HOME` ne' in
|
||||
`CARGO_HOME/registry`, e **ogni** build Rust con dipendenze esterne muore
|
||||
con `Permission denied (os error 13)`. Gli assert devono verificare la
|
||||
**scrivibilita'** (`sudo -u ci_build test -w`), non solo `test -x` sui
|
||||
binari: altrimenti il template rotto passa la sua build e fallisce nei job
|
||||
dei consumatori.
|
||||
2. **`/etc/profile.d` da solo non basta.** L'orchestratore esegue i comandi
|
||||
con paramiko `exec_command` + `sh -c` (`transport/ssh.py`,
|
||||
`commands/build.py`): shell **non di login**, `profile.d` non viene mai
|
||||
sorgiato. `RUSTUP_HOME`/`CARGO_HOME` vanno anche in `/etc/environment`
|
||||
(letto da `pam_env` all'apertura della sessione SSH) e i proxy rustup
|
||||
symlinkati in `/usr/local/bin`.
|
||||
|
||||
---
|
||||
|
||||
## Transport layer
|
||||
@@ -236,3 +277,9 @@ Configurazione in `PSScriptAnalyzerSettings.psd1`. Regole principali:
|
||||
11. **Machine-id identico tra clone Linux** — le cloud image Ubuntu hanno un `/etc/machine-id` fisso. VMware DHCP assegna l'IP tramite DHCP client-id derivato da machine-id: se tutti i clone hanno lo stesso machine-id ottengono lo stesso IP e si bloccano per "IP collision". Fix nel template (prima di prendere lo snapshot): `sudo truncate -s 0 /etc/machine-id && sudo rm -f /var/lib/dbus/machine-id && sudo shutdown -h now`, poi ricreare lo snapshot `BaseClean-Linux` da stato powered-off.
|
||||
12. **`& nativecmd 2>$null` NON sopprime stderr in PS 5.1 con `$ErrorActionPreference='Stop'`** — la stderr del processo nativo viene convertita in ErrorRecord nel pipeline di PowerShell; sotto `'Stop'` questo diventa un errore terminante PRIMA che `2>$null` possa scartarlo. Esempio: `ssh-keygen -R <ip> -f <file>` stampa "Host X not found in file" su stderr → eccezione terminante. Fix: usare `$ErrorActionPreference = 'SilentlyContinue'` attorno alla chiamata oppure `2>&1 | Out-Null`. Per i job CI su VM ephemere locali, usare direttamente `StrictHostKeyChecking=no UserKnownHostsFile=NUL` (default in `_Transport.psm1` con `KnownHostsFile=''`) — nessun `ssh-keygen` necessario.
|
||||
13. **Quote WinRM/desktop-heap troppo basse per builds Windows paralleli** — sintomo: `MSBuild error MSB6003: CL.exe could not be run. System.ComponentModel.Win32Exception (0x80004005): Not enough quota is available to process this command` (oppure le altre tool MSVC: link.exe, mt.exe) quando il build interno fa fan-out parallelo (es. matrix x86/x64/x86-ansi, MSBuild `/maxcpucount`). Causa: il plugin endpoint Microsoft.PowerShell del guest ha `MaxMemoryPerShellMB=150` di default e l'heap del desktop non-interattivo (Session 0) ha `SharedSection 3rd field=768 KB` — entrambi insufficienti per più CL.exe concorrenti via WinRM. **Non emerge** in pre-migration Win→Win perché `Invoke-Command` su `PSSession` localhost-style eredita quote più larghe; emerge appena il path passa per `pypsrp` Linux→Win. Fix nel template (Deploy-WinBuild2025.ps1 / 2022 lo fa, Install-CIToolchain lo valida): `Set-Item WSMan:\localhost\Plugin\Microsoft.PowerShell\Quotas\MaxMemoryPerShellMB 2048`, `Set-Item WSMan:\localhost\Shell\MaxProcessesPerShell 100`, registry `HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems\Windows` patch del 3° campo `SharedSection` a 4096, **reboot** (csrss legge SharedSection solo al boot), nuovo `BaseClean`. Dettagli e procedura completa in `docs/WINDOWS-TEMPLATE-SETUP.md § "WinRM quotas e desktop heap"`.
|
||||
|
||||
14. **`deploy-* --force` lanciato mentre la VM target è ACCESA** — corrompe la VM in esecuzione e produce un timeout allo Step 7 che *sembra* un problema di rete. Occorso il 2026-07-22 su `LinuxRust2404`, con un `prepare-rust` ancora in corso sulla stessa VMX. Meccanica: (a) Step 1 vede `<disk>.vmdk.lck` e lo cancella come "stale artifact" — **non era stale**, apparteneva al processo vivo; (b) Step 4 riscrive il VMDK base sotto il guest in esecuzione, che muore; (c) Step 6 lancia il power-on, il nuovo `vmware-vmx` muore subito perché la VMX è già occupata, ma il controllo `[OK] VM appears in vmrun list` **passa lo stesso** perché vede l'istanza vecchia; (d) Step 7 interroga per 10 minuti un guest morto e riporta `Error: The VMware Tools are not running in the virtual machine`. Diagnosi in 5 secondi: `ps -eo pid,lstart,etime,args | grep vmware-vmx` — se il `vmware-vmx` vivo è più vecchio del deploy appena lanciato, è questo il caso. Recupero: `vmrun stop <vmx> hard`, rimuovere i delta orfani `<disk>-00000*.vmdk`, verificare `vmrun list` = 0, poi rilanciare. **Non** interpretarlo come DHCP incastrato (vedi #15) e non risolverlo con un retry automatico: riavviare una VM già corrotta ripete il fallimento con la causa ormai illeggibile.
|
||||
|
||||
15. **Step 7 in timeout: distinguere tre cause diverse che danno lo stesso messaggio** — `getGuestIPAddress` risponde `The VMware Tools are not running` sia quando il guest non ha IP, sia quando ha l'IP ma i Tools non rispondono. Ordine di verifica, dal più veloce: (a) **collisione** — `ps | grep vmware-vmx`, processo più vecchio del deploy corrente → vedi #14; (b) **DHCP host incastrato** — `ip -4 addr show vmnet8` deve dare `192.168.79.1/24` e `ps -ef | grep vmnet-dhcpd` deve mostrarlo vivo; se no, `sudo systemctl restart vmware-networks` (o `vmware-host.service`); (c) **guest senza lease o Tools non pronti** — cercare il MAC della VMX in `/etc/vmware/vmnet8/dhcpd/dhcpd.leases` e in `ip neigh show dev vmnet8`: se un lease c'è, il guest è vivo e mancano solo i Tools, quindi sondare TCP/22 direttamente invece di aspettare `getGuestIPAddress`.
|
||||
|
||||
16. **Delta di snapshot orfani dopo `--force`** — `deploy-*` cancella `<vm>.vmsd` (il database snapshot) per evitare l'errore di resize sulla catena, ma **non** cancella i file delta `<disk>-00000N.vmdk`. Restano su disco con un `parentCID` che non corrisponde più al base ricreato: innocui (fuori dal percorso di boot, la VMX punta al base con `parentCID=ffffffff`) ma confondono la diagnosi e vanno rimossi a mano. Verifica della catena: `head -c 2000 <disk>.vmdk | strings | grep -E '^CID|parentCID'`.
|
||||
|
||||
@@ -106,6 +106,14 @@ The host **never executes build tools directly** — it only orchestrates VM lif
|
||||
| WinBuild2025 | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` | `BaseClean` | WinRM HTTPS/5986 |
|
||||
| WinBuild2022 | `F:\CI\Templates\WinBuild2022\WinBuild2022.vmx` | `BaseClean` | WinRM HTTPS/5986 |
|
||||
| LinuxBuild2404 | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` | `BaseClean-Linux` | SSH/22 (`ci_build`, key `F:\CI\keys\ci_linux`) |
|
||||
| LinuxRust2404 | `LinuxRust2404/LinuxRust2404.vmx` (templates dir) | `BaseClean-LinuxRust` | SSH/22 (same user/key as LinuxBuild2404) |
|
||||
|
||||
`LinuxRust2404` is a LinuxBuild2404 variant for Rust workspaces (Tauri):
|
||||
`ci template deploy-rust` / `ci template prepare-rust` provision it via
|
||||
`template/Install-CIToolchain-LinuxRust2404.sh` (webview/GTK libs + system-wide
|
||||
rustup under `/opt/rust` + cargo-audit binary; the audit advisory DB is fetched
|
||||
at runtime, never baked). `--rust-channel` pins the baked toolchain (default
|
||||
`stable`, a moving target).
|
||||
|
||||
Snapshots **must be taken from powered-off state** — presence of `.vmem` in the template dir means the snapshot captured running memory and `vmrun clone ... linked` will fail.
|
||||
|
||||
|
||||
@@ -312,6 +312,34 @@ mai rilasciati. Workaround manuale: reset a `{}` con `build-vms/` vuoto.
|
||||
cui clone-dir non esiste più in `CloneBaseDir`. Opzionale: allargare il pool
|
||||
(es. 201–210) per dare margine oltre parallelism. Aggiungere test.
|
||||
|
||||
### 2.9 [P2] [ ] `retention run` non copre backup/template/ISO — APERTO (2026-07-22)
|
||||
|
||||
`ci-retention-policy` agisce solo su **artifact, log e lease IP**. Su questo host
|
||||
quei tre insiemi pesano 52 KB in tutto, mentre il disco era pieno al 94% per
|
||||
`backups/` (195 G), `templates/` (128 G) e `iso/` (69 G) — tutti fuori dal suo
|
||||
raggio d'azione.
|
||||
|
||||
Sintomo osservato: il timer girava, rilevava meno di 50 GB liberi, dichiarava
|
||||
`WARNING: Free space below 50 GB — aggressive retention: 7d` e liberava
|
||||
**0.0 GB**, due esecuzioni di fila. L'allarme suonava ma il meccanismo non
|
||||
poteva agire su ciò che pesava. Un guardiano che non sorveglia nulla è peggio di
|
||||
nessun guardiano: dà l'impressione che il problema sia sotto controllo.
|
||||
|
||||
Mitigato il 2026-07-22 (backup svuotati, `--keep-count 1 --exclude WinBuildTest`
|
||||
nella unit), ma è una correzione manuale: la policy automatica resta cieca.
|
||||
|
||||
**Fix proposto**: estendere `retention run` ai backup (per numero di generazioni
|
||||
o per età) e almeno segnalare — non cancellare — ISO e template che superano una
|
||||
soglia. In alternativa, se i backup restano governati solo da `--keep-count`,
|
||||
far sì che il warning sullo spazio dica **quali** directory pesano, invece di
|
||||
lamentarsi senza indicare dove guardare.
|
||||
|
||||
**Nota**: `iso/` contiene coppie originale + `.patched` e versioni April
|
||||
superate da May (~38 G recuperabili); le `.patched` sono rigenerate da
|
||||
`deploy-win`. `templates/WinBuildTest` (41 G, ultimo uso 10 giugno, citato solo
|
||||
in `docs/archived/2026-05-10/`) è candidato alla dismissione: escluso dai backup
|
||||
ma ancora su disco.
|
||||
|
||||
---
|
||||
|
||||
## 3. Performance & throughput
|
||||
@@ -518,6 +546,54 @@ Già supportato lato Gitea, basta replicare il setup.
|
||||
|
||||
**Deferred**: in un home lab single-host questa funzionalità non serve. Non pianificare.
|
||||
|
||||
### 6.5 [P3] [ ] Upgrade act_runner v1.0.4 → v2.x — VALUTATO E RIMANDATO (2026-07-22)
|
||||
|
||||
Versione installata: **v1.0.4** (18 mag 2026). Ultima upstream al momento della
|
||||
valutazione: **v2.1.0** (16 lug 2026).
|
||||
Release: https://gitea.com/gitea/runner/releases
|
||||
|
||||
**Decisione: non aggiornare ora.** Il beneficio netto per questo sistema è
|
||||
marginale. Valutazione fatta ispezionando il binario v2.1.0 (checksum
|
||||
verificato), non solo il changelog.
|
||||
|
||||
Cosa **non** cambia — verificato sul binario, non dedotto:
|
||||
|
||||
- v2.1.0 esporta al job esattamente le stesse variabili di v1.0.4
|
||||
(`RUNNER_ARCH/TEMP/DEBUG/OS/TOOL_CACHE`), **nessun `RUNNER_LABELS`**. Il
|
||||
`GITEA_RUNNER_LABELS` del changelog v2.1.0 è operator-side: imposta le label
|
||||
del daemon all'avvio, non le espone al workflow. Il routing label → template
|
||||
continua a richiedere un'istanza runner per label (vedi RUNBOOK-PhaseC,
|
||||
sezione `deploy-rust`).
|
||||
|
||||
Cosa non ci riguarda: il grosso di v2.x è lavoro su Docker/container
|
||||
(credenziali di pull, service container, dind, IPv6). Qui `container.enabled`
|
||||
è `false`, host mode puro. Anche l'unico breaking change di v2.0.0
|
||||
(`DOCKER_USERNAME`/`DOCKER_PASSWORD` non più impliciti nei pull) è inapplicabile.
|
||||
|
||||
Cosa ci riguarderebbe:
|
||||
|
||||
| Novità | Valore reale |
|
||||
|---|---|
|
||||
| Cancellation handling completa (v2.0.0) + reap processi (v1.0.7/1.0.8) | Un job cancellato può lasciare una build VM orfana — ma `ci-cleanup-orphans.timer` gira già ogni 6h |
|
||||
| `runner.post_task_script` (v2.0.0) | Aggancerebbe `vm cleanup` dopo ogni task: latenza orfani da ≤6h a immediata |
|
||||
| `jobs.<id>.timeout-minutes` / `continue-on-error` (v2.0.0) | Ergonomia workflow |
|
||||
| `register --token-file` (v2.1.0) | Già implementato a mano in `scripts/install-rust-runner.sh` |
|
||||
|
||||
Schema di configurazione retrocompatibile: il diff v2.1.0 vs il nostro config è
|
||||
solo additivo, nessuna chiave rimossa.
|
||||
|
||||
**Trigger per riaprire**: quando serve `runner.post_task_script` per azzerare la
|
||||
latenza del cleanup orfani, oppure quando la 2.x è matura (era vecchia di 6
|
||||
giorni alla valutazione). Non aggiornare "per stare aggiornati".
|
||||
|
||||
**Vincolo operativo da ricordare**: i due runner (`act-runner.service` e
|
||||
`act-runner-rust.service`) condividono **lo stesso binario**
|
||||
`/opt/ci/act_runner/act_runner`. Sostituirlo aggiorna entrambi insieme. Per un
|
||||
rollout graduale serve un secondo binario affiancato
|
||||
(`act_runner-2.1.0`), l'`ExecStart` del solo servizio rust puntato lì, un job di
|
||||
prova su `runs-on: rust-build`, e solo dopo la promozione per il runner
|
||||
principale — tenendo v1.0.4 per il rollback.
|
||||
|
||||
### 6.4 [P3] [x] Build matrix nel workflow
|
||||
File: [gitea/workflows/build-ns7zip.yml](gitea/workflows/build-ns7zip.yml).
|
||||
|
||||
|
||||
@@ -77,10 +77,12 @@ sudo); `--uninstall` removes the block. The script defines two helpers:
|
||||
| `ci vmware --vmx ...` | Open a VMX in the VMware Workstation GUI | [§4](#4-manual-vm-lifecycle) |
|
||||
| `ci creds set --user ...` | Store guest credentials in the keyring | [§5](#5-credentials--template-provisioning) |
|
||||
| `ci template deploy-linux` | Build the Linux template VM | [§5](#5-credentials--template-provisioning) |
|
||||
| `ci template deploy-rust` | Build the Rust Linux template VM (LinuxRust2404) | [§5](#5-credentials--template-provisioning) |
|
||||
| `ci template check-win-iso` | Report the newest WS2025 ISO from massgrave + cache status | [§5](#5-credentials--template-provisioning) |
|
||||
| `ci template patch-win-iso` | Inject autounattend + no-prompt boot into a Windows ISO | [§5](#5-credentials--template-provisioning) |
|
||||
| `ci template deploy-win` | Build the Windows Server 2025 template VM (download→patch→deploy) | [§5](#5-credentials--template-provisioning) |
|
||||
| `ci template prepare-linux` | Provision the Linux template over SSH | [§5](#5-credentials--template-provisioning) |
|
||||
| `ci template prepare-rust` | Provision the Rust Linux template over SSH | [§5](#5-credentials--template-provisioning) |
|
||||
| `ci template prepare-win` | Provision a Windows template over WinRM | [§5](#5-credentials--template-provisioning) |
|
||||
| `ci template backup` | Timestamped copy of the template directories | [§5](#5-credentials--template-provisioning) |
|
||||
| `ci retention run` | Purge old artifacts and logs | [§6](#6-maintenance) |
|
||||
@@ -412,12 +414,139 @@ Run `ci template <sub> --help` for the (many) per-template options.
|
||||
|
||||
```bash
|
||||
ci template deploy-linux # build the Linux template VM from scratch (Ubuntu 24.04)
|
||||
ci template deploy-rust # build the Rust Linux template VM (LinuxRust2404)
|
||||
ci template deploy-win # build the Windows Server 2025 template VM (see below)
|
||||
ci template prepare-linux # provision an existing Linux template over SSH
|
||||
ci template prepare-rust # provision the Rust Linux template over SSH
|
||||
ci template prepare-win # provision a Windows template over WinRM (Linux-host driven)
|
||||
ci template backup # timestamped backup of the template directories
|
||||
```
|
||||
|
||||
### `deploy-rust` / `prepare-rust` — the Rust Linux template (LinuxRust2404)
|
||||
|
||||
A separate template for Rust workspaces (e.g. Tauri apps): same Ubuntu 24.04
|
||||
cloud image and guest layout as `LinuxBuild2404`, but `prepare-rust` runs
|
||||
`template/Install-CIToolchain-LinuxRust2404.sh`, which additionally bakes:
|
||||
|
||||
- the Tauri v2 webview/GTK development libraries
|
||||
(`libwebkit2gtk-4.1-dev`, `libgtk-3-dev`, `libayatana-appindicator3-dev`,
|
||||
`librsvg2-dev`);
|
||||
- a system-wide Rust toolchain via rustup under `/opt/rust`
|
||||
(`RUSTUP_HOME=/opt/rust/rustup`, `CARGO_HOME=/opt/rust/cargo`) with the
|
||||
`rustfmt` and `clippy` components. The tree is `chown`ed to `ci_build`
|
||||
**after** the installs, not only before — otherwise every write the build
|
||||
user makes (toolchain sync, dependency download into
|
||||
`CARGO_HOME/registry`, `cargo install`) fails with `Permission denied`.
|
||||
Exposure is threefold because the orchestrator runs build commands in a
|
||||
**non-login** shell (`exec_command` + `sh -c`), which never sources
|
||||
`profile.d`: `/etc/profile.d/rust.sh` for interactive shells,
|
||||
`/etc/environment` (read by `pam_env` at SSH session open) for the two
|
||||
home variables, and `/usr/local/bin` symlinks for the rustup proxies;
|
||||
- the `cargo-audit` binary (skip with `--no-cargo-audit`). The audit
|
||||
**advisory DB is never baked** — `cargo audit` fetches it at runtime.
|
||||
|
||||
```bash
|
||||
ci template deploy-rust # same flags as deploy-linux; 60 GB disk default
|
||||
ci template prepare-rust # default VMX: <CI_TEMPLATES>/LinuxRust2404/...
|
||||
# snapshot: BaseClean-LinuxRust
|
||||
ci template prepare-rust --rust-channel 1.97.1 # pin an exact toolchain
|
||||
|
||||
# Both phases in one run, unattended. deploy and prepare stay separate
|
||||
# commands — --then-prepare only chains them, reusing the VM deploy left
|
||||
# running (no second power-on, no second IP detection).
|
||||
#
|
||||
# Run from the repo root: the guest toolchain script is looked up under
|
||||
# <cwd>/template/. With --then-prepare this is checked BEFORE the deploy
|
||||
# starts, so a wrong directory costs two seconds instead of failing the
|
||||
# hand-off after a ~45-minute deploy. Pass --toolchain-script to run from
|
||||
# anywhere.
|
||||
cd /opt/ci/local-ci-cd-system
|
||||
ci template deploy-rust --then-prepare --rust-channel 1.97.1
|
||||
ci template deploy-linux --then-prepare
|
||||
|
||||
# from any directory
|
||||
ci template deploy-rust --then-prepare --rust-channel 1.97.1 \
|
||||
--toolchain-script /opt/ci/local-ci-cd-system/template/Install-CIToolchain-LinuxRust2404.sh
|
||||
```
|
||||
|
||||
`--snapshot-name` on `deploy-linux`/`deploy-rust` names the snapshot that
|
||||
`prepare-*` will create (`BaseClean-Linux` / `BaseClean-LinuxRust`) — the
|
||||
deploy commands take no snapshot of their own, unlike `deploy-win`. With
|
||||
`--then-prepare` the value is handed to `prepare-*`, so overriding it on the
|
||||
deploy side changes what actually gets created.
|
||||
|
||||
Both `prepare-linux` and `prepare-rust` default `--vmx` to their template VMX
|
||||
under `<CI_TEMPLATES>` (`LinuxBuild2404` / `LinuxRust2404`) when neither
|
||||
`--vmx` nor `--ip` is passed — so the plain `ci template prepare-rust` just
|
||||
works after `deploy-rust`. Pass `--ip` to provision a running guest without
|
||||
VM lifecycle (no auto power-on/shutdown/snapshot).
|
||||
|
||||
`--rust-channel` defaults to `stable` — a moving target: when a new stable
|
||||
ships, `rustup show` in a job re-downloads the toolchain at runtime. Pin an
|
||||
exact version for a fully deterministic snapshot (the consumer repo decides
|
||||
this via its `rust-toolchain.toml`). Refresh the snapshot when the pinned
|
||||
channel or the apt security baseline moves.
|
||||
|
||||
Two ways to route jobs to it:
|
||||
|
||||
1. **Per job (no host change).** Pass `template-path` + `snapshot-name` to the
|
||||
`local-ci-build` composite action. This cannot leave a job unschedulable,
|
||||
which is why consumer repos default to it.
|
||||
2. **By label** — `runs-on: rust-build`. This needs a **second act_runner
|
||||
instance**, not just an extra label on the existing one: act_runner reads a
|
||||
single `runner.envs` block per process and never tells the workflow which
|
||||
label picked the job (there is no `RUNNER_LABELS` variable — v1.0.4 exposes
|
||||
only `RUNNER_OS/ARCH/TEMP/TOOL_CACHE/DEBUG/VERSION`). A label can select a
|
||||
template only by selecting a runner whose envs name that template.
|
||||
|
||||
```bash
|
||||
# 1. mint a registration token from the stored GiteaPAT (0600 file, never
|
||||
# printed — pass it by path so it stays out of `ps` and shell history)
|
||||
sudo -u ci-runner /opt/ci/venv/bin/python tools/gitea-runner-token.py \
|
||||
--out /var/lib/ci/.rust-runner-regtoken
|
||||
|
||||
# 2. provision + register + enable the unit
|
||||
sudo ./scripts/install-rust-runner.sh \
|
||||
--token-file /var/lib/ci/.rust-runner-regtoken
|
||||
|
||||
# 3. the token is single-use — destroy it
|
||||
sudo shred -u /var/lib/ci/.rust-runner-regtoken
|
||||
```
|
||||
|
||||
Provisions `/var/lib/ci/runner-rust/` from `deploy/runner-rust-config.yaml`
|
||||
(label `rust-build:host`, `GITEA_CI_LINUX_TEMPLATE_PATH` →
|
||||
`LinuxRust2404`, `GITEA_CI_LINUX_SNAPSHOT_NAME` → `BaseClean-LinuxRust`),
|
||||
registers it, and installs `act-runner-rust.service`. Its `capacity` adds
|
||||
to the main runner's — keep the sum inside the host RAM budget (currently
|
||||
2 + 1 = 3 concurrent build VMs).
|
||||
|
||||
**Verify the label is announced before any workflow depends on it**: a
|
||||
`runs-on` value that no runner advertises leaves the job unschedulable with
|
||||
no error anywhere — silently zero runs.
|
||||
|
||||
```bash
|
||||
sudo -u ci-runner /opt/ci/venv/bin/python tools/gitea-runner-list.py \
|
||||
--label rust-build # exit 1 unless an ONLINE runner announces it
|
||||
```
|
||||
|
||||
Note that `runner.file` in the config is an **absolute** path. act_runner
|
||||
resolves a relative `file:` against the process CWD, so registering from
|
||||
anywhere else drops the registration state (which contains the runner
|
||||
token) into that directory and the daemon then fails with
|
||||
`registration file not found`.
|
||||
|
||||
Both runner services share **one binary**, `/opt/ci/act_runner/act_runner`.
|
||||
Replacing it upgrades `act-runner.service` and `act-runner-rust.service`
|
||||
together — a staged rollout needs a second binary alongside it and the
|
||||
`ExecStart` of one unit pointed at it. Current version is v1.0.4; the
|
||||
upgrade to v2.x was evaluated and deferred (TODO §6.5).
|
||||
|
||||
Note that `guest-os: 'Auto'` cannot pick a template by itself, for the same
|
||||
reason: the label is invisible to the action, and the VMX `guestOS` field is
|
||||
only readable *after* the clone. With `Auto` the action requires
|
||||
`template-path` **and** `snapshot-name` and fails fast otherwise, instead of
|
||||
silently falling back to the Windows template as it did before.
|
||||
|
||||
### `deploy-win` — build the Windows Server 2025 template
|
||||
|
||||
Takes a Windows Server 2025 install ISO — downloaded from `--iso-url` (cached
|
||||
|
||||
@@ -250,6 +250,7 @@ Estimated time: 2-4 hours including Windows Update.
|
||||
| Template corrupt | Remove `*.lck` files; if persistent, restore from `F:\CI\Backups\` |
|
||||
| Snapshot missing | `vmrun listSnapshots <vmx>`; update `GITEA_CI_SNAPSHOT_NAME` |
|
||||
| IP collision | `Remove-Item F:\CI\State\ip-leases\*.lease`; lower `capacity` |
|
||||
| Step 7: no guest IP | `ps -eo pid,lstart,args \| grep vmware-vmx` — see §16 |
|
||||
|
||||
---
|
||||
|
||||
@@ -868,3 +869,92 @@ This is **optional** — the default boots-to-Linux behaviour is intentional so
|
||||
the machine comes back as the Linux CI host after any unattended reboot
|
||||
(power-loss, kernel update). Leave it as-is unless Windows becomes the daily
|
||||
driver.
|
||||
|
||||
---
|
||||
|
||||
## 16. `deploy-*` step 7 in timeout — nessun IP dal guest
|
||||
|
||||
**Sintomo.** `deploy-linux` / `deploy-rust` cicla su
|
||||
`... waiting for guest IP (open-vm-tools) ...` per 10 minuti e chiude con
|
||||
`Error: [Deploy Step 7] Timed out waiting for guest IP.` Interrogando a mano:
|
||||
|
||||
```
|
||||
$ vmrun -T ws getGuestIPAddress <vmx>
|
||||
Error: The VMware Tools are not running in the virtual machine
|
||||
```
|
||||
|
||||
Quel messaggio è ambiguo: esce identico sia quando il guest **non ha** un IP,
|
||||
sia quando ce l'ha ma i Tools non rispondono. Tre cause distinte, in ordine di
|
||||
verifica dal più veloce al più lento.
|
||||
|
||||
### 16.1 Collisione con una VM già accesa (la più insidiosa)
|
||||
|
||||
Succede quando si lancia `deploy-* --force` mentre la stessa VMX è in uso —
|
||||
tipicamente un `prepare-*` ancora in corso. Occorso il 2026-07-22 su
|
||||
`LinuxRust2404`.
|
||||
|
||||
```bash
|
||||
ps -eo pid,lstart,etime,args | grep vmware-vmx | grep -v grep
|
||||
```
|
||||
|
||||
Se il `vmware-vmx` vivo è **più vecchio** del deploy appena lanciato, è questo
|
||||
il caso: il deploy ha cancellato il `.vmdk.lck` della VM viva credendolo stale,
|
||||
ha riscritto il VMDK base sotto il guest in esecuzione, e il suo power-on è
|
||||
morto subito perché la VMX era occupata. Il controllo
|
||||
`[OK] VM appears in vmrun list` **non protegge**: vede l'istanza vecchia.
|
||||
|
||||
Recupero:
|
||||
|
||||
```bash
|
||||
sudo -u ci-runner vmrun -T ws stop <vmx> hard
|
||||
sudo rm -f <vm-dir>/<disk>-00000*.vmdk # delta orfani, vedi 16.4
|
||||
sudo -u ci-runner vmrun -T ws list # deve dire 0
|
||||
# poi rilanciare il deploy, con nient'altro in esecuzione sulla stessa VMX
|
||||
```
|
||||
|
||||
Non risolvere con un retry: riavviare una VM già corrotta ripete il fallimento
|
||||
con la causa ormai illeggibile.
|
||||
|
||||
### 16.2 DHCP dell'host incastrato
|
||||
|
||||
```bash
|
||||
ip -4 addr show vmnet8 # atteso: inet 192.168.79.1/24
|
||||
ps -ef | grep vmnet-dhcpd # atteso: due istanze (vmnet1 + vmnet8)
|
||||
```
|
||||
|
||||
Se `vmnet8` manca o `vmnet-dhcpd` non c'è:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart vmware-networks # oppure vmware-host.service
|
||||
```
|
||||
|
||||
### 16.3 Guest senza lease, oppure Tools non ancora pronti
|
||||
|
||||
```bash
|
||||
grep -A1 '^lease' /etc/vmware/vmnet8/dhcpd/dhcpd.leases | tail -20
|
||||
ip neigh show dev vmnet8
|
||||
```
|
||||
|
||||
Se compare un lease per il MAC della VM, **il guest è vivo e ha rete**: mancano
|
||||
solo i Tools. Sondare direttamente la porta 22 invece di aspettare
|
||||
`getGuestIPAddress`:
|
||||
|
||||
```bash
|
||||
timeout 5 bash -c 'cat < /dev/null > /dev/tcp/<ip>/22' && echo "SSH aperta"
|
||||
```
|
||||
|
||||
Se invece non c'è nessun lease e le due verifiche precedenti sono pulite, il
|
||||
guest non sta completando il boot: cloud-init fallito o immagine corrotta.
|
||||
|
||||
### 16.4 Delta di snapshot orfani
|
||||
|
||||
`deploy-*` cancella `<vm>.vmsd` per evitare l'errore di resize sulla catena
|
||||
snapshot, ma **non** rimuove i file delta `<disk>-00000N.vmdk`. Restano con un
|
||||
`parentCID` che non corrisponde più al base ricreato. Sono innocui — la VMX
|
||||
punta al base, riconoscibile da `parentCID=ffffffff` — ma confondono la
|
||||
diagnosi. Verifica della catena:
|
||||
|
||||
```bash
|
||||
grep -i 'scsi0:0.fileName' <vmx>
|
||||
head -c 2000 <disk>.vmdk | strings | grep -E '^CID|parentCID'
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user