Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add script for checking if agents support upgrade to v4 #4995

Merged
merged 6 commits into from
Sep 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Predict whether agents will be able to upgrade from pipeline agent v2 to agent v3
Predict whether agents will be able to upgrade from pipeline agent v2 or v3 to agent v4
.DESCRIPTION
The Azure Pipeline agent v2 uses .NET 3.1 Core, while agent v3 runs on .NET 6. This means agent v3 will drop support for operating systems not supported by .NET 6 (https://github.com/dotnet/core/blob/main/release-notes/6.0/supported-os.md)
The Azure Pipeline agent v2 uses .NET 3.1 Core, and agent v3 uses .NET 6, while agent v4 runs on .NET 8. This means agent v4 will drop support for operating systems not supported by .NET 8 (https://github.com/dotnet/core/blob/main/release-notes/8.0/supported-os.md)
This script will try to predict whether an agent will be able to upgrade, using the osDescription attribute of the agent. For Linux and macOS, this contains the output of 'uname -a`.
Note the Pipeline agent has more context about the operating system of the host it is running on (e.g. 'lsb_release -a' output), and is able to make a better informed decision on whether to upgrade or not.
Hence the output of this script is an indication wrt what the agent will do, but will include results where there is no sufficient information to include a prediction.
@@ -17,7 +17,7 @@
./QueryAgentPoolsForCompatibleOS.ps1 -Token "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
.EXAMPLE
$env:AZURE_DEVOPS_EXT_PAT = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
./QueryAgentPoolsForCompatibleOS.ps1 -PoolId 1234 -Filter V3InCompatible -Verbose -OpenCsv
./QueryAgentPoolsForCompatibleOS.ps1 -PoolId 1234 -Filter V4InCompatible -Verbose -OpenCsv
#>

#Requires -Version 7.2
@@ -47,9 +47,9 @@ param (
[parameter(Mandatory=$false)]
[parameter(ParameterSetName="pool")]
[parameter(ParameterSetName="os")]
[ValidateSet("All", "ExcludeMissingOS", "MissingOS", "V3Compatible", "V3CompatibilityIssues", "V3CompatibilityUnknown", "V3InCompatible")]
[ValidateSet("All", "ExcludeMissingOS", "MissingOS", "V4Compatible", "V4CompatibilityIssues", "V4CompatibilityUnknown", "V4InCompatible")]
[string]
$Filter="V3CompatibilityIssues",
$Filter="V4CompatibilityIssues",

[parameter(Mandatory=$false)]
[switch]
@@ -66,11 +66,11 @@ param (

class ClassificationResult {
hidden [int]$_sortOrder = 1
hidden [string]$_upgradeStatement = "OS (version) unknown, v2 agent won't upgrade to v3 automatically"
hidden [string]$_upgradeStatement = "OS (version) unknown, agent won't upgrade to v4 automatically"
[ValidateSet($null, $true, $false)]
hidden [object]$_v3AgentSupportsOS
hidden [object]$_v4AgentSupportsOS
[ValidateSet("MissingOS", "Unsupported", "Unknown", "UnknownOS", "UnknownOSVersion", "UnsupportedOSVersion", "Supported")]
hidden [string]$_v3AgentSupportsOSText = "Unknown"
hidden [string]$_v4AgentSupportsOSText = "Unknown"
[string]$_reason

ClassificationResult() {
@@ -95,36 +95,36 @@ class ClassificationResult {

$this._upgradeStatement = $value
}
$this | Add-Member -Name V3AgentSupportsOS -MemberType ScriptProperty -Value {
$this | Add-Member -Name V4AgentSupportsOS -MemberType ScriptProperty -Value {
# Get
return $this._v3AgentSupportsOS
return $this._v4AgentSupportsOS
} -SecondValue {
# Set
param($value)

$this._v3AgentSupportsOS = $value
if ($value -eq $null) {
$this._v4AgentSupportsOS = $value
if ($null -eq $value) {
$this._sortOrder = 1
$this._v3AgentSupportsOSText = "Unknown"
$this._upgradeStatement = "OS (version) unknown, v2 agent won't upgrade to v3 automatically"
$this._v4AgentSupportsOSText = "Unknown"
$this._upgradeStatement = "OS (version) unknown, agent won't upgrade to v4 automatically"
} elseif ($value) {
$this._sortOrder = 2
$this._v3AgentSupportsOSText = "Supported"
$this._upgradeStatement = "OS supported by v3 agent, v2 agent will automatically upgrade to v3"
$this._v4AgentSupportsOSText = "Supported"
$this._upgradeStatement = "OS supported by v4 agent, agent will automatically upgrade to v4"
} else {
$this._sortOrder = 0
$this._v3AgentSupportsOSText = "Unsupported"
$this._upgradeStatement = "OS not supported by v3 agent, v2 agent won't upgrade to v3"
$this._v4AgentSupportsOSText = "Unsupported"
$this._upgradeStatement = "OS not supported by v4 agent, agent won't upgrade to v4"
}
}
$this | Add-Member -Name V3AgentSupportsOSText -MemberType ScriptProperty -Value {
$this | Add-Member -Name V4AgentSupportsOSText -MemberType ScriptProperty -Value {
# Get
return $this._v3AgentSupportsOSText
return $this._v4AgentSupportsOSText
} -SecondValue {
# Set
param($value)

$this._v3AgentSupportsOSText = $value
$this._v4AgentSupportsOSText = $value
}
}
}
@@ -153,17 +153,17 @@ function Filter-Agents (
"MissingOS" {
$Agents | Where-Object {[string]::IsNullOrWhiteSpace($_.OS)}
}
"V3Compatible" {
$Agents | Where-Object {$_.ValidationResult.V3AgentSupportsOS -eq $true}
"V4Compatible" {
$Agents | Where-Object {$_.ValidationResult.V4AgentSupportsOS -eq $true}
}
"V3CompatibilityIssues" {
$Agents | Where-Object {$_.ValidationResult.V3AgentSupportsOS -ne $true} | Where-Object {![string]::IsNullOrWhiteSpace($_.OS)}
"V4CompatibilityIssues" {
$Agents | Where-Object {$_.ValidationResult.V4AgentSupportsOS -ne $true} | Where-Object {![string]::IsNullOrWhiteSpace($_.OS)}
}
"V3CompatibilityUnknown" {
$Agents | Where-Object {$_.ValidationResult.V3AgentSupportsOS -eq $null}
"V4CompatibilityUnknown" {
$Agents | Where-Object {$null -eq $_.ValidationResult.V4AgentSupportsOS}
}
"V3InCompatible" {
$Agents | Where-Object {$_.ValidationResult.V3AgentSupportsOS -eq $false}
"V4InCompatible" {
$Agents | Where-Object {$_.ValidationResult.V4AgentSupportsOS -eq $false}
}
default {
$Agents
@@ -180,7 +180,7 @@ function Open-Document (
return
}
if ($IsWindows) {
start $Document
Start-Process $Document
return
}
}
@@ -196,7 +196,7 @@ function Validate-OS {
if (!$OSDescription) {
$result = [ClassificationResult]::new()
$result.UpgradeStatement = "OS description missing"
$result.V3AgentSupportsOSText = "MissingOS"
$result.V4AgentSupportsOSText = "MissingOS"
return $result
}

@@ -207,16 +207,16 @@ function Validate-OS {
Write-Debug "Debian: '$OSDescription'"
[version]$kernelVersion = ("{0}.{1}" -f $Matches["Major"],$Matches["Minor"])
Write-Debug "Debian Linux Kernel $($kernelVersion.ToString())"
[version]$minKernelVersion = '4.19' # https://wiki.debian.org/DebianBuster
[version]$minKernelVersion = '5.10' # https://wiki.debian.org/DebianBullseye

if ($kernelVersion -ge $minKernelVersion) {
$result.Reason = "Supported Debian Linux kernel version: ${kernelVersion}"
$result.V3AgentSupportsOS = $true
$result.V4AgentSupportsOS = $true
return $result
} else {
$result.Reason = "Unsupported Debian Linux kernel version: ${kernelVersion} (see https://wiki.debian.org/DebianReleases)"
$result.V3AgentSupportsOS = $false
$result.V3AgentSupportsOSText = "UnsupportedOSVersion"
$result.V4AgentSupportsOS = $false
$result.V4AgentSupportsOSText = "UnsupportedOSVersion"
return $result
}
}
@@ -226,14 +226,14 @@ function Validate-OS {
[int]$fedoraVersion = $Matches["Major"]
Write-Debug "Fedora ${fedoraVersion}"

if ($fedoraVersion -ge 33) {
if ($fedoraVersion -ge 38) {
$result.Reason = "Supported Fedora version: ${fedoraVersion}"
$result.V3AgentSupportsOS = $true
$result.V4AgentSupportsOS = $true
return $result
} else {
$result.Reason = "Unsupported Fedora version: ${fedoraVersion}"
$result.V3AgentSupportsOS = $false
$result.V3AgentSupportsOSText = "UnsupportedOSVersion"
$result.V4AgentSupportsOS = $false
$result.V4AgentSupportsOSText = "UnsupportedOSVersion"
return $result
}
}
@@ -243,14 +243,14 @@ function Validate-OS {
[int]$majorVersion = $Matches["Major"]
Write-Debug "Red Hat ${majorVersion}"

if ($majorVersion -ge 7) {
if ($majorVersion -ge 8) {
$result.Reason = "Supported RHEL / CentOS / Oracle Linux version: ${majorVersion}"
$result.V3AgentSupportsOS = $true
$result.V4AgentSupportsOS = $true
return $result
} else {
$result.Reason = "Unsupported RHEL / CentOS / Oracle Linux version: ${majorVersion}"
$result.V3AgentSupportsOS = $false
$result.V3AgentSupportsOSText = "UnsupportedOSVersion"
$result.V4AgentSupportsOS = $false
$result.V4AgentSupportsOSText = "UnsupportedOSVersion"
return $result
}
}
@@ -260,19 +260,19 @@ function Validate-OS {
[int]$majorVersion = $Matches["Major"]
Write-Debug "Ubuntu ${majorVersion}"

if ($majorVersion -lt 16) {
if ($majorVersion -lt 20) {
$result.Reason = "Unsupported Ubuntu version: ${majorVersion}"
$result.V3AgentSupportsOS = $false
$result.V3AgentSupportsOSText = "UnsupportedOSVersion"
$result.V4AgentSupportsOS = $false
$result.V4AgentSupportsOSText = "UnsupportedOSVersion"
return $result
}
if (($majorVersion % 2) -ne 0) {
$result.Reason = "non-LTS Ubuntu version: ${majorVersion}"
$result.V3AgentSupportsOSText = "UnsupportedOSVersion"
$result.V4AgentSupportsOSText = "UnsupportedOSVersion"
return $result
}
Write-Debug "Supported Ubuntu version: ${majorVersion}"
$result.V3AgentSupportsOS = $true
$result.V4AgentSupportsOS = $true
return $result
}
# Ubuntu "Linux 3.19.0-26-generic #28-Ubuntu SMP Tue Aug 11 14:16:32 UTC 2015"
@@ -282,104 +282,104 @@ function Validate-OS {
[version]$kernelVersion = ("{0}.{1}" -f $Matches["KernelMajor"],$Matches["KernelMinor"])
Write-Debug "Ubuntu Linux Kernel $($kernelVersion.ToString())"
[version[]]$supportedKernelVersions = @(
'4.4', # 16.04
'4.8', # 16.10
'4.15', # 18.04
'4.18', # 18.04
'5.4', # 20.04
'5.8', # 20.04
'5.15' # 22.04
'5.15', # 22.04
'6.18' # 24.04
)
[version]$minKernelVersion = ($supportedKernelVersions | Measure-Object -Minimum | Select-Object -ExpandProperty Minimum)

if ($kernelVersion -lt $minKernelVersion ) {
$result.Reason = "Unsupported Ubuntu Linux kernel version: ${kernelVersion}` (see https://ubuntu.com/kernel/lifecycle)"
$result.V3AgentSupportsOS = $false
$result.V3AgentSupportsOSText = "UnsupportedOSVersion"
$result.V4AgentSupportsOS = $false
$result.V4AgentSupportsOSText = "UnsupportedOSVersion"
return $result
}
if ($kernelVersion -in $supportedKernelVersions) {
$result.Reason = "Supported Ubuntu Linux kernel version: ${kernelVersion}"
$result.V3AgentSupportsOS = $true
$result.V4AgentSupportsOS = $true
return $result
}

$result.Reason = "Unknown Ubuntu version: '$OSDescription'"
$result.V3AgentSupportsOSText = "UnknownOSVersion"
$result.V4AgentSupportsOSText = "UnknownOSVersion"
return $result
}
# macOS "Darwin 17.6.0 Darwin Kernel Version 17.6.0: Tue May 8 15:22:16 PDT 2018; root:xnu-4570.61.1~1/RELEASE_X86_64"
"(?im)^Darwin (?<DarwinMajor>[\d]+)(\.(?<DarwinMinor>[\d]+)).*$" {
Write-Debug "macOS (Darwin): '$OSDescription'"
[version]$darwinVersion = ("{0}.{1}" -f $Matches["DarwinMajor"],$Matches["DarwinMinor"])
Write-Debug "Darwin $($darwinVersion.ToString())"
[version]$minDarwinVersion = '19.0'
[version]$minDarwinVersion = '21.0'

if ($darwinVersion -ge $minDarwinVersion) {
$result.Reason = "Supported Darwin (macOS) version: ${darwinVersion}"
$result.V3AgentSupportsOS = $true
$result.V4AgentSupportsOS = $true
return $result
} else {
$result.Reason = "Unsupported Darwin (macOS) version): ${darwinVersion} (see https://en.wikipedia.org/wiki/Darwin_(operating_system)"
$result.V3AgentSupportsOS = $false
$result.V3AgentSupportsOSText = "UnsupportedOSVersion"
$result.V4AgentSupportsOS = $false
$result.V4AgentSupportsOSText = "UnsupportedOSVersion"
return $result
}
}
# Windows 10 / Server 2016+ "Microsoft Windows 10.0.20348"
# Windows 10 / 11 / Server 2016+ "Microsoft Windows 10.0.20348"
"(?im)^(Microsoft Windows|Windows_NT) (?<Major>[\d]+)(\.(?<Minor>[\d]+))(\.(?<Build>[\d]+)).*$" {
[int]$windowsMajorVersion = $Matches["Major"]
[int]$windowsMinorVersion = $Matches["Minor"]
[int]$windowsBuild = $Matches["Build"]
[version]$windowsVersion = ("{0}.{1}.{2}" -f $Matches["Major"],$Matches["Minor"],$Matches["Build"])
Write-Debug "Windows: '$OSDescription'"
Write-Debug "Windows $($windowsVersion.ToString())"
if (($windowsMajorVersion -eq 6) -and ($windowsMinorVersion -eq 1)) {
# Windows 7
if ($windowsBuild -ge 7601) {
$result.Reason = "Supported Windows 7 build: ${windowsVersion}"
$result.V3AgentSupportsOS = $true
if (($windowsMajorVersion -eq 10) -and ($windowsMinorVersion -eq 0)) {
if ($windowsBuild -eq 14393) {
# Windows 10 / Windows Server 2016
$result.Reason = "Supported Windows build: ${windowsVersion}"
$result.V4AgentSupportsOS = $true
return $result
} elseif ($windowsBuild -eq 17763) {
# Windows 10 / Windows Server 2019
$result.Reason = "Supported Windows build: ${windowsVersion}"
$result.V4AgentSupportsOS = $true
return $result
} elseif ($windowsBuild -ge 19044) {
# Windows 10 / Windows Server 2022 / Windows 11
$result.Reason = "Supported Windows build: ${windowsVersion}"
$result.V4AgentSupportsOS = $true
return $result
} else {
$result.Reason = "Unsupported Windows 7 build: ${windowsVersion}"
$result.V3AgentSupportsOS = $false
$result.V3AgentSupportsOSText = "UnsupportedOSVersion"
$result.Reason = "Unsupported Windows build: ${windowsVersion}"
$result.V4AgentSupportsOS = $false
$result.V4AgentSupportsOSText = "UnsupportedOSVersion"
return $result
}
}
if (($windowsMajorVersion -eq 6) -and ($windowsMinorVersion -eq 2)) {
# Windows 8 / Windows Server 2012 R1
$result.Reason = "Windows 8 is not supported: ${windowsVersion}"
$result.V3AgentSupportsOS = $false
$result.V3AgentSupportsOSText = "UnsupportedOSVersion"
if (($windowsMajorVersion -eq 6) -and ($windowsMinorVersion -eq 2) -and ($windowsBuild -eq 9200)) {
# Windows Server 2012
$result.Reason = "Supported Windows Server 2012 version: ${windowsVersion}"
$result.V4AgentSupportsOS = $true
return $result
}
if (($windowsMajorVersion -eq 6) -and ($windowsMinorVersion -eq 3)) {
# Windows 8.1 / Windows Server 2012 R2
$result.Reason = "Supported Windows 8.1 version: ${windowsVersion}"
$result.V3AgentSupportsOS = $true
if (($windowsMajorVersion -eq 6) -and ($windowsMinorVersion -eq 3) -and ($windowsBuild -eq 9600)) {
# Windows Server 2012 R2
$result.Reason = "Supported Windows Server 2012-R2 version: ${windowsVersion}"
$result.V4AgentSupportsOS = $true
return $result
}
if ($windowsMajorVersion -eq 10) {
# Windows 10 / Windows Server 2016+
if ($windowsBuild -ge 14393) {
$result.Reason = "Supported Windows 10 / Windows Server 2016+ build: ${windowsVersion}"
$result.V3AgentSupportsOS = $true
return $result
} else {
$result.Reason = "Unsupported Windows 10 / Windows Server 2016+ build: ${windowsVersion}"
$result.V3AgentSupportsOS = $false
$result.V3AgentSupportsOSText = "UnsupportedOSVersion"
return $result
}
if ($windowsMajorVersion -eq 6) {
# Windows 7 / 8 / Windows Server 2012 R1
$result.Reason = "Windows 7 / Windows 8 / Windows Server 2012-R1 is not supported: ${windowsVersion}"
$result.V4AgentSupportsOS = $false
$result.V4AgentSupportsOSText = "UnsupportedOSVersion"
return $result
}
$result.Reason = "Unknown Windows version: '${OSDescription}'"
$result.V3AgentSupportsOSText = "UnknownOSVersion"
$result.V4AgentSupportsOSText = "UnknownOSVersion"
return $result
}
default {
$result.Reason = "Unknown operating system: '$OSDescription'"
$result.V3AgentSupportsOSText = "UnknownOS"
$result.V4AgentSupportsOSText = "UnknownOS"
return $result
}
}
@@ -401,9 +401,9 @@ if ($OS) {
} | Filter-Agents -AgentFilter $Filter `
| Format-Table -Property OS,`
@{Label="UpgradeStatement"; Expression={
if ($_.ValidationResult.V3AgentSupportsOS -eq $null) {
if ($_.ValidationResult.V4AgentSupportsOS -eq $null) {
"$($PSStyle.Formatting.Warning)$($_.ValidationResult.UpgradeStatement)$($PSStyle.Reset)"
} elseif ($_.ValidationResult.V3AgentSupportsOS) {
} elseif ($_.ValidationResult.V4AgentSupportsOS) {
$_.ValidationResult.UpgradeStatement
} else {
"$($PSStyle.Formatting.Error)$($_.ValidationResult.UpgradeStatement)$($PSStyle.Reset)"
@@ -496,11 +496,11 @@ try {
-o tsv `
| Set-Variable poolName

Write-Host "Retrieving v2 agents for pool '${poolName}' (${poolUrl})..."
Write-Debug "az pipelines agent list --pool-id ${individualPoolId} --include-capabilities --query `"[?starts_with(version,'2.') ]`""
Write-Host "Retrieving v2 and v3 agents for pool '${poolName}' (${poolUrl})..."
Write-Debug "az pipelines agent list --pool-id ${individualPoolId} --include-capabilities --query `"[?starts_with(version,'2.') || starts_with(version,'3.')]`""
az pipelines agent list --pool-id $individualPoolId `
--include-capabilities `
--query "[?starts_with(version,'2.') ]" `
--query "[?starts_with(version,'2.') || starts_with(version,'3.')]" `
-o json `
| ConvertFrom-Json `
| Set-Variable agents
@@ -555,7 +555,7 @@ try {
| Select-Object -Property @{Label="Name"; Expression={$_.name}},`
@{Label="Id"; Expression={$_.id}},`
@{Label="OS"; Expression={$_.OS -replace ";",""}},`
@{Label="V3OS"; Expression={$_.ValidationResult.V3AgentSupportsOSText}},`
@{Label="V4OS"; Expression={$_.ValidationResult.V4AgentSupportsOSText}},`
@{Label="UpgradeStatement"; Expression={$_.ValidationResult.UpgradeStatement}},`
@{Label="Reason"; Expression={$_.ValidationResult.Reason}},`
@{Label="CreatedOn"; Expression={$_.createdOn}},`
@@ -576,15 +576,15 @@ try {
| Format-Table -Property @{Label="Name"; Expression={$_.name}},`
OS,`
@{Label="UpgradeStatement"; Expression={
if ($_.ValidationResult.V3AgentSupportsOS -eq $null) {
if ($_.ValidationResult.V4AgentSupportsOS -eq $null) {
"$($PSStyle.Formatting.Warning)$($_.ValidationResult.UpgradeStatement)$($PSStyle.Reset)"
} elseif ($_.ValidationResult.V3AgentSupportsOS) {
} elseif ($_.ValidationResult.V4AgentSupportsOS) {
$_.ValidationResult.UpgradeStatement
} else {
"$($PSStyle.Formatting.Error)$($_.ValidationResult.UpgradeStatement)$($PSStyle.Reset)"
}
}},`
@{Label="V3OS"; Expression={$_.ValidationResult.V3AgentSupportsOSText}},`
@{Label="V4OS"; Expression={$_.ValidationResult.V4AgentSupportsOSText}},`
PoolName,`
AgentUrl `
| Out-Host -Paging
@@ -596,13 +596,13 @@ try {
Write-Host "`nRetrieved agents with filter '${Filter}' in organization (${OrganizationUrl}) have been saved to ${exportFilePath}"
Write-Host "Processed ${totalNumberOfAgents} agents in ${totalNumberOfPools} in organization '${OrganizationUrl}'"
$statisticsFilter = (($Filter -ieq "All") -or $IncludeMissingOSInStatistics ? "All" : "ExcludeMissingOS")
Write-Host "`nAgents by v2 -> v3 compatibility (${statisticsFilter}):"
Write-Host "`nAgents by v2/v3 -> v4 compatibility (${statisticsFilter}):"

$script:allAgents | Filter-Agents -AgentFilter $statisticsFilter `
| Group-Object {$_.ValidationResult.V3AgentSupportsOSText} `
| Group-Object {$_.ValidationResult.V4AgentSupportsOSText} `
| Set-Variable agentsSummary
$agentsSummary | Measure-Object -Property Count -Sum | Select-Object -ExpandProperty Sum | Set-Variable totalNumberOfFilteredAgents
$agentsSummary | Format-Table -Property @{Label="V3AgentSupportsOS"; Expression={$_.Name}},`
$agentsSummary | Format-Table -Property @{Label="V4AgentSupportsOS"; Expression={$_.Name}},`
Count,`
@{Label="Percentage"; Expression={($_.Count / $totalNumberOfFilteredAgents).ToString("p")}}
}