Remove obsolete ADO pipelines and scripts (#11640)

This commit is contained in:
Alexey-Ayupov
2025-02-24 19:53:50 +01:00
committed by GitHub
parent cec14e5822
commit f8ba10395e
10 changed files with 0 additions and 1251 deletions

View File

@@ -1,14 +0,0 @@
param(
[String] [Parameter (Mandatory=$true)] $RepoUrl,
[String] [Parameter (Mandatory=$true)] $RepoBranch
)
Write-Host "Clean up default repository"
Remove-Item -path './*' -Recurse -Force
Write-Host "Download ${RepoBranch} branch from ${RepoUrl}"
$env:GIT_REDIRECT_STDERR = '2>&1'
git clone $RepoUrl . -b $RepoBranch --single-branch --depth 1
Write-Host "Latest commit:"
git --no-pager log --pretty=format:"Date: %cd; Commit: %H - %s; Author: %an <%ae>" -1

View File

@@ -1,181 +0,0 @@
# Ideally we would use GitHub Actions for this, but since we use self-hosted machines to run image builds
# we need the following features to use GitHub Actions for Images CI:
# - https://github.community/t5/GitHub-Actions/Make-secrets-available-to-builds-of-forks/m-p/30678#M508
# - https://github.community/t5/GitHub-Actions/GitHub-Actions-Manual-Trigger-Approvals/td-p/31504
# - https://github.community/t5/GitHub-Actions/Protecting-github-workflows/td-p/30290
parameters:
- name: job_id
type: string
default: 'generate_image'
- name: image_type
type: string
- name: image_template_name
type: string
- name: image_readme_name
type: string
- name: agent_pool
type: object
default:
name: 'ci-agent-pool'
- name: variable_group_name
type: string
default: 'Image Generation Variables'
- name: create_release
type: boolean
default: true
- name: repository_ref
type: string
default: 'self'
jobs:
- job: ${{ parameters.job_id }}
displayName: Image Generation (${{ parameters.image_type }})
timeoutInMinutes: 600
cancelTimeoutInMinutes: 30
pool: ${{ parameters.agent_pool }}
variables:
- group: ${{ parameters.variable_group_name }}
steps:
- checkout: ${{ parameters.repository_ref }}
clean: true
fetchDepth: 0
fetchTags: false
- task: PowerShell@2
displayName: 'Download custom repository'
condition: and(ne(variables['CUSTOM_REPOSITORY_URL'], ''), ne(variables['CUSTOM_REPOSITORY_BRANCH'], ''))
inputs:
targetType: 'filePath'
filePath: ./images.CI/download-repo.ps1
arguments: -RepoUrl $(CUSTOM_REPOSITORY_URL) `
-RepoBranch $(CUSTOM_REPOSITORY_BRANCH)
- task: AzureCLI@2
displayName: 'Set variables'
inputs:
azureSubscription: 'spn-hosted-runners'
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
$ImageType = "${{ parameters.image_type }}"
$TemplateDirectoryName = if ($ImageType.StartsWith("ubuntu")) { "ubuntu/templates" } else { "windows/templates" }
$TemplateDirectoryPath = Join-Path "images" $TemplateDirectoryName | Resolve-Path
$TemplateFileName = "${{ parameters.image_template_name }}"
$TemplatePath = Join-Path $TemplateDirectoryPath $TemplateFileName
Write-Host "##vso[task.setvariable variable=TemplateDirectoryPath;]$TemplateDirectoryPath"
Write-Host "##vso[task.setvariable variable=TemplatePath;]$TemplatePath"
$ManagedImageName = "${{ parameters.image_type }}-$(Build.BuildId)"
Write-Host "##vso[task.setvariable variable=ManagedImageName;]$ManagedImageName"
$TempResourceGroupName = "packer-temp-$ManagedImageName"
Write-Host "##vso[task.setvariable variable=TempResourceGroupName;]$TempResourceGroupName"
$clientSecret = $(az keyvault secret show --name "spnhostedrunners" --vault-name "gh-imagegeneration" --query value -o tsv)
Write-Host "##vso[task.setvariable variable=ClientSecret;issecret=true]$clientSecret"
- task: PowerShell@2
displayName: 'Build VM'
inputs:
targetType: filePath
filePath: ./images.CI/linux-and-win/build-image.ps1
arguments: -ClientId $(CLIENT_ID) `
-ClientSecret "$(ClientSecret)" `
-TemplatePath $(TemplatePath) `
-ImageName "$(ManagedImageName)" `
-ImageResourceGroupName $(AZURE_RESOURCE_GROUP) `
-TempResourceGroupName "$(TempResourceGroupName)" `
-SubscriptionId $(AZURE_SUBSCRIPTION) `
-TenantId $(AZURE_TENANT) `
-Location $(AZURE_LOCATION) `
-VirtualNetworkName $(BUILD_AGENT_VNET_NAME) `
-VirtualNetworkRG $(BUILD_AGENT_VNET_RESOURCE_GROUP) `
-VirtualNetworkSubnet $(BUILD_AGENT_SUBNET_NAME)
env:
PACKER_LOG: 1
PACKER_LOG_PATH: "$(Agent.TempDirectory)/packer-log.txt"
- task: PowerShell@2
displayName: 'Copy image artifacts to the separate directory'
inputs:
targetType: 'inline'
script: |
$ImageType = "${{ parameters.image_type }}"
$rootDirectoryName = if ($ImageType.StartsWith("ubuntu")) { "ubuntu" } else { "windows" }
$rootDirectoryPath = Join-Path "images" $rootDirectoryName | Resolve-Path
$readmePath = Join-Path $rootDirectoryPath "${{ parameters.image_readme_name }}"
$softwareReportPath = Join-Path $rootDirectoryPath "software-report.json"
Copy-Item -Path $readmePath -Destination "$(Build.ArtifactStagingDirectory)/"
if (Test-Path $softwareReportPath) {
Copy-Item -Path $softwareReportPath -Destination "$(Build.ArtifactStagingDirectory)/"
}
- task: PowerShell@2
displayName: 'Print markdown software report'
inputs:
targetType: 'inline'
script: |
Get-Content -Path "$(Build.ArtifactStagingDirectory)/${{ parameters.image_readme_name }}"
- task: PowerShell@2
displayName: 'Print json software report'
inputs:
targetType: 'inline'
script: |
$softwareReportPath = "$(Build.ArtifactStagingDirectory)/software-report.json"
if (Test-Path $softwareReportPath) {
Get-Content -Path $softwareReportPath
}
- task: PublishBuildArtifacts@1
inputs:
ArtifactName: 'Built_VM_Artifacts'
displayName: Publish Artifacts
- task: PowerShell@2
displayName: 'Print provisioners duration'
inputs:
targetType: 'filePath'
filePath: ./images.CI/measure-provisioners-duration.ps1
arguments: -PackerLogPath "$(Agent.TempDirectory)/packer-log.txt" `
-PrefixToPathTrim "$(TemplateDirectoryPath)" `
-PrintTopNLongest 25
- ${{ if eq(parameters.create_release, true) }}:
- task: PowerShell@2
displayName: 'Create release for VM deployment'
inputs:
targetType: filePath
filePath: ./images.CI/linux-and-win/create-release.ps1
arguments: -BuildId $(Build.BuildId) `
-Organization $(RELEASE_TARGET_ORGANIZATION) `
-DefinitionId $(RELEASE_TARGET_DEFINITION_ID) `
-Project $(RELEASE_TARGET_PROJECT) `
-ImageType "${{ parameters.image_type }}" `
-ManagedImageName "$(ManagedImageName)" `
-AccessToken $(RELEASE_TARGET_TOKEN)
- task: PowerShell@2
displayName: 'Clean up resources'
condition: always()
inputs:
targetType: filePath
filePath: ./images.CI/linux-and-win/cleanup.ps1
arguments: -TempResourceGroupName "$(TempResourceGroupName)" `
-SubscriptionId $(AZURE_SUBSCRIPTION) `
-ClientId $(CLIENT_ID) `
-ClientSecret "$(ClientSecret)" `
-TenantId $(AZURE_TENANT)

View File

@@ -1,21 +0,0 @@
schedules:
- cron: "0 0 * * *"
displayName: Daily
branches:
include:
- main
always: true
trigger: none
pr:
autoCancel: true
branches:
include:
- main
jobs:
- template: image-generation.yml
parameters:
image_type: ubuntu2004
image_readme_name: Ubuntu2004-Readme.md
image_template_name: ubuntu-20.04.pkr.hcl

View File

@@ -1,21 +0,0 @@
schedules:
- cron: "0 0 * * *"
displayName: Daily
branches:
include:
- main
always: true
trigger: none
pr:
autoCancel: true
branches:
include:
- main
jobs:
- template: image-generation.yml
parameters:
image_type: ubuntu2204
image_readme_name: Ubuntu2204-Readme.md
image_template_name: ubuntu-22.04.pkr.hcl

View File

@@ -1,21 +0,0 @@
schedules:
- cron: "0 0 * * *"
displayName: Daily
branches:
include:
- main
always: true
trigger: none
pr:
autoCancel: true
branches:
include:
- main
jobs:
- template: image-generation.yml
parameters:
image_type: ubuntu2404
image_readme_name: Ubuntu2404-Readme.md
image_template_name: ubuntu-24.04.pkr.hcl

View File

@@ -1,21 +0,0 @@
schedules:
- cron: "0 0 * * *"
displayName: Daily
branches:
include:
- main
always: true
trigger: none
pr:
autoCancel: true
branches:
include:
- main
jobs:
- template: image-generation.yml
parameters:
image_type: windows2019
image_readme_name: Windows2019-Readme.md
image_template_name: windows-2019.pkr.hcl

View File

@@ -1,21 +0,0 @@
schedules:
- cron: "0 0 * * *"
displayName: Daily
branches:
include:
- main
always: true
trigger: none
pr:
autoCancel: true
branches:
include:
- main
jobs:
- template: image-generation.yml
parameters:
image_type: windows2022
image_readme_name: Windows2022-Readme.md
image_template_name: windows-2022.pkr.hcl

View File

@@ -1,248 +0,0 @@
function Push-AnkaTemplateToRegistry {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $RegistryUrl,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $TagName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $TemplateName
)
# if registry uuid doesn't match then delete an image in registry
$AnkaCaCrtPath="$HOME/.config/anka/certs/anka-ca-crt.pem"
$images = anka --machine-readable registry --cacert $AnkaCaCrtPath --registry-path $RegistryUrl list | ConvertFrom-Json | ForEach-Object body
$images | Where-Object name -eq $TemplateName | ForEach-Object {
$id = $_.uuid
Show-StringWithFormat "Deleting '$TemplateName[$id]' VM and '$TagName' tag"
$curlCommand='curl -s -X DELETE -k "{0}/registry/vm?id={1}"' -f $RegistryUrl, $id
Invoke-AnkaCommand -Command $curlCommand
}
$command = "anka registry --cacert $AnkaCaCrtPath --registry-path $RegistryUrl push --force --tag $TagName $TemplateName"
Invoke-AnkaCommand -Command $command
}
function Get-AnkaVM {
param(
[string] $VMName
)
$command = "anka --machine-readable list"
if (-not [string]::IsNullOrEmpty($VMName)) {
$command = "anka --machine-readable show $VMName"
}
Invoke-AnkaCommand -Command $command | ConvertFrom-Json | Foreach-Object body
}
function Get-AnkaVMStatus {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $VMName
)
$command = "anka --machine-readable list $VMName"
Invoke-AnkaCommand -Command $command | ConvertFrom-Json | Foreach-Object { $_.body.status }
}
function Get-AnkaVMIPAddress {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $VMName
)
Get-AnkaVM -VMName $VMName | Foreach-Object ip
}
function Invoke-AnkaCommand {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $Command
)
$result = bash -c "$Command 2>&1"
if ($LASTEXITCODE -ne 0) {
Write-Error "There is an error during command execution:`n$result"
exit 1
}
$result
}
function New-AnkaVMTemplate {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $InstallerPath,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $TemplateName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $TemplateUsername,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $TemplatePassword,
[Parameter(Mandatory)]
[int] $CPUCount,
[Parameter(Mandatory)]
[int] $RamSizeGb,
[Parameter(Mandatory)]
[int] $DiskSizeGb
)
$env:ANKA_DEFAULT_USER = $TemplateUsername
$env:ANKA_DEFAULT_PASSWD = $TemplatePassword
$env:ANKA_CREATE_SUSPEND = 0
$command = "anka create --cpu-count '$CPUCount' --ram-size '${RamSizeGb}G' --disk-size '${DiskSizeGb}G' --app '$InstallerPath' $TemplateName"
Invoke-AnkaCommand -Command $command
}
function Remove-AnkaVM {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $VMName
)
$command = "anka delete $VMName --yes"
$isTemplateExists = Get-AnkaVM | Where-Object name -eq $VMName
if ($isTemplateExists) {
$null = Invoke-AnkaCommand -Command $command
}
}
function Set-AnkaVMVideoController {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $VMName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $ShortMacOSVersion,
[ValidateSet("fbuf", "pg")]
[string] $Controller = "pg"
)
$command = "anka modify $VMName set display -c $Controller"
$null = Invoke-AnkaCommand -Command $command
}
function Set-AnkaVMDisplayResolution {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $VMName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $DisplayResolution
)
$command = "anka modify $VMName set display -r $DisplayResolution"
$null = Invoke-AnkaCommand -Command $command
}
function Start-AnkaVM {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $VMName
)
$command = "anka start $VMName"
$vmStatus = Get-AnkaVMStatus -VMName $VMName
if ($vmStatus -eq "stopped") {
$null = Invoke-AnkaCommand -Command $command
}
}
function Stop-AnkaVM {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $VMName
)
$command = "anka stop $VMName"
$vmStatus = Get-AnkaVMStatus -VMName $VMName
if ($vmStatus -eq "running") {
$null = Invoke-AnkaCommand -Command $command
}
}
function Wait-AnkaVMIPAddress {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $VMName,
[int] $RetryCount = 20,
[int] $Seconds = 60
)
$condition = {
$vmStatus = Get-AnkaVMStatus -VMName $VMName
if ($vmStatus -eq "failed") {
Write-Host "`t [-] $VMName is in failed status"
exit 1
}
Get-AnkaVMIPAddress -VMName $VMName
}
$null = Invoke-WithRetry -BreakCondition $condition -RetryCount $RetryCount -Seconds $Seconds
}
function Wait-AnkaVMSSHService {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $VMName,
[int] $RetryCount = 20,
[int] $Seconds = 60
)
Start-Sleep -Seconds $Seconds
Write-Host "`t[*] Waiting for '$VMName' VM to get an IP address"
Wait-AnkaVMIPAddress -VMName $VMName -RetryCount $RetryCount -Seconds $Seconds
$ipAddress = Get-AnkaVMIPAddress -VMName $VMName
Write-Host "`t[*] The '$ipAddress' IP address for '$VMName' VM"
Write-Host "`t[*] Checking if SSH on a port is open"
$isSSHPortOpen = Test-SSHPort -IPAddress $ipAddress
if (-not $isSSHPortOpen) {
Write-Host "`t[x] SSH port is closed"
exit 1
}
}
function Set-AnkaVMUuid {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $VMName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $Uuid
)
$command = "anka modify $VMName set custom-variable hw.uuid $Uuid"
Write-Host "`t[*] Setting $VMName uuid to $Uuid"
Invoke-AnkaCommand -Command $command
}

View File

@@ -1,227 +0,0 @@
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[version] $MacOSVersion,
[ValidateNotNullOrEmpty()]
[string] $TemplateUsername,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $TemplatePassword,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $RegistryUrl,
[ValidateNotNullOrEmpty()]
[string] $TemplateName,
[bool] $DownloadLatestVersion = $true,
[bool] $PushToRegistry = $true,
[bool] $BetaSearch = $false,
[bool] $InstallSoftwareUpdate = $true,
[bool] $EnableAutoLogon = $true,
[int] $CPUCount = 6,
[int] $RamSizeGb = 7,
[int] $DiskSizeGb = 325,
[string] $DisplayResolution = "1920x1080",
[string] $TagName = [DateTimeOffset]::Now.ToUnixTimeSeconds(),
[string] $Uuid = "4203018E-580F-C1B5-9525-B745CECA79EB"
)
$ErrorActionPreference = "Stop"
$WarningPreference = "SilentlyContinue"
# Import helper modules
Import-Module "$PSScriptRoot/Anka.Helpers.psm1"
Import-Module "$PSScriptRoot/Service.Helpers.psm1"
# Helper functions
function Invoke-EnableAutoLogon {
if (-not $EnableAutoLogon) {
Write-Host "`t[*] Skip configuring AutoLogon"
return
}
$ipAddress = Get-AnkaVMIPAddress -VMName $TemplateName
Wait-AnkaVMSSHService -VMName $TemplateName -Seconds 30
Write-Host "`t[*] Enable AutoLogon"
Enable-AutoLogon -HostName $ipAddress -UserName $TemplateUsername -Password $TemplatePassword
Write-Host "`t[*] Reboot '$TemplateName' VM to enable AutoLogon"
Restart-VMSSH -HostName $ipAddress | Show-StringWithFormat
Wait-AnkaVMSSHService -VMName $TemplateName -Seconds 30
Write-Host "`t[*] Checking if AutoLogon is enabled"
Test-AutoLogon -VMName $TemplateName -UserName $TemplateUsername
}
function Invoke-SoftwareUpdate {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $Password
)
if (-not $InstallSoftwareUpdate) {
Write-Host "`t[*] Skip installing software updates"
return
}
$ipAddress = Get-AnkaVMIPAddress -VMName $TemplateName
# Unenroll Seed
Write-Host "`t[*] Resetting the seed before requesting stable versions"
Remove-CurrentBetaSeed -HostName $ipAddress | Show-StringWithFormat
# Install Software Updates
# Security updates may not be able to install(hang, freeze) when AutoLogon is turned off
Write-Host "`t[*] Finding available software"
$newUpdates = Get-SoftwareUpdate -HostName $ipAddress
if (-not $newUpdates) {
Write-Host "`t[*] No Updates Available"
return
}
# Define the next macOS version
$command = "sw_vers"
$guestMacosVersion = Invoke-SSHPassCommand -HostName $ipAddress -Command $command
switch -regex ($guestMacosVersion[1]) {
'12.\d' { $nextOSVersion = 'macOS Ventura|macOS Sonoma|macOS Sequoia' }
'13.\d' { $nextOSVersion = 'macOS Sonoma|macOS Sequoia' }
'14.\d' { $nextOSVersion = 'macOS Sequoia' }
}
Write-Host "`t[*] Fetching Software Updates ready to install on '$TemplateName' VM:"
Show-StringWithFormat $newUpdates
$listOfNewUpdates = $($($newUpdates.Split("*")).Split("Title").where({$_ -match "Label:"}).Replace("Label: ", '').where({$_ -notmatch $nextOSVersion}))
Write-Host "`t[*] Installing Software Updates on '$TemplateName' VM:"
Install-SoftwareUpdate -HostName $ipAddress -listOfUpdates $listOfNewUpdates -Password $Password | Show-StringWithFormat
Write-Host "`t[*] Sleep 60 seconds before the software updates have been installed"
Start-Sleep -Seconds 60
Write-Host "`t[*] Waiting for loginwindow process"
Wait-LoginWindow -HostName $ipAddress | Show-StringWithFormat
# Re-enable AutoLogon after installing a new security software update
Invoke-EnableAutoLogon
foreach ($newupdate in $listOfNewUpdates) {
# Check software updates have been installed
$updates = Get-SoftwareUpdate -HostName $ipAddress
if ($updates.Contains("Action: restart") -and !($updates -match $nextOSVersion)) {
Write-Host "`t[x] Software updates failed to install: "
Show-StringWithFormat $updates
exit 1
}
}
Write-Host "`t[*] Show the install history:"
$hUpdates = Get-SoftwareUpdateHistory -HostName $ipAddress
Show-StringWithFormat $hUpdates
Write-Host "`t[*] The current macOS version:"
$command = "sw_vers"
Invoke-SSHPassCommand -HostName $ipAddress -Command $command | Show-StringWithFormat
}
function Invoke-UpdateSettings {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $Password
)
$isConfRequired = $InstallSoftwareUpdate -or $EnableAutoLogon
if (-not $isConfRequired) {
Write-Host "`t[*] Skip additional configuration"
return
}
Write-Host "`t[*] Starting '$TemplateName' VM"
Start-AnkaVM -VMName $TemplateName
Write-Host "`t[*] Waiting for SSH service on '$TemplateName' VM"
Wait-AnkaVMSSHService -VMName $TemplateName -Seconds 30
# Configure AutoLogon
Invoke-EnableAutoLogon
# Install software updates
Invoke-SoftwareUpdate -Password $Password
Write-Host "`t[*] Stopping '$TemplateName' VM"
Stop-AnkaVM -VMName $TemplateName
}
function Test-VMStopped {
$vmStatus = Get-AnkaVMStatus -VMName $TemplateName
if ($vmStatus -ne "stopped") {
Write-Host "`t[x] VM '$TemplateName' state is not stopped. The current state is '$vmStatus'"
exit 1
}
}
# Password is passed as env-var "SSHPASS"
$env:SSHUSER = $TemplateUsername
$env:SSHPASS = $TemplatePassword
Write-Host "`n[#1] Download macOS application installer:"
$shortMacOSVersion = Get-ShortMacOSVersion -MacOSVersion $MacOSVersion
if ([string]::IsNullOrEmpty($TemplateName)) {
$osArch = $(arch)
if ($osArch -eq "arm64") {
$macOSInstaller = Get-MacOSIPSWInstaller -MacOSVersion $MacOSVersion -DownloadLatestVersion $DownloadLatestVersion -BetaSearch $BetaSearch
$TemplateName = "clean_macos_${shortMacOSVersion}_${osArch}"
} else {
$macOSInstaller = Get-MacOSInstaller -MacOSVersion $MacOSVersion -DownloadLatestVersion $DownloadLatestVersion -BetaSearch $BetaSearch
$TemplateName = "clean_macos_${shortMacOSVersion}"
}
}
Write-Host "`n[#2] Create a VM template:"
Write-Host "`t[*] Deleting existed template with name '$TemplateName' before creating a new one"
Remove-AnkaVM -VMName $TemplateName
# Temporary disable VNC for macOS 14
# It's probably Anka's bug fixed in 3.3.2
if ($shortMacOSVersion -eq "14") {
$env:ANKA_CREATE_VNC = 0
}
Write-Host "`t[*] Creating Anka VM template with name '$TemplateName' and '$TemplateUsername' user"
Write-Host "`t[*] CPU Count: $CPUCount, RamSize: ${RamSizeGb}G, DiskSizeGb: ${DiskSizeGb}G, InstallerPath: $macOSInstaller, TemplateName: $TemplateName"
New-AnkaVMTemplate -InstallerPath "$macOSInstaller" `
-TemplateName $TemplateName `
-TemplateUsername $TemplateUsername `
-TemplatePassword $TemplatePassword `
-CPUCount $CPUCount `
-RamSizeGb $RamSizeGb `
-DiskSizeGb $DiskSizeGb | Show-StringWithFormat
Write-Host "`n[#3] Configure AutoLogon and/or install software updates:"
Invoke-UpdateSettings -Password $TemplatePassword
Write-Host "`n[#4] Finalization '$TemplateName' configuration and push to the registry:"
Write-Host "`t[*] The '$TemplateName' VM status is stopped"
Test-VMStopped
# Configure graphics settings
Write-Host "`t[*] Enabling Graphics Acceleration with Apple Metal for '$TemplateName' VM"
Set-AnkaVMVideoController -VMName $TemplateName -ShortMacOSVersion $ShortMacOSVersion
Write-Host "`t[*] Setting screen resolution to $DisplayResolution for $TemplateName"
Set-AnkaVMDisplayResolution -VMName $TemplateName -DisplayResolution $DisplayResolution
# Set static UUID
Set-AnkaVMUuid -VMName $TemplateName -Uuid $Uuid
if ($PushToRegistry) {
# Push a VM template (and tag) to the Cloud
Write-Host "`t[*] Pushing '$TemplateName' image with '$TagName' tag to the '$RegistryUrl' registry..."
Push-AnkaTemplateToRegistry -RegistryUrl $registryUrl -TagName $TagName -TemplateName $TemplateName
}

View File

@@ -1,476 +0,0 @@
function Enable-AutoLogon {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $HostName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $UserName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $Password
)
$url = "https://raw.githubusercontent.com/actions/runner-images/main/images/macos/assets/bootstrap-provisioner/setAutoLogin.sh"
$script = Invoke-RestMethod -Uri $url
$base64 = [Convert]::ToBase64String($script.ToCharArray())
$command = "echo $base64 | base64 --decode > ./setAutoLogin.sh;sudo bash ./setAutoLogin.sh '${UserName}' '${Password}';rm ./setAutoLogin.sh"
Invoke-SSHPassCommand -HostName $HostName -Command $command
}
function Invoke-SoftwareUpdateArm64 {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $HostName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $Password,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[array] $ListOfUpdates
)
# Define the next macOS version
$command = "sw_vers"
$guestMacosVersion = Invoke-SSHPassCommand -HostName $HostName -Command $command
switch -regex ($guestMacosVersion[1]) {
'12.\d' { $nextOSVersion = 'macOS Ventura|macOS Sonoma|macOS Sequoia' }
'13.\d' { $nextOSVersion = 'macOS Sonoma|macOS Sequoia' }
'14.\d' { $nextOSVersion = 'macOS Sequoia' }
}
$url = "https://raw.githubusercontent.com/actions/runner-images/main/images/macos/assets/auto-software-update-arm64.exp"
$script = Invoke-RestMethod -Uri $url
foreach ($update in $ListOfUpdates) {
if ($update -notmatch $nextOSVersion) {
$updatedScript = $script.Replace("MACOSUPDATE", $($($update.trim()).Replace(" ","\ ")))
$base64 = [Convert]::ToBase64String($updatedScript.ToCharArray())
$command = "echo $base64 | base64 --decode > ./auto-software-update-arm64.exp;chmod +x ./auto-software-update-arm64.exp; ./auto-software-update-arm64.exp ${Password};rm ./auto-software-update-arm64.exp"
Invoke-SSHPassCommand -HostName $HostName -Command $command
}
}
}
function Get-AvailableVersions {
param (
[bool] $IsBeta = $false
)
if ($IsBeta) {
$searchPostfix = " beta"
}
$command = { /usr/sbin/softwareupdate --list-full-installers | grep "macOS" }
$condition = { $LASTEXITCODE -eq 0 }
$softwareUpdates = Invoke-WithRetry -Command $command -BreakCondition $condition | Where-Object { $_.Contains("Title: macOS") -and $_ -match $searchPostfix }
$allVersions = $softwareUpdates -replace "(\* )?(Title|Version|Size):" | ConvertFrom-Csv -Header OSName, OSVersion | Select-Object OSName, OSVersion -Unique
$allVersions
}
function Get-AvailableIPSWVersions {
param (
[bool] $IsBeta = $false,
[bool] $IsLatest = $true,
[string] $MacOSCodeNameOrVersion
)
if ($IsBeta) {
$command = { mist list firmware "$MacOSCodeNameOrVersion" --compatible --include-betas --latest --export "/Applications/export.json" }
} elseif ($IsLatest) {
$command = { mist list firmware "$MacOSCodeNameOrVersion" --compatible --latest --export "/Applications/export.json" }
} else {
$command = { mist list firmware "$MacOSCodeNameOrVersion" --compatible --export "/Applications/export.json" }
}
$condition = { $LASTEXITCODE -eq 0 }
Invoke-WithRetry -Command $command -BreakCondition $condition | Out-Null
$softwareList = get-content -Path "/Applications/export.json"
$availableBuilds = ($softwareList | ConvertFrom-Json).build
if ($null -eq $availableBuilds) {
Write-Host "Requested macOS '$MacOSCodeNameOrVersion' version not found in the list of available installers."
$command = { mist list firmware "$($MacOSCodeNameOrVersion.split('.')[0])" }
Invoke-WithRetry -Command $command -BreakCondition $condition
exit 1
}
return $availableBuilds
}
function Get-MacOSIPSWInstaller {
param (
[Parameter(Mandatory)]
[version] $MacOSVersion,
[bool] $DownloadLatestVersion = $false,
[bool] $BetaSearch = $false
)
if ($MacOSVersion -eq [version] "13.0") {
$MacOSName = "macOS Ventura"
} elseif ($MacOSVersion -eq [version] "14.0") {
$MacOSName = "macOS Sonoma"
} else {
$MacOSName = $MacOSVersion.ToString()
}
Write-Host "`t[*] Finding available full installers"
if ($DownloadLatestVersion -eq $true) {
$targetBuild = Get-AvailableIPSWVersions -IsLatest $true -MacOSCodeNameOrVersion $MacOSName
Write-Host "`t[*] The 'DownloadLatestVersion' flag is set to true. Latest compatible macOS build of '$MacOSName' is '$targetBuild'"
} elseif ($BetaSearch -eq $true) {
$targetBuild = Get-AvailableIPSWVersions -IsBeta $true -MacOSCodeNameOrVersion $MacOSName
Write-Host "`t[*] The 'BetaSearch' flag is set to true. Latest compatible beta macOS build of '$MacOSName' is '$targetBuild'"
} else {
$targetBuild = Get-AvailableIPSWVersions -MacOSCodeNameOrVersion $MacOSName -IsLatest $false
Write-Host "`t[*] Available compatible macOS builds of '$MacOSName' are: $($targetBuild -join ', ')"
if ($targetBuild.Count -gt 1) {
Write-Error "`t[*] Please specify the exact build number of macOS you want to install"
exit 1
}
}
$installerPathPattern = "/Applications/Install ${macOSName}*.ipsw"
if (Test-Path $installerPathPattern) {
$previousInstallerPath = Get-Item -Path $installerPathPattern
Write-Host "`t[*] Removing '$previousInstallerPath' installation app before downloading the new one"
sudo rm -rf "$previousInstallerPath"
}
# Download macOS installer
$installerDir = "/Applications/"
$installerName = "Install ${macOSName}.ipsw"
Write-Host "`t[*] Requested macOS '$targetBuild' version installer found, fetching it from mist database"
Invoke-WithRetry { mist download firmware "$targetBuild" --output-directory $installerDir --firmware-name "$installerName" } { $LASTEXITCODE -eq 0 } | Out-Null
if (Test-Path "$installerDir$installerName") {
$result = "$installerDir$installerName"
} else {
Write-Error "`t[*] Requested macOS '$targetBuild' version installer failed to download"
exit 1
}
return $result
}
function Get-MacOSInstaller {
param (
[Parameter(Mandatory)]
[version] $MacOSVersion,
[bool] $DownloadLatestVersion = $false,
[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 "`t[*] Beta Version requested. Enrolling machine to DeveloperSeed"
sudo $seedutil enroll DeveloperSeed | Out-Null
} else {
Write-Host "`t[*] Resetting the seed before requesting stable versions"
sudo $seedutil unenroll | Out-Null
}
# Validate there is no software update at the moment
Test-SoftwareUpdate
# Validate availability OSVersion
Write-Host "`t[*] Finding available full installers"
$availableVersions = Get-AvailableVersions -IsBeta $BetaSearch
if ($DownloadLatestVersion) {
$shortMacOSVersion = Get-ShortMacOSVersion -MacOSVersion $MacOSVersion
$filterSearch = "${shortMacOSVersion}."
$filteredVersions = $availableVersions.Where{ $_.OSVersion.StartsWith($filterSearch) }
if (-not $filteredVersions) {
Write-Host "`t[x] Failed to find any macOS versions using '$filterSearch' search condition"
Show-StringWithFormat $availableVersions
exit 1
}
Show-StringWithFormat $filteredVersions
$osVersions = $filteredVersions.OSVersion | Sort-Object { [version]$_ }
$MacOSVersion = $osVersions | Select-Object -Last 1
Write-Host "`t[*] The 'DownloadLatestVersion' flag is set. Latest macOS version is '$MacOSVersion' now"
}
$macOSName = $availableVersions.Where{ $MacOSVersion -eq $_.OSVersion }.OSName.Split(" ")[1]
if (-not $macOSName) {
Write-Host "`t[x] Requested macOS '$MacOSVersion' version not found in the list of available installers. Available versions are:`n$($availableVersions.OSVersion)"
Write-Host "`t[x] Make sure to pass '-BetaSearch `$true' if you need a beta version installer"
exit 1
}
# Clear LastRecommendedMajorOSBundleIdentifier to prevent error during fetching updates
# Install failed with error: Update not found
Update-SoftwareBundle
# Download macOS installer
Write-Host "`t[*] Requested macOS '$MacOSVersion' version installer found, fetching it from Apple Software Update"
Invoke-WithRetry -Command { sudo /usr/local/bin/mist download installer $MacOSVersion application --force --export installer.json --output-directory /Applications } -BreakCondition { $LASTEXITCODE -eq 0 } | Out-Null
if (-not(Test-Path installer.json -PathType leaf)) {
Write-Host "`t[x] Failed to fetch $MacOSVersion macOS"
exit 1
}
$installerPath = (Get-Content installer.json | Out-String | ConvertFrom-Json).options.applicationPath
if (-not $installerPath) {
Write-Host "`t[x] Path not found using '$installerPathPattern'"
exit 1
}
Write-Host "`t[*] Installer successfully downloaded to '$installerPath'"
$installerPath
}
function Get-ShortMacOSVersion {
param (
[Parameter(Mandatory)]
[version] $MacOSVersion
)
# Take Major.Minor version for macOS 10 (10.14 or 10.15) and Major for all further versions
$MacOSVersion.Major -eq 10 ? $MacOSVersion.ToString(2) : $MacOSVersion.ToString(1)
}
function Get-SoftwareUpdate {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $HostName
)
$command = "/usr/sbin/softwareupdate --list"
$result = Invoke-SSHPassCommand -HostName $HostName -Command $command
$result | Where-Object { $_ -match "(Label|Title):" } | Out-String
}
function Get-SoftwareUpdateHistory {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $HostName
)
$command = "/usr/sbin/softwareupdate --history"
Invoke-SSHPassCommand -HostName $HostName -Command $command | Out-String
}
function Install-SoftwareUpdate {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $HostName,
[array] $listOfUpdates,
[string] $Password
)
# If an update is happening on macOS arm64 we will use the additional tool to install updates.
$osArch = $(arch)
if ($osArch -eq "arm64") {
Invoke-SoftwareUpdateArm64 -HostName $HostName -Password $Password -ListOfUpdates $listOfUpdates
} else {
foreach ($update in $listOfUpdates) {
$command = "sudo /usr/sbin/softwareupdate --restart --verbose --install '$($update.trim())'"
Invoke-SSHPassCommand -HostName $HostName -Command $command
}
}
}
function Invoke-SSHPassCommand {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $HostName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $Command,
[int] $ConnectTimeout = 10,
[int] $ConnectionAttempts = 10,
[int] $ServerAliveInterval = 30
)
$sshArg = @(
"sshpass"
"-e"
"ssh"
"-o UserKnownHostsFile=/dev/null"
"-o StrictHostKeyChecking=no"
"-o ConnectTimeout=$ConnectTimeout"
"-o ConnectionAttempts=$ConnectionAttempts"
"-o LogLevel=ERROR"
"-o ServerAliveInterval=$ServerAliveInterval"
"${env:SSHUSER}@${HostName}"
)
$sshPassOptions = $sshArg -join " "
if ($PSVersionTable.PSVersion.Major -eq 7 -and $PSVersionTable.PSVersion.Minor -le 2) {
$result = bash -c "$sshPassOptions \""$Command\"" 2>&1"
} else {
$result = bash -c "$sshPassOptions `"$Command`" 2>&1"
}
if ($LASTEXITCODE -ne 0) {
Write-Error "There is an error during command execution:`n$result"
exit 1
}
$result
}
function Invoke-WithRetry {
param(
[scriptblock] $Command,
[scriptblock] $BreakCondition,
[int] $RetryCount = 20,
[int] $Seconds = 60
)
while ($RetryCount -gt 0) {
try {
if ($Command) {
$result = & $Command
}
if (& $BreakCondition) {
return $result
}
} catch {
Write-Host "`t [!] Error during command execution: $_"
}
$RetryCount--
if ($RetryCount -eq 0) {
Write-Error "No more attempts left: $BreakCondition"
}
Write-Host "`t [/] Waiting $Seconds seconds before retrying. Retries left: $RetryCount"
Start-Sleep -Seconds $Seconds
}
$result
}
function Restart-VMSSH {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $HostName
)
#
# https://unix.stackexchange.com/questions/58271/closing-connection-after-executing-reboot-using-ssh-command
#
$command = '(sleep 1 && sudo reboot &) && exit'
Invoke-SSHPassCommand -HostName $HostName -Command $command
}
function Show-StringWithFormat {
param(
[Parameter(ValuefromPipeline)]
[object] $string
)
process {
($string | Out-String).Trim().split("`n") | ForEach-Object { Write-Host "`t $_" }
}
}
function Remove-CurrentBetaSeed {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $HostName
)
$command = "sudo /System/Library/PrivateFrameworks/Seeding.framework/Versions/Current/Resources/seedutil unenroll"
Invoke-SSHPassCommand -HostName $HostName -Command $command | Out-String
}
function Test-AutoLogon {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $VMName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $UserName
)
Invoke-WithRetry -BreakCondition {
# pwsh crashes if it invokes directly
# https://github.com/dotnet/runtime/issues/59059
$ankaUser = "" | bash -c "anka run $VMName /usr/bin/id -nu"
$UserName -eq $ankaUser
}
}
function Test-SoftwareUpdate {
param (
[string] $UpdateProcessName = "softwareupdate"
)
$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 = /bin/ps -o command= $updateProcess
Write-Host "`t[*] Another software update process with '$updateProcess' id is in place with the following arguments '$processName'"
}
}
$condition = {
$null -eq (Get-Process -Name $UpdateProcessName -ErrorAction SilentlyContinue)
}
Invoke-WithRetry -Command $command -BreakCondition $condition
}
function Test-SSHPort {
param(
[Parameter(Mandatory)]
[ipaddress] $IPAddress,
[int] $Port = 22,
[int] $Timeout = 2000
)
Invoke-WithRetry -Command {$true} -BreakCondition {
try {
$client = [System.Net.Sockets.TcpClient]::new()
$client.ConnectAsync($IPAddress, $Port).Wait($Timeout)
}
catch {
$false
}
finally {
$client.Close()
}
}
}
function Wait-LoginWindow {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $HostName,
[int] $RetryCount = 60,
[int] $Seconds = 60
)
$condition = {
$psCommand = "/bin/ps auxww"
$lw = "/System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow"
$ctk = "/System/Library/Frameworks/CryptoTokenKit.framework/ctkahp.bundle/Contents/MacOS/ctkahp"
$proc = Invoke-SSHPassCommand -HostName $HostName -Command $psCommand | Out-String
$proc.Contains($lw) -and $proc.Contains($ctk)
}
Invoke-WithRetry -RetryCount $RetryCount -Seconds $Seconds -BreakCondition $condition
}
function Update-SoftwareBundle {
$productVersion = sw_vers -productVersion
if ( $productVersion.StartsWith('11.') ) {
sudo rm -rf /Library/Preferences/com.apple.commerce.plist
sudo /usr/bin/defaults delete /Library/Preferences/com.apple.SoftwareUpdate.plist LastRecommendedMajorOSBundleIdentifier | Out-Null
}
}