# Fase B — Checklist finale per l'utente La Fase B è la migrazione del runner CI dall'host Windows attuale a un nuovo host **Linux Mint LTS** con VMware Workstation Pro Linux. > **Stato repo**: solo lo step **B5** (unit `systemd` per i task > periodici) è già committato in `deploy/systemd/` sul branch > `feature/python-rewrite-phase-a` (commit `50d37b5`). > Tutti gli altri step (B1–B4, B6–B8) sono **operazioni hardware** > sull'host Linux nuovo e devono essere eseguiti dall'utente. > **Pre-requisito**: la Fase A deve essere `done` (vedi > `plans/PhaseA-user-checklist.md` Passo 9, merge + tag). > B1, B2, B3 possono partire in parallelo a A3/A4/A5; B4–B8 sono > sequenziali e iniziano solo dopo "A done". > **Tempo stimato totale**: 1–2 giorni di lavoro distribuiti su una > finestra di 1–2 settimane (per consentire il burn-in tra B6 e B8). --- ## Passo 1 — Setup host Linux Mint (B1) **Obiettivo**: hardware target con Linux Mint LTS, VMware Workstation Pro Linux, layout storage e venv Python pronti. - [ ] Installare Linux Mint LTS sull'hardware target. - [ ] `sudo apt update && sudo apt full-upgrade -y && sudo reboot` - [ ] Scaricare e installare VMware Workstation Pro Linux (bundle `.bundle` da Broadcow): ```bash sudo bash VMware-Workstation-Full-*.bundle vmrun -T ws --version # deve ritornare versione coerente ``` - [ ] Smoke test Workstation (UI): creare VM trivia, clone, start, stop, delete. - [ ] Configurare `vmnet8` NAT range `192.168.79.0/24` (allineato a Windows) editando `/etc/vmware/vmnet8/dhcpd/dhcpd.conf` o via `vmware-netcfg`. - [ ] Creare utente di servizio `ci-runner`: ```bash sudo useradd -r -m -s /bin/bash ci-runner ``` - [ ] Creare layout storage: ```bash sudo mkdir -p /var/lib/ci/{build-vms,artifacts,templates,keys} sudo chown -R ci-runner:ci-runner /var/lib/ci sudo chmod 750 /var/lib/ci /var/lib/ci/* sudo setfacl -d -m u:ci-runner:rwX /var/lib/ci/build-vms ``` - [ ] Installare Python 3.11+ e creare venv produzione: ```bash sudo apt install -y python3.11 python3.11-venv git sudo mkdir -p /opt/ci sudo python3.11 -m venv /opt/ci/venv sudo chown -R ci-runner:ci-runner /opt/ci ``` - [ ] Clonare il repo e installare il package nel venv: ```bash sudo -u ci-runner git clone https://gitea.emulab.it/Simone/local-ci-cd-system.git /opt/ci/local-ci-cd-system sudo -u ci-runner /opt/ci/venv/bin/pip install -e /opt/ci/local-ci-cd-system sudo -u ci-runner /opt/ci/venv/bin/python -m ci_orchestrator --help ``` Atteso: lista degli 11 sub-comandi. - [ ] Installare PowerShell Core (richiesto da `Invoke-RetentionPolicy.ps1` e `Backup-CITemplate.ps1`): ```bash sudo apt install -y wget apt-transport-https software-properties-common source /etc/os-release wget -q https://packages.microsoft.com/config/ubuntu/${VERSION_ID}/packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb sudo apt update && sudo apt install -y powershell pwsh --version ``` --- ## Passo 2 — Trasferimento template VM (B2) **Obiettivo**: copiare i template VMware da `F:\CI\Templates\` su `/var/lib/ci/templates/` mantenendo gli snapshot. > ⚠️ AGENTS.md errore #9: i template devono essere **fully > powered-off** prima della copia. Verificare assenza di `*.vmem` / > `*.vmsn` di runtime. - [ ] Sull'host Windows: ```powershell Get-ChildItem 'F:\CI\Templates' -Recurse -Include *.vmem,*.vmsn # atteso: nessun risultato ``` - [ ] Sull'host Linux, eseguire rsync via SSH dall'host Windows (richiede OpenSSH Server attivo su Windows o, in alternativa, `scp -r` lanciato da Windows verso Linux): ```bash sudo -u ci-runner rsync -av --progress \ user@windows-host:/cygdrive/f/CI/Templates/ \ /var/lib/ci/templates/ ``` - [ ] Validare integrità snapshot: ```bash find /var/lib/ci/templates -name '*.vmx' -exec vmrun -T ws listSnapshots {} \; ``` Atteso: `BaseClean` su `WinBuild2025.vmx` e `WinBuild2022.vmx`, `BaseClean-Linux` su `LinuxBuild2404.vmx`. - [ ] Aprire ciascun `.vmx` su Workstation Linux per registrarli; al prompt rispondere "**I copied it**". - [ ] Smoke test pipeline VM: ```bash sudo -u ci-runner /opt/ci/venv/bin/python -m ci_orchestrator vm new \ --template /var/lib/ci/templates/WinBuild2025/WinBuild2025.vmx \ --snapshot BaseClean --name smoke-b2-win sudo -u ci-runner /opt/ci/venv/bin/python -m ci_orchestrator wait-ready \ --vmx /var/lib/ci/build-vms/smoke-b2-win/smoke-b2-win.vmx \ --guest-os windows --timeout 180 sudo -u ci-runner /opt/ci/venv/bin/python -m ci_orchestrator vm remove \ --vmx /var/lib/ci/build-vms/smoke-b2-win/smoke-b2-win.vmx --force ``` Ripetere per `LinuxBuild2404` (snapshot `BaseClean-Linux`, `--guest-os linux`). --- ## Passo 3 — Trasferimento credenziali e chiavi (B3) **Obiettivo**: chiavi SSH e credenziali guest disponibili al user `ci-runner` headless. - [ ] Copiare le chiavi SSH guest Linux: ```bash sudo mkdir -p /etc/ci/keys sudo scp user@windows-host:/cygdrive/f/CI/keys/ci_linux /etc/ci/keys/ sudo scp user@windows-host:/cygdrive/f/CI/keys/ci_linux.pub /etc/ci/keys/ sudo chown ci-runner:ci-runner /etc/ci/keys/* sudo chmod 600 /etc/ci/keys/ci_linux sudo chmod 644 /etc/ci/keys/ci_linux.pub ``` - [ ] Re-store credenziale guest Windows (sostituire la password al prompt — **NON** inserirla in chat o issue): ```bash sudo -u ci-runner secret-tool store --label='BuildVMGuest' service ci target BuildVMGuest ``` - [ ] Re-store Gitea PAT: ```bash sudo -u ci-runner secret-tool store --label='GiteaPAT' service ci target GiteaPAT ``` - [ ] Validare lettura interattiva: ```bash sudo -u ci-runner /opt/ci/venv/bin/python -c \ "import keyring; print(keyring.get_credential('BuildVMGuest', None))" ``` - [ ] **PoC headless** (critico): verificare lettura keyring da contesto systemd (no D-Bus user session): ```bash sudo systemd-run --uid=ci-runner --pipe \ /opt/ci/venv/bin/python -c \ "import keyring; print(keyring.get_credential('BuildVMGuest', None))" ``` Se fallisce → implementare backend keyring file-based con `age` o `sops` come fallback. Documentare la scelta finale in `docs/HOST-SETUP.md` prima di proseguire. --- ## Passo 4 — Setup act_runner come systemd service (B4) **Obiettivo**: act_runner Linux registrato verso Gitea, gestito da systemd. - [ ] Scaricare il binario act_runner Linux ≥ v1.0.2: ```bash sudo mkdir -p /opt/ci/act_runner sudo wget -O /opt/ci/act_runner/act_runner \ https://gitea.com/gitea/act_runner/releases/download/v1.0.2/act_runner-1.0.2-linux-amd64 sudo chmod +x /opt/ci/act_runner/act_runner sudo chown -R ci-runner:ci-runner /opt/ci/act_runner ``` - [ ] Generare token registrazione su Gitea (Admin → Runners → Create new runner). - [ ] Registrare il runner (sostituire ``): ```bash sudo -u ci-runner mkdir -p /var/lib/ci/runner cd /var/lib/ci/runner sudo -u ci-runner /opt/ci/act_runner/act_runner register \ --no-interactive \ --instance https://gitea.emulab.it \ --token \ --name ci-linux \ --labels windows-build:host,linux-build:host ``` > ⚠️ Lasciare il runner in stato **paused** lato Gitea UI fino al > cutover (Passo 6), per non intercettare job di produzione. - [ ] Creare `/etc/systemd/system/act-runner.service`: ```ini [Unit] Description=Gitea Act Runner After=network-online.target Wants=network-online.target [Service] Type=simple User=ci-runner WorkingDirectory=/var/lib/ci/runner Environment="PYTHONIOENCODING=utf-8" Environment="CI_ROOT=/var/lib/ci" Environment="CI_TEMPLATES=/var/lib/ci/templates" Environment="CI_BUILD_VMS=/var/lib/ci/build-vms" Environment="CI_ARTIFACTS=/var/lib/ci/artifacts" Environment="CI_KEYS=/etc/ci/keys" ExecStart=/opt/ci/act_runner/act_runner daemon Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target ``` - [ ] Creare `/etc/ci/environment` (letto dalle unit dei task periodici di B5; vedi `deploy/systemd/README.md`): ```bash sudo tee /etc/ci/environment <<'EOF' PYTHONIOENCODING=utf-8 CI_ROOT=/var/lib/ci CI_TEMPLATES=/var/lib/ci/templates CI_BUILD_VMS=/var/lib/ci/build-vms CI_ARTIFACTS=/var/lib/ci/artifacts CI_KEYS=/etc/ci/keys EOF sudo chmod 644 /etc/ci/environment ``` - [ ] Abilitare e avviare: ```bash sudo systemctl daemon-reload sudo systemctl enable --now act-runner.service sudo systemctl status act-runner sudo journalctl -u act-runner -f # Ctrl+C dopo conferma OK ``` - [ ] Smoke job: triggerare manualmente `self-test.yml` selezionando il runner Linux (mettere temporaneamente in pausa quello Windows o usare label distinte). Atteso: PASS. --- ## Passo 5 — Installare i timer systemd (B5) **Obiettivo**: attivare le coppie `.service`+`.timer` già committate in `deploy/systemd/` per replicare i task periodici di `Register-CIScheduledTasks.ps1`. - [ ] Copiare le unit: ```bash cd /opt/ci/local-ci-cd-system sudo cp deploy/systemd/ci-*.service deploy/systemd/ci-*.timer /etc/systemd/system/ sudo systemctl daemon-reload ``` - [ ] Abilitare e avviare tutti i timer: ```bash for t in ci-cleanup-orphans ci-retention-policy \ ci-watch-disk-space ci-watch-runner-health \ ci-backup-template; do sudo systemctl enable --now "${t}.timer" done ``` - [ ] Verificare lo schedule: ```bash systemctl list-timers --all 'ci-*' ``` Atteso: 5 timer in stato `active`. - [ ] Trigger manuale di ciascun service per validare l'esecuzione one-shot: ```bash for s in ci-cleanup-orphans ci-watch-disk-space ci-watch-runner-health; do sudo systemctl start "${s}.service" sudo systemctl status "${s}.service" --no-pager done ``` > `ci-retention-policy` e `ci-backup-template` chiamano `pwsh`: > eseguirli solo dopo aver verificato che `pwsh --version` funzioni > sotto user `ci-runner`. - [ ] Per maggiori dettagli (mapping Windows→Linux, troubleshooting, rollback) vedi `deploy/systemd/README.md`. --- ## Passo 6 — Cutover (B6) **Obiettivo**: spostare la produzione dall'host Windows a Linux in una finestra di manutenzione concordata. > ⚠️ Eseguire solo dopo che i Passi 1–5 sono tutti `[x]` PASS. - [ ] Annunciare la finestra di manutenzione (durata stimata: 30–60 min). - [ ] Verificare nessun job in coda lato Gitea (Admin → Actions → Tasks). - [ ] **Stop** act_runner sull'host Windows: ```powershell Stop-Service actions-runner Get-Service actions-runner # atteso: Stopped ``` - [ ] **Disabilitare** scheduled task Windows: ```powershell Get-ScheduledTask -TaskName 'CI-*' | Unregister-ScheduledTask -Confirm:$false ``` - [ ] Rsync incrementale finale degli artifact: ```bash sudo -u ci-runner rsync -av --delete \ user@windows-host:/cygdrive/f/CI/Artifacts/ \ /var/lib/ci/artifacts/ ``` - [ ] Sbloccare il runner Linux su Gitea UI (rimuovere `paused` o ripristinare le label di produzione `windows-build:host,linux-build:host`). - [ ] Verificare runner Linux online su Gitea UI. - [ ] Smoke trigger: - [ ] `self-test.yml` → PASS dal runner Linux - [ ] `build-nsInnoUnp.yml` matrix Win+Linux → PASS dal runner Linux - [ ] Monitorare per ≥30 min: ```bash sudo journalctl -u act-runner -f --since "30min ago" ``` Nessun errore di severità critica atteso. > **Rollback (entro 30 min se PASS critico fallisce)**: > 1. `sudo systemctl stop act-runner` su Linux > 2. `Start-Service actions-runner` su Windows > 3. Re-registrare scheduled task con `scripts\Register-CIScheduledTasks.ps1` > 4. Documentare incidente in `TODO.md` e tornare a B1–B5 per fix --- ## Passo 7 — Capacity burn-in (B7) **Obiettivo**: validare il carico target con tempi paragonabili al baseline Windows (entro ±20%). - [ ] Burn-in 4 job concorrenti × 10 round su `WinBuild2025` (lo script `Test-CapacityBurnIn.ps1` ora delega via shim alla CLI Python `job` e gira anche da `pwsh` su Linux): ```bash pwsh /opt/ci/local-ci-cd-system/scripts/Test-CapacityBurnIn.ps1 \ -Concurrency 4 -Rounds 10 -Template /var/lib/ci/templates/WinBuild2025/WinBuild2025.vmx ``` - [ ] Burn-in 4 × 10 su `LinuxBuild2404` (analogo, `--Template` sul VMX Linux). - [ ] Misurare: - [ ] Tempo medio per job, confronto con baseline A5 - [ ] Tutti i 80 job (2 × 4 × 10) PASS - [ ] Zero VM orfane in `/var/lib/ci/build-vms/`: ```bash sudo -u ci-runner /opt/ci/venv/bin/python -m ci_orchestrator vm cleanup --dry-run ``` - [ ] Spazio disco `/var/lib/ci/build-vms/` torna al baseline post-cleanup - [ ] Documentare i risultati in `docs/RUNBOOK.md` (sezione "Linux host baseline"). - [ ] Se delta > 20% vs baseline Windows: aprire issue in `TODO.md` con dettagli per profiling (probabile candidato: filesystem ext4 vs NTFS — valutare XFS/BTRFS). --- ## Passo 8 — Stabilità ≥1 settimana (gate per B8) **Obiettivo**: verificare ≥1 settimana di esercizio Linux senza incidenti critici prima di dismettere l'host Windows. - [ ] Esercizio normale per ≥7 giorni con runner Linux primario. - [ ] Verifica giornaliera (bastano 2 minuti): ```bash sudo systemctl --failed # nessun service in failed systemctl list-timers --all 'ci-*' # tutti gli ultimi run OK sudo journalctl -u act-runner --since "24h ago" -p err ``` - [ ] Nessun rollback effettuato durante la settimana. --- ## Passo 9 — Decommissioning host Windows (B8, opzionale) > ⚠️ Procedere solo dopo Passo 8 `[x]`. L'host Windows va lasciato > spento ma intatto per ≥1 mese come rollback. - [ ] Backup finale di `F:\CI\` su archivio esterno: ```powershell $stamp = Get-Date -Format 'yyyyMMdd' $archive = "E:\Backup\CI-$stamp.tar" & 'C:\Program Files\Git\usr\bin\tar.exe' -cf $archive 'F:\CI\' Get-FileHash $archive -Algorithm SHA256 | Tee-Object "$archive.sha256" ``` - [ ] Verifica integrità (estrazione di prova in tmp): ```powershell $test = "$env:TEMP\ci-restore-test" & 'C:\Program Files\Git\usr\bin\tar.exe' -tf $archive | Select-Object -First 20 ``` - [ ] Spegnere host Windows (`shutdown /s /t 0`). - [ ] Lasciare hardware integro e spento per ≥1 mese. - [ ] Aggiornare `docs/RUNBOOK.md` con la procedura di riaccensione + ri-registrazione scheduled task come rollback. - [ ] Dopo 1 mese senza rollback: riallocare hardware. --- ## Tracciamento globale | Passo | Step | Descrizione | Stato | | ----- | ---- | -------------------------------------------------- | ----- | | 1 | B1 | Setup host Linux Mint (OS, Workstation, venv, ACL) | [ ] | | 2 | B2 | Trasferimento template VM + smoke `vm new` | [ ] | | 3 | B3 | Chiavi SSH + keyring (PoC headless) | [ ] | | 4 | B4 | act_runner systemd service registrato | [ ] | | 5 | B5 | Timer systemd installati e attivi | [ ] | | 6 | B6 | Cutover (stop Windows, runner Linux primario) | [ ] | | 7 | B7 | Capacity burn-in 4 × 10 (Win + Linux) | [ ] | | 8 | — | ≥1 settimana di stabilità senza rollback | [ ] | | 9 | B8 | Decommissioning host Windows (opzionale) | [ ] | Quando tutti i passi sono `[x]`, la **Fase B è chiusa** e si può valutare l'apertura della Fase C (backend ESXi, vedi `plans/idea-3-esxi-support.md`).