Skip to content

Commit e55b765

Browse files
authored
v0.8.4: Step.3 advisor enhancements (A/B/C) + Step.6 per-cluster Step Summary + Node 24 opt-in + RBAC role rename + install-step version banner (#73)
* Publish v0.8.4 * v0.8.4 follow-up: correct ADO Step.6 banner count + allow migration-tip line Two Pester drift-test issues found by full-suite execution: 1. ADO Step.6 banner test expected 2 emits per file (one per install step). The second install step (ApplyUpdates stage) deliberately skips ##vso[task.uploadsummary] - there is a comment in the yml explaining that this avoids duplicating the banner in the rendered Summary. Correct the expectation to 1 per yml (10 ADO Summary emits total). 2. RBAC bare-name test flagged the migration-tip blockquote in Automation-Pipeline-Examples/README.md that intentionally quotes "Name": "Azure Stack HCI Update Operator" to explain the rename. Allowlist lines that contain "pre-v0.8.4" - that marker is exclusive to explicit migration documentation. Also correct the stale "11 ADO install sites" claim in: - AzLocal.UpdateManagement/README.md (What's New in v0.8.4) - AzLocal.UpdateManagement/CHANGELOG.md (v0.8.4 section, 2 places) - AzLocal.UpdateManagement/AzLocal.UpdateManagement.psd1 (ReleaseNotes) Accurate description: one banner per yml across all 20 bundled Step.{0..9}.yml templates (Step.6 ADO has 2 install steps but the second deliberately skips upload to avoid duplicating the banner). Drift subset re-run: 8 Passed, 0 Failed.
1 parent cd77db3 commit e55b765

31 files changed

Lines changed: 1554 additions & 126 deletions

AzLocal.UpdateManagement/Automation-Pipeline-Examples/README.md

Lines changed: 31 additions & 29 deletions
Large diffs are not rendered by default.

AzLocal.UpdateManagement/Automation-Pipeline-Examples/azlocal-update-management-custom-role.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"Name": "Azure Stack HCI Update Operator",
2+
"Name": "Azure Stack HCI Update Operator (custom)",
33
"IsCustom": true,
4-
"Description": "Can read and apply Azure Local cluster updates, manage UpdateRing tags, and read the fleet-connectivity inventory (Arc-enabled machines, edge-device NICs, Azure Resource Bridges) needed to assess pre-update connectivity.",
4+
"Description": "Customer-managed custom role - reference by roleDefinitionId (GUID) in automation rather than by name to remain stable if Microsoft later ships a built-in role with a similar display name. Can read and apply Azure Local cluster updates, manage UpdateRing tags, and read the fleet-connectivity inventory (Arc-enabled machines, edge-device NICs, Azure Resource Bridges) needed to assess pre-update connectivity.",
55
"Actions": [
66
"Microsoft.AzureStackHCI/clusters/read",
77
"Microsoft.AzureStackHCI/clusters/updateSummaries/read",

AzLocal.UpdateManagement/Automation-Pipeline-Examples/azure-devops/Step.0_authentication-test.yml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ variables:
5959
# log if the YAML appears stale - prompting you to refresh via
6060
# Copy-AzLocalPipelineExample -Update. See Automation-Pipeline-Examples/README.md section 5.
6161
- name: GENERATED_AGAINST_MODULE_VERSION
62-
value: '0.8.3'
62+
value: '0.8.4'
6363
# Resolution order for the module version pin (leave all unset to install the latest,
6464
# which is the default "fix-forward" behaviour): queue-time parameter > pipeline variable
6565
# 'REQUIRED_MODULE_VERSION' overridden at queue time > empty (latest).
@@ -130,6 +130,23 @@ stages:
130130
$msg = "AzLocal.UpdateManagement v$latest is available on PSGallery; this run installed v$installed. Review the module CHANGELOG before bumping REQUIRED_MODULE_VERSION (or clear the pin to install the latest automatically)."
131131
Write-Host "##vso[task.logissue type=warning]$msg"
132132
}
133+
134+
# v0.8.4 - one-line version banner uploaded to the build run
135+
# Summary so the YAML version (GENERATED_AGAINST_MODULE_VERSION),
136+
# the module version actually loaded on the agent, the PSGallery
137+
# latest, and the REQUIRED_MODULE_VERSION pin status are visible
138+
# at the top of every run summary without scrolling the agent
139+
# log. Same data is also echoed to the console above.
140+
$pin = if ($env:REQUIRED_MODULE_VERSION) { "pinned to v$($env:REQUIRED_MODULE_VERSION)" } else { 'latest (fix-forward)' }
141+
$latestStr = if ($latest) { "v$latest" } else { '(PSGallery lookup failed)' }
142+
$verdict = if ($installed -lt $generated) { 'YAML newer than module - check REQUIRED_MODULE_VERSION' }
143+
elseif ($installed -gt $generated) { 'YAML older than module - run Copy-AzLocalPipelineExample -Update' }
144+
elseif ($latest -and ($latest -gt $installed)) { 'newer module available on PSGallery' }
145+
else { 'in sync' }
146+
$bannerPath = Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY 'module-version-banner.md'
147+
"_Pipeline YAML v$generated | Module v$installed installed ($pin) | PSGallery latest $latestStr | $verdict_" | Out-File -FilePath $bannerPath -Encoding utf8
148+
Write-Host "##vso[task.uploadsummary]$bannerPath"
149+
133150
# Persist the three versions so the report step (below) can include them
134151
# in the JUnit XML + markdown summary alongside the auth/RBAC checks.
135152
Write-Host "##vso[task.setvariable variable=installedModuleVersion;isOutput=false]$installed"

AzLocal.UpdateManagement/Automation-Pipeline-Examples/azure-devops/Step.1_inventory-clusters.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ variables:
4242
# log if the YAML appears stale - prompting you to refresh via
4343
# Copy-AzLocalPipelineExample -Update. See Automation-Pipeline-Examples/README.md section 5.
4444
- name: GENERATED_AGAINST_MODULE_VERSION
45-
value: '0.8.3'
45+
value: '0.8.4'
4646
# Resolution order for the module version pin (leave all unset to install the latest,
4747
# which is the default "fix-forward" behaviour): queue-time parameter > pipeline variable
4848
# 'REQUIRED_MODULE_VERSION' overridden at queue time > empty (latest).
@@ -114,6 +114,22 @@ stages:
114114
$msg = "AzLocal.UpdateManagement v$latest is available on PSGallery; this run installed v$installed. Review the module CHANGELOG before bumping REQUIRED_MODULE_VERSION (or clear the pin to install the latest automatically)."
115115
Write-Host "##vso[task.logissue type=warning]$msg"
116116
}
117+
118+
# v0.8.4 - one-line version banner uploaded to the build run
119+
# Summary so the YAML version (GENERATED_AGAINST_MODULE_VERSION),
120+
# the module version actually loaded on the agent, the PSGallery
121+
# latest, and the REQUIRED_MODULE_VERSION pin status are visible
122+
# at the top of every run summary without scrolling the agent
123+
# log. Same data is also echoed to the console above.
124+
$pin = if ($env:REQUIRED_MODULE_VERSION) { "pinned to v$($env:REQUIRED_MODULE_VERSION)" } else { 'latest (fix-forward)' }
125+
$latestStr = if ($latest) { "v$latest" } else { '(PSGallery lookup failed)' }
126+
$verdict = if ($installed -lt $generated) { 'YAML newer than module - check REQUIRED_MODULE_VERSION' }
127+
elseif ($installed -gt $generated) { 'YAML older than module - run Copy-AzLocalPipelineExample -Update' }
128+
elseif ($latest -and ($latest -gt $installed)) { 'newer module available on PSGallery' }
129+
else { 'in sync' }
130+
$bannerPath = Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY 'module-version-banner.md'
131+
"_Pipeline YAML v$generated | Module v$installed installed ($pin) | PSGallery latest $latestStr | $verdict_" | Out-File -FilePath $bannerPath -Encoding utf8
132+
Write-Host "##vso[task.uploadsummary]$bannerPath"
117133
118134
- task: AzureCLI@2
119135
displayName: 'Run Cluster Inventory'

AzLocal.UpdateManagement/Automation-Pipeline-Examples/azure-devops/Step.2_manage-updatering-tags.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ variables:
4545
# log if the YAML appears stale - prompting you to refresh via
4646
# Copy-AzLocalPipelineExample -Update. See Automation-Pipeline-Examples/README.md section 5.
4747
- name: GENERATED_AGAINST_MODULE_VERSION
48-
value: '0.8.3'
48+
value: '0.8.4'
4949
# Resolution order for the module version pin (leave all unset to install the latest,
5050
# which is the default "fix-forward" behaviour): queue-time parameter > pipeline variable
5151
# 'REQUIRED_MODULE_VERSION' overridden at queue time > empty (latest).
@@ -206,6 +206,22 @@ stages:
206206
$msg = "AzLocal.UpdateManagement v$latest is available on PSGallery; this run installed v$installed. Review the module CHANGELOG before bumping REQUIRED_MODULE_VERSION (or clear the pin to install the latest automatically)."
207207
Write-Host "##vso[task.logissue type=warning]$msg"
208208
}
209+
210+
# v0.8.4 - one-line version banner uploaded to the build run
211+
# Summary so the YAML version (GENERATED_AGAINST_MODULE_VERSION),
212+
# the module version actually loaded on the agent, the PSGallery
213+
# latest, and the REQUIRED_MODULE_VERSION pin status are visible
214+
# at the top of every run summary without scrolling the agent
215+
# log. Same data is also echoed to the console above.
216+
$pin = if ($env:REQUIRED_MODULE_VERSION) { "pinned to v$($env:REQUIRED_MODULE_VERSION)" } else { 'latest (fix-forward)' }
217+
$latestStr = if ($latest) { "v$latest" } else { '(PSGallery lookup failed)' }
218+
$verdict = if ($installed -lt $generated) { 'YAML newer than module - check REQUIRED_MODULE_VERSION' }
219+
elseif ($installed -gt $generated) { 'YAML older than module - run Copy-AzLocalPipelineExample -Update' }
220+
elseif ($latest -and ($latest -gt $installed)) { 'newer module available on PSGallery' }
221+
else { 'in sync' }
222+
$bannerPath = Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY 'module-version-banner.md'
223+
"_Pipeline YAML v$generated | Module v$installed installed ($pin) | PSGallery latest $latestStr | $verdict_" | Out-File -FilePath $bannerPath -Encoding utf8
224+
Write-Host "##vso[task.uploadsummary]$bannerPath"
209225
210226
- task: AzureCLI@2
211227
displayName: 'Apply UpdateRing Tags'

AzLocal.UpdateManagement/Automation-Pipeline-Examples/azure-devops/Step.3_apply-updates-schedule-audit.yml

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ parameters:
7070
type: boolean
7171
default: true
7272

73+
- name: clusterCsvPath
74+
displayName: 'Path to the source-controlled cluster inventory CSV (the same file Step.2 consumes - default `config/ClusterUpdateRings.csv`). When set, the Recommend view emits a NoWindowTag remediation section: for each cluster missing an UpdateStartWindow tag, the advisor proposes a peer-derived value and tells the operator which row of the CSV to edit (or to re-run Step.1 if the cluster is absent from the CSV). Leave empty to skip the CSV-driven remediation.'
75+
type: string
76+
default: 'config/ClusterUpdateRings.csv'
77+
7378
- name: moduleVersion
7479
displayName: 'Pin AzLocal.UpdateManagement version (empty = latest from PSGallery). See Automation-Pipeline-Examples/README.md section 5 "Optional configuration".'
7580
type: string
@@ -81,7 +86,7 @@ parameters:
8186
default: false
8287

8388
variables:
84-
GENERATED_AGAINST_MODULE_VERSION: '0.8.3'
89+
GENERATED_AGAINST_MODULE_VERSION: '0.8.4'
8590
REQUIRED_MODULE_VERSION: '${{ parameters.moduleVersion }}'
8691
reportsPath: '$(Build.ArtifactStagingDirectory)/reports'
8792

@@ -136,6 +141,22 @@ stages:
136141
Write-Host "##vso[task.logissue type=warning]AzLocal.UpdateManagement v$latest is available on PSGallery; this run installed v$installed."
137142
}
138143
144+
# v0.8.4 - one-line version banner uploaded to the build run
145+
# Summary so the YAML version (GENERATED_AGAINST_MODULE_VERSION),
146+
# the module version actually loaded on the agent, the PSGallery
147+
# latest, and the REQUIRED_MODULE_VERSION pin status are visible
148+
# at the top of every run summary without scrolling the agent
149+
# log. Same data is also echoed to the console above.
150+
$pin = if ($env:REQUIRED_MODULE_VERSION) { "pinned to v$($env:REQUIRED_MODULE_VERSION)" } else { 'latest (fix-forward)' }
151+
$latestStr = if ($latest) { "v$latest" } else { '(PSGallery lookup failed)' }
152+
$verdict = if ($installed -lt $generated) { 'YAML newer than module - check REQUIRED_MODULE_VERSION' }
153+
elseif ($installed -gt $generated) { 'YAML older than module - run Copy-AzLocalPipelineExample -Update' }
154+
elseif ($latest -and ($latest -gt $installed)) { 'newer module available on PSGallery' }
155+
else { 'in sync' }
156+
$bannerPath = Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY 'module-version-banner.md'
157+
"_Pipeline YAML v$generated | Module v$installed installed ($pin) | PSGallery latest $latestStr | $verdict_" | Out-File -FilePath $bannerPath -Encoding utf8
158+
Write-Host "##vso[task.uploadsummary]$bannerPath"
159+
139160
- task: AzureCLI@2
140161
displayName: 'Run Schedule Coverage Audit'
141162
name: audit
@@ -157,6 +178,7 @@ stages:
157178
$leadTime = [int]"${{ parameters.leadTimeMinutes }}"
158179
$firesPerWin = [int]"${{ parameters.firesPerWindow }}"
159180
$includeUnt = ${{ lower(parameters.includeUntagged) }}
181+
$clusterCsv = "${{ parameters.clusterCsvPath }}"
160182
$debug = ('${{ parameters.debug }}' -ieq 'true')
161183
162184
# Debug toggle: flips Verbose/Debug preferences and emits a
@@ -185,6 +207,11 @@ stages:
185207
# no 'required:' keyword, so validate at runtime instead.
186208
$havePipeline = -not [string]::IsNullOrWhiteSpace($pipelinePath)
187209
$haveSchedule = -not [string]::IsNullOrWhiteSpace($schedulePath) -and (Test-Path -LiteralPath $schedulePath)
210+
# v0.8.4: clusterCsvPath is optional. If the file is missing on the agent
211+
# we skip the NoWindowTag remediation section quietly (vs throwing) so the
212+
# pipeline keeps emitting the legacy advisor output for repos that don't
213+
# version-control a cluster CSV yet.
214+
$haveCsv = -not [string]::IsNullOrWhiteSpace($clusterCsv) -and (Test-Path -LiteralPath $clusterCsv)
188215
if (-not $havePipeline) {
189216
throw "pipelinePath parameter is required. Set it to the folder containing Step.6_apply-updates.yml (default '.azure-pipelines' matches the standard consumer layout). The Recommend view diffs its proposed crons against this file - leaving it empty would make every recommendation a false positive."
190217
}
@@ -202,6 +229,7 @@ stages:
202229
Write-Host "LeadTimeMinutes : $leadTime"
203230
Write-Host "FiresPerWindow : $firesPerWin (1 = opening edge only, 2 = belt-and-braces opening + mid-window retry)"
204231
Write-Host "IncludeUntagged : $includeUnt"
232+
Write-Host "ClusterCsvPath : $(if ($haveCsv) { $clusterCsv } else { '(skipped - clusterCsvPath empty or file missing)' })"
205233
Write-Host ""
206234
207235
$auditCsv = Join-Path $outputDir 'schedule-coverage-audit.csv'
@@ -224,12 +252,16 @@ stages:
224252
if ($havePipeline) { $auditArgs.PipelineYamlPath = $pipelinePath }
225253
if ($haveSchedule) { $auditArgs.SchedulePath = $schedulePath }
226254
if ($includeUnt) { $auditArgs.IncludeUntagged = $true }
255+
if ($haveCsv) { $auditArgs.ClusterCsvPath = $clusterCsv }
227256
$auditResult = Test-AzLocalApplyUpdatesScheduleCoverage @auditArgs
228257
if (-not $auditResult) { $auditResult = @() }
229258
230259
Test-AzLocalApplyUpdatesScheduleCoverage -View Matrix -LeadTimeMinutes $leadTime -ExportPath $matrixCsv | Out-Null
231260
# v0.8.3: pass -PipelineYamlPath so Recommend diff-prunes crons
232261
# already present in Step.6 and only emits the truly missing ones.
262+
# v0.8.4: also pass -SchedulePath (so the Cycle calendar +
263+
# Configured exclusion windows informational sections render) and
264+
# -ClusterCsvPath (so the NoWindowTag remediation section renders).
233265
$recoArgs = @{
234266
View = 'Recommend'
235267
LeadTimeMinutes = $leadTime
@@ -238,6 +270,8 @@ stages:
238270
ExportPath = $recoMd
239271
}
240272
if ($havePipeline) { $recoArgs.PipelineYamlPath = $pipelinePath }
273+
if ($haveSchedule) { $recoArgs.SchedulePath = $schedulePath }
274+
if ($haveCsv) { $recoArgs.ClusterCsvPath = $clusterCsv }
241275
Test-AzLocalApplyUpdatesScheduleCoverage @recoArgs | Out-Null
242276
243277
$covered = @($auditResult | Where-Object Status -eq 'Covered')

AzLocal.UpdateManagement/Automation-Pipeline-Examples/azure-devops/Step.4_fleet-connectivity-status.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ variables:
102102
# the version actually installed and to the latest on PSGallery, and emits a warning
103103
# log if the YAML appears stale - prompting you to refresh via
104104
# Copy-AzLocalPipelineExample -Update. See Automation-Pipeline-Examples/README.md section 5.
105-
GENERATED_AGAINST_MODULE_VERSION: '0.8.3'
105+
GENERATED_AGAINST_MODULE_VERSION: '0.8.4'
106106
# Resolution order for the module version pin (leave all unset to install the latest,
107107
# which is the default "fix-forward" behaviour): queue-time parameter > pipeline variable
108108
# 'REQUIRED_MODULE_VERSION' overridden at queue time > empty (latest).
@@ -168,6 +168,22 @@ stages:
168168
Write-Host "##vso[task.logissue type=warning]AzLocal.UpdateManagement v$latest is available on PSGallery; this run installed v$installed."
169169
}
170170
171+
# v0.8.4 - one-line version banner uploaded to the build run
172+
# Summary so the YAML version (GENERATED_AGAINST_MODULE_VERSION),
173+
# the module version actually loaded on the agent, the PSGallery
174+
# latest, and the REQUIRED_MODULE_VERSION pin status are visible
175+
# at the top of every run summary without scrolling the agent
176+
# log. Same data is also echoed to the console above.
177+
$pin = if ($env:REQUIRED_MODULE_VERSION) { "pinned to v$($env:REQUIRED_MODULE_VERSION)" } else { 'latest (fix-forward)' }
178+
$latestStr = if ($latest) { "v$latest" } else { '(PSGallery lookup failed)' }
179+
$verdict = if ($installed -lt $generated) { 'YAML newer than module - check REQUIRED_MODULE_VERSION' }
180+
elseif ($installed -gt $generated) { 'YAML older than module - run Copy-AzLocalPipelineExample -Update' }
181+
elseif ($latest -and ($latest -gt $installed)) { 'newer module available on PSGallery' }
182+
else { 'in sync' }
183+
$bannerPath = Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY 'module-version-banner.md'
184+
"_Pipeline YAML v$generated | Module v$installed installed ($pin) | PSGallery latest $latestStr | $verdict_" | Out-File -FilePath $bannerPath -Encoding utf8
185+
Write-Host "##vso[task.uploadsummary]$bannerPath"
186+
171187
- task: AzureCLI@2
172188
displayName: 'Collect Fleet Connectivity Data'
173189
name: collect

AzLocal.UpdateManagement/Automation-Pipeline-Examples/azure-devops/Step.5_assess-update-readiness.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ variables:
6363
# the version actually installed and to the latest on PSGallery, and emits a warning
6464
# log if the YAML appears stale - prompting you to refresh via
6565
# Copy-AzLocalPipelineExample -Update. See Automation-Pipeline-Examples/README.md section 5.
66-
GENERATED_AGAINST_MODULE_VERSION: '0.8.3'
66+
GENERATED_AGAINST_MODULE_VERSION: '0.8.4'
6767
# Resolution order for the module version pin (leave all unset to install the latest,
6868
# which is the default "fix-forward" behaviour): queue-time parameter > pipeline variable
6969
# 'REQUIRED_MODULE_VERSION' overridden at queue time > empty (latest).
@@ -125,6 +125,22 @@ stages:
125125
Write-Host "##vso[task.logissue type=warning]$msg"
126126
}
127127
128+
# v0.8.4 - one-line version banner uploaded to the build run
129+
# Summary so the YAML version (GENERATED_AGAINST_MODULE_VERSION),
130+
# the module version actually loaded on the agent, the PSGallery
131+
# latest, and the REQUIRED_MODULE_VERSION pin status are visible
132+
# at the top of every run summary without scrolling the agent
133+
# log. Same data is also echoed to the console above.
134+
$pin = if ($env:REQUIRED_MODULE_VERSION) { "pinned to v$($env:REQUIRED_MODULE_VERSION)" } else { 'latest (fix-forward)' }
135+
$latestStr = if ($latest) { "v$latest" } else { '(PSGallery lookup failed)' }
136+
$verdict = if ($installed -lt $generated) { 'YAML newer than module - check REQUIRED_MODULE_VERSION' }
137+
elseif ($installed -gt $generated) { 'YAML older than module - run Copy-AzLocalPipelineExample -Update' }
138+
elseif ($latest -and ($latest -gt $installed)) { 'newer module available on PSGallery' }
139+
else { 'in sync' }
140+
$bannerPath = Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY 'module-version-banner.md'
141+
"_Pipeline YAML v$generated | Module v$installed installed ($pin) | PSGallery latest $latestStr | $verdict_" | Out-File -FilePath $bannerPath -Encoding utf8
142+
Write-Host "##vso[task.uploadsummary]$bannerPath"
143+
128144
- task: AzureCLI@2
129145
displayName: 'Run readiness + blocking health checks'
130146
inputs:

0 commit comments

Comments
 (0)