Skip to content

Commit 13908cf

Browse files
azure-sdkheaths
andauthored
Sync eng/common directory with azure-sdk-tools for PR 1912 (#20340)
* Attempt to purge all vaults, managed HSMs Reverts #1910. Vaults and managed HSMs are automatically purged on their purge date. The point was to purge them daily to preserve capacity. The default purge date is +90 days. * Add timeout and more logging * Pass required -Resource * Fix log message * Ensure the $Resource is correctly captured Added comment to new code explaining why, since ScriptBlock.GetNewClosure() is not working as expected. * Add -ErrorAction to Receive-Job Worked without terminating when run locally, but failed on the first error in the AzDO agent. * Use $using:r instead of creating ScriptBlock More idiomatic for passing ScriptBlocks to jobs. * Resolve PR feedback * Change default DeleteAfterHours to 120 Resolves #1917 * Use the Az cmdlets built-in -AsJob Co-authored-by: Heath Stewart <[email protected]>
1 parent bb1f601 commit 13908cf

File tree

3 files changed

+102
-43
lines changed

3 files changed

+102
-43
lines changed

eng/common/TestResources/New-TestResources.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ param (
5050

5151
[Parameter()]
5252
[ValidateRange(1, [int]::MaxValue)]
53-
[int] $DeleteAfterHours = 48,
53+
[int] $DeleteAfterHours = 120,
5454

5555
[Parameter()]
5656
[string] $Location = '',

eng/common/TestResources/New-TestResources.ps1.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ Aliases:
307307

308308
Required: False
309309
Position: Named
310-
Default value: 48
310+
Default value: 120
311311
Accept pipeline input: False
312312
Accept wildcard characters: False
313313
```

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

Lines changed: 100 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,48 +7,42 @@ function Get-PurgeableGroupResources {
77
)
88
$purgeableResources = @()
99

10+
# Discover Managed HSMs first since they are a premium resource.
11+
Write-Verbose "Retrieving deleted Managed HSMs from resource group $ResourceGroupName"
12+
13+
# Get any Managed HSMs in the resource group, for which soft delete cannot be disabled.
14+
$deletedHsms = Get-AzKeyVaultManagedHsm -ResourceGroupName $ResourceGroupName -ErrorAction Ignore `
15+
| Add-Member -MemberType NoteProperty -Name AzsdkResourceType -Value 'Managed HSM' -PassThru `
16+
| Add-Member -MemberType AliasProperty -Name AzsdkName -Value VaultName -PassThru
17+
18+
if ($deletedHsms) {
19+
Write-Verbose "Found $($deletedHsms.Count) deleted Managed HSMs to potentially purge."
20+
$purgeableResources += $deletedHsms
21+
}
22+
1023
Write-Verbose "Retrieving deleted Key Vaults from resource group $ResourceGroupName"
1124

1225
# Get any Key Vaults that will be deleted so they can be purged later if soft delete is enabled.
1326
$deletedKeyVaults = Get-AzKeyVault -ResourceGroupName $ResourceGroupName -ErrorAction Ignore | ForEach-Object {
1427
# Enumerating vaults from a resource group does not return all properties we required.
1528
Get-AzKeyVault -VaultName $_.VaultName -ErrorAction Ignore | Where-Object { $_.EnableSoftDelete } `
16-
| Add-Member -MemberType NoteProperty -Name AzsdkResourceType -Value 'Key Vault' -PassThru
17-
}
29+
| Add-Member -MemberType NoteProperty -Name AzsdkResourceType -Value 'Key Vault' -PassThru `
30+
| Add-Member -MemberType AliasProperty -Name AzsdkName -Value VaultName -PassThru
31+
}
1832

1933
if ($deletedKeyVaults) {
2034
Write-Verbose "Found $($deletedKeyVaults.Count) deleted Key Vaults to potentially purge."
2135
$purgeableResources += $deletedKeyVaults
2236
}
2337

24-
Write-Verbose "Retrieving deleted Managed HSMs from resource group $ResourceGroupName"
25-
26-
# Get any Managed HSMs in the resource group, for which soft delete cannot be disabled.
27-
$deletedHsms = Get-AzKeyVaultManagedHsm -ResourceGroupName $ResourceGroupName -ErrorAction Ignore `
28-
| Add-Member -MemberType NoteProperty -Name AzsdkResourceType -Value 'Managed HSM' -PassThru
29-
30-
if ($deletedHsms) {
31-
Write-Verbose "Found $($deletedHsms.Count) deleted Managed HSMs to potentially purge."
32-
$purgeableResources += $deletedHsms
33-
}
34-
3538
return $purgeableResources
3639
}
40+
3741
function Get-PurgeableResources {
3842
$purgeableResources = @()
3943
$subscriptionId = (Get-AzContext).Subscription.Id
4044

41-
Write-Verbose "Retrieving deleted Key Vaults from subscription $subscriptionId"
42-
43-
# Get deleted Key Vaults for the current subscription.
44-
$deletedKeyVaults = Get-AzKeyVault -InRemovedState `
45-
| Add-Member -MemberType NoteProperty -Name AzsdkResourceType -Value 'Key Vault' -PassThru
46-
47-
if ($deletedKeyVaults) {
48-
Write-Verbose "Found $($deletedKeyVaults.Count) deleted Key Vaults to potentially purge."
49-
$purgeableResources += $deletedKeyVaults
50-
}
51-
45+
# Discover Managed HSMs first since they are a premium resource.
5246
Write-Verbose "Retrieving deleted Managed HSMs from subscription $subscriptionId"
5347

5448
# Get deleted Managed HSMs for the current subscription.
@@ -60,6 +54,7 @@ function Get-PurgeableResources {
6054
foreach ($r in $content.value) {
6155
$deletedHsms += [pscustomobject] @{
6256
AzsdkResourceType = 'Managed HSM'
57+
AzsdkName = $r.name
6358
Id = $r.id
6459
Name = $r.name
6560
Location = $r.properties.location
@@ -75,6 +70,18 @@ function Get-PurgeableResources {
7570
}
7671
}
7772

73+
Write-Verbose "Retrieving deleted Key Vaults from subscription $subscriptionId"
74+
75+
# Get deleted Key Vaults for the current subscription.
76+
$deletedKeyVaults = Get-AzKeyVault -InRemovedState `
77+
| Add-Member -MemberType NoteProperty -Name AzsdkResourceType -Value 'Key Vault' -PassThru `
78+
| Add-Member -MemberType AliasProperty -Name AzsdkName -Value VaultName -PassThru
79+
80+
if ($deletedKeyVaults) {
81+
Write-Verbose "Found $($deletedKeyVaults.Count) deleted Key Vaults to potentially purge."
82+
$purgeableResources += $deletedKeyVaults
83+
}
84+
7885
return $purgeableResources
7986
}
8087

@@ -83,7 +90,14 @@ function Get-PurgeableResources {
8390
filter Remove-PurgeableResources {
8491
param (
8592
[Parameter(Position=0, ValueFromPipeline=$true)]
86-
[object[]] $Resource
93+
[object[]] $Resource,
94+
95+
[Parameter()]
96+
[ValidateRange(1, [int]::MaxValue)]
97+
[int] $Timeout = 30,
98+
99+
[Parameter()]
100+
[switch] $PassThru
87101
)
88102

89103
if (!$Resource) {
@@ -93,38 +107,43 @@ filter Remove-PurgeableResources {
93107
$subscriptionId = (Get-AzContext).Subscription.Id
94108

95109
foreach ($r in $Resource) {
110+
Log "Attempting to purge $($r.AzsdkResourceType) '$($r.AzsdkName)'"
96111
switch ($r.AzsdkResourceType) {
97112
'Key Vault' {
98-
Log "Attempting to purge $($r.AzsdkResourceType) '$($r.VaultName)'"
99113
if ($r.EnablePurgeProtection) {
100-
# We will try anyway but will ignore errors
114+
# We will try anyway but will ignore errors.
101115
Write-Warning "Key Vault '$($r.VaultName)' has purge protection enabled and may not be purged for $($r.SoftDeleteRetentionInDays) days"
102116
}
103117

104-
Remove-AzKeyVault -VaultName $r.VaultName -Location $r.Location -InRemovedState -Force -ErrorAction Continue
118+
# Use `-AsJob` to start a lightweight, cancellable job and pass to `Wait-PurgeableResoruceJob` for consistent behavior.
119+
Remove-AzKeyVault -VaultName $r.VaultName -Location $r.Location -InRemovedState -Force -ErrorAction Continue -AsJob `
120+
| Wait-PurgeableResourceJob -Resource $r -Timeout $Timeout -PassThru:$PassThru
105121
}
106122

107123
'Managed HSM' {
108-
Log "Attempting to purge $($r.AzsdkResourceType) '$($r.Name)'"
109124
if ($r.EnablePurgeProtection) {
110-
# We will try anyway but will ignore errors
125+
# We will try anyway but will ignore errors.
111126
Write-Warning "Managed HSM '$($r.Name)' has purge protection enabled and may not be purged for $($r.SoftDeleteRetentionInDays) days"
112127
}
113128

114-
$response = Invoke-AzRestMethod -Method POST -Path "/subscriptions/$subscriptionId/providers/Microsoft.KeyVault/locations/$($r.Location)/deletedManagedHSMs/$($r.Name)/purge?api-version=2021-04-01-preview" -ErrorAction Ignore
115-
if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 300) {
116-
Write-Warning "Successfully requested that Managed HSM '$($r.Name)' be purged, but may take a few minutes before it is actually purged."
117-
} elseif ($response.Content) {
118-
$content = $response.Content | ConvertFrom-Json
119-
if ($content.error) {
120-
$err = $content.error
121-
Write-Warning "Failed to deleted Managed HSM '$($r.Name)': ($($err.code)) $($err.message)"
122-
}
123-
}
129+
# Use `GetNewClosure()` on the `-Action` ScriptBlock to make sure variables are captured.
130+
Invoke-AzRestMethod -Method POST -Path "/subscriptions/$subscriptionId/providers/Microsoft.KeyVault/locations/$($r.Location)/deletedManagedHSMs/$($r.Name)/purge?api-version=2021-04-01-preview" -ErrorAction Ignore -AsJob `
131+
| Wait-PurgeableResourceJob -Resource $r -Timeout $Timeout -PassThru:$PassThru -Action {
132+
param ( $response )
133+
if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 300) {
134+
Write-Warning "Successfully requested that Managed HSM '$($r.Name)' be purged, but may take a few minutes before it is actually purged."
135+
} elseif ($response.Content) {
136+
$content = $response.Content | ConvertFrom-Json
137+
if ($content.error) {
138+
$err = $content.error
139+
Write-Warning "Failed to deleted Managed HSM '$($r.Name)': ($($err.code)) $($err.message)"
140+
}
141+
}
142+
}.GetNewClosure()
124143
}
125144

126145
default {
127-
Write-Warning "Cannot purge resource type $($r.AzsdkResourceType). Add support to https://github.com/Azure/azure-sdk-tools/blob/main/eng/common/scripts/Helpers/Resource-Helpers.ps1."
146+
Write-Warning "Cannot purge $($r.AzsdkResourceType) '$($r.AzsdkName)'. Add support to https://github.com/Azure/azure-sdk-tools/blob/main/eng/common/scripts/Helpers/Resource-Helpers.ps1."
128147
}
129148
}
130149
}
@@ -134,3 +153,43 @@ filter Remove-PurgeableResources {
134153
function Log($Message) {
135154
Write-Host ('{0} - {1}' -f [DateTime]::Now.ToLongTimeString(), $Message)
136155
}
156+
157+
function Wait-PurgeableResourceJob {
158+
param (
159+
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
160+
$Job,
161+
162+
# The resource is used for logging and to return if `-PassThru` is specified
163+
# so we can easily see all resources that may be in a bad state when the script has completed.
164+
[Parameter(Mandatory=$true)]
165+
$Resource,
166+
167+
# Optional ScriptBlock should define params corresponding to the associated job's `Output` property.
168+
[Parameter()]
169+
[scriptblock] $Action,
170+
171+
[Parameter()]
172+
[ValidateRange(1, [int]::MaxValue)]
173+
[int] $Timeout = 30,
174+
175+
[Parameter()]
176+
[switch] $PassThru
177+
)
178+
179+
$null = Wait-Job -Job $Job -Timeout $Timeout
180+
181+
if ($Job.State -eq 'Completed' -or $Job.State -eq 'Failed') {
182+
$result = Receive-Job -Job $Job -ErrorAction Continue
183+
184+
if ($Action) {
185+
$null = $Action.Invoke($result)
186+
}
187+
} else {
188+
Write-Warning "Timed out waiting to purge $($Resource.AzsdkResourceType) '$($Resource.AzsdkName)'. Cancelling job."
189+
$Job.Cancel()
190+
191+
if ($PassThru) {
192+
$Resource
193+
}
194+
}
195+
}

0 commit comments

Comments
 (0)