dd238121b3
Sistema CI locale basato su VMware Workstation + Gitea Actions + act_runner. Testato e2e con nsis-plugin-nsinnounp (MSBuild + Python, 4 configurazioni parallele). - scripts/: Invoke-CIJob, Invoke-RemoteBuild, New/Remove-BuildVM, Wait-VMReady, Get-BuildArtifacts - runner/: act_runner config (windows-build label, capacity 4) - gitea/workflows/: build-nsis.yml (template per progetti MSBuild/Python) - template/: script di provisioning template VM (VS BuildTools 2026, .NET SDK 10, Python 3.13) - docs/: ARCHITECTURE, CI-FLOW, OPTIMIZATION, BEST-PRACTICES, Setup-GiteaSSH Verificato: e2e-009 SUCCESS in 02:09, cleanup automatico VM confermato.
243 lines
10 KiB
PowerShell
243 lines
10 KiB
PowerShell
#Requires -Version 5.1
|
|
<#
|
|
.SYNOPSIS
|
|
HOST-side script: delivers and runs Setup-TemplateVM.ps1 inside the template VM.
|
|
|
|
.DESCRIPTION
|
|
Automates the template VM provisioning from the host machine:
|
|
1. Verifies the VM is reachable via WinRM (must already be enabled in guest)
|
|
2. Copies Setup-TemplateVM.ps1 into the VM via WinRM
|
|
3. Runs Setup-TemplateVM.ps1 inside the VM with the given parameters
|
|
4. Handles the reboot-required case (exit 3010) and optionally re-runs
|
|
|
|
PREREQUISITES (do these manually before running this script):
|
|
a. VM NIC is set to VMnet8 (NAT) — the VM needs internet for downloads
|
|
b. Windows Server is installed and booted
|
|
c. WinRM is enabled inside the VM. From an elevated cmd/PS in the VM run:
|
|
winrm quickconfig -q
|
|
Enable-PSRemoting -Force -SkipNetworkProfileCheck
|
|
d. You know the IP address the VM got from DHCP on VMnet8 (NAT)
|
|
(check via: ipconfig inside the VM, or VMware → VM → Settings →
|
|
Network Adapter → Advanced → MAC address, then check DHCP leases)
|
|
|
|
AFTER THIS SCRIPT COMPLETES:
|
|
1. Shut down the VM
|
|
2. Take snapshot: VM → Snapshot → Take Snapshot → name: BaseClean
|
|
(VM stays on VMnet8 NAT — internet access is required for builds)
|
|
3. Store credentials on host:
|
|
New-StoredCredential -Target 'BuildVMGuest' -UserName 'ci_build' `
|
|
-Password 'CIBuild!ChangeMe2026' -Persist LocalMachine
|
|
|
|
.PARAMETER VMIPAddress
|
|
IP address of the template VM while it is on NAT (VMnet8).
|
|
Example: 192.168.79.130
|
|
|
|
.PARAMETER AdminUsername
|
|
Administrator username inside the VM. Default: Administrator
|
|
|
|
.PARAMETER AdminPassword
|
|
Administrator password inside the VM. If not supplied, prompts interactively.
|
|
|
|
.PARAMETER BuildPassword
|
|
Password to set for the ci_build user inside the VM.
|
|
Default: CIBuild!ChangeMe2026 — CHANGE THIS before production use.
|
|
|
|
.PARAMETER DotNetSdkVersion
|
|
.NET SDK channel to install in the VM. Default: 10.0 (matches host SDK).
|
|
|
|
.PARAMETER SkipWindowsUpdate
|
|
Pass through to Setup-TemplateVM.ps1 to skip the Windows Update step.
|
|
|
|
.EXAMPLE
|
|
# Interactive (prompts for admin password):
|
|
.\Prepare-TemplateSetup.ps1 -VMIPAddress 192.168.79.130
|
|
|
|
# With explicit credentials:
|
|
.\Prepare-TemplateSetup.ps1 -VMIPAddress 192.168.79.130 `
|
|
-AdminPassword 'YourAdminPass' -BuildPassword 'StrongCIPass!2026'
|
|
|
|
# Skip Windows Update (already applied):
|
|
.\Prepare-TemplateSetup.ps1 -VMIPAddress 192.168.79.130 -SkipWindowsUpdate
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[ValidatePattern('^(\d{1,3}\.){3}\d{1,3}$')]
|
|
[string] $VMIPAddress,
|
|
|
|
[string] $AdminUsername = 'Administrator',
|
|
|
|
[string] $AdminPassword = '',
|
|
|
|
[string] $BuildPassword = 'CIBuild!ChangeMe2026',
|
|
|
|
[string] $DotNetSdkVersion = '10.0',
|
|
|
|
[switch] $SkipWindowsUpdate
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
|
|
# ── Build PSCredential ────────────────────────────────────────────────────────
|
|
if ($AdminPassword -eq '') {
|
|
Write-Host "[Prepare] Enter administrator credentials for the template VM ($VMIPAddress):"
|
|
$credential = Get-Credential -UserName $AdminUsername -Message "Template VM administrator ($VMIPAddress)"
|
|
}
|
|
else {
|
|
$secPwd = ConvertTo-SecureString $AdminPassword -AsPlainText -Force
|
|
$credential = New-Object System.Management.Automation.PSCredential($AdminUsername, $secPwd)
|
|
}
|
|
|
|
$sessionOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
|
|
|
|
# ── Configure HOST-side WinRM client (required for Basic auth over HTTP) ──────
|
|
# These settings apply to this machine (the host), not the VM.
|
|
# AllowUnencrypted is needed for HTTP/5985 Basic auth in a lab environment.
|
|
Write-Host "[Prepare] Configuring host WinRM client for unencrypted Basic auth..."
|
|
try {
|
|
Set-Item WSMan:\localhost\Client\AllowUnencrypted $true -Force -ErrorAction Stop
|
|
# Add VM IP to TrustedHosts if not already present
|
|
$currentTrusted = (Get-Item WSMan:\localhost\Client\TrustedHosts).Value
|
|
if ($currentTrusted -ne '*' -and $currentTrusted -notlike "*$VMIPAddress*") {
|
|
$newTrusted = if ($currentTrusted -eq '') { $VMIPAddress } else { "$currentTrusted,$VMIPAddress" }
|
|
Set-Item WSMan:\localhost\Client\TrustedHosts -Value $newTrusted -Force -ErrorAction Stop
|
|
}
|
|
Write-Host "[Prepare] Host WinRM client configured."
|
|
}
|
|
catch {
|
|
Write-Warning "[Prepare] Could not configure host WinRM client settings (need elevation?)."
|
|
Write-Warning "Run once in an elevated PowerShell on the HOST:"
|
|
Write-Warning " Set-Item WSMan:\localhost\Client\AllowUnencrypted `$true -Force"
|
|
Write-Warning " Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*' -Force"
|
|
Write-Warning "Then re-run this script."
|
|
exit 1
|
|
}
|
|
|
|
|
|
Write-Host "[Prepare] Testing WinRM connectivity to $VMIPAddress..."
|
|
try {
|
|
Test-WSMan -ComputerName $VMIPAddress -Credential $credential `
|
|
-Authentication Basic -ErrorAction Stop | Out-Null
|
|
Write-Host "[Prepare] WinRM reachable."
|
|
}
|
|
catch {
|
|
Write-Error @"
|
|
[Prepare] Cannot reach $VMIPAddress via WinRM.
|
|
|
|
Ensure:
|
|
- The VM is running and on VMnet8 (NAT) with internet access
|
|
- WinRM is enabled inside the VM (run as Administrator in VM):
|
|
winrm quickconfig -q
|
|
Enable-PSRemoting -Force -SkipNetworkProfileCheck
|
|
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*' -Force
|
|
- Windows Firewall allows port 5985 inbound
|
|
- The IP is correct (check ipconfig inside the VM)
|
|
|
|
Error: $_
|
|
"@
|
|
exit 1
|
|
}
|
|
|
|
# ── Open session ──────────────────────────────────────────────────────────────
|
|
Write-Host "[Prepare] Opening PSSession..."
|
|
$session = New-PSSession `
|
|
-ComputerName $VMIPAddress `
|
|
-Credential $credential `
|
|
-SessionOption $sessionOptions `
|
|
-Authentication Basic `
|
|
-ErrorAction Stop
|
|
|
|
try {
|
|
# ── Copy Setup-TemplateVM.ps1 into the VM ─────────────────────────────────
|
|
$setupScript = Join-Path $scriptDir 'Setup-TemplateVM.ps1'
|
|
$guestScriptPath = 'C:\CI\Setup-TemplateVM.ps1'
|
|
|
|
Write-Host "[Prepare] Ensuring C:\CI exists on guest..."
|
|
Invoke-Command -Session $session -ScriptBlock {
|
|
if (-not (Test-Path 'C:\CI')) {
|
|
New-Item -ItemType Directory -Path 'C:\CI' -Force | Out-Null
|
|
}
|
|
}
|
|
|
|
Write-Host "[Prepare] Copying Setup-TemplateVM.ps1 -> guest $guestScriptPath ..."
|
|
Copy-Item -Path $setupScript -Destination $guestScriptPath -ToSession $session -Force
|
|
|
|
# ── Build argument list for Setup-TemplateVM.ps1 ─────────────────────────
|
|
$setupArgs = @{
|
|
BuildPassword = $BuildPassword
|
|
DotNetSdkVersion = $DotNetSdkVersion
|
|
}
|
|
if ($SkipWindowsUpdate) { $setupArgs['SkipWindowsUpdate'] = $true }
|
|
|
|
# ── Run Setup-TemplateVM.ps1 inside the VM ────────────────────────────────
|
|
Write-Host "[Prepare] Running Setup-TemplateVM.ps1 inside VM (this will take a while)..."
|
|
Write-Host "[Prepare] Output from guest:"
|
|
Write-Host "------------------------------------------------------------"
|
|
|
|
$result = Invoke-Command -Session $session -ScriptBlock {
|
|
param($scriptPath, $scriptArgs)
|
|
Set-ExecutionPolicy Bypass -Scope Process -Force
|
|
$exitCode = 0
|
|
try {
|
|
& $scriptPath @scriptArgs
|
|
$exitCode = $LASTEXITCODE
|
|
if ($null -eq $exitCode) { $exitCode = 0 }
|
|
}
|
|
catch {
|
|
Write-Error $_
|
|
$exitCode = 1
|
|
}
|
|
return $exitCode
|
|
} -ArgumentList $guestScriptPath, $setupArgs
|
|
|
|
Write-Host "------------------------------------------------------------"
|
|
|
|
# ── Handle reboot required (exit 3010) ───────────────────────────────────
|
|
if ($result -eq 3010) {
|
|
Write-Host ""
|
|
Write-Warning "*** REBOOT REQUIRED after Windows Update. ***"
|
|
Write-Warning " The VM will reboot. Wait for it to come back up, then run:"
|
|
Write-Warning " .\Prepare-TemplateSetup.ps1 -VMIPAddress $VMIPAddress -SkipWindowsUpdate"
|
|
|
|
# Reboot the VM
|
|
Write-Host "[Prepare] Sending reboot command to VM..."
|
|
Invoke-Command -Session $session -ScriptBlock { Restart-Computer -Force }
|
|
exit 3010
|
|
}
|
|
|
|
if ($result -ne 0) {
|
|
throw "Setup-TemplateVM.ps1 exited with code $result"
|
|
}
|
|
|
|
# ── Success ───────────────────────────────────────────────────────────────
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Green
|
|
Write-Host " Template VM provisioning complete!" -ForegroundColor Green
|
|
Write-Host "============================================================" -ForegroundColor Green
|
|
Write-Host ""
|
|
Write-Host " NOW DO THESE STEPS (manual):"
|
|
Write-Host ""
|
|
Write-Host " 1. Shut down the VM: Start -> Shut down"
|
|
Write-Host " (VM stays on VMnet8 NAT for internet access during builds)"
|
|
Write-Host ""
|
|
Write-Host " 2. Take snapshot:"
|
|
Write-Host " VM -> Snapshot -> Take Snapshot"
|
|
Write-Host " Name it EXACTLY: BaseClean"
|
|
Write-Host ""
|
|
Write-Host " 3. Store CI credentials on this HOST:"
|
|
Write-Host " (run in elevated PowerShell with CredentialManager module)"
|
|
Write-Host " New-StoredCredential -Target 'BuildVMGuest' ``"
|
|
Write-Host " -UserName 'ci_build' -Password '$BuildPassword' ``"
|
|
Write-Host " -Persist LocalMachine"
|
|
Write-Host ""
|
|
Write-Host " 4. Verify runner online in Gitea: http://10.10.20.11:3100"
|
|
Write-Host " Admin -> Runners -> local-windows-runner -> should show Online"
|
|
Write-Host ""
|
|
}
|
|
finally {
|
|
Remove-PSSession $session -ErrorAction SilentlyContinue
|
|
}
|