diff --git a/scripts/Remove-AzOpsTestsDeployment.ps1 b/scripts/Remove-AzOpsTestsDeployment.ps1 index 625176f7..0af993f5 100644 --- a/scripts/Remove-AzOpsTestsDeployment.ps1 +++ b/scripts/Remove-AzOpsTestsDeployment.ps1 @@ -2,9 +2,9 @@ <# .SYNOPSIS - Assist in removal of AzOps Test Deployments, destructive command removes resources in the context executed. + Removes all resources and configurations created by AzOps test deployments. This is a destructive operation intended for cleaning up test environments. .DESCRIPTION - Assist in removal of AzOps Test Deployments, destructive command removes resources in the context executed. + This command assists in cleaning up resources, management groups, role assignments, policy assignments, and deployments created during AzOps testing. It is intended for use in test or development environments only, as it will permanently delete resources in the current context. .EXAMPLE > Remove-AzOpsTestsDeployment -CleanupEnvironment:$true #> diff --git a/src/AzOps.psd1 b/src/AzOps.psd1 index be10a1c1..99937c55 100644 --- a/src/AzOps.psd1 +++ b/src/AzOps.psd1 @@ -3,7 +3,7 @@ # # Generated by: Customer Architecture Team (CAT) # -# Generated on: 03/24/2025 +# Generated on: 5/20/2025 # @{ @@ -52,10 +52,10 @@ PowerShellVersion = '7.2' # Modules that must be imported into the global environment prior to importing this module RequiredModules = @(@{ModuleName = 'PSFramework'; RequiredVersion = '1.12.346'; }, - @{ModuleName = 'Az.Accounts'; RequiredVersion = '4.0.2'; }, + @{ModuleName = 'Az.Accounts'; RequiredVersion = '5.0.0'; }, @{ModuleName = 'Az.Billing'; RequiredVersion = '2.2.0'; }, - @{ModuleName = 'Az.ResourceGraph'; RequiredVersion = '1.2.0'; }, - @{ModuleName = 'Az.Resources'; RequiredVersion = '7.9.0'; }) + @{ModuleName = 'Az.ResourceGraph'; RequiredVersion = '1.2.1'; }, + @{ModuleName = 'Az.Resources'; RequiredVersion = '8.0.0'; }) # Assemblies that must be loaded prior to importing this module # RequiredAssemblies = @() diff --git a/src/localized/en-us/Strings.psd1 b/src/localized/en-us/Strings.psd1 index a0a002e0..c7dd52f8 100644 --- a/src/localized/en-us/Strings.psd1 +++ b/src/localized/en-us/Strings.psd1 @@ -215,7 +215,7 @@ 'Invoke-AzOpsPush.Change.Delete.TempFile' = 'Creating temporary file dir for deletion processing: {0}' # $fileName 'Invoke-AzOpsPush.Change.Delete.NextTempFile' = 'Exiting while loop, file detected in $DeleteSetContents for deletion processing based on this content line: [{0}]' # $currentLine 'Invoke-AzOpsPush.Change.Delete.SetTempFileContent' = 'Set temporary file content: [{1}], in [{0}]' # $fileName, $jsonValue - 'Invoke-AzOpsPush.Deletion.Failed' = 'Deletion of resources {0}, has failed using templates: {1}, {2}, this could be due to delayed deletion acceptance from Azure, please investigate and take action.' # $fail.ScopeObject.Scope, $fail.TemplateFilePath, $fail.TemplateParameterFilePath + 'Invoke-AzOpsPush.Deletion.Failed' = 'Deletion of resources {0}, have failed using templates: {1}, {2}, this could be due to delayed deletion acceptance from Azure, please investigate and take action.' # $fail.ScopeObject.Scope, $fail.TemplateFilePath, $fail.TemplateParameterFilePath 'Invoke-AzOpsPush.Deletion.Retry' = 'Deletion of {0} resources unsuccessful, initiate final retry combination.' # $retry.Count 'Invoke-AzOpsPush.Deploy.ProviderFeature' = 'Invoking new state deployment - *.providerfeatures.json for a file {0}' # $addition 'Invoke-AzOpsPush.Deploy.ResourceProvider' = 'Invoking new state deployment - *.resourceproviders.json for a file {0}' # $addition @@ -230,16 +230,16 @@ 'Invoke-AzOpsPush.Deployment.TemporaryDeploymentStackTemplateFilePath.Exist' = 'Temporary processing deployment template file [{0}] already exists for [{1}]' # $tempDeploymentFilePath, $target.TemplateFilePath 'Invoke-AzOpsPush.Deployment.TemporaryDeploymentStackTemplateFilePath.Remove' = 'Removing temporary processing deployment template file [{0}]' # $tempDeploymentFilePath 'Invoke-AzOpsPush.Deployment.TemporaryDeploymentStackTemplateFilePath.New' = 'Create temporary processing deployment template file [{0}] for [{1}]' # $tempDeploymentFilePath, $target.TemplateFilePath - 'Invoke-AzOpsPush.Dependency.Missing' = 'Missing resource dependency for successfull deletion. Error exiting runtime.' + 'Invoke-AzOpsPush.Dependency.Missing' = 'Missing resource dependency for successful deletion. Error exiting runtime.' 'Invoke-AzOpsPush.DeploymentList.NotFound' = 'Expecting deploymentList object, it was not found. Error exiting runtime.' 'Invoke-AzOpsPush.Duration' = 'AzOps Push completed in {0}' # $stopWatch.Elapsed 'Invoke-AzOpsPush.Resolve.DeployDeletionOverlap' = 'The file: {0} is targeted for deletion, skipping deployment file association' # 'Invoke-AzOpsPush.Resolve.FoundTemplate' = 'Found template {1} for parameters {0}' # $FilePath, $templatePath 'Invoke-AzOpsPush.Resolve.FoundBicepTemplate' = 'Found Bicep template {1} for parameters {0}' # $FilePath, $bicepTemplatePath 'Invoke-AzOpsPush.Resolve.FromMainTemplate' = 'Determining template from main template file: {0}' # $mainTemplateItem.FullName - 'Invoke-AzOpsPush.Resolve.MainTemplate.NotSupported' = 'effectiveResourceType: {0} AzOpsMainTemplate does NOT supports resource type {0} in {1}. Deployment will be ignored' # $effectiveResourceType, $AzOpsMainTemplate.FullName + 'Invoke-AzOpsPush.Resolve.MainTemplate.NotSupported' = 'effectiveResourceType: {0} AzOpsMainTemplate does NOT support resource type {0} in {1}. Deployment will be ignored' # $effectiveResourceType, $AzOpsMainTemplate.FullName 'Invoke-AzOpsPush.Resolve.MultipleTemplateParameterFile' = 'Found AllowMultipleTemplateParameterFile {0}' # $FilePath - 'Invoke-AzOpsPush.Resolve.MainTemplate.Supported' = 'effectiveResourceType: {0} - AzOpsMainTemplate supports resource type {0} in {1}' # $effectiveResourceType, $AzOpsMainTemplate.FullName + 'Invoke-AzOpsPush.Resolve.MainTemplate.Supported' = 'effectiveResourceType: {0} - AzOpsMainTemplate support resource type {0} in {1}' # $effectiveResourceType, $AzOpsMainTemplate.FullName 'Invoke-AzOpsPush.Resolve.NoJson' = 'The specified file is not a json or bicep file! Skipping {0}' # $fileItem.FullName 'Invoke-AzOpsPush.Resolve.NotFoundTemplate' = 'Did NOT find template {1} for parameters {0}' # $FilePath, $templatePath 'Invoke-AzOpsPush.Resolve.ParameterFound' = 'Found parameter file for template {0} : {1}' # $FilePath, $parameterPath @@ -353,7 +353,7 @@ 'Set-AzOpsWhatIfOutput.WhatIfFile' = 'Creating WhatIf markdown and json files' # 'Set-AzOpsWhatIfOutput.WhatIfFileAdding' = 'Adding content to WhatIf {0} file for template {1} with parameter file {2}' # '', $FilePath, $ParameterFilePath 'Set-AzOpsWhatIfOutput.WhatIfFileMax' = 'WhatIf markdown and json files have reached character limit, unable to append more information to files. WhatIf is too large for comment field, for more details look at PR files to determine changes.' # $ResultSizeMaxLimit, $ResultSizeLimit - 'Set-AzOpsWhatIfOutput.WhatIfMessageMax' = 'WhatIf have reached maximum character limit, unable to append warning message. WhatIf is too large for comment field, for more details look at PR files to determine changes.' # $ResultSizeMaxLimit, $ResultSizeLimit + 'Set-AzOpsWhatIfOutput.WhatIfMessageMax' = 'WhatIf has reached maximum character limit, unable to append warning message. WhatIf is too large for comment field, for more details look at PR files to determine changes.' # $ResultSizeMaxLimit, $ResultSizeLimit 'Set-AzOpsWhatIfOutput.WhatIfResults' = 'WhatIf Output {0}' # $results or $allResults 'Set-AzOpsWhatIfOutput.WhatIfFile.Remove' = 'Removing WhatIf markdown and json files lingering from previous run' # } \ No newline at end of file diff --git a/src/tests/integration/Repository.Tests.ps1 b/src/tests/integration/Repository.Tests.ps1 index aec3b65d..83685fff 100644 --- a/src/tests/integration/Repository.Tests.ps1 +++ b/src/tests/integration/Repository.Tests.ps1 @@ -102,6 +102,9 @@ Describe "Repository" { throw } + # Pause for resource consistency + Start-Sleep -Seconds 120 + # Wait for Management Group structure consistency $script:managementGroupDeployment = (Get-AzManagementGroupDeployment -ManagementGroupId "$script:tenantId" -Name "AzOps-Tests") @@ -166,11 +169,13 @@ Describe "Repository" { $script:policyExemptions = Get-AzPolicyExemption -Name "PolicyExemptionTest" -Scope "/subscriptions/$script:subscriptionId" $script:routeTable = (Get-AzResource -Name "RouteTable" -ResourceGroupName $script:resourceGroup.ResourceGroupName) $script:policyAssignmentsDeletion = Get-AzPolicyAssignment -Name "TestPolicyAssignmentDeletion" -Scope "/subscriptions/$script:subscriptionId/resourceGroups/$($script:resourceGroupCustomDeletion.ResourceGroupName)" - $script:ruleCollectionGroups = (Get-AzResource -ExpandProperties -Name "TestPolicy" -ResourceGroupName $($script:resourceGroup).ResourceGroupName).Properties.ruleCollectionGroups.id.split("/")[-1] + $firewallPolicy = Search-AzGraph -Subscription $script:subscriptionId -Query "resources | where type == 'microsoft.network/firewallpolicies' and resourceGroup =~ '$($script:resourceGroup.ResourceGroupName)' and name =~ 'TestPolicy'" | Select-Object -First 1 + $script:ruleCollectionGroups = $firewallPolicy.Properties.ruleCollectionGroups | ForEach-Object { $_.id.Split('/')[-1] } $script:logAnalyticsWorkspace = (Get-AzResource -Name "thisisalongloganalyticsworkspacename123456789011121314151617181" -ResourceGroupName $($script:resourceGroup).ResourceGroupName) } catch { Write-PSFMessage -Level Critical -Message "Failed to get deployed services" -Exception $_.Exception -FunctionName "BeforeAll" + throw } # Invoke the Invoke-AzOpsPull function to generate the scope data which can be tested against to ensure structure is correct and data model hasn't changed. @@ -1291,14 +1296,15 @@ Describe "Repository" { Start-Sleep -Seconds 60 $script:deployAllStaParamPathDeployment = Get-AzResource -ResourceGroupName $script:resourceGroupParallelDeploy.ResourceGroupName -ResourceType 'Microsoft.Storage/storageAccounts' $script:deployAllStaParamPathDeployment.Count | Should -Be 4 - $query = "resourcechanges | where resourceGroup =~ '$($($script:resourceGroupParallelDeploy).ResourceGroupName)' and properties.targetResourceType == 'microsoft.storage/storageaccounts' and properties.changeType == 'Create' | extend changeTime=todatetime(properties.changeAttributes.timestamp), targetResourceId=tostring(properties.targetResourceId) | summarize arg_max(changeTime, *) by targetResourceId | project changeTime, targetResourceId, properties.changeType, properties.targetResourceType | order by changeTime asc" - $createTime = Search-AzGraph -Query $query -Subscription $script:subscriptionId - $parallelTimes = $createTime | Where-Object { $_.targetResourceId -match '^.*/p[123]azops' } | Select-Object -ExpandProperty changeTime + $deployments = Get-AzResourceGroupDeployment -ResourceGroupName $script:resourceGroupParallelDeploy.ResourceGroupName + $parallelDeployments = $deployments | Where-Object { $_.Parameters.staName.Value -match '^p[123]azops$' } + $serialDeployment = $deployments | Where-Object { $_.Parameters.staName.Value -eq 's1azops' } + $parallelTimes = $parallelDeployments | Select-Object -ExpandProperty Timestamp $maxParallel = ($parallelTimes | Measure-Object -Maximum).Maximum $minParallel = ($parallelTimes | Measure-Object -Minimum).Minimum $diffParallel = New-TimeSpan -Start $minParallel -End $maxParallel $diffParallel.TotalSeconds | Should -BeLessThan 25 - $serialTime = ($createTime | Where-Object { $_.targetResourceId -match '^.*/s1azops' }).changeTime + $serialTime = $serialDeployment.Timestamp $diffSerial = New-TimeSpan -Start $maxParallel -End $serialTime $diffSerial.TotalSeconds | Should -BeGreaterThan 15 Set-PSFConfig -FullName AzOps.Core.AllowMultipleTemplateParameterFiles -Value $false