Skip to content

Commit 8bb877d

Browse files
azure-sdkbenbp
andauthored
Reduce unnecessary delete calls to ARM for storage accounts (Azure#1888)
Co-authored-by: Ben Broderick Phillips <[email protected]>
1 parent 9bc2dae commit 8bb877d

File tree

1 file changed

+93
-97
lines changed

1 file changed

+93
-97
lines changed

eng/common/scripts/Helpers/Resource-Helpers.ps1

Lines changed: 93 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -232,104 +232,10 @@ function Remove-WormStorageAccounts() {
232232
foreach ($group in $groups) {
233233
Write-Host "========================================="
234234
$accounts = Get-AzStorageAccount -ResourceGroupName $group.ResourceGroupName
235-
if ($accounts) {
236-
foreach ($account in $accounts) {
237-
if ($WhatIfPreference) {
238-
Write-Host "What if: Removing $($account.StorageAccountName) in $($account.ResourceGroupName)"
239-
}
240-
else {
241-
Write-Host "Removing $($account.StorageAccountName) in $($account.ResourceGroupName)"
242-
}
243-
244-
$hasContainers = ($account.Kind -ne "FileStorage")
245-
246-
# If it doesn't have containers then we can skip the explicit clean-up of this storage account
247-
if (!$hasContainers) { continue }
248-
249-
$ctx = New-AzStorageContext -StorageAccountName $account.StorageAccountName
250-
$containers = $ctx | Get-AzStorageContainer
251-
$blobs = $containers | Get-AzStorageBlob
252-
253-
$immutableBlobs = $containers `
254-
| Where-Object { $_.BlobContainerProperties.HasImmutableStorageWithVersioning } `
255-
| Get-AzStorageBlob
256-
try {
257-
foreach ($blob in $immutableBlobs) {
258-
# We can't edit blobs with customer encryption without using that key
259-
# so just try to delete them fully instead. It is unlikely they
260-
# will also have a legal hold enabled.
261-
if (($blob | Get-Member 'ListBlobProperties') `
262-
-and $blob.ListBlobProperties.Properties.CustomerProvidedKeySha256) {
263-
Write-Host "Removing customer encrypted blob: $($blob.Name), account: $($account.StorageAccountName), group: $($group.ResourceGroupName)"
264-
$blob | Remove-AzStorageBlob -Force
265-
continue
266-
}
267-
268-
if (!($blob | Get-Member 'BlobProperties')) {
269-
continue
270-
}
271-
272-
if ($blob.BlobProperties.LeaseState -eq 'Leased') {
273-
Write-Host "Breaking blob lease: $($blob.Name), account: $($account.StorageAccountName), group: $($group.ResourceGroupName)"
274-
$blob.ICloudBlob.BreakLease()
275-
}
235+
if (!$accounts) { break }
276236

277-
if ($blob.BlobProperties.HasLegalHold) {
278-
Write-Host "Removing legal hold - blob: $($blob.Name), account: $($account.StorageAccountName), group: $($group.ResourceGroupName)"
279-
$blob | Set-AzStorageBlobLegalHold -DisableLegalHold | Out-Null
280-
}
281-
}
282-
} catch {
283-
Write-Warning "Ensure user has 'Storage Blob Data Owner' RBAC permission on subscription or resource group"
284-
Write-Error $_
285-
throw
286-
}
287-
# Sometimes we get a 404 blob not found but can still delete containers,
288-
# and sometimes we must delete the blob if there's a legal hold.
289-
# Try to remove the blob, but keep running regardless.
290-
$succeeded = $false
291-
for ($attempt = 0; $attempt -lt 2; $attempt++) {
292-
if ($succeeded) {
293-
break
294-
}
295-
296-
try {
297-
foreach ($blob in $blobs) {
298-
if ($blob.BlobProperties.ImmutabilityPolicy.PolicyMode) {
299-
Write-Host "Removing immutability policy - blob: $($blob.Name), account: $($ctx.StorageAccountName), group: $($group.ResourceGroupName)"
300-
$null = $blob | Remove-AzStorageBlobImmutabilityPolicy
301-
}
302-
}
303-
}
304-
catch {}
305-
306-
try {
307-
foreach ($blob in $blobs) {
308-
$blob | Remove-AzStorageBlob -Force
309-
}
310-
$succeeded = $true
311-
}
312-
catch {
313-
Write-Warning "Failed to remove blobs - account: $($ctx.StorageAccountName), group: $($group.ResourceGroupName)"
314-
Write-Warning $_
315-
}
316-
}
317-
318-
try {
319-
# Use AzRm cmdlet as deletion will only work through ARM with the immutability policies defined on the blobs
320-
$containers | ForEach-Object { Remove-AzRmStorageContainer -Name $_.Name -StorageAccountName $ctx.StorageAccountName -ResourceGroupName $group.ResourceGroupName -Force }
321-
} catch {
322-
Write-Warning "Container removal failed. Ignoring the error and trying to delete the storage account."
323-
Write-Warning $_
324-
}
325-
Remove-AzStorageAccount -StorageAccountName $account.StorageAccountName -ResourceGroupName $account.ResourceGroupName -Force
326-
}
327-
}
328-
if ($WhatIfPreference) {
329-
Write-Host "What if: Removing resource group $($group.ResourceGroupName)"
330-
}
331-
else {
332-
Remove-AzResourceGroup -ResourceGroupName $group.ResourceGroupName -Force -AsJob
237+
foreach ($account in $accounts) {
238+
RemoveStorageAccount -Account $account
333239
}
334240
}
335241
}
@@ -401,6 +307,96 @@ function SetStorageNetworkAccessRules([string]$ResourceGroupName, [array]$AllowI
401307
}
402308
}
403309

310+
function RemoveStorageAccount($Account) {
311+
Write-Host ($WhatIfPreference ? 'What if: ' : '') + "Readying $($Account.StorageAccountName) in $($Account.ResourceGroupName) for deletion"
312+
# If it doesn't have containers then we can skip the explicit clean-up of this storage account
313+
if ($Account.Kind -eq "FileStorage") { return }
314+
315+
$containers = New-AzStorageContext -StorageAccountName $Account.StorageAccountName | Get-AzStorageContainer
316+
$blobs = $containers | Get-AzStorageBlob
317+
$deleteNow = @()
318+
319+
try {
320+
foreach ($blob in $blobs) {
321+
$shouldDelete = EnableBlobDeletion -Blob $blob -StorageAccountName $Account.StorageAccountName -ResourceGroupName $Account.ResourceGroupName
322+
if ($shouldDelete) {
323+
$deleteNow += $blob
324+
}
325+
}
326+
} catch {
327+
Write-Warning "Ensure user has 'Storage Blob Data Owner' RBAC permission on subscription or resource group"
328+
Write-Error $_
329+
throw
330+
}
331+
332+
# Blobs with legal holds or immutability policies must be deleted individually
333+
# before the container/account can be deleted
334+
foreach ($blobToDelete in $deleteNow) {
335+
try {
336+
$blobToDelete | Remove-AzStorageBlob -Force
337+
} catch {
338+
Write-Host "Blob removal failed: $($Blob.Name), account: $($Account.storageAccountName), group: $($Account.ResourceGroupName)"
339+
Write-Warning "Ignoring the error and trying to delete the storage account"
340+
Write-Warning $_
341+
}
342+
}
343+
344+
foreach ($container in $containers) {
345+
if ($container.BlobContainerProperties.HasImmutableStorageWithVersioning) {
346+
try {
347+
# Use AzRm cmdlet as deletion will only work through ARM with the immutability policies defined on the blobs
348+
Remove-AzRmStorageContainer -Name $container.Name -StorageAccountName $Account.StorageAccountName -ResourceGroupName $Account.ResourceGroupName -Force
349+
#$container | Remove-AzStorageContainer
350+
} catch {
351+
Write-Host "Container removal failed: $($container.Name), account: $($Account.storageAccountName), group: $($Account.ResourceGroupName)"
352+
Write-Warning "Ignoring the error and trying to delete the storage account"
353+
Write-Warning $_
354+
}
355+
}
356+
}
357+
358+
if ($containers) {
359+
Remove-AzStorageAccount -StorageAccountName $Account.StorageAccountName -ResourceGroupName $Account.ResourceGroupName -Force
360+
}
361+
}
362+
363+
function EnableBlobDeletion($Blob, $StorageAccountName, $ResourceGroupName) {
364+
# Some properties like immutability policies require the blob to be
365+
# deleted before the container can be deleted
366+
$forceBlobDeletion = $false
367+
368+
# We can't edit blobs with customer encryption without using that key
369+
# so just try to delete them fully instead. It is unlikely they
370+
# will also have a legal hold enabled.
371+
if (($Blob | Get-Member 'ListBlobProperties') `
372+
-and $Blob.ListBlobProperties.Properties.CustomerProvidedKeySha256) {
373+
return $true
374+
}
375+
376+
if (!($Blob | Get-Member 'BlobProperties')) {
377+
return $false
378+
}
379+
380+
if ($Blob.BlobProperties.ImmutabilityPolicy.PolicyMode) {
381+
Write-Host "Removing immutability policy - blob: $($Blob.Name), account: $StorageAccountName, group: $ResourceGroupName"
382+
$null = $Blob | Remove-AzStorageBlobImmutabilityPolicy
383+
$forceBlobDeletion = $true
384+
}
385+
386+
if ($Blob.BlobProperties.HasLegalHold) {
387+
Write-Host "Removing legal hold - blob: $($Blob.Name), account: $StorageAccountName, group: $ResourceGroupName"
388+
$Blob | Set-AzStorageBlobLegalHold -DisableLegalHold | Out-Null
389+
$forceBlobDeletion = $true
390+
}
391+
392+
if ($Blob.BlobProperties.LeaseState -eq 'Leased') {
393+
Write-Host "Breaking blob lease: $($Blob.Name), account: $StorageAccountName, group: $ResourceGroupName"
394+
$Blob.ICloudBlob.BreakLease()
395+
}
396+
397+
return $forceBlobDeletion
398+
}
399+
404400
function DoesSubnetOverlap([string]$ipOrCidr, [string]$overlapIp) {
405401
[System.Net.IPAddress]$overlapIpAddress = $overlapIp
406402
$parsed = $ipOrCidr -split '/'

0 commit comments

Comments
 (0)