552eb628b7
Sprint 4 — qualità codice: - scripts/_Common.psm1: New-CISessionOption, Resolve-VmrunPath, Invoke-Vmrun - PSScriptAnalyzerSettings.psd1: project-wide PSSA rules (security + formatting) - Remove-BuildVM.ps1: SupportsShouldProcess (-WhatIf support) - Invoke-RemoteBuild.ps1, Get-BuildArtifacts.ps1: use New-CISessionOption from module - New-BuildVM.ps1: use Resolve-VmrunPath + Invoke-Vmrun from module Sprint 5 — affidabilità: - Backup-CITemplate.ps1: stop runner, timestamped VMDK backup, prune old, restart - Watch-RunnerHealth.ps1: auto-restart act_runner, cooldown 3/h, EventLog + webhook - Register-CIScheduledTasks.ps1: add CI-RunnerHealth task (every 15 min) Sprint 6 — perf baseline: - Set-TemplateSharedFolders.ps1: idempotent VMX editor for NuGet/pip shared folders - Invoke-RemoteBuild.ps1: -UseSharedCache injects NUGET_PACKAGES + PIP_CACHE_DIR in guest - Measure-CIBenchmark.ps1: times clone/start/IP/WinRM/destroy, appends to benchmark.jsonl Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
199 lines
9.0 KiB
PowerShell
199 lines
9.0 KiB
PowerShell
#Requires -Version 5.1
|
|
#Requires -RunAsAdministrator
|
|
<#
|
|
.SYNOPSIS
|
|
Registers Windows Scheduled Tasks for CI system maintenance.
|
|
|
|
.DESCRIPTION
|
|
Creates or updates four tasks under the \CI\ task folder:
|
|
|
|
CI-CleanupOrphans — Runs Cleanup-OrphanedBuildVMs.ps1 every 6 hours
|
|
and at host startup. Destroys stale build VMs
|
|
(those older than -MaxAgeHours, default 4) that
|
|
were not cleaned up after a crash or timeout.
|
|
|
|
CI-RetentionPolicy — Runs Invoke-RetentionPolicy.ps1 daily at 3:00 AM
|
|
and at host startup (with a 15-min random delay).
|
|
Purges old artifact and log directories per the
|
|
configured retention window.
|
|
|
|
CI-DiskSpaceAlert — Runs Watch-DiskSpace.ps1 every 15 minutes.
|
|
Writes an Event Log warning and optional webhook
|
|
when CI drive free space falls below 50 GB.
|
|
|
|
CI-RunnerHealth — Runs Watch-RunnerHealth.ps1 every 15 minutes.
|
|
Auto-restarts act_runner if stopped; rate-limited
|
|
to 3 restarts per hour before requiring manual fix.
|
|
|
|
All tasks run as SYSTEM with highest privilege. Idempotent: safe to re-run
|
|
after updating the scripts — existing tasks are overwritten (-Force).
|
|
|
|
.PARAMETER ScriptRoot
|
|
Directory containing the CI scripts. Default: N:\Code\Workspace\Local-CI-CD-System\scripts
|
|
|
|
.PARAMETER MaxAgeHours
|
|
Passed to Cleanup-OrphanedBuildVMs.ps1. VMs older than this are treated as
|
|
orphaned. Must exceed the longest expected build duration. Default: 4
|
|
|
|
.EXAMPLE
|
|
# Register (or update) tasks — run from an elevated PowerShell session
|
|
.\Register-CIScheduledTasks.ps1
|
|
|
|
# Preview what would be registered
|
|
.\Register-CIScheduledTasks.ps1 -WhatIf
|
|
#>
|
|
[CmdletBinding(SupportsShouldProcess)]
|
|
param(
|
|
[string] $ScriptRoot = 'N:\Code\Workspace\Local-CI-CD-System\scripts',
|
|
|
|
[ValidateRange(1, 168)]
|
|
[int] $MaxAgeHours = 4
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$psExe = "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe"
|
|
$taskPath = '\CI\'
|
|
$principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -RunLevel Highest
|
|
|
|
# Ensure task folder exists (Register-ScheduledTask creates it, but be explicit)
|
|
$schedulerService = New-Object -ComObject 'Schedule.Service'
|
|
$schedulerService.Connect()
|
|
$rootFolder = $schedulerService.GetFolder('\')
|
|
try { $rootFolder.GetFolder('CI') | Out-Null }
|
|
catch { $rootFolder.CreateFolder('CI') | Out-Null }
|
|
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($schedulerService) | Out-Null
|
|
|
|
# ── Task 1: CI-CleanupOrphans ─────────────────────────────────────────────────
|
|
$cleanupScript = Join-Path $ScriptRoot 'Cleanup-OrphanedBuildVMs.ps1'
|
|
if (-not (Test-Path $cleanupScript -PathType Leaf)) {
|
|
Write-Warning "Script not found — skipping CI-CleanupOrphans: $cleanupScript"
|
|
} else {
|
|
$cleanupAction = New-ScheduledTaskAction `
|
|
-Execute $psExe `
|
|
-Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$cleanupScript`" -MaxAgeHours $MaxAgeHours"
|
|
|
|
# Repeat every 6 hours indefinitely (Once trigger + RepetitionInterval)
|
|
$repeat6h = New-ScheduledTaskTrigger -Once -At '00:00' `
|
|
-RepetitionInterval (New-TimeSpan -Hours 6)
|
|
$atStartup = New-ScheduledTaskTrigger -AtStartup
|
|
|
|
$cleanupSettings = New-ScheduledTaskSettingsSet `
|
|
-ExecutionTimeLimit (New-TimeSpan -Hours 1) `
|
|
-MultipleInstances IgnoreNew `
|
|
-StartWhenAvailable
|
|
|
|
if ($PSCmdlet.ShouldProcess('CI-CleanupOrphans', 'Register/update scheduled task')) {
|
|
Register-ScheduledTask `
|
|
-TaskName 'CI-CleanupOrphans' `
|
|
-TaskPath $taskPath `
|
|
-Action $cleanupAction `
|
|
-Trigger @($repeat6h, $atStartup) `
|
|
-Principal $principal `
|
|
-Settings $cleanupSettings `
|
|
-Description "Destroys orphaned CI build VMs older than ${MaxAgeHours}h (Local CI/CD System)" `
|
|
-Force | Out-Null
|
|
Write-Host "[Register] CI-CleanupOrphans registered (every 6h + at startup, -MaxAgeHours $MaxAgeHours)." -ForegroundColor Green
|
|
}
|
|
}
|
|
|
|
# ── Task 2: CI-RetentionPolicy ────────────────────────────────────────────────
|
|
$retentionScript = Join-Path $ScriptRoot 'Invoke-RetentionPolicy.ps1'
|
|
if (-not (Test-Path $retentionScript -PathType Leaf)) {
|
|
Write-Warning "Script not found — skipping CI-RetentionPolicy: $retentionScript"
|
|
} else {
|
|
$retentionAction = New-ScheduledTaskAction `
|
|
-Execute $psExe `
|
|
-Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$retentionScript`""
|
|
|
|
$daily3am = New-ScheduledTaskTrigger -Daily -At '03:00' `
|
|
-RandomDelay (New-TimeSpan -Minutes 30)
|
|
$atStartup2 = New-ScheduledTaskTrigger -AtStartup `
|
|
-RandomDelay (New-TimeSpan -Minutes 15)
|
|
|
|
$retentionSettings = New-ScheduledTaskSettingsSet `
|
|
-ExecutionTimeLimit (New-TimeSpan -Hours 1) `
|
|
-MultipleInstances IgnoreNew `
|
|
-StartWhenAvailable
|
|
|
|
if ($PSCmdlet.ShouldProcess('CI-RetentionPolicy', 'Register/update scheduled task')) {
|
|
Register-ScheduledTask `
|
|
-TaskName 'CI-RetentionPolicy' `
|
|
-TaskPath $taskPath `
|
|
-Action $retentionAction `
|
|
-Trigger @($daily3am, $atStartup2) `
|
|
-Principal $principal `
|
|
-Settings $retentionSettings `
|
|
-Description 'Purges old CI artifacts, logs, and stale IP leases (Local CI/CD System)' `
|
|
-Force | Out-Null
|
|
Write-Host "[Register] CI-RetentionPolicy registered (daily 03:00 + at startup)." -ForegroundColor Green
|
|
}
|
|
}
|
|
|
|
# ── Task 3: CI-DiskSpaceAlert ─────────────────────────────────────────────────
|
|
$diskScript = Join-Path $ScriptRoot 'Watch-DiskSpace.ps1'
|
|
if (-not (Test-Path $diskScript -PathType Leaf)) {
|
|
Write-Warning "Script not found — skipping CI-DiskSpaceAlert: $diskScript"
|
|
} else {
|
|
$diskAction = New-ScheduledTaskAction `
|
|
-Execute $psExe `
|
|
-Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$diskScript`""
|
|
|
|
# Every 15 minutes indefinitely
|
|
$disk15min = New-ScheduledTaskTrigger -Once -At '00:00' `
|
|
-RepetitionInterval (New-TimeSpan -Minutes 15)
|
|
|
|
$diskSettings = New-ScheduledTaskSettingsSet `
|
|
-ExecutionTimeLimit (New-TimeSpan -Minutes 5) `
|
|
-MultipleInstances IgnoreNew `
|
|
-StartWhenAvailable
|
|
|
|
if ($PSCmdlet.ShouldProcess('CI-DiskSpaceAlert', 'Register/update scheduled task')) {
|
|
Register-ScheduledTask `
|
|
-TaskName 'CI-DiskSpaceAlert' `
|
|
-TaskPath $taskPath `
|
|
-Action $diskAction `
|
|
-Trigger $disk15min `
|
|
-Principal $principal `
|
|
-Settings $diskSettings `
|
|
-Description 'Alerts via Event Log when CI drive free space drops below 50 GB (Local CI/CD System)' `
|
|
-Force | Out-Null
|
|
Write-Host "[Register] CI-DiskSpaceAlert registered (every 15 min)." -ForegroundColor Green
|
|
}
|
|
}
|
|
|
|
# ── Task 4: CI-RunnerHealth ───────────────────────────────────────────────────
|
|
$healthScript = Join-Path $ScriptRoot 'Watch-RunnerHealth.ps1'
|
|
if (-not (Test-Path $healthScript -PathType Leaf)) {
|
|
Write-Warning "Script not found — skipping CI-RunnerHealth: $healthScript"
|
|
} else {
|
|
$healthAction = New-ScheduledTaskAction `
|
|
-Execute $psExe `
|
|
-Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$healthScript`""
|
|
|
|
# Every 15 minutes indefinitely
|
|
$health15min = New-ScheduledTaskTrigger -Once -At '00:00' `
|
|
-RepetitionInterval (New-TimeSpan -Minutes 15)
|
|
|
|
$healthSettings = New-ScheduledTaskSettingsSet `
|
|
-ExecutionTimeLimit (New-TimeSpan -Minutes 5) `
|
|
-MultipleInstances IgnoreNew `
|
|
-StartWhenAvailable
|
|
|
|
if ($PSCmdlet.ShouldProcess('CI-RunnerHealth', 'Register/update scheduled task')) {
|
|
Register-ScheduledTask `
|
|
-TaskName 'CI-RunnerHealth' `
|
|
-TaskPath $taskPath `
|
|
-Action $healthAction `
|
|
-Trigger $health15min `
|
|
-Principal $principal `
|
|
-Settings $healthSettings `
|
|
-Description 'Auto-restarts act_runner service if stopped; rate-limited to 3 restarts/h (Local CI/CD System)' `
|
|
-Force | Out-Null
|
|
Write-Host "[Register] CI-RunnerHealth registered (every 15 min, max 3 restarts/h)." -ForegroundColor Green
|
|
}
|
|
}
|
|
|
|
Write-Host "`n[Register] Done. Verify with: Get-ScheduledTask -TaskPath '\CI\' | Format-Table TaskName, State" -ForegroundColor Cyan
|