Skip to content

Commit e47d04b

Browse files
azure-sdkibrandesCopilot
authored
Sync eng/common directory with azure-sdk-tools for PR 14973 (#46199)
* adding support for soft deleted blobs and blob versions during resource cleanup * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Isabelle <ibrandes@microsoft.com> Co-authored-by: Isabelle <141270045+ibrandes@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent da39271 commit e47d04b

1 file changed

Lines changed: 47 additions & 6 deletions

File tree

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

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,11 +434,17 @@ function RemoveStorageAccount($Account) {
434434

435435
try {
436436
foreach ($container in $containers) {
437-
$blobs = $container | Get-AzStorageBlob
438-
foreach ($blob in $blobs) {
439-
$shouldDelete = EnableBlobDeletion -Blob $blob -Container $container -StorageAccountName $Account.StorageAccountName -ResourceGroupName $Account.ResourceGroupName
440-
if ($shouldDelete) {
441-
$deleteNow += $blob
437+
# VLW containers need version-aware cleanup: soft-delete causes deleted blobs to linger
438+
# as non-current versions that block container deletion. See Remove-VlwContainerBlobs.
439+
if (($container | Get-Member 'BlobContainerProperties') -and $container.BlobContainerProperties.HasImmutableStorageWithVersioning) {
440+
Remove-VlwContainerBlobs -Container $container -StorageAccountName $Account.StorageAccountName -ResourceGroupName $Account.ResourceGroupName
441+
} else {
442+
$blobs = $container | Get-AzStorageBlob
443+
foreach ($blob in $blobs) {
444+
$shouldDelete = EnableBlobDeletion -Blob $blob -Container $container -StorageAccountName $Account.StorageAccountName -ResourceGroupName $Account.ResourceGroupName
445+
if ($shouldDelete) {
446+
$deleteNow += $blob
447+
}
442448
}
443449
}
444450
}
@@ -524,6 +530,41 @@ function EnableBlobDeletion($Blob, $Container, $StorageAccountName, $ResourceGro
524530
return $forceBlobDeletion
525531
}
526532

533+
# In VLW (Versioned-Level WORM) containers with soft-delete enabled, deleting a blob creates a
534+
# non-current version instead of truly removing it. A standard Get-AzStorageBlob listing can't
535+
# see these leftovers, but they still block container deletion (409 Conflict on the management
536+
# plane DELETE). Listing with -IncludeVersion -IncludeDeleted makes them visible so we can clear
537+
# immutability policies / legal holds and delete each version individually. Multiple passes handle
538+
# new non-current versions that surface after each round of deletions.
539+
function Remove-VlwContainerBlobs($Container, $StorageAccountName, $ResourceGroupName) {
540+
Write-Host "Cleaning VLW container '$($Container.Name)' versions and soft-deleted blobs in account '$StorageAccountName', group: $ResourceGroupName"
541+
542+
for ($round = 0; $round -lt 5; $round++) {
543+
$found = $false
544+
$blobs = @($Container | Get-AzStorageBlob -IncludeVersion -IncludeDeleted -ErrorAction SilentlyContinue)
545+
546+
foreach ($blob in $blobs) {
547+
$found = $true
548+
549+
# Unconditionally clear legal holds and immutability policies. Errors are expected for
550+
# soft-deleted blobs or blobs that don't have these set.
551+
try { $blob | Set-AzStorageBlobLegalHold -DisableLegalHold | Out-Null } catch { }
552+
try { $blob | Remove-AzStorageBlobImmutabilityPolicy | Out-Null } catch { }
553+
try {
554+
$blob | Remove-AzStorageBlob -Force
555+
} catch {
556+
# Deleting the current version by version ID returns 403
557+
# (OperationNotAllowedOnRootBlob); fall back to base blob deletion.
558+
try {
559+
Remove-AzStorageBlob -Container $Container.Name -Blob $blob.Name -Context $Container.Context -Force
560+
} catch { }
561+
}
562+
}
563+
564+
if (-not $found) { break }
565+
}
566+
}
567+
527568
function DoesSubnetOverlap([string]$ipOrCidr, [string]$overlapIp) {
528569
[System.Net.IPAddress]$overlapIpAddress = $overlapIp
529570
$parsed = $ipOrCidr -split '/'
@@ -543,4 +584,4 @@ function DoesSubnetOverlap([string]$ipOrCidr, [string]$overlapIp) {
543584
}
544585

545586
return $baseIp.Address -eq ($overlapIpAddress.Address -band ([System.Net.IPAddress]$mask).Address)
546-
}
587+
}

0 commit comments

Comments
 (0)