Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
Jefajers authored Mar 5, 2024
1 parent 9951e2f commit 7191fee
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 116 deletions.
6 changes: 3 additions & 3 deletions src/AzOps.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# Generated by: Customer Architecture Team (CAT)
#
# Generated on: 2/20/2024
# Generated on: 3/5/2024
#

@{
Expand Down Expand Up @@ -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.10.318'; },
@{ModuleName = 'Az.Accounts'; RequiredVersion = '2.15.1'; },
@{ModuleName = 'Az.Accounts'; RequiredVersion = '2.16.0'; },
@{ModuleName = 'Az.Billing'; RequiredVersion = '2.0.3'; },
@{ModuleName = 'Az.ResourceGraph'; RequiredVersion = '0.13.0'; },
@{ModuleName = 'Az.Resources'; RequiredVersion = '6.15.1'; })
@{ModuleName = 'Az.Resources'; RequiredVersion = '6.16.0'; })

# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()
Expand Down
2 changes: 1 addition & 1 deletion src/functions/Invoke-AzOpsPush.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@
Start-Sleep -Seconds 30
# Reset the status of failed attempts and perform recursive removal
foreach ($try in $retry) { $try.Status = $null }
$removeActionRecursive = Remove-AzResourceRawRecursive -InputObject $retry
$removeActionRecursive = Remove-AzResourceRaw -InputObject $retry -Recursive
$removeActionFail = $removeActionRecursive | Where-Object { $_.Status -eq 'failed' }
# If removal fails, log and attempt to fetch the resource causing the failure
if ($removeActionFail) {
Expand Down
3 changes: 2 additions & 1 deletion src/internal/functions/Remove-AzOpsDeployment.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@
foreach ($change in $removalJobChanges) {
$resource = $null
$resourceScopeObject = $null
$removeAction = $null
# Check if the resource exists
$resourceScopeObject = New-AzOpsScope -Scope $change.FullyQualifiedResourceId -WhatIf:$false
$resource = Get-AzOpsResource -ScopeObject $resourceScopeObject -ErrorAction SilentlyContinue
Expand Down Expand Up @@ -411,7 +412,7 @@
# Retry failed removals recursively
Write-AzOpsMessage -LogLevel InternalComment -LogString 'Remove-AzOpsDeployment.Resource.RetryCount' -LogStringValues $retry.Count
foreach ($try in $retry) { $try.Status = $null }
$removeActionRecursive = Remove-AzResourceRawRecursive -InputObject $retry
$removeActionRecursive = Remove-AzResourceRaw -InputObject $retry -Recursive
$removeActionRecursiveRemaining = $removeActionRecursive | Where-Object { $_.Status -eq 'failed' }
return $removeActionRecursiveRemaining
}
Expand Down
183 changes: 148 additions & 35 deletions src/internal/functions/Remove-AzResourceRaw.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
Path where the parameters of the ARM templates can be found.
.PARAMETER ScopeObject
Resource to delete.
.PARAMETER InputObject
Object containing items for processing, used in combination with parameter Recursive.
.PARAMETER Recursive
If specified, performs recursive resource deletion and requires use of parameter InputObject.
.EXAMPLE
> Remove-AzResourceRaw -ScopeObject $ScopeObject -TemplateFilePath $TemplateFilePath -TemplateParameterFilePath $TemplateParameterFilePath
Name Value
Expand All @@ -19,6 +23,14 @@
TemplateParameterFilePath /root/managementgroup/subscription/resourcegroup/template.parameters.json
ScopeObject ScopeObject
Status success
> Remove-AzResourceRaw -InputObject $retry -Recursive
Name Value
---- -----
TemplateFilePath /root/managementgroup/subscription/resourcegroup/template.json
TemplateParameterFilePath /root/managementgroup/subscription/resourcegroup/template.parameters.json
ScopeObject ScopeObject
Status success
#>

[CmdletBinding()]
Expand All @@ -27,51 +39,152 @@
$TemplateFilePath,
[string]
$TemplateParameterFilePath,
[Parameter(Mandatory = $true)]
[AzOpsScope]
$ScopeObject
$ScopeObject,
[array]
$InputObject,
[switch]
$Recursive
)

process {
# Construct result object
$result = [PSCustomObject]@{
TemplateFilePath = $TemplateFilePath
TemplateParameterFilePath = $TemplateParameterFilePath
ScopeObject = $ScopeObject
Status = 'success'
}
# Check if the resource exists
$resource = Get-AzOpsResource -ScopeObject $ScopeObject -ErrorAction SilentlyContinue
# Remove the resource if it exists
if ($resource) {
try {
# Set Azure context for removal operation
Set-AzOpsContext -ScopeObject $ScopeObject
$null = Remove-AzResource -ResourceId $ScopeObject.Scope -Force -ErrorAction Stop
$maxAttempts = 4
$attempt = 1
$gone = $false
while ($gone -eq $false -and $attempt -le $maxAttempts) {
Write-AzOpsMessage -LogLevel InternalComment -LogString 'Remove-AzResourceRaw.Resource.CheckExistence' -LogStringValues $ScopeObject.Scope
Start-Sleep -Seconds 10
$tryResource = Get-AzOpsResource -ScopeObject $ScopeObject -ErrorAction SilentlyContinue
if (-not $tryResource) {
$gone = $true
function Remove-AzResourceRawRecursive {

<#
.SYNOPSIS
Performs recursive resource deletion in Azure at any scope.
.DESCRIPTION
Takes $InputObject and performs recursive resource deletion in Azure and exhaust any permutation.
.PARAMETER InputObject
Parameter containing items for processing.
.PARAMETER CurrentOrder
Internal parameter to track recursive progress.
.PARAMETER OutputObject
Track item processing and return result.
.EXAMPLE
> $successFullItems, $failedItems = Remove-AzResourceRawRecursive -InputObject $retry
Example of a $retry array with 6 items, the number of permutations will be 6×5×4×3×2×1=720
#>

[CmdletBinding()]
param (
[array]
$InputObject,
[array]
$CurrentOrder = @(),
[array]
$OutputObject = @()
)

process {
if ($InputObject.Count -eq 0) {
# Base case: All items have been used, perform action on the current order
foreach ($item in $CurrentOrder) {
if ($item.Status -eq 'failed' -or $null -eq $item.Status) {
Write-AzOpsMessage -LogLevel InternalComment -LogString 'Remove-AzResourceRawRecursive.Processing' -LogStringValues $item.ScopeObject.Resource, $item.ScopeObject.Scope
# Attempt to remove the resource
$result = Remove-AzResourceRaw -ScopeObject $item.ScopeObject -TemplateFilePath $item.TemplateFilePath -TemplateParameterFilePath $item.TemplateParameterFilePath
if ($result.Status -eq 'failed' -and $result.ScopeObject.Scope -notin $OutputObject.ScopeObject.Scope){
# Add failed result to the output object
$OutputObject += $result
}
}
}
# Return the final result
return $OutputObject
}
else {
if ($InputObject -and $OutputObject) {
# Filter out items already processed successfully
$filteredOutputObject = @()
foreach ($item in $InputObject) {
if ($item.ScopeObject.Scope -in $OutputObject.ScopeObject.Scope) {
foreach ($output in $OutputObject) {
if ($output.ScopeObject.Scope -eq $item.ScopeObject.Scope -and $output.Status -eq 'failed') {
# Add previously failed item to the filtered output
$filteredOutputObject += $output
continue
}
}
}
}
if ($filteredOutputObject) {
$InputObject = $filteredOutputObject
}
}
# Recursive case: Try each item in the current position and recurse with the remaining items
foreach ($item in $InputObject) {
$remainingItems = $InputObject -ne $item
$newOrder = $CurrentOrder + $item
# Recursively call Remove-AzResourceRawRecursive
$OutputObject = Remove-AzResourceRawRecursive -InputObject $remainingItems -CurrentOrder $newOrder -OutputObject $OutputObject
}
$attempt++
# Return the output after all permutations
return $OutputObject
}
}
catch {
# Log failure message
Write-AzOpsMessage -LogLevel InternalComment -LogString 'Remove-AzResourceRaw.Resource.Failed' -LogStringValues $ScopeObject.Resource, $ScopeObject.Scope
$result.Status = 'failed'
}
if ($null -ne $InputObject -and $Recursive) {
# Perform recursive resource deletion
$result = Remove-AzResourceRawRecursive -InputObject $InputObject
if ($result) {
return $result
}
else {
return
}
}
elseif ($null -eq $InputObject -and $Recursive) {
# Recursive resource deletion missing input
Write-AzOpsMessage -LogLevel Error -LogString 'Remove-AzResourceRaw.Resource.Recursive.Missing'
return
}
else {
# Log not found message
$result.Status = 'notfound'
if (-not $ScopeObject) {
# Resource deletion missing input
Write-AzOpsMessage -LogLevel Error -LogString 'Remove-AzResourceRaw.Resource.Missing'
return
}
# Construct result object
$result = [PSCustomObject]@{
TemplateFilePath = $TemplateFilePath
TemplateParameterFilePath = $TemplateParameterFilePath
ScopeObject = $ScopeObject
Status = 'success'
}
# Check if the resource exists
$resource = Get-AzOpsResource -ScopeObject $ScopeObject -ErrorAction SilentlyContinue
# Remove the resource if it exists
if ($resource) {
try {
# Set Azure context for removal operation
Set-AzOpsContext -ScopeObject $ScopeObject
$null = Remove-AzResource -ResourceId $ScopeObject.Scope -Force -ErrorAction Stop
$maxAttempts = 4
$attempt = 1
$gone = $false
while ($gone -eq $false -and $attempt -le $maxAttempts) {
Write-AzOpsMessage -LogLevel InternalComment -LogString 'Remove-AzResourceRaw.Resource.CheckExistence' -LogStringValues $ScopeObject.Scope
Start-Sleep -Seconds 10
$tryResource = Get-AzOpsResource -ScopeObject $ScopeObject -ErrorAction SilentlyContinue
if (-not $tryResource) {
$gone = $true
}
$attempt++
}
}
catch {
# Log failure message
Write-AzOpsMessage -LogLevel InternalComment -LogString 'Remove-AzResourceRaw.Resource.Failed' -LogStringValues $ScopeObject.Resource, $ScopeObject.Scope
$result.Status = 'failed'
}
}
else {
# Log not found message
$result.Status = 'notfound'
}
# Return result object
return $result
}
# Return result object
return $result
}
}
76 changes: 0 additions & 76 deletions src/internal/functions/Remove-AzResourceRawRecursive.ps1

This file was deleted.

2 changes: 2 additions & 0 deletions src/localized/en-us/Strings.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@
'Remove-AzOpsDeployment.ResourceNotFound' = 'Unable to find resource of type {0} with id {1}.'# $scopeObject.Resource, $scopeObject.Scope, $resultsError
'Remove-AzOpsDeployment.SkipUnsupportedResource' = 'Deletion of AzOps generated file resources is only supported for locks, policyAssignments, policyDefinitions, policyExemptions, policySetDefinitions and roleAssignments. Will NOT proceed with deletion of resource in file {0}'# $TemplateFilePath

'Remove-AzResourceRaw.Resource.Recursive.Missing' = 'Missing required parameter InputObject, when running Recursive'#
'Remove-AzResourceRaw.Resource.Missing' = 'Missing required parameter ScopeObject'#
'Remove-AzResourceRaw.Resource.CheckExistence' = 'Checking existence after deletion of: [{0}]'# $FullyQualifiedResourceId
'Remove-AzResourceRaw.Resource.Failed' = 'Unable to delete resource of type {0} with id {1}'# $ScopeObject.Resource, $ScopeObject.Scope
'Remove-AzResourceRawRecursive.Processing' = 'Recursive retry processing to delete resource of type {0} with id {1}'# $item.ScopeObject.Resource, $item.ScopeObject.Scope
Expand Down

0 comments on commit 7191fee

Please sign in to comment.