284 lines
9.9 KiB
PowerShell
Raw Permalink Normal View History

# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: MIT
#
<#
.SYNOPSIS
Creates a Windows virtual machine image, set up for vcpkg's CI.
.DESCRIPTION
create-image.ps1 creates an Azure Windows VM image, set up for vcpkg's CI system.
This script assumes you have installed Azure tools into PowerShell by following the instructions
at https://docs.microsoft.com/en-us/powershell/azure/install-az-ps?view=azps-3.6.1
or are running from Azure Cloud Shell.
#>
$Location = 'westus3'
$DatePrefixComponent = Get-Date -Format 'yyyy-MM-dd'
$Prefix = "Win-$DatePrefixComponent"
$GalleryImageVersion = $DatePrefixComponent.Replace('-','.')
$VMSize = 'Standard_D8ads_v5'
$ProtoVMName = 'PROTOTYPE'
$WindowsServerSku = '2022-datacenter-azure-edition'
$ErrorActionPreference = 'Stop'
$ProgressActivity = 'Creating Windows Image'
$TotalProgress = 17
$CurrentProgress = 1
# Assigning this to another variable helps when running the commands in this script manually for
# debugging
$Root = $PSScriptRoot
2024-07-03 20:01:35 -07:00
<#
.SYNOPSIS
Generates a random password.
.DESCRIPTION
New-Password generates a password, randomly, of length $Length, containing
only alphanumeric characters, underscore, and dash.
.PARAMETER Length
The length of the returned password.
#>
function New-Password {
Param ([int] $Length = 32)
$alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"
if ($alphabet.Length -ne 64) {
throw 'Bad alphabet length'
}
$result = New-Object SecureString
2024-07-03 20:01:35 -07:00
for ($idx = 0; $idx -lt $Length; $idx++) {
2024-08-30 11:07:40 -07:00
$result.AppendChar($alphabet[(Get-SecureRandom -Maximum $alphabet.Length)])
2024-07-03 20:01:35 -07:00
}
return $result
}
<#
.SYNOPSIS
Waits for the shutdown of the specified resource.
.DESCRIPTION
Wait-Shutdown takes a VM, and checks if there's a 'PowerState/stopped'
code; if there is, it returns. If there isn't, it waits ten seconds and
tries again.
.PARAMETER ResourceGroupName
The name of the resource group to look up the VM in.
.PARAMETER Name
The name of the virtual machine to wait on.
#>
function Wait-Shutdown {
[CmdletBinding()]
Param([string]$ResourceGroupName, [string]$Name)
Write-Host "Waiting for $Name to stop..."
while ($true) {
$Vm = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $Name -Status
$highestStatus = $Vm.Statuses.Count
for ($idx = 0; $idx -lt $highestStatus; $idx++) {
if ($Vm.Statuses[$idx].Code -eq 'PowerState/stopped') {
return
}
}
Write-Host "... not stopped yet, sleeping for 10 seconds"
Start-Sleep -Seconds 10
}
}
$AdminPW = New-Password
$Credential = New-Object System.Management.Automation.PSCredential ("AdminUser", $AdminPW)
$VirtualNetwork = Get-AzVirtualNetwork -ResourceGroupName 'vcpkg-image-minting' -Name 'vcpkg-image-mintingNetwork'
####################################################################################################
Write-Progress `
-Activity $ProgressActivity `
-Status 'Creating prototype VM' `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
$NicName = $Prefix + 'NIC'
$Nic = New-AzNetworkInterface `
-Name $NicName `
-ResourceGroupName 'vcpkg-image-minting' `
-Location $Location `
-Subnet $VirtualNetwork.Subnets[0] `
-EnableAcceleratedNetworking
$VM = New-AzVMConfig -Name $ProtoVMName -VMSize $VMSize -SecurityType TrustedLaunch -IdentityType SystemAssigned
$VM = Set-AzVMOperatingSystem `
-VM $VM `
-Windows `
-ComputerName $ProtoVMName `
-Credential $Credential `
-ProvisionVMAgent
$VM = Add-AzVMNetworkInterface -VM $VM -Id $Nic.Id
$VM = Set-AzVMOSDisk -VM $VM -StorageAccountType 'Premium_LRS' -CreateOption 'FromImage'
$VM = Set-AzVMSourceImage `
-VM $VM `
-PublisherName 'MicrosoftWindowsServer' `
-Offer 'WindowsServer' `
-Skus $WindowsServerSku `
-Version latest
$VM = Set-AzVMBootDiagnostic -VM $VM -Disable
New-AzVm `
-ResourceGroupName 'vcpkg-image-minting' `
-Location $Location `
-VM $VM
$VMCreated = Get-AzVM -ResourceGroupName 'vcpkg-image-minting' -Name $ProtoVMName
$VMCreatedOsDisk = $VMCreated.StorageProfile.OsDisk.Name
####################################################################################################
Write-Progress `
-Activity $ProgressActivity `
2024-07-03 20:01:35 -07:00
-Status 'Minting token for vcpkg-image-minting storage account' `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
$VcpkgImageMintingAccount = Get-AzStorageAccount -ResourceGroupName 'vcpkg-image-minting' -Name 'vcpkgimageminting'
2024-07-03 20:01:35 -07:00
$AssetStorageContext = New-AzStorageContext -StorageAccountName 'vcpkgimageminting' -UseConnectedAccount
$StartTime = Get-Date
2024-07-03 20:01:35 -07:00
$ExpiryTime = $StartTime.AddHours(4)
$AssetsSas = New-AzStorageContainerSASToken -Name 'assets' -Permission r -StartTime $StartTime -ExpiryTime $ExpiryTime -Context $AssetStorageContext
####################################################################################################
function Invoke-ScriptWithPrefix {
param(
[string]$ScriptName,
2024-07-03 20:01:35 -07:00
[switch]$SkipSas
)
Write-Progress `
-Activity $ProgressActivity `
-Status "Running provisioning script $ScriptName in VM" `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
$UtilityPrefixContent = Get-Content "$Root\utility-prefix.ps1" -Encoding utf8NoBOM -Raw
$tempScriptFilename = "$env:TEMP\temp-script.txt"
try {
$script = Get-Content "$Root\$ScriptName" -Encoding utf8NoBOM -Raw
2024-07-03 20:01:35 -07:00
$replacement = @"
if (Test-Path "`$PSScriptRoot/utility-prefix.ps1") {
. "`$PSScriptRoot/utility-prefix.ps1"
}
"@
$script = $script.Replace($replacement, $UtilityPrefixContent);
Set-Content -Path $tempScriptFilename -Value $script -Encoding utf8NoBOM
$parameter = $null
2024-07-03 20:01:35 -07:00
if (-not $SkipSas) {
$parameter = @{SasToken = "`"$AssetsSas`"";}
}
2024-07-03 20:01:35 -07:00
$InvokeResult = Invoke-AzVMRunCommand `
-ResourceGroupName 'vcpkg-image-minting' `
-VMName $ProtoVMName `
-CommandId 'RunPowerShellScript' `
-ScriptPath $tempScriptFilename `
-Parameter $parameter
Write-Host "$ScriptName output: $($InvokeResult.value.Message)"
} finally {
Remove-Item $tempScriptFilename -Force
}
}
####################################################################################################
2024-07-03 20:01:35 -07:00
Invoke-ScriptWithPrefix -ScriptName 'deploy-tlssettings.ps1' -SkipSas
Write-Host 'Waiting 1 minute for VM to reboot...'
Start-Sleep -Seconds 60
####################################################################################################
2024-07-03 20:01:35 -07:00
Invoke-ScriptWithPrefix -ScriptName 'deploy-visual-studio.ps1'
####################################################################################################
2024-07-03 20:01:35 -07:00
Invoke-ScriptWithPrefix -ScriptName 'deploy-mpi.ps1'
####################################################################################################
2024-07-03 20:01:35 -07:00
Invoke-ScriptWithPrefix -ScriptName 'deploy-cuda.ps1'
####################################################################################################
2024-07-03 20:01:35 -07:00
Invoke-ScriptWithPrefix -ScriptName 'deploy-cudnn.ps1'
####################################################################################################
2024-07-03 20:01:35 -07:00
Invoke-ScriptWithPrefix -ScriptName 'deploy-inteloneapi.ps1'
####################################################################################################
2024-07-03 20:01:35 -07:00
Invoke-ScriptWithPrefix -ScriptName 'deploy-pwsh.ps1'
2024-07-15 23:18:52 -07:00
####################################################################################################
Invoke-ScriptWithPrefix -ScriptName 'deploy-azure-cli.ps1'
####################################################################################################
2024-07-03 20:01:35 -07:00
Invoke-ScriptWithPrefix -ScriptName 'deploy-settings.txt' -SkipSas
Restart-AzVM -ResourceGroupName 'vcpkg-image-minting' -Name $ProtoVMName
####################################################################################################
2024-07-03 20:01:35 -07:00
Invoke-ScriptWithPrefix -ScriptName 'sysprep.ps1'
####################################################################################################
Write-Progress `
-Activity $ProgressActivity `
-Status 'Waiting for VM to shut down' `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
Wait-Shutdown -ResourceGroupName 'vcpkg-image-minting' -Name $ProtoVMName
####################################################################################################
Write-Progress `
-Activity $ProgressActivity `
-Status 'Converting VM to Image' `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
Stop-AzVM `
-ResourceGroupName 'vcpkg-image-minting' `
-Name $ProtoVMName `
-Force
Set-AzVM `
-ResourceGroupName 'vcpkg-image-minting' `
-Name $ProtoVMName `
-Generalized
2024-07-15 23:18:52 -07:00
$westus3Location = @{Name = 'West US 3';}
$westusLocation = @{Name = 'West US';}
2024-07-15 23:18:52 -07:00
New-AzGalleryImageVersion `
-ResourceGroupName 'vcpkg-image-minting' `
-GalleryName 'vcpkg_gallery_wus3' `
-GalleryImageDefinitionName 'PrWinWus3-TrustedLaunch' `
-Name $GalleryImageVersion `
-Location $Location `
-SourceImageVMId $VMCreated.ID `
-ReplicaCount 1 `
-StorageAccountType 'Premium_LRS' `
2024-07-15 23:18:52 -07:00
-PublishingProfileExcludeFromLatest `
-TargetRegion @($westus3Location, $westusLocation)
####################################################################################################
Write-Progress `
-Activity $ProgressActivity `
-Status 'Deleting unused temporary resources' `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
Remove-AzVM -Id $VMCreated.ID -Force
Remove-AzDisk -ResourceGroupName 'vcpkg-image-minting' -Name $VMCreatedOsDisk -Force
Remove-AzNetworkInterface -ResourceGroupName 'vcpkg-image-minting' -Name $NicName -Force
####################################################################################################
Write-Progress -Activity $ProgressActivity -Completed
Write-Host "Generated Image: $GalleryImageVersion"
Write-Host 'Finished!'
$AdminPW.Dispose()