mirror of
https://github.com/actions/runner-images.git
synced 2025-12-16 06:40:32 +00:00
228 lines
7.7 KiB
PowerShell
228 lines
7.7 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[Version] $MacOSVersion,
|
|
|
|
[ValidateNotNullOrEmpty()]
|
|
[String] $TemplateUsername,
|
|
|
|
[Parameter(Mandatory)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[String] $TemplatePassword,
|
|
|
|
[Parameter(Mandatory)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[String] $RegistryUrl,
|
|
|
|
[Bool] $BetaSearch = $false,
|
|
[Int] $CpuCount = 6,
|
|
[Int] $RamSizeGb = 7,
|
|
[Int] $DiskSizeGb = 300,
|
|
[String] $DisplayResolution = "1920x1080"
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Get-MacOSInstallers {
|
|
param (
|
|
[version] $MacOSVersion,
|
|
[bool] $BetaSearch = $false
|
|
)
|
|
|
|
# Enroll machine to DeveloperSeed if we need beta and unenroll otherwise
|
|
$seedutil = "/System/Library/PrivateFrameworks/Seeding.framework/Versions/Current/Resources/seedutil"
|
|
if ($BetaSearch) {
|
|
Write-Host "Beta Version requested. Enrolling machine to DeveloperSeed"
|
|
sudo $seedutil enroll DeveloperSeed | Out-Null
|
|
} else {
|
|
Write-Host "Reseting the seed before requesting stable versions"
|
|
sudo $seedutil unenroll | Out-Null
|
|
}
|
|
|
|
# Validate there is no softwareupdate at the moment
|
|
Test-SoftwareUpdate
|
|
|
|
# Validate availability OSVersion
|
|
$availableVersions = Get-AvailableVersions -IsBeta $BetaSearch
|
|
$macOSName = $availableVersions.Where{ $_.OSVersion -eq $MacOSVersion }.OSName
|
|
if (-not $macOSName) {
|
|
Write-Host "Requested macOS '$MacOSVersion' version not found in the list of available installers. Available versions are:`n$($availableVersions.OSVersion)"
|
|
Write-Host 'Make sure to pass "-BetaSearch $true" if you need a beta version installer'
|
|
exit 1
|
|
}
|
|
|
|
$installerPathPattern = "/Applications/Install*${macOSName}.app"
|
|
if (Test-Path $installerPathPattern) {
|
|
$previousInstallerPath = Get-Item -Path $installerPathPattern
|
|
Write-Host "Removing '$previousInstallerPath' installation app before downloading the new one"
|
|
sudo rm -rf "$previousInstallerPath"
|
|
}
|
|
|
|
# Download macOS installer
|
|
Write-Host "Requested macOS '$MacOSVersion' version installer found, fetching it from Apple Software Update"
|
|
$result = Invoke-WithRetry { softwareupdate --fetch-full-installer --full-installer-version $MacOSVersion } {$LASTEXITCODE -eq 0} | Out-String
|
|
if (-not $result.Contains("Install finished successfully")) {
|
|
Write-Host "[Error]: failed to fetch $MacOSVersion macOS '$MacOSVersion' `n$result"
|
|
exit 1
|
|
}
|
|
|
|
$installerPath = Get-Item -Path $installerPathPattern
|
|
Write-Host "Installer successfully downloaded to '$installerPath'"
|
|
|
|
return $installerPath.FullName
|
|
}
|
|
|
|
function Invoke-WithRetry {
|
|
param(
|
|
[scriptblock] $Command,
|
|
[scriptblock] $BreakCondition,
|
|
[int] $RetryCount = 20,
|
|
[int] $Seconds = 60
|
|
)
|
|
|
|
while ($RetryCount -gt 0) {
|
|
$result = & $Command
|
|
|
|
if (& $BreakCondition) {
|
|
break
|
|
}
|
|
|
|
$RetryCount--
|
|
Write-Host "Waiting $Seconds seconds before retrying. Retries left: $RetryCount"
|
|
Start-Sleep -Seconds $Seconds
|
|
}
|
|
|
|
$result
|
|
}
|
|
|
|
function Get-AvailableVersions {
|
|
param (
|
|
[Int] $RetryCount = 20,
|
|
[Int] $RetryInterval = 60,
|
|
[Bool] $IsBeta = $false
|
|
)
|
|
|
|
if ($IsBeta) {
|
|
$searchPostfix = " beta"
|
|
}
|
|
|
|
$softwareUpdates = Invoke-WithRetry { softwareupdate --list-full-installers | Where-Object { $_.Contains("Title: macOS") -and $_ -match $searchPostfix } } { {$LASTEXITCODE -eq 0}}
|
|
$allVersions = $softwareUpdates -replace "(\* )?(Title|Version|Size):" | ConvertFrom-Csv -Header OsName, OsVersion
|
|
|
|
return $allVersions
|
|
}
|
|
|
|
function Test-SoftwareUpdate {
|
|
param (
|
|
[String] $UpdateProcessName = "softwareupdate",
|
|
[Int] $RetryCount = 20,
|
|
[Int] $RetryInterval = 60
|
|
)
|
|
|
|
$command = {
|
|
$updateProcess = (Get-Process -Name $UpdateProcessName -ErrorAction SilentlyContinue).id
|
|
if ($updateProcess) {
|
|
# Workaround to get commandline param as it doesn't work for macOS atm https://github.com/PowerShell/PowerShell/issues/13943
|
|
$processName = ps -o command= $updateProcess
|
|
Write-Host "Another software update process is in place with the following arguments '$processName', wait $RetryInterval seconds, $RetryCount attempts left"
|
|
}
|
|
}
|
|
$condition = {
|
|
$null -eq (Get-Process -Name $UpdateProcessName -ErrorAction SilentlyContinue)
|
|
}
|
|
|
|
Invoke-WithRetry -Command $command -BreakCondition $condition
|
|
}
|
|
|
|
function New-AnkaVMTemplate {
|
|
param (
|
|
[String] $InstallerPath,
|
|
[String] $ShortMacOSVersion,
|
|
[String] $TemplateName,
|
|
[String] $TemplateUsername,
|
|
[String] $TemplatePassword,
|
|
[Int] $CpuCount,
|
|
[Int] $RamSizeGb,
|
|
[Int] $DiskSizeGb,
|
|
[String] $DisplayResolution
|
|
)
|
|
|
|
$isTemplateExists = (Invoke-Anka { anka --machine-readable list } | ConvertFrom-Json).body.name -eq $templateName
|
|
if ($isTemplateExists) {
|
|
Write-Host "Deleting existed template with name '$templateName' before creating a new one"
|
|
Invoke-Anka { anka delete $templateName --yes }
|
|
}
|
|
|
|
Write-Host "Creating Anka VM template with name '$TemplateName' and user $TemplateUsername"
|
|
$env:ANKA_DEFAULT_USER = $TemplateUsername
|
|
$env:ANKA_DEFAULT_PASSWD = $TemplatePassword
|
|
$env:ANKA_CREATE_SUSPEND = 0
|
|
Write-Host "Cpu Count: $CpuCount, RamSize: ${RamSizeGb}G, DiskSizeGb: ${DiskSizeGb}G, InstallerPath: $InstallerPath, TemplateName: $templateName"
|
|
Invoke-Anka { anka create --cpu-count $CpuCount --ram-size "${RamSizeGb}G" --disk-size "${DiskSizeGb}G" --app $InstallerPath $templateName }
|
|
|
|
# Apple Metal is available starting from Big Sur
|
|
if (-not $ShortMacOSVersion.StartsWith("10.")) {
|
|
Write-Host "Enabling Graphics Acceleration with Apple Metal for $templateName"
|
|
Invoke-Anka { anka modify $templateName set display -c pg }
|
|
}
|
|
|
|
Write-Host "Setting screen resolution to $DisplayResolution for $templateName"
|
|
Invoke-Anka { anka modify $templateName set display -r $DisplayResolution }
|
|
|
|
return $templateName
|
|
}
|
|
|
|
function Add-AnkaImageToRegistry {
|
|
param (
|
|
[String] $RegistryUrl,
|
|
[String] $ShortMacOSVersion,
|
|
[String] $TemplateName
|
|
)
|
|
|
|
Write-Host "Pushing image to the registry..."
|
|
Invoke-Anka { anka registry -a $RegistryUrl push -t $ShortMacOSVersion $TemplateName }
|
|
}
|
|
|
|
function Invoke-Anka {
|
|
param (
|
|
[scriptblock] $Cmd
|
|
)
|
|
|
|
& $Cmd
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "There is an error during command execution"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
function Get-ShortMacOSVersion {
|
|
param (
|
|
[Version] $MacOSVersion
|
|
)
|
|
|
|
# Take Major.Minor version for macOS 10 (10.14 or 10.15) and Major for all further versions
|
|
if ($MacOSVersion.Major -eq 10) {
|
|
$shortMacOSVersion = $MacOSVersion.ToString(2)
|
|
}
|
|
else {
|
|
$shortMacOSVersion = $MacOSVersion.Major
|
|
}
|
|
|
|
return $shortMacOSVersion
|
|
}
|
|
|
|
$macOSInstaller = Get-MacOSInstallers -MacOSVersion $MacOSVersion -BetaSearch $BetaSearch
|
|
$shortMacOSVersion = Get-ShortMacOSVersion -MacOSVersion $MacOSVersion
|
|
$templateName = "clean_macos_${shortMacOSVersion}_${DiskSizeGb}gb"
|
|
New-AnkaVMTemplate -InstallerPath $macOSInstaller `
|
|
-ShortMacOSVersion $shortMacOSVersion `
|
|
-TemplateName $templateName `
|
|
-TemplateUsername $TemplateUsername `
|
|
-TemplatePassword $TemplatePassword `
|
|
-CpuCount $CpuCount `
|
|
-RamSizeGb $RamSizeGb `
|
|
-DiskSizeGb $DiskSizeGb `
|
|
-DisplayResolution $DisplayResolution
|
|
|
|
Add-AnkaImageToRegistry -RegistryUrl $registryUrl -ShortMacOSVersion $shortMacOSVersion -TemplateName $templateName |