Files
Simone 8ca3e530c5 feat(low): sprint 4 Low items tutti 5 completati
codice:
- template/Validate-SetupState.ps1: docblock HTTP/Basic -> HTTPS/Basic, port 5986
- scripts/Validate-HostState.ps1 (nuovo): check ACL SSH key ci_linux, Credential Manager
  target BuildVMGuest, struttura dir F:\CI\, vmrun.exe raggiungibile

docs:
- docs/TEST-PLAN-v1.3-to-HEAD.md sezione 3.6: campi JSONL corretti (cloneSec/startSec/
  ipSec/winrmSec/destroySec/totalBootSec) per riflettere output reale di Measure-CIBenchmark.ps1
- docs/CI-FLOW.md tabella failure: 'partial artifacts' -> Get-GuestDiagnostics a diagnostics/
- docs/CHANGELOG.md (nuovo): log reverse-cronologico di tutti gli sprint completati
- plans/final-master-plan.md: tutti i Low marcati done
2026-05-13 10:26:08 +02:00

292 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CI Pipeline Flow — Step by Step
## Trigger to Artifact: Complete Pipeline Walk-Through
---
### Step 0 — Prerequisites (one-time setup)
Before any CI job runs, the following must be in place:
| Component | State |
| ------------------ | ----------------------------------------------------------------------------- |
| Gitea server | Running, accessible on LAN |
| act_runner | Registered, running as Windows service on host |
| Template VM (Win) | Provisioned, snapshot "BaseClean" taken, VM powered off |
| Template VM (Lin) | Ubuntu 24.04 LTS, snapshot "BaseClean-Linux" taken, VM powered off (optional) |
| WinRM | Enabled on Windows template VM (inherits to all clones) |
| SSH key | `F:\CI\keys\ci_linux` (ed25519) present; public key in Linux template |
| vmrun.exe | Present at `C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe` |
| `F:\CI\BuildVMs\` | Directory exists and writable |
| `F:\CI\Artifacts\` | Directory exists and writable |
---
### Step 1 — Developer Pushes Code
```
Developer → git push origin main
```
- Git push lands on Gitea server
- Gitea evaluates `.gitea/workflows/build.yml` in the repository
- If the workflow trigger matches (e.g. `on: push` to `main`), Gitea enqueues a new **Actions job**
- Job is tagged with the label defined in the workflow (`runs-on: windows-build`)
---
### Step 2 — act_runner Picks Up the Job
```
act_runner (host) ─polling─► Gitea Actions API
◄─job data─
```
- act_runner polls the Gitea API approximately every 510 seconds
- Detects a pending job matching its labels (`windows-build`)
- Downloads the workflow YAML and job parameters
- If `capacity` slots are available, starts job execution immediately
- If all slots are busy, job waits in Gitea queue until a slot frees
---
### Step 3 — act_runner Executes Workflow Steps
The workflow YAML defines steps that run as PowerShell commands **on the host**.
The first substantive step calls `Invoke-CIJob.ps1`:
```yaml
- name: Run CI Job
shell: pwsh
run: |
& 'N:\Code\Workspace\Local-CI-CD-System\scripts\Invoke-CIJob.ps1' `
-JobId '${{ github.run_id }}' `
-RepoUrl 'ssh://gitea-ci/Simone/<repo>.git' `
-Branch '${{ github.ref_name }}' `
-Commit '${{ github.sha }}' `
-TemplatePath $env:GITEA_CI_TEMPLATE_PATH `
-Submodules `
-BuildCommand 'python build_plugin.py --final --dist-dir dist' `
-GuestArtifactSource 'dist'
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
```
> Il parametro `-VMIPAddress` **non è più necessario** — l'IP viene rilevato automaticamente
> tramite `vmrun getGuestIPAddress` dopo l'avvio della VM.
---
### Step 4 — Invoke-CIJob.ps1: Clone VM
```
New-BuildVM.ps1
vmrun.exe -T ws clone <template.vmx> <clone.vmx> linked -snapshot "BaseClean"
```
- Generates unique clone name: `Clone_{JobId}_{yyyyMMdd_HHmmss}`
- Creates clone directory under `F:\CI\BuildVMs\`
- **Linked clone** creation takes ~515 seconds
- The template snapshot "BaseClean" is **not modified**
- Returns the full path to the new `.vmx` file
---
### Step 5 — Start VM
```
vmrun.exe -T ws start <clone.vmx> nogui
```
- Starts the cloned VM in headless (no GUI) mode
- VM boots from the "BaseClean" state: clean OS, build tools installed, WinRM enabled
- Boot takes ~2040 seconds
---
### Step 6 — Wait for VM Readiness
```
Wait-VMReady.ps1 -VMPath <clone.vmx> -IPAddress <dynamic-NAT-ip> -TimeoutSeconds 300
```
IP is discovered dynamically via `vmrun getGuestIPAddress` (VMnet8 NAT, subnet 192.168.79.0/24).
No hardcoded IPs — each clone gets a DHCP-assigned address from VMware NAT.
Three-phase readiness check (retried every 5 seconds, up to 300s timeout).
Transport is selected automatically from the VMX `guestOS` field (`-Transport WinRM` for Windows, `-Transport SSH` for Linux):
```
Phase 1: vmrun getState → must return "running"
Windows (-Transport WinRM, default):
Phase 2: Test-Connection (ICMP ping) → must succeed
Phase 3: Test-WSMan → WinRM listener must respond
Linux (-Transport SSH):
Phase 2: Test-NetConnection -Port 22 → must succeed
Phase 3: ssh -o ConnectTimeout=5 ... "echo ready" → must return "ready"
```
- Total wait is typically **3090 seconds** after `vmrun start`
- If timeout exceeded, VM is destroyed and job fails with a clear error message
- On success, IP and credentials are ready for PSSession
---
### Step 7 — Remote Build Execution
```
Invoke-RemoteBuild.ps1
-IPAddress <dynamic-NAT-ip> # from vmrun getGuestIPAddress
-GuestOS Windows|Linux # auto-detected from VMX guestOS field
# Windows path (default):
-Credential (from Windows Credential Manager)
-BuildCommand 'python build_plugin.py --final --dist-dir dist'
-GuestArtifactSource 'dist'
# Linux path (-GuestOS Linux):
-SshKeyPath F:\CI\keys\ci_linux
-SshUser ci_build
-CloneUrl / -CloneBranch # always in-VM git clone for Linux
-BuildCommand 'make all'
```
Sequence inside the PSSession:
```
1. New-PSSession → open WinRM session to VM
2a. (default) Compress-Archive (host) → copy zip to C:\CI\build.zip (guest) → Expand-Archive to C:\CI\build\
(source code è già clonato sull'host in Phase 1 — nessun git clone nella VM)
2b. (opt-in, `-UseGitClone`, §3.3 DONE 2026-05-10)
git clone direttamente in VM tramite `ssh://gitea-ci/...` (richiede Git+7-Zip in template, §6.6 Tier-1)
Vantaggio: skip host-zip-transfer, -25.7% durata pipeline (e2e PASS). Verifica SHA commit post-clone.
3. Invoke-Expression "$BuildCommand" in C:\CI\build\
Esempio: python build_plugin.py --final --dist-dir dist
a. Build 4 configurazioni MSBuild in parallelo (x86-unicode, x64-unicode, cli-x86, cli-x64)
b. Raccoglie artifact in C:\CI\build\dist\
c. Cleanup build dir (--final)
4. Compress-Archive C:\CI\build\$GuestArtifactSource C:\CI\output\artifacts.zip
5. Cattura exit code; se non-zero il job fallisce con errore chiaro
6. Remove-PSSession
```
- Output standard e stderr dalla build sono streamati all'host e catturati da act_runner per i log Gitea Actions
- Se la build fallisce (exit code ≠ 0), il controllo passa al blocco `finally`
---
### Step 8 — Collect Artifacts
```
Get-BuildArtifacts.ps1
-IPAddress <dynamic-NAT-ip>
-GuestOS Windows|Linux # auto-detected from Invoke-CIJob
# Windows path (default):
-Credential (from Windows Credential Manager)
-GuestArtifactPath C:\CI\output\artifacts.zip
# Linux path (-GuestOS Linux):
-SshKeyPath F:\CI\keys\ci_linux
-GuestArtifactPath /opt/ci/output
-HostArtifactDir F:\CI\Artifacts\{JobId}\
```
- Windows: apre PSSession e copia `C:\CI\output\artifacts.zip` tramite WinRM
- Linux: `scp -r ci_build@<ip>:/opt/ci/output/. <HostArtifactDir>` tramite `_Transport.psm1`
- In entrambi i casi valida che almeno un file sia stato trasferito
---
### Step 9 — Destroy VM
```
Remove-BuildVM.ps1 -VMPath <clone.vmx>
```
Sequence:
```
1. vmrun stop <clone.vmx> soft (graceful shutdown attempt)
2. Wait 5 seconds
3. vmrun getState → if still "running":
vmrun stop <clone.vmx> hard (force off)
4. vmrun deleteVM <clone.vmx> (removes VMX + VMDK delta files)
5. Remove-Item <clone dir> -Recurse (removes any leftover files)
```
- VM is gone from disk within ~510 seconds
- No state, no temp files, no credentials remain in the clone
- Template VM and "BaseClean" snapshot are unaffected
> **Note:** This step runs in a `finally` block inside `Invoke-CIJob.ps1`, so it
> executes even if Steps 68 failed. A build VM is **never** left running.
---
### Step 10 — Report Status & Upload Artifacts
```
act_runner ─► Gitea Actions API (job status: success / failure)
act_runner ─► Gitea artifact store (uploads F:\CI\Artifacts\{JobId}\*)
```
- act_runner reads the exit code from `Invoke-CIJob.ps1`
- Reports `success` or `failure` to Gitea
- Uploads artifacts using `actions/upload-artifact` step in the workflow YAML
- Build log (stdout from all steps) is stored in Gitea Actions UI
- Commit/PR status badge is updated
---
## Parallel Build Flow
When multiple pushes happen concurrently (or multiple PRs are open):
```
act_runner (capacity: 4)
├── Job #1 ──► Clone_Job_001 (192.168.79.x) → build → destroy
├── Job #2 ──► Clone_Job_002 (192.168.79.x) → build → destroy
├── Job #3 ──► Clone_Job_003 (192.168.79.x) → build → destroy
└── Job #4 ──► Clone_Job_004 (192.168.79.x) → build → destroy
(Job #5 waits in Gitea queue)
```
Note: each clone gets a dynamic IP from VMware NAT DHCP (192.168.79.0/24). IP is discovered
automatically via `vmrun getGuestIPAddress` — no static assignment required.
- Each job creates its own independently named clone
- Clones share the parent "BaseClean" snapshot (read-only CoW)
- No filesystem or process overlap between concurrent builds
- act_runner enforces the `capacity` limit
---
## Failure Scenarios
| Failure Point | Behavior |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| VM clone fails | `Invoke-CIJob.ps1` throws; no VM to destroy; job fails immediately |
| VM never reaches ready state (timeout) | `Wait-VMReady.ps1` throws; `finally` destroys the (running) VM |
| Build fails inside VM | `Invoke-RemoteBuild.ps1` throws; `finally` runs `Get-GuestDiagnostics` (best-effort, to `F:\CI\Artifacts\<jobId>\diagnostics\`), destroys VM |
| Artifact collection fails | Job marked failed; VM is still destroyed in `finally` |
| Host machine loses power mid-job | `act_runner` resumes on reboot, marks in-flight job as failed; orphan VMs must be cleaned up manually (see TODO.md) |
---
## Timing Summary (typical build)
| Phase | Typical Duration |
| ---------------------------- | -------------------- |
| Gitea → act_runner poll | 510 s |
| Linked clone creation | 515 s |
| VM boot | 2040 s |
| WinRM readiness | 1030 s (after boot) |
| git clone (from local Gitea) | 210 s |
| dotnet restore + build | project-dependent |
| Artifact collection | 210 s |
| VM destruction | 510 s |
| **Overhead total** | **~60120 s** |