From 1bc5d40e6cbc5b7b058dce070cb2c19f91a8286a Mon Sep 17 00:00:00 2001 From: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com> Date: Thu, 11 Jan 2024 23:31:21 +0000 Subject: [PATCH] feat: Region Rotator for Az Deployment Tests (#782) ## Description This PR is to support the capability of rotating regions at random during module deployment. due to availbility constraints we no longer wish to target a single region for all module testing. this PR brings the addition of a powershell script to filter regions based on the following: - Recommended Regions from Microsoft - Paired Regions - Exclusion of regions with availability constraints ## Testing | Pipelines | | --------- | | [![avm.res.automation.automation-account](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml/badge.svg?branch=csidebotham-regionv2)](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml) (Not Related)| | [![avm.res.key-vault.vault](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=csidebotham-regionv2)](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml)| | [![avm.res.network.dns-zone](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.network.dns-zone.yml/badge.svg?branch=csidebotham-regionv2)](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.network.dns-zone.yml) | |[![avm.res.compute.ssh-public-key](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml/badge.svg?branch=csidebotham-regionv2)](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml)| |[![avm.res.web.serverfarm](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml/badge.svg?branch=csidebotham-regionv2)](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml)| |[![avm.res.logic.workflow](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.logic.workflow.yml/badge.svg?branch=csidebotham-regionv2)](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.logic.workflow.yml)| |[![avm.res.data-factory.factory](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml/badge.svg?branch=csidebotham-regionv2)](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml)| --------- Co-authored-by: Alexander Sehr --- .../avm-validateModuleDeployment/action.yml | 35 +++++- .github/workflows/avm.template.module.yml | 2 - .../regionSelector/Get-AzDeploymentRegion.ps1 | 113 ++++++++++++++++++ 3 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 avm/utilities/pipelines/e2eValidation/regionSelector/Get-AzDeploymentRegion.ps1 diff --git a/.github/actions/templates/avm-validateModuleDeployment/action.yml b/.github/actions/templates/avm-validateModuleDeployment/action.yml index 09cf3b70ee..1ecac1373b 100644 --- a/.github/actions/templates/avm-validateModuleDeployment/action.yml +++ b/.github/actions/templates/avm-validateModuleDeployment/action.yml @@ -57,6 +57,37 @@ runs: creds: ${{ env.AZURE_CREDENTIALS }} enable-AzPSSession: true + # [Set Deployment Location] task(s) + # --------------------------- + - name: "Get Deployment Location" + id: get-deployment-location + uses: azure/powershell@v1 + with: + azPSVersion: "latest" + inlineScript: | + # Grouping task logs + Write-Output '::group::Get Recommended Regions' + + # Load used functions + . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'e2eValidation' 'regionSelector' 'Get-AzDeploymentRegion.ps1') + + # Set fucntion input parameters + $functionInput = @{ + usePairedRegionsOnly = $true + useKnownRegionsOnly = $true + } + + Write-Verbose "Invoke function with" -Verbose + Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose + + $location = Get-AzDeploymentRegion @functionInput + + $deploymentLocation = @{} + Write-Verbose ('{0}-{1}' -f 'deploymentLocation', $location) -Verbose + Write-Output ('{0}={1}' -f 'deploymentLocation', $location) >> $env:GITHUB_OUTPUT + + Write-Output '::endgroup::' + # [Token replacement] task(s) # --------------------------- - name: "Replace tokens in template file" @@ -139,7 +170,7 @@ runs: # Prepare general parameters # -------------------------- # Fetching parameters - $location = '${{ inputs.location }}' + $location = '${{ steps.get-deployment-location.outputs.deploymentLocation }}' $subscriptionId = '${{ inputs.subscriptionId }}' $managementGroupId = '${{ inputs.managementGroupId }}' @@ -189,7 +220,7 @@ runs: # Prepare general parameters # -------------------------- - $location = '${{ inputs.location }}' + $location ='${{ steps.get-deployment-location.outputs.deploymentLocation }}' $subscriptionId = '${{ inputs.subscriptionId }}' $managementGroupId = '${{ inputs.managementGroupId }}' diff --git a/.github/workflows/avm.template.module.yml b/.github/workflows/avm.template.module.yml index e3e75b060f..100eea27c4 100644 --- a/.github/workflows/avm.template.module.yml +++ b/.github/workflows/avm.template.module.yml @@ -85,7 +85,6 @@ jobs: (fromJson(inputs.workflowInput)).deploymentValidation == 'true' && needs.job_module_static_validation.result != 'failure' needs: - job_module_static_validation - # - job_psrule_test # Ignoring dependency whilst PSRule gets bedded in, in this project strategy: fail-fast: false matrix: @@ -103,7 +102,6 @@ jobs: uses: ./.github/actions/templates/avm-validateModuleDeployment with: templateFilePath: "${{ inputs.modulePath }}/${{ matrix.testCases.path }}" - location: "WestEurope" subscriptionId: "${{ secrets.ARM_SUBSCRIPTION_ID }}" managementGroupId: "${{ secrets.ARM_MGMTGROUP_ID }}" removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" diff --git a/avm/utilities/pipelines/e2eValidation/regionSelector/Get-AzDeploymentRegion.ps1 b/avm/utilities/pipelines/e2eValidation/regionSelector/Get-AzDeploymentRegion.ps1 new file mode 100644 index 0000000000..897b81dbf5 --- /dev/null +++ b/avm/utilities/pipelines/e2eValidation/regionSelector/Get-AzDeploymentRegion.ps1 @@ -0,0 +1,113 @@ +<# +.SYNOPSIS +Set the deployment region for the module deployment + +.DESCRIPTION +This script is used to set the deployment region for the module deployment. + +.PARAMETER excludedRegions +Optional. The regions to exclude from the recommended regions list. + +.PARAMETER usePairedRegionsOnly +Optional. If set, only paired regions will be returned. + +.PARAMETER useKnownRegionsOnly +Optional. If set, only known regions will be returned. + +.PARAMETER knownRegionList +Optional. The list of known regions to use when useKnownRegionsOnly is set. ARM Deployment are limited to 10 active deployment regions per subscription. + +.EXAMPLE +Get-AzDeploymentRegion -excludedRegions @("West Europe", "Brazil South", "West US 2", "East US 2", "South Central US") -usePairedRegionsOnly -useKnownRegionsOnly + +Get the recommended regions using known regions excluding the regions specified in the excludedRegions parameter and only paired regions. + +.EXAMPLE +Get-AzDeploymentRegion -excludedRegions @("West Europe", "Brazil South", "West US 2", "East US 2", "South Central US") -usePairedRegionsOnly + +Get the recommended regions excluding the regions specified in the excludedRegions parameter and only paired regions. + +.EXAMPLE +Get-AzDeploymentRegion -excludedRegions @("West Europe", "Brazil South", "West US 2", "East US 2", "South Central US") + +Get the recommended regions excluding the regions specified in the excludedRegions parameter. + +.EXAMPLE +Get-AzDeploymentRegion -usePairedRegionsOnly + +Get the recommended paired regions. +#> + +function Get-AzDeploymentRegion { + param ( + [Parameter(Mandatory = $false)] + [array] $excludedRegions = @( + "westeurope", + "westus2", + "eastus2", + "centralus", + "southcentralus", + "brazilsouth", + "koreacentral", + "qatarcentral" + ), + + [Parameter(Mandatory = $false)] + [cmdletbinding()] + [switch] $usePairedRegionsOnly, + + [Parameter(Mandatory = $false)] + [cmdletbinding()] + [switch] $useKnownRegionsOnly, + + [Parameter(Mandatory = $false)] + [array] $knownRegionList = @( + "northeurope", + "eastus", + "polandcentral", + "germanywestcentral", + "francecentral", + "westus3", + "australiaeast", + "uksouth", + "westeurope" + ) + ) + + $allRegions = Get-AzLocation -ExtendedLocation $true + + # Filter regions where Location is in the known regions list + if ($useKnownRegionsOnly) { + $regionList = $allRegions | Where-Object { $_.Location -in $knownRegionList } + } + else { + $regionList = $allRegions + } + + + $exclusions = @() + $exclusions = $excludedRegions | Where-Object { $_ -in ($_ -like '* *' ? $regionList.DisplayName : $regionList.Location) } + Write-Verbose ('Excluding regions: {0}' -f ($exclusions | ConvertTo-Json)) -Verbose + + + # Filter regions where RegionCategory is 'Recommended' and not in the excluded list + $recommendedRegions = $regionList | Where-Object { $_.RegionCategory -eq "Recommended" -and $_.Location -notin $exclusions } + Write-Verbose "Recommended regions: $($recommendedRegions.Location | ConvertTo-Json)" + + if ($usePairedRegionsOnly) { + # Filter regions where PairedRegionName is not null + $recommendedRegions = $recommendedRegions | Where-Object { $null -ne $_.PairedRegion } + Write-Verbose "Paired regions only: $($recommendedRegions.Location | ConvertTo-Json)" + } + + # Display indexed regions + Write-Verbose "Recommended regions: $($recommendedRegions.Location | ConvertTo-Json)" -Verbose + + $index = Get-Random -Maximum ($recommendedRegions.Count) + Write-Verbose "Generated random index [$index]" + + $location = $recommendedRegions[$index].Location + Write-Verbose "Selected location [$location]" -Verbose + + return $location +}