docs(linux): rewrite LINUX-TEMPLATE-SETUP as implementation plan checklist (automated cloud-init approach)
This commit is contained in:
+291
-248
@@ -1,346 +1,389 @@
|
|||||||
# Linux Template VM Setup — DRAFT / TODO
|
# Linux Template VM Setup Piano di implementazione
|
||||||
|
|
||||||
> **Status**: bozza. Non implementato. Vedi [TODO.md §6.1](../TODO.md) (P2).
|
> **Status**: pianificato non ancora implementato. Vedi [TODO.md §6.1](../TODO.md) (P2).
|
||||||
> Documento di pianificazione per estendere il sistema CI con build su Linux,
|
> Distro scelta: **Ubuntu 24.04 LTS** (cloud image, cloud-init). Approccio simmetrico a Windows.
|
||||||
> in parallelo al template Windows già operativo.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Obiettivo
|
## Architettura: tre script + modulo transport
|
||||||
|
|
||||||
Aggiungere supporto a build su Linux per:
|
| Script / Modulo | Dove gira | Ruolo |
|
||||||
- Compilazione cross-platform (es. versione Linux di plugin C/C++, build check con GCC/Clang)
|
| --------------------------------------- | -------------- | ----------------------------------------------------------------- |
|
||||||
- Test su distro Linux per progetti che lo richiedono
|
| `template/Deploy-LinuxBuild2404.ps1` | **Host** (PS) | Crea VM da cloud image VMDK, genera seed ISO cloud-init, avvia, aspetta SSH |
|
||||||
- Build matrix `[windows, linux]` nei workflow Gitea
|
| `template/Prepare-LinuxBuild2404.ps1` | **Host** (PS) | Copia + esegue setup via SSH, valida stato, prende snapshot |
|
||||||
|
| `template/Setup-LinuxBuild2404.sh` | **Guest** (Bash) | Installa toolchain CI, dirs, hardening, gate finale |
|
||||||
|
| `scripts/_Transport.psm1` | **Host** (PS) | Interfaccia comune WinRM/SSH per Invoke-CIJob e script CI |
|
||||||
|
|
||||||
Architettura simmetrica al template Windows: VM template → snapshot `BaseClean-Linux` →
|
Perche tre script separati (non tutto-in-uno): cloud-init copre solo il bootstrap OS
|
||||||
linked clone per ogni job → cleanup automatico.
|
(utente, SSH key, pacchetti base). Il toolchain CI e le validazioni per step sono piu
|
||||||
|
leggibili e manutenibili in un secondo script dedicato identico alla divisione
|
||||||
|
Deploy/Setup/Prepare di Windows.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Decisioni di design (da validare)
|
## Specifiche VM
|
||||||
|
|
||||||
### Distro
|
|
||||||
|
|
||||||
| Opzione | Pro | Contro |
|
|
||||||
| ------------------------ | ------------------------------------------------------------------ | -------------------------------------------- |
|
|
||||||
| **Ubuntu 24.04 LTS** | Toolchain recente, supporto LTS fino al 2029, cloud-init ottimo | Snap default (lento per CI) |
|
|
||||||
| Debian 12 | Stabile, leggero, no snap | Toolchain meno recente |
|
|
||||||
| Rocky Linux 9 / Alma 9 | RHEL-compat, glibc moderno, dnf | Meno comune in workflow CI tipici |
|
|
||||||
|
|
||||||
**Scelta proposta**: Ubuntu 24.04 LTS minimal. Rationale: maggior parità con runner GitHub
|
|
||||||
ufficiali (`ubuntu-latest` mappa a 22.04/24.04), toolchain recente out-of-box, cloud-init
|
|
||||||
maturo per provisioning automatico.
|
|
||||||
|
|
||||||
### Transport host → VM
|
|
||||||
|
|
||||||
| Opzione | Pro | Contro |
|
|
||||||
| ------------------------ | ------------------------------------------------------------------ | -------------------------------------------- |
|
|
||||||
| **SSH (chiave pubblica)**| Standard Linux, supporto nativo OpenSSH su Win11/Server 2025 | Diversa API rispetto WinRM (PSSession) |
|
|
||||||
| WinRM su Linux (PSCore) | Codice script unificato | Setup complesso, non standard, fragile |
|
|
||||||
|
|
||||||
**Scelta proposta**: SSH key-based con `ssh.exe` + `scp.exe` (built-in Windows 10+) o
|
|
||||||
modulo `Posh-SSH`. WinRM su Linux non è production-ready.
|
|
||||||
|
|
||||||
### Layer di astrazione
|
|
||||||
|
|
||||||
Aggiungere `scripts/_Transport.psm1` con interfaccia comune:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# Pseudo-API
|
|
||||||
function Invoke-RemoteCommand {
|
|
||||||
param($Target, $ScriptBlock, $Args, [ValidateSet('WinRM','SSH')] $Transport)
|
|
||||||
}
|
|
||||||
function Copy-RemoteItem {
|
|
||||||
param($Source, $Destination, $Target, $Direction, $Transport)
|
|
||||||
}
|
|
||||||
function Test-RemoteReady {
|
|
||||||
param($Target, $TimeoutSec, $Transport)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Implementazioni:
|
|
||||||
- **WinRM** wrapper: `New-PSSession` + `Invoke-Command` + `Copy-Item -ToSession`
|
|
||||||
- **SSH** wrapper: `ssh.exe` + `scp.exe` con `-i $keyfile -o StrictHostKeyChecking=accept-new`
|
|
||||||
|
|
||||||
`Invoke-CIJob.ps1` riceve `-GuestOS Windows|Linux` (o auto-detect dal VMX `guestOS`),
|
|
||||||
sceglie transport.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Specifiche VM proposte
|
|
||||||
|
|
||||||
| Parametro | Valore |
|
| Parametro | Valore |
|
||||||
| ----------------------- | --------------------------------------------------------------- |
|
| ------------- | --------------------------------------------------- |
|
||||||
| OS | Ubuntu Server 24.04 LTS minimal |
|
| OS | Ubuntu 24.04 LTS (cloud image, non ISO installer) |
|
||||||
|
| Immagine base | `ubuntu-24.04-server-cloudimg-amd64.vmdk` |
|
||||||
|
| Download | `https://cloud-images.ubuntu.com/noble/current/` |
|
||||||
| vCPU | 4 |
|
| vCPU | 4 |
|
||||||
| RAM | 4096 MB (4 GB) — meno di Windows, footprint Linux più snello |
|
| RAM | 4096 MB |
|
||||||
| Disco | 40 GB thin |
|
| Disco | 40 GB thin (resize del cloud VMDK) |
|
||||||
| NIC | VMnet8 (NAT) — internet per `apt` |
|
| NIC | VMnet8 (NAT) vmxnet3 diretto (driver nativo kernel) |
|
||||||
| VMX path | `F:\CI\Templates\LinuxBuild\LinuxBuild.vmx` |
|
| VMX path | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` |
|
||||||
| ISO | `ubuntu-24.04.x-live-server-amd64.iso` (in `F:\CI\ISO\`) |
|
|
||||||
| Snapshot name | `BaseClean-Linux` |
|
| Snapshot name | `BaseClean-Linux` |
|
||||||
|
|
||||||
|
Differenza chiave da Windows: l'immagine di partenza e gia installata (cloud VMDK,
|
||||||
|
~600 MB). Nessuna fase di installazione OS cloud-init provvede al bootstrap al primo
|
||||||
|
boot in 30-60 secondi. La NIC non richiede lo swap e1000e vmxnet3 perche il kernel
|
||||||
|
Linux ha il driver vmxnet3 nativo.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## TODO — Implementazione
|
## Prerequisiti host
|
||||||
|
|
||||||
### Pre-requisiti host
|
- [ ] **SSH key CI dedicata** generare una volta sola (no passphrase):
|
||||||
|
|
||||||
- [ ] **OpenSSH client** verificato presente su host (default Win11/Server 2025)
|
|
||||||
```powershell
|
|
||||||
Get-WindowsCapability -Online -Name OpenSSH.Client*
|
|
||||||
```
|
|
||||||
- [ ] **Genera SSH key dedicata** per CI (no passphrase, separata da chiavi utente):
|
|
||||||
```powershell
|
```powershell
|
||||||
|
New-Item -ItemType Directory -Force F:\CI\keys | Out-Null
|
||||||
ssh-keygen -t ed25519 -f F:\CI\keys\ci_linux -N '""' -C 'ci-linux-runner'
|
ssh-keygen -t ed25519 -f F:\CI\keys\ci_linux -N '""' -C 'ci-linux-runner'
|
||||||
|
# Risultato: F:\CI\keys\ci_linux (privata) + F:\CI\keys\ci_linux.pub (pubblica)
|
||||||
```
|
```
|
||||||
- [ ] **Aggiungere a `Setup-Host.ps1`** uno step opzionale `-GenerateLinuxCIKey` che crea
|
- [ ] **OpenSSH client** verificato presente sull'host (default su Windows 11):
|
||||||
la chiave e la archivia con permessi corretti (`F:\CI\keys\` con ACL ristretta)
|
```powershell
|
||||||
|
Get-WindowsCapability -Online -Name OpenSSH.Client* | Select-Object State
|
||||||
|
# Atteso: State = Installed
|
||||||
|
```
|
||||||
|
- [ ] **Download cloud image VMDK** in `F:\CI\ISO\`:
|
||||||
|
```
|
||||||
|
https://cloud-images.ubuntu.com/noble/current/ubuntu-24.04-server-cloudimg-amd64.vmdk
|
||||||
|
```
|
||||||
|
- [ ] **`F:\CI\Templates\LinuxBuild2404\`** creata (Setup-Host.ps1 o manuale)
|
||||||
|
|
||||||
### Fase A — Crea VM e installa Ubuntu
|
---
|
||||||
|
|
||||||
- [ ] Crea nuova VM in VMware Workstation (4 vCPU, 4 GB RAM, 40 GB thin)
|
## Fase A Deploy-LinuxBuild2404.ps1
|
||||||
- [ ] NIC: VMnet8 (NAT)
|
|
||||||
- [ ] Boot da ISO Ubuntu Server 24.04 LTS minimal
|
|
||||||
- [ ] Durante install scegli:
|
|
||||||
- [ ] **Minimal install** (no extra packages)
|
|
||||||
- [ ] OpenSSH server: **Yes**
|
|
||||||
- [ ] Username: `ci_build`
|
|
||||||
- [ ] Hostname: `ci-linux-template`
|
|
||||||
- [ ] LVM: opzionale (non necessario per template)
|
|
||||||
- [ ] Annota IP DHCP (`ip a`)
|
|
||||||
|
|
||||||
### Fase B — Provisioning iniziale (manuale, una volta)
|
Script host-side. Produce una VM pronta con cloud-init completato e SSH raggiungibile.
|
||||||
|
Non richiede installazione OS parte dal cloud VMDK pre-built.
|
||||||
|
|
||||||
Dentro la VM, come `ci_build`:
|
- [ ] **Step 1 Validate prerequisites**
|
||||||
|
- `vmrun.exe` presente nel path atteso
|
||||||
|
- Cloud image VMDK sorgente presente in `F:\CI\ISO\`
|
||||||
|
- SSH key `F:\CI\keys\ci_linux.pub` presente
|
||||||
|
- Cartella destinazione VMX non gia occupata (o `-Force` per sovrascrivere)
|
||||||
|
|
||||||
- [ ] **Disabilita swap permanente** (overhead I/O su NVMe condivisa):
|
- [ ] **Step 2 Genera cloud-init user-data + meta-data** (inline, no template esterno)
|
||||||
```bash
|
- `meta-data`: `instance-id: linuxbuild-001`, `local-hostname: ci-linux-template`
|
||||||
sudo swapoff -a
|
- `user-data` (YAML):
|
||||||
sudo sed -i '/ swap / s/^/#/' /etc/fstab
|
- `hostname: ci-linux-template`, `timezone: Europe/Rome`
|
||||||
|
- `users`: utente `ci_build`, shell `/bin/bash`, `sudo: ALL=(ALL) NOPASSWD:ALL`,
|
||||||
|
`ssh_authorized_keys` con contenuto di `ci_linux.pub`
|
||||||
|
- `packages`: `[openssh-server, curl, ca-certificates, p7zip-full]`
|
||||||
|
- `package_update: true`
|
||||||
|
- `runcmd`: `swapoff -a`, commenta swap in `/etc/fstab`,
|
||||||
|
`sed PasswordAuthentication no` in sshd_config, `systemctl restart sshd`
|
||||||
|
- `power_state`: `mode: reboot` dopo primo provisioning
|
||||||
|
|
||||||
|
- [ ] **Step 3 Costruisce seed ISO nocloud** via IMAPI2FS COM
|
||||||
|
- Due file: `user-data` + `meta-data` (volume label: `cidata`)
|
||||||
|
- Stesso codice COM gia usato in Deploy-WinBuild2025.ps1 Step 3
|
||||||
|
- Output: `F:\CI\Templates\LinuxBuild2404\cloud-init-seed.iso`
|
||||||
|
|
||||||
|
- [ ] **Step 4 Copia e ridimensiona cloud VMDK**
|
||||||
|
- Copia `ubuntu-24.04-server-cloudimg-amd64.vmdk` `LinuxBuild2404.vmdk`
|
||||||
|
- Ridimensiona a 40 GB: `vmware-vdiskmanager -x 40GB LinuxBuild2404.vmdk`
|
||||||
|
|
||||||
|
- [ ] **Step 5 Genera .vmx**
|
||||||
|
- `guestOS = "ubuntu-64"`, BIOS (cloud image Ubuntu compatibile entrambi;
|
||||||
|
BIOS piu semplice per lab)
|
||||||
|
- NIC: `vmxnet3`, VMnet8
|
||||||
|
- Disco: `LinuxBuild2404.vmdk` (scsi0:0)
|
||||||
|
- CD-ROM secondario: `cloud-init-seed.iso` (connesso)
|
||||||
|
- Nessun USB controller, nessuna sound card
|
||||||
|
- `memsize = 4096`, `numvcpus = 4`
|
||||||
|
|
||||||
|
- [ ] **Step 6 Power on** (`vmrun start nogui`)
|
||||||
|
|
||||||
|
- [ ] **Step 7 Polling SSH port 22** fino a ready
|
||||||
|
- `Test-NetConnection -ComputerName $IP -Port 22` ogni 10 secondi
|
||||||
|
- Timeout: 5 minuti (cloud-init + reboot finale)
|
||||||
|
- IP rilevato via `vmrun getGuestIPAddress`
|
||||||
|
|
||||||
|
> open-vm-tools e pre-installato nell'Ubuntu 24.04 cloud image.
|
||||||
|
> `vmrun getGuestIPAddress` funziona senza installazione aggiuntiva.
|
||||||
|
|
||||||
|
- [ ] **Step 8 Verifica cloud-init completato**
|
||||||
|
```powershell
|
||||||
|
ssh -i F:\CI\keys\ci_linux -o StrictHostKeyChecking=accept-new `
|
||||||
|
-o ConnectTimeout=5 ci_build@$IP `
|
||||||
|
"test -f /var/lib/cloud/instance/boot-finished && echo OK"
|
||||||
|
# Atteso: OK
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Disabilita servizi non necessari** (snap, motd-news, ecc.):
|
- [ ] **Step 9 Rimuove seed ISO dal VMX**
|
||||||
```bash
|
- Setta `ide1:0.present = "FALSE"` nel VMX
|
||||||
sudo systemctl disable --now snapd.service snapd.socket snapd.seeded.service 2>/dev/null
|
- Evita che linked clone ricevano il seed ISO e ri-eseguano cloud-init
|
||||||
sudo systemctl disable --now motd-news.timer 2>/dev/null
|
|
||||||
sudo systemctl disable --now apt-daily.timer apt-daily-upgrade.timer
|
|
||||||
```
|
|
||||||
Rationale: snap e timer apt rallentano boot e mangiano CPU su VM efimere.
|
|
||||||
|
|
||||||
- [ ] **Sudo passwordless** per `ci_build` (parità con WinRM admin senza prompt UAC):
|
- [ ] **Step 10 Print summary** (VMX path, IP, SSH fingerprint)
|
||||||
```bash
|
|
||||||
echo 'ci_build ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/90-ci_build
|
---
|
||||||
sudo chmod 440 /etc/sudoers.d/90-ci_build
|
|
||||||
|
## Fase B Prepare-LinuxBuild2404.ps1
|
||||||
|
|
||||||
|
Script host-side. Copia il setup script, lo esegue via SSH, valida stato, prende snapshot.
|
||||||
|
Equivalente di `Prepare-WinBuild2025.ps1` con SSH al posto di WinRM.
|
||||||
|
|
||||||
|
- [ ] **Step 1 Pre-flight**
|
||||||
|
- VMX presente; se VM spenta, avvia con `vmrun start nogui`
|
||||||
|
- SSH key `F:\CI\keys\ci_linux` presente
|
||||||
|
- `ssh.exe` e `scp.exe` nel PATH host
|
||||||
|
- TCP/22 raggiungibile (`Test-NetConnection`)
|
||||||
|
|
||||||
|
- [ ] **Step 2 Auto-detect IP** via `vmrun getGuestIPAddress $VMXPath`
|
||||||
|
- Se `-VMIPAddress` e fornito esplicitamente, salta il rilevamento automatico
|
||||||
|
|
||||||
|
- [ ] **Step 3 Aggiungi host key a known_hosts**
|
||||||
|
```powershell
|
||||||
|
ssh -i F:\CI\keys\ci_linux -o StrictHostKeyChecking=accept-new `
|
||||||
|
ci_build@$IP "echo connected" | Out-Null
|
||||||
|
```
|
||||||
|
Solo al primo run; idempotente se gia presente.
|
||||||
|
|
||||||
|
- [ ] **Step 4 Copia Setup-LinuxBuild2404.sh in VM**
|
||||||
|
```powershell
|
||||||
|
scp -i F:\CI\keys\ci_linux `
|
||||||
|
"$PSScriptRoot\Setup-LinuxBuild2404.sh" `
|
||||||
|
"ci_build@${IP}:/tmp/Setup-LinuxBuild2404.sh"
|
||||||
|
```
|
||||||
|
Valida: confronta size locale vs remota via `ssh ... stat -c %s /tmp/...`
|
||||||
|
|
||||||
|
- [ ] **Step 5 Esegui setup script** nel guest
|
||||||
|
```powershell
|
||||||
|
ssh -i F:\CI\keys\ci_linux ci_build@$IP `
|
||||||
|
"chmod +x /tmp/Setup-LinuxBuild2404.sh && sudo /tmp/Setup-LinuxBuild2404.sh"
|
||||||
|
# Cattura exit code; != 0 => abort con errore leggibile
|
||||||
|
```
|
||||||
|
Flag opzionali passabili: `--skip-update`, `--dotnet`, `--mingw`
|
||||||
|
|
||||||
|
- [ ] **Step 6 Post-setup remote validation** (batch via singola sessione SSH)
|
||||||
|
- `systemctl is-active ssh` = `active`
|
||||||
|
- `id ci_build` contiene `sudo`
|
||||||
|
- `sudo -n true` exit 0 (passwordless sudo)
|
||||||
|
- `which gcc g++ clang cmake python3 git 7z` tutti trovati
|
||||||
|
- `test -d /opt/ci/build -a -d /opt/ci/output -a -d /opt/ci/scripts` exit 0
|
||||||
|
- `swapon --show` output vuoto (swap disabilitato)
|
||||||
|
- `grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config`
|
||||||
|
|
||||||
|
- [ ] **Step 7 Shutdown VM**
|
||||||
|
```powershell
|
||||||
|
& $vmrun stop $VMXPath soft
|
||||||
|
# Polling vmrun list fino a VM non piu presente
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Authorized SSH key** dell'host CI:
|
- [ ] **Step 8 Snapshot BaseClean-Linux**
|
||||||
```bash
|
```powershell
|
||||||
mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
& $vmrun snapshot $VMXPath 'BaseClean-Linux'
|
||||||
# Incolla la chiave pubblica generata su host (F:\CI\keys\ci_linux.pub)
|
|
||||||
echo 'ssh-ed25519 AAAA... ci-linux-runner' >> ~/.ssh/authorized_keys
|
|
||||||
chmod 600 ~/.ssh/authorized_keys
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **SSH hardening** per template (ma non così stretto da bloccare CI):
|
- [ ] **Final Print summary** (VMX, snapshot name, toolchain versions rilevate)
|
||||||
```bash
|
|
||||||
sudo sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
|
|
||||||
sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
|
|
||||||
sudo systemctl restart sshd
|
|
||||||
```
|
|
||||||
|
|
||||||
### Fase C — Setup-LinuxTemplateVM.sh (script equivalente a Setup-WinBuild2025.ps1)
|
---
|
||||||
|
|
||||||
Da creare: `template/Setup-LinuxTemplateVM.sh` con `set -euo pipefail` + `assert_step()` helper.
|
## Fase C Setup-LinuxBuild2404.sh
|
||||||
|
|
||||||
- [ ] **Helper `assert_step`** (throw on fail, log su success):
|
Script guest-side (Bash). Installazione toolchain CI e hardening.
|
||||||
```bash
|
Eseguito da Prepare via SSH come `ci_build` con sudo.
|
||||||
assert_step() {
|
|
||||||
local step="$1"; local desc="$2"; shift 2
|
|
||||||
if "$@" >/dev/null 2>&1; then
|
|
||||||
echo " [OK] [$step] $desc"
|
|
||||||
else
|
|
||||||
echo " [FAIL] [$step] $desc" >&2; exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 1 — `apt update` + upgrade**
|
Header: `#!/usr/bin/env bash` + `set -euo pipefail`
|
||||||
|
Helper `assert_step()`: stampa `[OK] [Step N] desc` su successo, `exit 1` su fallimento.
|
||||||
|
|
||||||
|
- [ ] **Step 1 apt update + upgrade** (saltabile con `--skip-update`)
|
||||||
```bash
|
```bash
|
||||||
sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
|
sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
|
||||||
sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -y -qq
|
sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -y -qq
|
||||||
assert_step 'apt' 'no errors' true
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Step 2 — Toolchain build essentials**
|
- [ ] **Step 2 Toolchain build essentials**
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get install -y -qq \
|
sudo apt-get install -y -qq \
|
||||||
build-essential gcc g++ clang \
|
build-essential gcc g++ clang \
|
||||||
make cmake ninja-build \
|
make cmake ninja-build \
|
||||||
pkg-config autoconf automake libtool \
|
pkg-config autoconf automake libtool
|
||||||
git curl wget ca-certificates \
|
|
||||||
python3 python3-pip python3-venv \
|
|
||||||
unzip zip xz-utils
|
|
||||||
assert_step 'toolchain' 'gcc presente' command -v gcc
|
|
||||||
assert_step 'toolchain' 'clang presente' command -v clang
|
|
||||||
assert_step 'toolchain' 'cmake presente' command -v cmake
|
|
||||||
assert_step 'toolchain' 'python3 presente' command -v python3
|
|
||||||
```
|
```
|
||||||
|
- assert: `command -v gcc`, `command -v clang`, `command -v cmake`
|
||||||
|
|
||||||
- [ ] **Step 3 — Toolchain extra opzionale**
|
- [ ] **Step 3 Python**
|
||||||
- [ ] **mingw-w64** se serve cross-compile per Windows: `sudo apt-get install -y mingw-w64`
|
```bash
|
||||||
- [ ] **.NET SDK** (per parità Windows): script `dotnet-install.sh` con channel pinned
|
sudo apt-get install -y -qq python3 python3-pip python3-venv
|
||||||
- [ ] **Node.js** se workflow lo richiede: nvm o nodesource repo
|
sudo ln -sf /usr/bin/python3 /usr/local/bin/python
|
||||||
|
```
|
||||||
|
- assert: `python3 --version`, `pip3 --version`
|
||||||
|
|
||||||
- [ ] **Step 4 — CI working directories**
|
- [ ] **Step 4 Tier-1 Toolchain** (speculare a §6.6 Windows: Git + 7-Zip)
|
||||||
|
```bash
|
||||||
|
sudo apt-get install -y -qq git p7zip-full curl wget ca-certificates
|
||||||
|
```
|
||||||
|
- assert: `command -v git`, `command -v 7z`
|
||||||
|
|
||||||
|
- [ ] **Step 4b .NET SDK** (opzionale, flag `--dotnet`)
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh \
|
||||||
|
| sudo bash -s -- --channel 10.0 --install-dir /usr/local/dotnet
|
||||||
|
sudo ln -sf /usr/local/dotnet/dotnet /usr/local/bin/dotnet
|
||||||
|
```
|
||||||
|
- assert: `dotnet --version`
|
||||||
|
|
||||||
|
- [ ] **Step 4c mingw-w64** (opzionale, flag `--mingw` cross-compile per Windows)
|
||||||
|
```bash
|
||||||
|
sudo apt-get install -y -qq mingw-w64
|
||||||
|
```
|
||||||
|
- assert: `command -v x86_64-w64-mingw32-gcc`
|
||||||
|
|
||||||
|
- [ ] **Step 5 CI directories**
|
||||||
```bash
|
```bash
|
||||||
sudo mkdir -p /opt/ci/{build,output,scripts,cache}
|
sudo mkdir -p /opt/ci/{build,output,scripts,cache}
|
||||||
sudo chown -R ci_build:ci_build /opt/ci
|
sudo chown -R ci_build:ci_build /opt/ci
|
||||||
assert_step 'dirs' 'tutte presenti' test -d /opt/ci/build -a -d /opt/ci/output
|
|
||||||
```
|
```
|
||||||
|
- assert: `test -d /opt/ci/build`, `test -d /opt/ci/output`, `test -d /opt/ci/scripts`
|
||||||
|
|
||||||
- [ ] **Step 5 — Disabilita auto-update apt** (no surprise reboot/lock):
|
- [ ] **Step 6 SSH hardening** (PasswordAuth off gia impostato da cloud-init, ri-validato)
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get remove -y unattended-upgrades 2>/dev/null
|
sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
|
||||||
sudo systemctl mask apt-daily.service apt-daily-upgrade.service
|
sudo sed -i 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
|
||||||
|
sudo systemctl restart sshd
|
||||||
|
```
|
||||||
|
- assert: `grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config`
|
||||||
|
|
||||||
|
- [ ] **Step 7 Disabilita swap permanente**
|
||||||
|
```bash
|
||||||
|
sudo swapoff -a
|
||||||
|
sudo sed -i '/ swap / s/^/#/' /etc/fstab
|
||||||
|
```
|
||||||
|
- assert: `swapon --show` output vuoto
|
||||||
|
|
||||||
|
- [ ] **Step 8 Disabilita apt auto-update** (no lock durante build)
|
||||||
|
```bash
|
||||||
|
sudo systemctl mask apt-daily.service apt-daily-upgrade.service \
|
||||||
|
apt-daily.timer apt-daily-upgrade.timer
|
||||||
|
sudo apt-get remove -y unattended-upgrades 2>/dev/null || true
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Step 6 — Cleanup pre-snapshot**
|
- [ ] **Step 9 Cleanup pre-snapshot**
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get clean
|
sudo apt-get clean
|
||||||
sudo rm -rf /var/lib/apt/lists/*
|
sudo rm -rf /var/lib/apt/lists/*
|
||||||
sudo journalctl --vacuum-time=1d
|
sudo journalctl --vacuum-time=1d
|
||||||
sudo rm -rf /tmp/* /var/tmp/*
|
sudo rm -rf /tmp/* /var/tmp/*
|
||||||
history -c && cat /dev/null > ~/.bash_history
|
history -c
|
||||||
# Zero free space (riduce dim VMDK dopo compact, opzionale)
|
cat /dev/null > ~/.bash_history
|
||||||
# sudo dd if=/dev/zero of=/zero bs=1M; sudo rm /zero
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Step 7 — Final pre-snapshot validation**
|
- [ ] **Final Gate pre-snapshot** (exit 1 se qualcosa manca)
|
||||||
- SSH server abilitato e in ascolto su 22
|
- Ogni tool richiesto raggiungibile con `command -v`
|
||||||
- `sudo` passwordless funzionante per `ci_build`
|
- `/opt/ci/{build,output,scripts}` esistenti con owner `ci_build`
|
||||||
- Tutti i tool elencati (`gcc --version`, `cmake --version`, ecc.) ritornano exit 0
|
- `swapon --show` vuoto
|
||||||
- `/opt/ci/{build,output,scripts}` esistono con owner corretto
|
- `sshd` attivo
|
||||||
- No leftover `/tmp/*`, history vuota
|
- `PasswordAuthentication no` in sshd_config
|
||||||
|
- Nessun installer residuo in `/tmp`
|
||||||
|
|
||||||
### Fase D — Prepare-LinuxTemplateSetup.ps1 (orchestratore host-side)
|
---
|
||||||
|
|
||||||
Equivalente di `Prepare-WinBuild2025.ps1` per Linux. Usa SSH invece di WinRM.
|
## Fase D Adattamento script CI
|
||||||
|
|
||||||
- [ ] **Pre-flight host**:
|
- [ ] **`scripts/_Transport.psm1`** nuovo modulo con interfaccia comune WinRM/SSH:
|
||||||
- SSH key esiste (`F:\CI\keys\ci_linux`)
|
|
||||||
- `ssh.exe` e `scp.exe` raggiungibili
|
|
||||||
- IP target risponde a `Test-NetConnection -Port 22`
|
|
||||||
|
|
||||||
- [ ] **Copia script in VM**:
|
|
||||||
```powershell
|
```powershell
|
||||||
scp -i F:\CI\keys\ci_linux -o StrictHostKeyChecking=accept-new `
|
function Invoke-RemoteCommand { param($Target, $Command, [ValidateSet('WinRM','SSH')] $Transport, ...) }
|
||||||
template\Setup-LinuxTemplateVM.sh ci_build@${VMIPAddress}:/tmp/
|
function Copy-RemoteItem { param($Source, $Dest, $Target, $Direction, $Transport, ...) }
|
||||||
|
function Test-RemoteReady { param($Target, $TimeoutSec, $Transport, ...) }
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Esegui script in VM**:
|
- [ ] **`scripts/Invoke-CIJob.ps1`** aggiungere parametro `-GuestOS Windows|Linux`
|
||||||
```powershell
|
- Auto-detect da VMX `guestOS` field se non fornito
|
||||||
ssh -i F:\CI\keys\ci_linux ci_build@${VMIPAddress} `
|
- Branch su transport (WinRM vs SSH) in ogni fase
|
||||||
"chmod +x /tmp/Setup-LinuxTemplateVM.sh && sudo /tmp/Setup-LinuxTemplateVM.sh"
|
|
||||||
```
|
|
||||||
Cattura stdout + exit code, parse `[OK]`/`[FAIL]` lines.
|
|
||||||
|
|
||||||
- [ ] **Post-setup remote validation** (parità Windows): query SSH per state checks:
|
- [ ] **`scripts/Wait-VMReady.ps1`** aggiungere `-Transport SSH`
|
||||||
- `systemctl is-active ssh` = active
|
- Probe: `Test-NetConnection -Port 22` + `ssh -o ConnectTimeout=5 ... "echo ok"`
|
||||||
- `id ci_build` ritorna gruppo + sudo
|
|
||||||
- `gcc --version`, `cmake --version`, `python3 --version` exit 0
|
|
||||||
- `test -d /opt/ci/build` exit 0
|
|
||||||
|
|
||||||
### Fase E — Snapshot
|
- [ ] **`scripts/Invoke-RemoteBuild.ps1`** branch SSH+scp per Linux
|
||||||
|
- Transfer: `scp` invece di `Copy-Item -ToSession`
|
||||||
|
- Build: `ssh ... "cd /opt/ci/build && $BuildCommand"`
|
||||||
|
|
||||||
- [ ] Solo se Prepare exit 0 → power off VM:
|
- [ ] **`scripts/Get-BuildArtifacts.ps1`** branch `scp` per Linux
|
||||||
```bash
|
- `scp -r ci_build@$IP:/opt/ci/output/* $LocalArtifactDir\`
|
||||||
sudo shutdown -h now
|
|
||||||
```
|
|
||||||
- [ ] Take snapshot in VMware Workstation: **`BaseClean-Linux`** (case-sensitive)
|
|
||||||
|
|
||||||
### Fase F — Adattamento script CI
|
- [ ] **`scripts/New-BuildVM.ps1`** gia OS-agnostic (vmrun clone)
|
||||||
|
- Verificare che `-SnapshotName BaseClean-Linux` funzioni correttamente
|
||||||
|
|
||||||
- [ ] **`scripts/_Transport.psm1`** (nuovo modulo) con interfaccia comune
|
- [ ] **`scripts/Remove-BuildVM.ps1`** gia OS-agnostic, nessuna modifica prevista
|
||||||
- [ ] **`scripts/Invoke-CIJob.ps1`** — aggiungere `-GuestOS Windows|Linux`, branching su transport
|
|
||||||
- [ ] **`scripts/Wait-VMReady.ps1`** — supporto SSH probe (`Test-NetConnection -Port 22` + `ssh -o ConnectTimeout=5 ...`)
|
|
||||||
- [ ] **`scripts/Invoke-RemoteBuild.ps1`** — branch SSH+scp per Linux
|
|
||||||
- [ ] **`scripts/Get-BuildArtifacts.ps1`** — `scp` per Linux invece di `Copy-Item -FromSession`
|
|
||||||
- [ ] **`scripts/New-BuildVM.ps1`** — already OS-agnostic (vmrun clone), verificare che `BaseClean-Linux` sia parametrizzabile
|
|
||||||
- [ ] **`scripts/Remove-BuildVM.ps1`** — already OS-agnostic
|
|
||||||
|
|
||||||
### Fase G — Workflow Gitea
|
---
|
||||||
|
|
||||||
- [ ] **Registrare label `linux-build`** sul runner (oppure secondo runner dedicato):
|
## Fase E Runner e workflow Gitea
|
||||||
|
|
||||||
|
- [ ] **Label `linux-build`** aggiunta al runner in `runner/config.yaml`:
|
||||||
```yaml
|
```yaml
|
||||||
# runner/config.yaml — aggiungere a labels esistenti
|
|
||||||
labels:
|
labels:
|
||||||
- 'windows-build:host'
|
- 'windows-build:host'
|
||||||
- 'linux-build:host'
|
- 'linux-build:host'
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Workflow matrix**:
|
- [ ] **Variabile d'ambiente** `GITEA_CI_LINUX_TEMPLATE_PATH` nel servizio act_runner:
|
||||||
|
`F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx`
|
||||||
|
|
||||||
|
- [ ] **Workflow matrix** di esempio (`gitea/workflow-example.yml` aggiornato):
|
||||||
```yaml
|
```yaml
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
target: [windows, linux]
|
target: [windows, linux]
|
||||||
runs-on: ${{ matrix.target }}-build
|
runs-on: ${{ matrix.target }}-build
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- run: pwsh -File scripts/Invoke-CIJob.ps1 -GuestOS ${{ matrix.target }}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fase H — Test e2e
|
|
||||||
|
|
||||||
- [ ] **Smoke test** clone + SSH ready:
|
|
||||||
```powershell
|
|
||||||
.\scripts\New-BuildVM.ps1 -JobId 'linux-smoke' -SnapshotName 'BaseClean-Linux'
|
|
||||||
.\scripts\Wait-VMReady.ps1 -JobId 'linux-smoke' -Transport SSH
|
|
||||||
.\scripts\Remove-BuildVM.ps1 -JobId 'linux-smoke'
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Build reale**: scegliere repo con build Linux nativo (es. `cmake` based) e
|
|
||||||
eseguire job e2e via `Invoke-CIJob.ps1 -GuestOS Linux`
|
|
||||||
|
|
||||||
- [ ] **Confronto artifact**: build dello stesso repo target Windows vs Linux,
|
|
||||||
verifica che entrambi vengano raccolti in `F:\CI\Artifacts\<jobId>\`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Differenze chiave rispetto al template Windows
|
## Fase F Test e2e
|
||||||
|
|
||||||
|
- [ ] **Smoke test** linked clone + SSH ready:
|
||||||
|
```powershell
|
||||||
|
.\scripts\New-BuildVM.ps1 -JobId 'linux-smoke-001' `
|
||||||
|
-TemplatePath 'F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx' `
|
||||||
|
-SnapshotName 'BaseClean-Linux'
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Build test** comando reale nella VM:
|
||||||
|
```powershell
|
||||||
|
.\scripts\Invoke-CIJob.ps1 -JobId 'linux-e2e-001' -GuestOS Linux `
|
||||||
|
-RepoUrl 'ssh://gitea-ci/Simone/<repo>.git' -Branch 'main' `
|
||||||
|
-TemplatePath 'F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx' `
|
||||||
|
-BuildCommand 'make -C /opt/ci/build all' `
|
||||||
|
-GuestArtifactSource '/opt/ci/output'
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Cleanup** linked clone rimosso dopo build (`Remove-BuildVM.ps1`)
|
||||||
|
- [ ] **Matrix build** run parallela Windows + Linux sullo stesso push
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Differenze da Windows riepilogo
|
||||||
|
|
||||||
| Aspetto | Windows | Linux |
|
| Aspetto | Windows | Linux |
|
||||||
| ----------------------- | -------------------------------------- | ------------------------------------------- |
|
| ------------------------ | -------------------------------------------- | --------------------------------------------- |
|
||||||
| Transport | WinRM HTTPS/5986 + Basic (-SkipCACheck) | SSH/22 + ed25519 key |
|
| Immagine di partenza | ISO installer (Deploy ~60-90 min unattended) | Cloud VMDK pre-built (boot + cloud-init ~60 s) |
|
||||||
| Auth fluid | `ci_build` admin + UAC off + LATFP=1 | `ci_build` + sudoers NOPASSWD |
|
| Provisioning unattended | `autounattend.xml` (Windows Setup) | cloud-init `user-data` (seed ISO nocloud) |
|
||||||
| Trasferimento file | `Copy-Item -ToSession` | `scp` o `rsync` |
|
| Transport host VM | WinRM HTTPS/5986 + PSSession | `ssh.exe` + `scp.exe` (built-in Windows 11) |
|
||||||
| Esecuzione remota | `Invoke-Command -Session` | `ssh user@host 'cmd'` |
|
| NIC strategia | e1000e install vmxnet3 swap post-Tools | vmxnet3 diretto (driver nativo kernel) |
|
||||||
| AV/Firewall disable | Defender + Win Firewall off | ufw inattivo (default), no AV |
|
| Setup script | `.ps1` (PowerShell, via WinRM) | `.sh` (Bash, via SSH) |
|
||||||
| Update package | Windows Update (COM API + sched task) | `apt-get update && upgrade` non-interactive |
|
| Rilevamento IP | `vmrun getGuestIPAddress` (VMware Tools) | `vmrun getGuestIPAddress` (open-vm-tools) |
|
||||||
| Toolchain | VS Build Tools 2026 + .NET SDK | gcc/g++/clang + cmake (+ .NET SDK opt) |
|
| Wait completamento | polling flag file via `vmrun copyFileFromGuestToHost` | polling SSH + `boot-finished` cloud-init |
|
||||||
|
| CI dirs | `C:\CI\{build,output,scripts}` | `/opt/ci/{build,output,scripts,cache}` |
|
||||||
| Snapshot name | `BaseClean` | `BaseClean-Linux` |
|
| Snapshot name | `BaseClean` | `BaseClean-Linux` |
|
||||||
| Footprint VM | 6 GB RAM, 80 GB disk | 4 GB RAM, 40 GB disk |
|
|
||||||
| Boot time | ~30-60 s post-clone | ~10-20 s post-clone (atteso) |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Backlog correlato (TODO.md)
|
## Riferimenti
|
||||||
|
|
||||||
- **§6.1 [P2]** Linux Build VM — entry parent
|
- [ARCHITECTURE.md](ARCHITECTURE.md) diagramma componenti (aggiornare dopo implementazione)
|
||||||
- **§6.4 [P3]** Build matrix `[windows, linux]` nel workflow
|
- [CI-FLOW.md](CI-FLOW.md) flusso pipeline (aggiornare Step 0 prerequisites)
|
||||||
- **§6.3 [P3]** Multi-host runner federation (se 4 VM Linux + 4 Windows non bastano)
|
- [HOST-SETUP.md](HOST-SETUP.md) Setup-Host.ps1 (aggiungere step generazione SSH key)
|
||||||
- **§5.2 [P2]** Modulo `_Transport.psm1` condiviso (prerequisito architetturale)
|
- [TODO.md §6.1](../TODO.md) tracking implementazione
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Domande aperte
|
|
||||||
|
|
||||||
1. **.NET SDK su Linux** — sempre installato o solo se workflow lo richiede?
|
|
||||||
Decisione: installare **se** workload richiede parità di build. Default off, opt-in via flag.
|
|
||||||
2. **Image size** — Ubuntu minimal + toolchain ≈ 5 GB. Compact post-snapshot per ridurre footprint VMDK?
|
|
||||||
Decisione: sì, `dd if=/dev/zero` + `vmware-vdiskmanager -k` (manuale, una tantum).
|
|
||||||
3. **Pre-warm pool Linux** — boot Linux è veloce, beneficio minore. Decisione: implementare solo se profile dimostra > 30% overhead.
|
|
||||||
4. **Cloud-init vs script manuale** — cloud-init richiede ISO seed o NoCloud datasource. Più pulito ma overhead di setup. Decisione: script bash diretto (parità con flusso Windows). Cloud-init valutabile in v2.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user