Skip to content

Commit

Permalink
[Utilities] Updated WhatIf feature to AVM changes (#4308)
Browse files Browse the repository at this point in the history
* Update to latest

* Implemented several fixes + aligned to AVM changes

* Update to latest

* Update to latest

* Update to latest
  • Loading branch information
AlexanderSehr authored Nov 30, 2023
1 parent 3b5965b commit d102bd5
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 99 deletions.
14 changes: 10 additions & 4 deletions utilities/pipelines/resourceDeployment/New-TemplateDeployment.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,6 @@ function New-TemplateDeploymentInner {

begin {
Write-Debug ('{0} entered' -f $MyInvocation.MyCommand)

# Load helper
. (Join-Path (Get-Item -Path $PSScriptRoot).parent.FullName 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1')
}

process {
Expand Down Expand Up @@ -375,6 +372,9 @@ Optional. Maximum retry limit if the deployment fails. Default is 3.
.PARAMETER doNotThrow
Optional. Do not throw an exception if it failed. Still returns the error message though
.PARAMETER RepoRoot
Optional. The path to the repository's root
.EXAMPLE
New-TemplateDeployment -templateFilePath 'C:/key-vault/vault/main.bicep' -parameterFilePath 'C:/key-vault/vault/.test/parameters.json' -location 'WestEurope' -resourceGroupName 'aLegendaryRg'
Expand Down Expand Up @@ -422,11 +422,17 @@ function New-TemplateDeployment {
[switch] $doNotThrow,

[Parameter(Mandatory = $false)]
[int]$retryLimit = 3
[int]$retryLimit = 3,

[Parameter(Mandatory = $false)]
[string] $RepoRoot = (Get-Item -Path $PSScriptRoot).parent.parent.parent.FullName
)

begin {
Write-Debug ('{0} entered' -f $MyInvocation.MyCommand)

# Load helper
. (Join-Path $RepoRoot 'utilities' 'pipelines' 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1')
}

process {
Expand Down
48 changes: 28 additions & 20 deletions utilities/pipelines/resourceDeployment/Test-TemplateDeployment.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ Optional. Name of the management group to deploy into. Mandatory if deploying in
.PARAMETER additionalParameters
Optional. Additional parameters you can provide with the deployment. E.g. @{ resourceGroupName = 'myResourceGroup' }
.PARAMETER RepoRoot
Optional. The path to the repository's root
.EXAMPLE
Test-TemplateDeployment -templateFilePath 'C:/key-vault/vault/main.bicep' -parameterFilePath 'C:/key-vault/vault/.test/parameters.json' -location 'WestEurope' -resourceGroupName 'aLegendaryRg'
Expand Down Expand Up @@ -68,17 +71,40 @@ function Test-TemplateDeployment {
[string] $managementGroupId,

[Parameter(Mandatory = $false)]
[Hashtable] $additionalParameters
[Hashtable] $additionalParameters,

[Parameter(Mandatory = $false)]
[string] $RepoRoot = (Get-Item -Path $PSScriptRoot).parent.parent.parent.FullName
)

begin {
Write-Debug ('{0} entered' -f $MyInvocation.MyCommand)

# Load helper
. (Join-Path (Get-Item -Path $PSScriptRoot).parent.FullName 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1')
. (Join-Path $RepoRoot 'utilities' 'pipelines' 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1')
}

process {
$deploymentNamePrefix = Split-Path -Path (Split-Path $templateFilePath -Parent) -LeafBase
if ([String]::IsNullOrEmpty($deploymentNamePrefix)) {
$deploymentNamePrefix = 'templateDeployment-{0}' -f (Split-Path $templateFilePath -LeafBase)
}

$modulesRegex = '.+[\\|\/]modules[\\|\/]'
if ($templateFilePath -match $modulesRegex) {
# If we can assume we're operating in a module structure, we can further fetch the provider namespace & resource type
$shortPathElem = (($templateFilePath -split $modulesRegex)[1] -replace '\\', '/') -split '/' # e.g., app-configuration, configuration-store, .test, common, main.test.bicep
$providerNamespace = $shortPathElem[0] # e.g., app-configuration
$providerNamespaceShort = ($providerNamespace -split '-' | ForEach-Object { $_[0] }) -join '' # e.g., ac

$resourceType = $shortPathElem[1] # e.g., configuration-store
$resourceTypeShort = ($resourceType -split '-' | ForEach-Object { $_[0] }) -join '' # e.g. cs

$testFolderShort = Split-Path (Split-Path $templateFilePath -Parent) -Leaf # e.g., common

$deploymentNamePrefix = "$providerNamespaceShort-$resourceTypeShort-$testFolderShort" # e.g., ac-cs-common
}

$DeploymentInputs = @{
TemplateFile = $templateFilePath
Verbose = $true
Expand All @@ -96,24 +122,6 @@ function Test-TemplateDeployment {

$deploymentScope = Get-ScopeOfTemplateFile -TemplateFilePath $templateFilePath -Verbose

$deploymentNamePrefix = Split-Path -Path (Split-Path $templateFilePath -Parent) -LeafBase
if ([String]::IsNullOrEmpty($deploymentNamePrefix)) {
$deploymentNamePrefix = 'templateDeployment-{0}' -f (Split-Path $templateFilePath -LeafBase)
}
if ($templateFilePath -match '.*(\\|\/)Microsoft.+') {
# If we can assume we're operating in a module structure, we can further fetch the provider namespace & resource type
$shortPathElem = (($templateFilePath -split 'Microsoft\.')[1] -replace '\\', '/') -split '/' # e.g., AppConfiguration, configurationStores, .test, common, main.test.bicep
$providerNamespace = $shortPathElem[0] # e.g., AppConfiguration
$providerNamespaceShort = ($providerNamespace -creplace '[^A-Z]').ToLower() # e.g., ac

$resourceType = $shortPathElem[1] # e.g., configurationStores
$resourceTypeShort = ('{0}{1}' -f ($resourceType.ToLower())[0], ($resourceType -creplace '[^A-Z]')).ToLower() # e.g. cs

$testFolderShort = Split-Path (Split-Path $templateFilePath -Parent) -Leaf # e.g., common

$deploymentNamePrefix = "$providerNamespaceShort-$resourceTypeShort-$testFolderShort" # e.g., ac-cs-common
}

# Generate a valid deployment name. Must match ^[-\w\._\(\)]+$
do {
$deploymentName = ('{0}-{1}' -f $deploymentNamePrefix, (Get-Date -Format 'yyyyMMddTHHMMssffffZ'))[0..63] -join ''
Expand Down
61 changes: 10 additions & 51 deletions utilities/tools/Test-ModuleLocally.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -37,31 +37,7 @@ Optional. A hashtable parameter that contains custom tokens to be replaced in th
$TestModuleLocallyInput = @{
TemplateFilePath = 'C:\network\route-table\main.bicep'
ModuleTestFilePath = 'C:\network\route-table\.test\parameters.json'
PesterTest = $false
DeploymentTest = $false
WhatIfTest = $false
ValidationTest = $true
ValidateOrDeployParameters = @{
Location = 'westeurope'
ResourceGroupName = 'validation-rg'
SubscriptionId = '00000000-0000-0000-0000-000000000000'
ManagementGroupId = '00000000-0000-0000-0000-000000000000'
RemoveDeployment = $false
}
AdditionalTokens = @{
tenantId = '00000000-0000-0000-0000-000000000000'
}
}
Test-ModuleLocally @TestModuleLocallyInput -Verbose
Run a Test-Az*Deployment using a specific parameter-template combination with the provided tokens
.EXAMPLE
$TestModuleLocallyInput = @{
TemplateFilePath = 'C:\network\route-table\main.bicep'
ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep'
ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep'
PesterTest = $false
DeploymentTest = $false
WhatIfTest = $false
Expand All @@ -84,7 +60,7 @@ Run a Test-Az*Deployment using a test file with the provided tokens
$TestModuleLocallyInput = @{
TemplateFilePath = 'C:\network\route-table\main.bicep'
ModuleTestFilePath = 'C:\network\route-table\.test\parameters.json'
ModuleTestFilePath = 'C:\network\route-table\tests\e2e\defaults\main.test.bicep'
PesterTest = $false
DeploymentTest = $false
WhatIfTest = $true
Expand All @@ -102,13 +78,13 @@ $TestModuleLocallyInput = @{
}
Test-ModuleLocally @TestModuleLocallyInput -Verbose
Get What-If deployment result using a specific parameter-template combination with the provided tokens
Get What-If deployment result using a specific test-template combination with the provided tokens
.EXAMPLE
$TestModuleLocallyInput = @{
TemplateFilePath = 'C:\network\route-table\main.bicep'
ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep'
ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep'
PesterTest = $false
DeploymentTest = $false
WhatIfTest = $true
Expand Down Expand Up @@ -190,7 +166,7 @@ function Test-ModuleLocally {
[string] $TemplateFilePath,

[Parameter(Mandatory = $false)]
[string] $ModuleTestFilePath = (Join-Path (Split-Path $TemplateFilePath -Parent) '.test'),
[string] $ModuleTestFilePath = (Join-Path (Split-Path $TemplateFilePath -Parent) 'tests'),

[Parameter(Mandatory = $false)]
[string] $PesterTestFilePath = 'utilities/pipelines/staticValidation/module.tests.ps1',
Expand Down Expand Up @@ -224,7 +200,7 @@ function Test-ModuleLocally {
# Load Modules Validation / Deployment Scripts
. (Join-Path $utilitiesFolderPath 'pipelines' 'resourceDeployment' 'New-TemplateDeployment.ps1')
. (Join-Path $utilitiesFolderPath 'pipelines' 'resourceDeployment' 'Test-TemplateDeployment.ps1')
. (Join-Path $utilitiesFolderPath 'pipelines' 'resourceDeployment' 'Get-TemplateDeploymenWhatIf.ps1')
. (Join-Path $PSScriptRoot 'helper' 'Get-TemplateDeploymentWhatIf.ps1')
}
process {

Expand Down Expand Up @@ -327,12 +303,7 @@ function Test-ModuleLocally {
# Loop through test files
foreach ($moduleTestFile in $moduleTestFiles) {
Write-Verbose ('Validating module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)) -Verbose
if ((Split-Path $moduleTestFile -Extension) -eq '.json') {
Test-TemplateDeployment @functionInput -ParameterFilePath $moduleTestFile
} else {
$functionInput['TemplateFilePath'] = $moduleTestFile
Test-TemplateDeployment @functionInput
}
Test-TemplateDeployment @functionInput -TemplateFilePath $moduleTestFile
}
}
# What-If validation for template
Expand All @@ -341,12 +312,7 @@ function Test-ModuleLocally {
# Loop through test files
foreach ($moduleTestFile in $moduleTestFiles) {
Write-Verbose ('Get Deployment What-If result for module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)) -Verbose
if ((Split-Path $moduleTestFile -Extension) -eq '.json') {
Get-TemplateDeploymenWhatIf @functionInput -ParameterFilePath $moduleTestFile
} else {
$functionInput['TemplateFilePath'] = $moduleTestFile
Get-TemplateDeploymenWhatIf @functionInput
}
Get-TemplateDeploymentWhatIf @functionInput -TemplateFilePath $moduleTestFile
}
}
# Deploy template
Expand All @@ -356,15 +322,8 @@ function Test-ModuleLocally {
# Loop through test files
foreach ($moduleTestFile in $moduleTestFiles) {
Write-Verbose ('Deploy Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)) -Verbose
if ((Split-Path $moduleTestFile -Extension) -eq '.json') {
if ($PSCmdlet.ShouldProcess(('Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)), 'Deploy')) {
New-TemplateDeployment @functionInput -ParameterFilePath $moduleTestFile
}
} else {
$functionInput['TemplateFilePath'] = $moduleTestFile
if ($PSCmdlet.ShouldProcess(('Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)), 'Deploy')) {
New-TemplateDeployment @functionInput
}
if ($PSCmdlet.ShouldProcess(('Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)), 'Deploy')) {
New-TemplateDeployment @functionInput -TemplateFilePath $moduleTestFile
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,25 @@ Optional. Name of the management group to deploy into. Mandatory if deploying in
.PARAMETER additionalParameters
Optional. Additional parameters you can provide with the deployment. E.g. @{ resourceGroupName = 'myResourceGroup' }
.PARAMETER RepoRoot
Optional. The path to the repository's root
.EXAMPLE
Get-TemplateDeploymenWhatIf -templateFilePath 'C:/key-vault/vault/main.bicep' -parameterFilePath 'C:/key-vault/vault/.test/parameters.json' -location 'WestEurope' -resourceGroupName 'aLegendaryRg'
Get-TemplateDeploymentWhatIf -templateFilePath 'C:/key-vault/vault/main.bicep' -parameterFilePath 'C:/key-vault/vault/.test/parameters.json' -location 'WestEurope' -resourceGroupName 'aLegendaryRg'
Get What-If deployment result for the main.bicep of the KeyVault module with the parameter file 'parameters.json' using the resource group 'aLegendaryRg' in location 'WestEurope'
.EXAMPLE
Get-TemplateDeploymenWhatIf -templateFilePath 'C:/key-vault/vault/main.bicep' -location 'WestEurope' -resourceGroupName 'aLegendaryRg'
Get-TemplateDeploymentWhatIf -templateFilePath 'C:/key-vault/vault/main.bicep' -location 'WestEurope' -resourceGroupName 'aLegendaryRg'
Get What-If deployment result for the main.bicep of the KeyVault module using the resource group 'aLegendaryRg' in location 'WestEurope'
.EXAMPLE
Get-TemplateDeploymenWhatIf -templateFilePath 'C:/resources/resource-group/main.json' -parameterFilePath 'C:/resources/resource-group/.test/parameters.json' -location 'WestEurope'
Get-TemplateDeploymentWhatIf -templateFilePath 'C:/resources/resource-group/main.json' -parameterFilePath 'C:/resources/resource-group/.test/parameters.json' -location 'WestEurope'
Get What-If deployment result for the main.json of the ResourceGroup module with the parameter file 'parameters.json' in location 'WestEurope'
#>
function Get-TemplateDeploymenWhatIf {
function Get-TemplateDeploymentWhatIf {

[CmdletBinding(SupportsShouldProcess)]
param (
Expand All @@ -68,17 +71,40 @@ function Get-TemplateDeploymenWhatIf {
[string] $managementGroupId,

[Parameter(Mandatory = $false)]
[Hashtable] $additionalParameters
[Hashtable] $additionalParameters,

[Parameter(Mandatory = $false)]
[string] $RepoRoot = (Get-Item -Path $PSScriptRoot).parent.parent.parent.FullName
)

begin {
Write-Debug ('{0} entered' -f $MyInvocation.MyCommand)

# Load helper
. (Join-Path (Get-Item -Path $PSScriptRoot).parent.FullName 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1')
. (Join-Path $repoRoot 'utilities' 'pipelines' 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1')
}

process {
$deploymentNamePrefix = Split-Path -Path (Split-Path $templateFilePath -Parent) -LeafBase
if ([String]::IsNullOrEmpty($deploymentNamePrefix)) {
$deploymentNamePrefix = 'templateDeployment-{0}' -f (Split-Path $templateFilePath -LeafBase)
}

$modulesRegex = '.+[\\|\/]modules[\\|\/]'
if ($templateFilePath -match $modulesRegex) {
# If we can assume we're operating in a module structure, we can further fetch the provider namespace & resource type
$shortPathElem = (($templateFilePath -split $modulesRegex)[1] -replace '\\', '/') -split '/' # e.g., app-configuration, configuration-store, .test, common, main.test.bicep
$providerNamespace = $shortPathElem[0] # e.g., app-configuration
$providerNamespaceShort = ($providerNamespace -split '-' | ForEach-Object { $_[0] }) -join '' # e.g., ac

$resourceType = $shortPathElem[1] # e.g., configuration-store
$resourceTypeShort = ($resourceType -split '-' | ForEach-Object { $_[0] }) -join '' # e.g. cs

$testFolderShort = Split-Path (Split-Path $templateFilePath -Parent) -Leaf # e.g., common

$deploymentNamePrefix = "$providerNamespaceShort-$resourceTypeShort-$testFolderShort" # e.g., ac-cs-common
}

$DeploymentInputs = @{
TemplateFile = $templateFilePath
Verbose = $true
Expand All @@ -96,24 +122,6 @@ function Get-TemplateDeploymenWhatIf {

$deploymentScope = Get-ScopeOfTemplateFile -TemplateFilePath $templateFilePath -Verbose

$deploymentNamePrefix = Split-Path -Path (Split-Path $templateFilePath -Parent) -LeafBase
if ([String]::IsNullOrEmpty($deploymentNamePrefix)) {
$deploymentNamePrefix = 'templateDeployment-{0}' -f (Split-Path $templateFilePath -LeafBase)
}
if ($templateFilePath -match '.*(\\|\/)Microsoft.+') {
# If we can assume we're operating in a module structure, we can further fetch the provider namespace & resource type
$shortPathElem = (($templateFilePath -split 'Microsoft\.')[1] -replace '\\', '/') -split '/' # e.g., AppConfiguration, configurationStores, .test, common, main.test.bicep
$providerNamespace = $shortPathElem[0] # e.g., AppConfiguration
$providerNamespaceShort = ($providerNamespace -creplace '[^A-Z]').ToLower() # e.g., ac

$resourceType = $shortPathElem[1] # e.g., configurationStores
$resourceTypeShort = ('{0}{1}' -f ($resourceType.ToLower())[0], ($resourceType -creplace '[^A-Z]')).ToLower() # e.g. cs

$testFolderShort = Split-Path (Split-Path $templateFilePath -Parent) -Leaf # e.g., common

$deploymentNamePrefix = "$providerNamespaceShort-$resourceTypeShort-$testFolderShort" # e.g., ac-cs-common
}

# Generate a valid deployment name. Must match ^[-\w\._\(\)]+$
do {
$deploymentName = ('{0}-{1}' -f $deploymentNamePrefix, (Get-Date -Format 'yyyyMMddTHHMMssffffZ'))[0..63] -join ''
Expand Down

0 comments on commit d102bd5

Please sign in to comment.