Skip to content

Sync eng/common directory with azure-sdk-tools for PR 14973#7051

Open
azure-sdk wants to merge 2 commits intomainfrom
sync-eng/common-storage/supportSoftDeletedBlobsDuringResourceCleanup-14973
Open

Sync eng/common directory with azure-sdk-tools for PR 14973#7051
azure-sdk wants to merge 2 commits intomainfrom
sync-eng/common-storage/supportSoftDeletedBlobsDuringResourceCleanup-14973

Conversation

@azure-sdk
Copy link
Copy Markdown
Collaborator

Sync eng/common directory with azure-sdk-tools for PR Azure/azure-sdk-tools#14973 See eng/common workflow

ibrandes and others added 2 commits April 8, 2026 18:27
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@azure-sdk azure-sdk requested review from Copilot and ibrandes April 8, 2026 18:39
@azure-sdk azure-sdk requested a review from a team as a code owner April 8, 2026 18:39
@azure-sdk azure-sdk added EngSys This issue is impacting the engineering system. Central-EngSys This issue is owned by the Engineering System team. labels Apr 8, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Syncs eng/common with azure-sdk-tools PR 14973 by improving storage account cleanup, specifically handling VLW (versioned immutability) containers where soft-delete/versioning can leave non-current versions that block container deletion.

Changes:

  • Detect VLW containers during storage account removal and apply version-aware cleanup.
  • Add Remove-VlwContainerBlobs to enumerate and delete versions/soft-deleted blobs while clearing holds/policies.
  • Update blob deletion loop to route VLW containers through the new cleanup path.

Comment on lines +551 to +559
try { $blob | Set-AzStorageBlobLegalHold -DisableLegalHold | Out-Null } catch { }
try { $blob | Remove-AzStorageBlobImmutabilityPolicy | Out-Null } catch { }
try {
$blob | Remove-AzStorageBlob -Force
} catch {
# Deleting the current version by version ID returns 403
# (OperationNotAllowedOnRootBlob); fall back to base blob deletion.
try {
Remove-AzStorageBlob -Container $Container.Name -Blob $blob.Name -Context $Container.Context -Force
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These try/catch blocks likely won’t behave as intended because many Az cmdlets emit non-terminating errors by default, which won’t be caught by catch. As a result, the fallback deletion path may never run (and the earlier suppression catches may not suppress anything). Add -ErrorAction Stop to the cmdlets you expect to throw so failures are caught deterministically.

Suggested change
try { $blob | Set-AzStorageBlobLegalHold -DisableLegalHold | Out-Null } catch { }
try { $blob | Remove-AzStorageBlobImmutabilityPolicy | Out-Null } catch { }
try {
$blob | Remove-AzStorageBlob -Force
} catch {
# Deleting the current version by version ID returns 403
# (OperationNotAllowedOnRootBlob); fall back to base blob deletion.
try {
Remove-AzStorageBlob -Container $Container.Name -Blob $blob.Name -Context $Container.Context -Force
try { $blob | Set-AzStorageBlobLegalHold -DisableLegalHold -ErrorAction Stop | Out-Null } catch { }
try { $blob | Remove-AzStorageBlobImmutabilityPolicy -ErrorAction Stop | Out-Null } catch { }
try {
$blob | Remove-AzStorageBlob -Force -ErrorAction Stop
} catch {
# Deleting the current version by version ID returns 403
# (OperationNotAllowedOnRootBlob); fall back to base blob deletion.
try {
Remove-AzStorageBlob -Container $Container.Name -Blob $blob.Name -Context $Container.Context -Force -ErrorAction Stop

Copilot uses AI. Check for mistakes.
try { $blob | Set-AzStorageBlobLegalHold -DisableLegalHold | Out-Null } catch { }
try { $blob | Remove-AzStorageBlobImmutabilityPolicy | Out-Null } catch { }
try {
$blob | Remove-AzStorageBlob -Force
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deletion relies on pipeline binding from the objects returned by Get-AzStorageBlob -IncludeVersion -IncludeDeleted. This is brittle across Az.Storage versions and can result in deleting only the base blob while leaving versions (or not targeting the intended version). Prefer calling Remove-AzStorageBlob with explicit -Container, -Blob, -Context, and (when present) -VersionId from the enumerated item, so each specific version/soft-deleted entry is unambiguously targeted.

Suggested change
$blob | Remove-AzStorageBlob -Force
if ($blob.VersionId) {
Remove-AzStorageBlob -Container $Container.Name -Blob $blob.Name -Context $Container.Context -VersionId $blob.VersionId -Force
} else {
Remove-AzStorageBlob -Container $Container.Name -Blob $blob.Name -Context $Container.Context -Force
}

Copilot uses AI. Check for mistakes.
Comment on lines +542 to +565
for ($round = 0; $round -lt 5; $round++) {
$found = $false
$blobs = @($Container | Get-AzStorageBlob -IncludeVersion -IncludeDeleted -ErrorAction SilentlyContinue)

foreach ($blob in $blobs) {
$found = $true

# Unconditionally clear legal holds and immutability policies. Errors are expected for
# soft-deleted blobs or blobs that don't have these set.
try { $blob | Set-AzStorageBlobLegalHold -DisableLegalHold | Out-Null } catch { }
try { $blob | Remove-AzStorageBlobImmutabilityPolicy | Out-Null } catch { }
try {
$blob | Remove-AzStorageBlob -Force
} catch {
# Deleting the current version by version ID returns 403
# (OperationNotAllowedOnRootBlob); fall back to base blob deletion.
try {
Remove-AzStorageBlob -Container $Container.Name -Blob $blob.Name -Context $Container.Context -Force
} catch { }
}
}

if (-not $found) { break }
}
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The combination of -ErrorAction SilentlyContinue on the listing call plus empty catch { } blocks can cause the cleanup to silently do nothing on auth/transient/storage errors (e.g., if Get-AzStorageBlob fails and returns nothing, $found stays false and the function exits). Consider surfacing at least a warning when the list call fails, and/or using -ErrorAction Stop with a catch that logs the exception message for unexpected failures while still ignoring known/expected cases.

Copilot uses AI. Check for mistakes.
Comment on lines +538 to +542
# new non-current versions that surface after each round of deletions.
function Remove-VlwContainerBlobs($Container, $StorageAccountName, $ResourceGroupName) {
Write-Host "Cleaning VLW container '$($Container.Name)' versions and soft-deleted blobs in account '$StorageAccountName', group: $ResourceGroupName"

for ($round = 0; $round -lt 5; $round++) {
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The max pass count 5 is a magic number that controls correctness for eventual consistency scenarios. To make this easier to tune and reason about, consider promoting it to a named constant/parameter (e.g., -MaxRounds) and documenting why that value is sufficient; optionally add a small delay/backoff between rounds if propagation timing is the reason multiple passes are needed.

Suggested change
# new non-current versions that surface after each round of deletions.
function Remove-VlwContainerBlobs($Container, $StorageAccountName, $ResourceGroupName) {
Write-Host "Cleaning VLW container '$($Container.Name)' versions and soft-deleted blobs in account '$StorageAccountName', group: $ResourceGroupName"
for ($round = 0; $round -lt 5; $round++) {
# new non-current versions that surface after each round of deletions. Default to 5 rounds to
# avoid unbounded retries while still covering expected propagation behavior; callers can raise
# the limit for slower eventual-consistency scenarios.
function Remove-VlwContainerBlobs($Container, $StorageAccountName, $ResourceGroupName, [int] $MaxRounds = 5) {
Write-Host "Cleaning VLW container '$($Container.Name)' versions and soft-deleted blobs in account '$StorageAccountName', group: $ResourceGroupName"
for ($round = 0; $round -lt $MaxRounds; $round++) {

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Central-EngSys This issue is owned by the Engineering System team. EngSys This issue is impacting the engineering system.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants