Files
runner-images/images/macos/provision/configuration/CreateCleanAnkaTemplate.ps1

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