diff --git a/docs/wiki/The CI environment - Pipeline design.md b/docs/wiki/The CI environment - Pipeline design.md index d431aa45a6..5387874d78 100644 --- a/docs/wiki/The CI environment - Pipeline design.md +++ b/docs/wiki/The CI environment - Pipeline design.md @@ -118,7 +118,7 @@ In addition to module pipelines, the repository includes several platform pipeli ## Dependencies pipeline -In order to successfully run module pipelines to validate and publish CARML modules to the target environment, certain Azure resources need to be deployed beforehand. +In order to successfully run module pipelines to validate and publish CARML modules to the target environment, certain Azure resources may need to be deployed beforehand. For example, any instance of the \[Virtual Machine] module needs an existing virtual network to be connected to and a Key Vault hosting its required local admin credentials to be referenced. diff --git a/utilities/pipelines/resourceDeployment/New-TemplateDeployment.ps1 b/utilities/pipelines/resourceDeployment/New-TemplateDeployment.ps1 index ea77202a1c..c882866976 100644 --- a/utilities/pipelines/resourceDeployment/New-TemplateDeployment.ps1 +++ b/utilities/pipelines/resourceDeployment/New-TemplateDeployment.ps1 @@ -252,6 +252,18 @@ function New-DeploymentWithParameterFile { $Stoploop = $true } } + if ($res.ProvisioningState -eq 'Failed') { + # Deployment failed but no exception was thrown. Hence we must do it for the command. + + $errorInputObject = @{ + DeploymentScope = $deploymentScope + DeploymentName = $deploymentName + ResourceGroupName = $resourceGroupName + } + $exceptionMessage = Get-ErrorMessageForScope @errorInputObject + + throw "Deployed failed with provisioning state [Failed]. Error Message: [$exceptionMessage]. Please review the Azure logs of deployment [$deploymentName] in scope [$deploymentScope] for further details." + } $Stoploop = $true } catch { if ($retryCount -ge $retryLimit) { diff --git a/utilities/pipelines/resourceDeployment/Test-TemplateDeployment.ps1 b/utilities/pipelines/resourceDeployment/Test-TemplateDeployment.ps1 index 0601075f47..168d8ccb2d 100644 --- a/utilities/pipelines/resourceDeployment/Test-TemplateDeployment.ps1 +++ b/utilities/pipelines/resourceDeployment/Test-TemplateDeployment.ps1 @@ -121,7 +121,7 @@ function Test-TemplateDeployment { } if (-not (Get-AzResourceGroup -Name $resourceGroupName -ErrorAction 'SilentlyContinue')) { if ($PSCmdlet.ShouldProcess("Resource group [$resourceGroupName] in location [$location]", 'Create')) { - New-AzResourceGroup -Name $resourceGroupName -Location $location + $null = New-AzResourceGroup -Name $resourceGroupName -Location $location } } if ($PSCmdlet.ShouldProcess('Resource group level deployment', 'Test')) { diff --git a/utilities/pipelines/resourceRemoval/Initialize-DeploymentRemoval.ps1 b/utilities/pipelines/resourceRemoval/Initialize-DeploymentRemoval.ps1 index af78109452..5aeca89f0a 100644 --- a/utilities/pipelines/resourceRemoval/Initialize-DeploymentRemoval.ps1 +++ b/utilities/pipelines/resourceRemoval/Initialize-DeploymentRemoval.ps1 @@ -66,6 +66,7 @@ function Initialize-DeploymentRemoval { 'Microsoft.Network/privateEndpoints', 'Microsoft.OperationsManagement/solutions', 'Microsoft.OperationalInsights/workspaces/linkedServices', + 'Microsoft.OperationalInsights/workspaces' 'Microsoft.Resources/resourceGroups', 'Microsoft.Compute/virtualMachines' ) diff --git a/utilities/pipelines/sharedScripts/Get-ModuleTestFileList.ps1 b/utilities/pipelines/sharedScripts/Get-ModuleTestFileList.ps1 index c219156f83..f2769cca1e 100644 --- a/utilities/pipelines/sharedScripts/Get-ModuleTestFileList.ps1 +++ b/utilities/pipelines/sharedScripts/Get-ModuleTestFileList.ps1 @@ -9,22 +9,33 @@ The relative path is returned instead of the full one to make paths easier to re .PARAMETER ModulePath Mandatory. The module path to search in. +.PARAMETER SearchFolder +Optional. The folder to search for files in + .EXAMPLE Get-ModuleTestFileList -ModulePath 'C:\ResourceModules\arm\Microsoft.Compute\virtualMachines' -Returns the relative file paths of all parameter files of the virtual machines module. +Returns the relative file paths of all test files of the virtual machines module in the default test folder ('.test'). + +.EXAMPLE +Get-ModuleTestFileList -ModulePath 'C:\ResourceModules\arm\Microsoft.Compute\virtualMachines' -SearchFolder 'parameters' + +Returns the relative file paths of all test files of the virtual machines module in folder 'parameters'. #> function Get-ModuleTestFileList { [CmdletBinding()] param ( [Parameter(Mandatory)] - [string] $ModulePath + [string] $ModulePath, + + [Parameter(Mandatory = $false)] + [string] $SearchFolder = '.test' ) $deploymentTests = @() - if (Test-Path (Join-Path $ModulePath '.test')) { - $deploymentTests += (Get-ChildItem -Path (Join-Path $ModulePath '.test') -Depth 0 -Include ('*.json', '*.bicep') -File).FullName + if (Test-Path (Join-Path $ModulePath $SearchFolder)) { + $deploymentTests += (Get-ChildItem -Path (Join-Path $ModulePath $SearchFolder) -Depth 0 -Include ('*.json', '*.bicep') -File).FullName } if (-not $deploymentTests) { diff --git a/utilities/tools/Test-ModuleLocally.ps1 b/utilities/tools/Test-ModuleLocally.ps1 index b21a2ff944..d3946801eb 100644 --- a/utilities/tools/Test-ModuleLocally.ps1 +++ b/utilities/tools/Test-ModuleLocally.ps1 @@ -74,7 +74,7 @@ $TestModuleLocallyInput = @{ } Test-ModuleLocally @TestModuleLocallyInput -Verbose -Run all Pesters test for a given template and a Test-Az*Deployment using each parameter file in the module's parameter folder in combination with the template and the provided tokens +Run all Pester tests for a given template and a Test-Az*Deployment using each test file in the module's default test folder ('.test') in combination with the template and the provided tokens .EXAMPLE @@ -171,7 +171,7 @@ function Test-ModuleLocally { Invoke-Pester -Configuration @{ Run = @{ Container = New-PesterContainer -Path (Join-Path $repoRootPath $moduleTestFilePath) -Data @{ - repoRootPath = $repoRootPath + repoRootPath = $repoRootPath moduleFolderPaths = Split-Path $TemplateFilePath -Parent enforcedTokenList = $enforcedTokenList } @@ -193,9 +193,9 @@ function Test-ModuleLocally { # Find Test Parameter Files # ------------------------- if ((Get-Item -Path $testFilePath) -is [System.IO.DirectoryInfo]) { - $ModuleParameterFiles = (Get-ChildItem -Path $testFilePath).FullName + $moduleTestFiles = (Get-ChildItem -Path $testFilePath).FullName } else { - $ModuleParameterFiles = @($testFilePath) + $moduleTestFiles = @($testFilePath) } # Replace parameter file tokens @@ -234,7 +234,7 @@ function Test-ModuleLocally { } # Invoke Token Replacement Functionality and Convert Tokens in Parameter Files - $ModuleParameterFiles | ForEach-Object { $null = Convert-TokensInFile @ConvertTokensInputs -FilePath $_ } + $moduleTestFiles | ForEach-Object { $null = Convert-TokensInFile @ConvertTokensInputs -FilePath $_ } # Deployment & Validation Testing # ------------------------------- @@ -251,9 +251,9 @@ function Test-ModuleLocally { # ----------------- if ($ValidationTest) { # Loop through test parameter files - foreach ($paramFilePath in $moduleParameterFiles) { - Write-Verbose ('Validating module [{0}] with parameter file [{1}]' -f $ModuleName, (Split-Path $paramFilePath -Leaf)) -Verbose - Test-TemplateDeployment @functionInput -ParameterFilePath $paramFilePath + foreach ($moduleTestFile in $moduleTestFiles) { + Write-Verbose ('Validating Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)) -Verbose + Test-TemplateDeployment @functionInput -ParameterFilePath $moduleTestFile } } @@ -263,10 +263,10 @@ function Test-ModuleLocally { if ($DeploymentTest) { $functionInput['retryLimit'] = 1 # Overwrite default of 3 # Loop through test parameter files - foreach ($paramFilePath in $moduleParameterFiles) { - Write-Verbose ('Deploy module [{0}] with parameter file [{1}]' -f $ModuleName, (Split-Path $paramFilePath -Leaf)) -Verbose - if ($PSCmdlet.ShouldProcess(('Module [{0}] with parameter file [{1}]' -f $ModuleName, (Split-Path $paramFilePath -Leaf)), 'Deploy')) { - New-TemplateDeployment @functionInput -ParameterFilePath $paramFilePath + foreach ($moduleTestFile in $moduleTestFiles) { + Write-Verbose ('Deploy Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)) -Verbose + if ($PSCmdlet.ShouldProcess(('Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)), 'Deploy')) { + New-TemplateDeployment @functionInput -ParameterFilePath $moduleTestFile } } } @@ -278,7 +278,7 @@ function Test-ModuleLocally { if (($ValidationTest -or $DeploymentTest) -and $ValidateOrDeployParameters) { # Replace Values with Tokens For Repo Updates Write-Verbose 'Restoring Tokens' - $ModuleParameterFiles | ForEach-Object { $null = Convert-TokensInFile @ConvertTokensInputs -FilePath $_ -SwapValueWithName $true } + $moduleTestFiles | ForEach-Object { $null = Convert-TokensInFile @ConvertTokensInputs -FilePath $_ -SwapValueWithName $true } } } }