425d8bc4f3
Reconcile docs with the end-to-end pipeline fixes: - upload/download-artifact @v4 -> @v3 (Gitea GHES) in WORKFLOW-AUTHORING and workflow-example.yml; add Common Mistakes rows (v4, action ref form + DEFAULT_ACTIONS_URL, public action repo). - BEST-PRACTICES / README / HOST-SETUP: guest credential must live in the LocalSystem vault with a host-qualified username; document Set-CIGuestCredential.ps1 / Test-CIGuestWinRM.ps1 and auth=ntlm. - README / AGENTS / HOST-SETUP: production venv install is NON-editable (LocalSystem); no CI workflow may install into it. - HOST-SETUP: add DEFAULT_ACTIONS_URL=github + full-URL uses: + public repo + @main requirements discovered during validation. - Correct stale repo name local-ci-system -> local-ci-cd-system. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
244 lines
14 KiB
Markdown
244 lines
14 KiB
Markdown
# Host Setup — Local CI/CD
|
||
|
||
Procedura di bootstrap della macchina host Windows (i9-10900X, 64 GB RAM, NVMe).
|
||
Eseguire **una volta** prima di qualsiasi provisioning del template VM o esecuzione di job CI.
|
||
|
||
---
|
||
|
||
## Prerequisiti host
|
||
|
||
| Componente | Versione/Note |
|
||
| ------------------ | ----------------------------------------------------------------- |
|
||
| OS | Windows 11 (host fisico) o Windows Server 2022+ |
|
||
| VMware Workstation | Pro 17.x — necessario per `vmrun.exe` e supporto linked clone |
|
||
| Storage | NVMe dedicato (consigliato `F:\` riservato a CI, ≥ 500 GB libero) |
|
||
| RAM | ≥ 32 GB (4 VM parallele × 6-8 GB) |
|
||
| Rete | VMnet8 (NAT) configurato in VMware Workstation |
|
||
| PowerShell | 5.1+ (built-in) o 7.x |
|
||
| Privilegi | Account amministrativo per Setup-Host.ps1 |
|
||
|
||
Software opzionali installati on-demand dallo script:
|
||
- **NSSM** — installazione automatica via Chocolatey se presente; altrimenti install manuale da https://nssm.cc
|
||
- **CredentialManager** module — installato automaticamente (scope CurrentUser)
|
||
|
||
---
|
||
|
||
## Directory layout
|
||
|
||
`Setup-Host.ps1` crea l'intera struttura sotto `$CIRoot` (default `F:\CI\`):
|
||
|
||
```
|
||
F:\CI\
|
||
├── BuildVMs\ # cloni temporanei delle VM build (auto-cleanup post-job)
|
||
├── Artifacts\ # output build raccolti dall'host
|
||
├── Logs\ # log per-job (retention: 30 giorni)
|
||
├── Templates\
|
||
│ ├── WinBuild2025\ # VMX template Windows (immutabile dopo snapshot)
|
||
│ └── LinuxBuild2404\ # VMX template Linux Ubuntu 24.04 (immutabile dopo snapshot)
|
||
├── keys\
|
||
│ ├── ci_linux # chiave privata SSH per Linux VMs (ed25519, no passphrase)
|
||
│ └── ci_linux.pub # chiave pubblica corrispondente
|
||
├── config.toml # configurazione Python orchestrator (ssh_key_path, ecc.)
|
||
├── act_runner\
|
||
│ ├── act_runner.exe # binario runner Gitea
|
||
│ ├── config.yaml # config runner (path, label, capacity)
|
||
│ └── logs\ # stdout/stderr del servizio
|
||
├── Cache\
|
||
│ └── NuGet\ # cache NuGet condivisa via shared folder (§3.1 — DONE 2026-05-10, vedi scripts/Set-TemplateSharedFolders.ps1)
|
||
├── RunnerWork\ # working dir di act_runner (job staging)
|
||
└── ISO\ # ISO di installazione (Windows Server 2025, ecc.)
|
||
```
|
||
|
||
---
|
||
|
||
## Procedura — esecuzione
|
||
|
||
### Step 1 — Clonare il repository
|
||
|
||
```powershell
|
||
git clone https://gitea.emulab.it/Simone/Local-CI-CD-System.git N:\Code\Workspace\Local-CI-CD-System
|
||
cd N:\Code\Workspace\Local-CI-CD-System
|
||
```
|
||
|
||
### Step 2 — Eseguire Setup-Host.ps1 (elevato)
|
||
|
||
Apri PowerShell **come Administrator**, poi:
|
||
|
||
```powershell
|
||
# Esecuzione minimale (crea dirs, archivia credenziali, salta install runner)
|
||
.\Setup-Host.ps1 -SkipRunnerInstall
|
||
|
||
# Setup completo con registrazione runner
|
||
.\Setup-Host.ps1 -GiteaRunnerToken 'abc123token'
|
||
|
||
# CI root su drive diverso
|
||
.\Setup-Host.ps1 -CIRoot 'D:\CI' -GiteaRunnerToken 'abc123token'
|
||
```
|
||
|
||
### Cosa fa Setup-Host.ps1 — passo per passo
|
||
|
||
1. **Crea albero directory** sotto `$CIRoot` (vedi layout sopra)
|
||
2. **Verifica VMware Workstation** — controlla presenza di `C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe`
|
||
3. **Installa modulo CredentialManager** (scope CurrentUser, se non presente)
|
||
4. **Archivia credenziali guest VM** in Windows Credential Manager (target `BuildVMGuest`)
|
||
- Se non passa `-GuestPassword`, prompt interattivo (SecureString)
|
||
- Se credenziale già esistente, non sovrascrive — istruzioni per update
|
||
5. **Copia `runner/config.yaml`** in `$CIRoot\act_runner\config.yaml` (se non esistente)
|
||
6. **Installa act_runner come servizio Windows** via NSSM:
|
||
- Verifica presenza NSSM in PATH; tenta install via `choco install nssm -y`
|
||
- Registra runner con Gitea (`act_runner register --no-interactive --instance ... --token ... --name local-windows-runner --labels windows-build:host,dotnet:host,msbuild:host`) se token fornito
|
||
- Crea servizio: `AppDirectory`, `AppParameters daemon --config <path>`, log rotation 10 MB
|
||
- Avvia servizio (`SERVICE_AUTO_START`)
|
||
7. **Configura SSH alias `gitea-ci`** in `~/.ssh/config` (HostName, Port, User git)
|
||
|
||
### Note operative (scoperte in validazione end-to-end)
|
||
|
||
Setup-Host.ps1 da solo **non basta** per la pipeline Python su runner
|
||
LocalSystem. Dopo Setup-Host:
|
||
|
||
- **Credenziale guest nel vault SYSTEM, username host-qualificato.** Lo
|
||
step 4 scrive in Windows Credential Manager dell'utente interattivo →
|
||
invisibile ad act_runner (LocalSystem). Esegui (elevato):
|
||
`\.\scripts\Set-CIGuestCredential.ps1 -UserName 'WINBUILD-2025\ci_build'`.
|
||
Bare `ci_build` viene rifiutato da NTLM (`SEC_E_UNKNOWN_CREDENTIALS`):
|
||
usa il computer name del guest (= CN del cert WinRM). Diagnostica:
|
||
`\.\scripts\Test-CIGuestWinRM.ps1 -IpAddress <guest-ip>`.
|
||
- **venv di produzione = install non-editable.** Popola
|
||
`F:\CI\python\venv` con `python -m pip install .` dal repo reale —
|
||
**mai** `pip install -e .` (il `.pth` punta a un path che LocalSystem
|
||
non risolve → `No module named ci_orchestrator`). Vedi
|
||
`plans/PhaseA-user-checklist.md` Passo 1. Nessun workflow CI deve
|
||
installare in quel venv (lint usa un venv effimero per-job).
|
||
- **Gitea `app.ini`:** imposta `[actions] DEFAULT_ACTIONS_URL = github`
|
||
e referenzia l'action col **URL completo**
|
||
(`https://gitea.emulab.it/Simone/local-ci-cd-system/.gitea/actions/local-ci-build@main`)
|
||
così le action GitHub (checkout, upload-artifact) restano risolvibili
|
||
e l'action locale punta all'istanza. Il repo `local-ci-cd-system` deve
|
||
essere **pubblico** (il runner clona l'action senza autenticazione) e
|
||
l'action deve esistere su `@main` (il ref che il runner clona).
|
||
|
||
---
|
||
|
||
## Parametri principali
|
||
|
||
| Parametro | Default | Note |
|
||
| ------------------------ | ------------------------------------ | ------------------------------------- |
|
||
| `-CIRoot` | `F:\CI` | Base directory per tutti i dati CI |
|
||
| `-GuestCredentialTarget` | `BuildVMGuest` | Target Credential Manager |
|
||
| `-GuestUsername` | `ci_build` | Account build dentro la VM |
|
||
| `-GuestPassword` | (prompt) | Mai hard-codare |
|
||
| `-ActRunnerExe` | `<CIRoot>\act_runner\act_runner.exe` | Path binario runner |
|
||
| `-ActRunnerConfigYaml` | `<repo>\runner\config.yaml` | Source del config da copiare |
|
||
| `-GiteaUrl` | `http://10.10.20.11:3100` | URL Gitea per registrazione |
|
||
| `-GiteaRunnerToken` | (vuoto) | Token registrazione (Admin → Runners) |
|
||
| `-SkipRunnerInstall` | `$false` | Salta installazione servizio |
|
||
| `-SkipSSHConfig` | `$false` | Salta scrittura SSH alias |
|
||
| `-GiteaSSHHost` | `10.10.20.11` | Hostname SSH Gitea |
|
||
| `-GiteaSSHPort` | `2222` | Porta SSH Gitea |
|
||
|
||
---
|
||
|
||
## Post-setup checklist
|
||
|
||
Allo `Setup-Host.ps1` exit 0:
|
||
|
||
1. **Posiziona binario act_runner** se non già fatto:
|
||
- Path: `F:\CI\act_runner\act_runner.exe`
|
||
- Download: https://gitea.com/gitea/act_runner/releases/tag/v1.0.2
|
||
|
||
2. **Posiziona ISO Windows Server 2025** in `F:\CI\ISO\`
|
||
(es. `26100.1742.240906-0331.ge_release_svc_refresh_SERVER_VOL_x64FRE_en-us.iso`)
|
||
|
||
3. **Configura host WinRM client** (necessario per Prepare-WinBuild2025.ps1):
|
||
```powershell
|
||
# AllowUnencrypted non serve — Prepare usa HTTPS/5986 (nessun testo in chiaro)
|
||
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '192.168.79.*' -Force -Concatenate
|
||
```
|
||
*Note*: Prepare-WinBuild2025.ps1 aggiunge l'IP specifico della VM in modo transitorio e lo ripristina nel `finally`.
|
||
|
||
4. **Provisiona il template VM Windows** — vedi [WINDOWS-TEMPLATE-SETUP.md](WINDOWS-TEMPLATE-SETUP.md)
|
||
|
||
5. **(Opzionale) Genera chiave SSH CI per Linux VMs** — necessaria solo se si vuole usare `linux-build`:
|
||
```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'
|
||
# Risultato: F:\CI\keys\ci_linux (privata) + F:\CI\keys\ci_linux.pub (pubblica)
|
||
```
|
||
Poi **provisiona il template VM Linux** — vedi [LINUX-TEMPLATE-SETUP.md](LINUX-TEMPLATE-SETUP.md)
|
||
|
||
6. **Crea `F:\CI\config.toml`** — necessario affinché il Python orchestrator trovi la chiave SSH e le altre impostazioni:
|
||
```powershell
|
||
Copy-Item N:\Code\Workspace\Local-CI-CD-System\config.example.toml F:\CI\config.toml
|
||
```
|
||
Il file `config.example.toml` contiene già i path corretti per Windows (`F:\CI\...`). Modificare solo se si usa un `$CIRoot` diverso da `F:\CI`.
|
||
|
||
Valori chiave configurati:
|
||
|
||
| Chiave | Valore default | Scopo |
|
||
| -------------------- | ----------------------- | -------------------------------------------- |
|
||
| `ssh_key_path` | `F:/CI/keys/ci_linux` | Chiave privata per SSH verso Linux guest |
|
||
| `guest_cred_target` | `BuildVMGuest` | Target Windows Credential Manager (WinRM) |
|
||
| `backend.type` | `workstation` | Backend VMware (solo `workstation` in Phase A) |
|
||
|
||
Le variabili d'ambiente `CI_SSH_KEY_PATH`, `CI_VMRUN_PATH`, `CI_GUEST_CRED_TARGET` sovrascrivono i valori del TOML se presenti.
|
||
|
||
6. **Registra chiave SSH con Gitea**:
|
||
- Gitea UI → User Settings → SSH Keys → Add Key
|
||
- Chiave pubblica: `%USERPROFILE%\.ssh\id_rsa.pub`
|
||
|
||
7. **Verifica runner online** in Gitea:
|
||
- `<GiteaUrl>/-/admin/runners`
|
||
- Status atteso: **Online**, label `windows-build:host,dotnet:host,msbuild:host`
|
||
|
||
---
|
||
|
||
## Reference Paths
|
||
|
||
| Item | Path / Value |
|
||
| ------------------------- | ------------------------------------------------------------ |
|
||
| vmrun.exe | `C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe` |
|
||
| act_runner exe | `F:\CI\act_runner\act_runner.exe` (servizio: `act_runner`) |
|
||
| act_runner config | `F:\CI\act_runner\config.yaml` |
|
||
| act_runner logs | `F:\CI\act_runner\logs\` (stdout.log, stderr.log) |
|
||
| Template VMX (Windows) | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` |
|
||
| Template VMX (Linux) | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` |
|
||
| Snapshot name (Windows) | `BaseClean` |
|
||
| Snapshot name (Linux) | `BaseClean-Linux` |
|
||
| SSH key (Linux VMs) | `F:\CI\keys\ci_linux` (privata), `F:\CI\keys\ci_linux.pub` |
|
||
| Orchestrator config TOML | `F:\CI\config.toml` (copia di `config.example.toml`) |
|
||
| Clone base dir | `F:\CI\BuildVMs\` |
|
||
| Artifact dir | `F:\CI\Artifacts\` |
|
||
| Log dir | `F:\CI\Logs\` (retention: 30 giorni) |
|
||
| Gitea URL (LAN) | `http://10.10.20.11:3100` |
|
||
| Gitea URL (ext) | `https://gitea.emulab.it` |
|
||
| Runner name | `local-windows-runner` (ID: 1) |
|
||
| Build VM subnet | `192.168.79.0/24` (VMnet8 — NAT, internet access per build) |
|
||
| Credential Manager target | `BuildVMGuest` |
|
||
| Guest username | `ci_build` |
|
||
|
||
---
|
||
|
||
## Maintenance & operational tasks
|
||
|
||
Task schedulati (vedi `scripts/Register-CIScheduledTasks.ps1` per il bootstrap):
|
||
|
||
- **§2.2** Cleanup VM orfane (`scripts/Cleanup-OrphanedBuildVMs.ps1`, ogni 6h, `-MaxAgeHours 4`)
|
||
- **§2.3** Retention artifact + log (`scripts/Invoke-RetentionPolicy.ps1`, daily)
|
||
- **§2.6** Backup template (`scripts/Backup-CITemplate.ps1`, weekly)
|
||
- **§2.7** Health check runner (`scripts/Watch-RunnerHealth.ps1`, ogni 15 min)
|
||
- **§4.3** Disk space alert (`scripts/Watch-DiskSpace.ps1`, ogni ora)
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
| Sintomo | Diagnosi / Fix |
|
||
| ------------------------------- | ---------------------------------------------------------------- |
|
||
| `vmrun.exe NOT found` | Installa VMware Workstation Pro, riesegui |
|
||
| `NSSM not available` | Install manuale da https://nssm.cc, aggiungi a PATH, riesegui |
|
||
| Runner registration `exit != 0` | Verifica token Gitea + URL raggiungibile da host |
|
||
| Service `act_runner` non parte | Check `F:\CI\act_runner\logs\stderr.log` |
|
||
| `New-StoredCredential` fail | Verifica modulo CredentialManager importato + scope corretto |
|
||
| Job CI fallisce su `Test-WSMan` | TrustedHosts host non include subnet VM, AllowUnencrypted=$false |
|
||
| `wait-ready` SSH: `No authentication methods available` | `F:\CI\config.toml` mancante o `ssh_key_path` non configurato. Crea il file (vedi step 6) oppure passa `--ssh-key-path F:\CI\keys\ci_linux` |
|