Build new images #499
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build missing images (after new windows updates) | |
on: | |
schedule: | |
- cron: '0 5 * * *' | |
workflow_dispatch: | |
inputs: | |
GenericTag: | |
description: Generic Tag (leave empty to use value in generic/tag.txt) | |
required: false | |
default: '' | |
PushToProd: | |
description: Push to production (Y/N) | |
required: false | |
default: 'Y' | |
env: | |
resGroup: "buildgeneric" | |
resLocation: "West Europe" | |
machines: "2" | |
ARMbranch: "master" | |
ARMtemplate: "buildagent" | |
permissions: | |
contents: read | |
defaults: | |
run: | |
shell: PowerShell | |
jobs: | |
AnalyzeImages: | |
runs-on: [ windows-latest ] | |
outputs: | |
server2022: ${{ steps.Analyze.outputs.server2022 }} | |
server2022count: ${{ steps.Analyze.outputs.server2022count }} | |
steps: | |
- uses: actions/checkout@main | |
- name: Analyze | |
id: Analyze | |
run: | | |
$erroractionpreference = "STOP" | |
try { | |
$unsupportedWindowsVersions = @("10.0.18363.*","10.0.18362.*") | |
Set-Location "generic" | |
$genericTag = '' | |
if ($env:GITHUB_EVENT_NAME -eq "workflow_dispatch") { | |
$genericTag = '${{ github.event.inputs.GenericTag }}' | |
} | |
if ($genericTag -eq '') { $genericTag = Get-Content -path 'tag.txt' } | |
[System.Version]$genericTag | Out-Null | |
Write-Host "Using generic Tag $genericTag" | |
$genericTag = "-$genericTag" | |
$webclient = New-Object System.Net.WebClient | |
$webclient.Headers.Add('Accept', "application/json") | |
$alltags = (($webclient.DownloadString("https://mcr.microsoft.com/v2/businesscentral/tags/list") | ConvertFrom-Json)).tags | |
$version = [System.Version]"0.0.0.0" | |
$versions = @($alltags | Where-Object { $_ -like "*$generictag" } | Where-Object { [System.Version]::TryParse($_.SubString(0,$_.Length-$generictag.Length), [ref] $version) } | Where-Object { -not ($UnsupportedWindowsVersions | Where-Object { "$version" -like $_ }) } | ForEach-Object { $version }) | |
$filesOnlyVersions = @($alltags | Where-Object { $_ -like "*$generictag-filesonly" } | Where-Object { [System.Version]::TryParse($_.SubString(0,$_.Length-$generictag.Length-10), [ref] $version) } | Where-Object { -not ($UnsupportedWindowsVersions | Where-Object { "$version" -like $_ }) } | ForEach-Object { $version }) | |
$missingImages = @{} | |
$missingFilesOnlyImages = @{} | |
$alldotnetFrameworkTags = (($webclient.DownloadString("https://mcr.microsoft.com/v2/dotnet/framework/runtime/tags/list") | ConvertFrom-Json)).tags | |
$alldotnetFrameworkTags | Where-Object { $_.startswith("4.8-w") -or $_.startswith("4.8-20") } | ForEach-Object { | |
$osVersion = [System.Version](($webclient.DownloadString("https://mcr.microsoft.com/v2/dotnet/framework/runtime/manifests/$_") | ConvertFrom-Json).history[0].v1Compatibility | ConvertFrom-Json)."os.version" | |
if (-not ($UnsupportedWindowsVersions | Where-Object { "$osVersion" -like $_ })) { | |
Write-Host -NoNewline "Test $_ ($OSVersion)" | |
if ($versions.Contains($osversion)) { | |
Write-Host -NoNewline " - OK" | |
} | |
else { | |
$missingImages."$osversion" = $_ | |
Write-Host -NoNewline " - Missing" | |
} | |
if ($filesOnlyVersions.Contains($osversion)) { | |
Write-Host " - OK" | |
} | |
else { | |
$missingFilesOnlyImages."$osversion" = $_ | |
Write-Host " - Missing" | |
} | |
} | |
} | |
$server2022array = @($missingImages.GetEnumerator() | Where-Object { $_ } | ForEach-Object { "$($_.name)|$($_.value)" }) | |
$server2022array += @($missingFilesOnlyImages.GetEnumerator() | Where-Object { $_ } | ForEach-Object { "$($_.name)-filesonly|$($_.value)" }) | |
$server2022count = $server2022array.Count | |
$server2022 = $server2022array | ConvertTo-Json -Compress | |
Add-Content -Path $ENV:GITHUB_OUTPUT -Value "server2022=[$("$server2022".Trim('[]'))]" | |
Write-Host "server2022=[$("$server2022".Trim('[]'))]" | |
Add-Content -Path $ENV:GITHUB_OUTPUT -Value "server2022count=$server2022count" | |
Write-Host "server2022count=$server2022count" | |
} | |
catch { | |
Write-Host "::Error::Error analyzing images. Error was $($_.Exception.Message)" | |
$host.SetShouldExit(1) | |
} | |
CreateAgents: | |
runs-on: [ windows-latest ] | |
needs: [ AnalyzeImages ] | |
if: ${{ needs.AnalyzeImages.outputs.server2022count > 0 }} | |
steps: | |
- uses: actions/checkout@main | |
- uses: azure/login@v1 | |
with: | |
creds: ${{ secrets.AZURE_CREDENTIALS }} | |
enable-AzPSSession: true | |
- name: Run Azure PowerShell script | |
uses: azure/powershell@v1 | |
env: | |
GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
with: | |
azPSVersion: "latest" | |
inlineScript: | | |
$resGroup = $env:resGroup | |
$resLocation = $env:resLocation | |
$repo = $env:GITHUB_REPOSITORY | |
$machines = [int]$env:machines | |
Write-Host "Resource Group is $resGroup" | |
$resourceGroup = Get-AzResourceGroup -name $resGroup -ErrorAction Ignore | |
if ($resourceGroup) { | |
Write-Host "Removing Resource Group $resGroup" | |
Remove-AzResourceGroup -Name $resGroup -Force | Out-Host | |
Write-Host "Done" | |
} | |
$runners = (gh api /repos/$repo/actions/runners | ConvertFrom-Json).runners | |
$runners | Where-Object { $_.status -eq "offline" } | ForEach-Object { | |
Write-host "Unregistering runner $($_.name)" | |
$id = $_.id | |
gh api -X DELETE /repos/$repo/actions/runners/$id | |
Write-Host "Done" | |
} | |
Write-Host "Creating resource group $resGroup in $resLocation" | |
$resourceGroup = New-AzResourceGroup -Name $resGroup -Location $resLocation -Force | |
Write-Host "Done" | |
1..$machines | ForEach-Object { | |
# Deployment | |
$no = $_ | |
# ARM template | |
$templateUri = "https://raw.githubusercontent.com/microsoft/nav-arm-templates/$($env:ARMbranch)/$($env:ARMtemplate).json" | |
$registrationToken = (gh api -X POST /repos/$repo/actions/runners/registration-token | ConvertFrom-Json).token | |
$headers = @{ | |
"Accept" = "application/json" | |
} | |
$uri = "https://api.github.com/repos/actions/runner/releases" | |
$result = Invoke-WebRequest -UseBasicParsing -Headers $headers -Uri $uri | |
$releases = $result.Content | ConvertFrom-Json | |
$asset = $releases[0].assets | Where-Object { $_.name -like "actions-runner-win-x64-*.*.?.zip" } | |
$Parameters = @{ | |
"VmName" = "$resgroup$no" | |
"Remotedesktopaccess" = "-" | |
"OperatingSystem" = "Windows Server 2022" | |
"VmSize" = "Standard_D4as_v5" | |
"OSDiskSize" = 128 | |
"StorageAccountType" = "Premium_LRS" | |
"AdminPassword" = [SecureString](ConvertTo-SecureString -String $env:GH_TOKEN -AsPlainText -Force) | |
"Count" = 1 | |
"Token" = $registrationToken | |
"Organization" = "https://github.com/$repo" | |
"LabelsOrPool" = "buildgeneric" | |
"AgentUrl" = $asset.browser_download_url | |
"InstallHyperV" = "Yes" | |
"RunInsideDocker" = "No" | |
"FinalSetupScriptUrl" = "additional-installforbuildagent.ps1" | |
} | |
$err = $resourceGroup | Test-AzResourceGroupDeployment -TemplateUri $templateUri -TemplateParameterObject $Parameters | |
if ($err) { | |
$err | |
throw "stop" | |
} | |
Write-Host "Creating Azure VM $($parameters.VmName)" | |
$resourceGroup | New-AzResourceGroupDeployment -TemplateUri $templateUri -TemplateParameterObject $Parameters -Name $Parameters.vmName -ErrorAction Ignore | |
Write-Host "Done" | |
} | |
Server2022: | |
runs-on: [ buildgeneric ] | |
needs: [ AnalyzeImages, CreateAgents ] | |
strategy: | |
matrix: | |
version: ${{fromJson(needs.AnalyzeImages.outputs.server2022)}} | |
fail-fast: false | |
max-parallel: 5 | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v2 | |
- name: Build Image | |
run: | | |
$erroractionpreference = "STOP" | |
Set-StrictMode -version 2.0 | |
try { | |
$pushRegistry = "mcrbusinesscentral.azurecr.io" | |
$job = start-job -ScriptBlock { Param($username, $token, $registry) | |
Write-Output $token | docker login --username $username --password-stdin $registry | |
} -ArgumentList '${{ secrets.PushUsername }}', '${{ secrets.PushToken }}', $pushRegistry | |
$job | Wait-Job -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | Out-Null | |
$result = Receive-Job -ErrorAction SilentlyContinue -WarningAction SilentlyContinue $job 2> $NULL | |
if ($result -ne 'Login Succeeded') { | |
throw "docker login failed" | |
} | |
Set-Location "generic" | |
$genericTag = '' | |
$pushToProd = $true | |
if ($env:GITHUB_EVENT_NAME -eq "workflow_dispatch") { | |
$genericTag = '${{ github.event.inputs.GenericTag }}' | |
$pushToProd = '${{ github.event.inputs.PushToProd }}' -eq 'Y' | |
} | |
if ($genericTag -eq '') { $genericTag = Get-Content -path 'tag.txt' } | |
[System.Version]$genericTag | Out-Null | |
$osversion = '${{ matrix.version }}'.split('|')[0].split('-')[0] | |
$filesonly = '' | |
if ('${{ matrix.version }}' -like '*-filesonly|*') { | |
$filesonly = '-filesonly' | |
} | |
$dotnetFrameworkTag = '${{ matrix.version }}'.split('|')[1] | |
$baseimage = "mcr.microsoft.com/dotnet/framework/runtime:$dotnetFrameworkTag" | |
$rootPath = Get-Location | |
$dockerfile = Join-Path $rootPath "DOCKERFILE$filesonly" | |
$image = "my:$osversion-$genericTag$filesonly" | |
$created = [DateTime]::Now.ToUniversalTime().ToString("yyyyMMddHHmm") | |
docker pull $baseimage | |
$inspect = docker inspect $baseimage | ConvertFrom-Json | |
$success = $false | |
docker build --build-arg baseimage=$baseimage ` | |
--build-arg created=$created ` | |
--build-arg tag="$genericTag" ` | |
--build-arg osversion="$osversion" ` | |
--isolation=hyperv ` | |
--memory 8G ` | |
--tag $image ` | |
--file $dockerfile ` | |
$RootPath | % { | |
$_ | Out-Host | |
if ($_ -like "Successfully built*") { | |
$success = $true | |
} | |
} | |
if (!$success) { | |
throw "Error building image" | |
} | |
$newtags = @( | |
"$pushRegistry/public/businesscentral:$osversion$filesonly-dev" | |
) | |
if ($pushToProd) { | |
$newtags += @( | |
"$pushRegistry/public/businesscentral:$osversion$filesonly" | |
"$pushRegistry/public/businesscentral:$osversion-$genericTag$filesonly" | |
) | |
} | |
$newtags | ForEach-Object { | |
Write-Host "Push $_" | |
docker tag $image $_ | |
docker push $_ | |
} | |
} | |
catch { | |
Write-Host "::Error::Error building images. Error was $($_.Exception.Message)" | |
$host.SetShouldExit(1) | |
} | |
RemoveAgents: | |
runs-on: [ windows-latest ] | |
needs: [ AnalyzeImages, CreateAgents, Server2022 ] | |
steps: | |
- uses: actions/checkout@main | |
- uses: azure/login@v1 | |
with: | |
creds: ${{ secrets.AZURE_CREDENTIALS }} | |
enable-AzPSSession: true | |
- name: Run Azure PowerShell script | |
uses: azure/powershell@v1 | |
env: | |
GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
with: | |
azPSVersion: "latest" | |
inlineScript: | | |
$resGroup = $env:resGroup | |
$resLocation = $env:resLocation | |
$repo = $env:GITHUB_REPOSITORY | |
Write-Host "Resource Group is $resGroup" | |
$resourceGroup = Get-AzResourceGroup -name $resGroup -ErrorAction Ignore | |
if ($resourceGroup) { | |
Write-Host "Removing Resource Group $resGroup" | |
Remove-AzResourceGroup -Name $resGroup -Force | Out-Host | |
Write-Host "Done" | |
} | |
$runners = (gh api /repos/$repo/actions/runners | ConvertFrom-Json).runners | |
$runners | Where-Object { $_.status -eq "offline" } | ForEach-Object { | |
Write-host "Unregistering runner $($_.name)" | |
$id = $_.id | |
gh api -X DELETE /repos/$repo/actions/runners/$id | |
Write-Host "Done" | |
} |