fix: stop SIG image-version GC from deleting every untagged version - #9397
fix: stop SIG image-version GC from deleting every untagged version#9397Ganeshkumar Ashokavardhanan (ganeshkumarashok) wants to merge 1 commit into
Conversation
vhdbuilder/packer/cleanup.sh ages off SIG image versions with
jq --arg dl $deadline '.[] | select(.tags.now < $dl).name'
but SIG image versions never carry a "now" tag. Packer applies azure_tags
to the managed image only; the shared_image_gallery_destination block has
no tags. So .tags.now is null for every version, and in jq null compares
less than any string, making the filter unconditionally true.
The result is that the "delete versions older than 168 hours" pass really
deletes the first 15 versions of every image definition in the gallery on
every linuxVhdMode build, regardless of age, including versions created
minutes earlier. Only the resource-lock check limited the damage.
The adjacent managed-image loop already guards with select(.tags.now !=
null) -- and managed images genuinely do carry the tag, so that loop is
correct. windows-sub-cleanup.sh already ages SIG versions off
publishingProfile.publishedDate. This aligns cleanup.sh with both.
Also fix the 2404gen2arm64gbcontainerd exemption, which additionally
required the version to start with "1.1.". GB builds moved to 1.2.x, so
the exemption silently stopped protecting anything and versions
1.2.103-1.2.106 were collected. It now matches the image definition.
Observed in ADO build 179633029, where a failed AzureLinuxV3gen1 build
ran cleanup and deleted 39 SIG versions across 2404gen2arm64gbcontainerd,
flatcargen2, flatcargen2arm64 and five Windows definitions.
Windows Unit Test Results 3 files 13 suites 51s ⏱️ Results for commit 3781e5e. |
There was a problem hiding this comment.
🟡 Changes recommended
The destructive cleanup behavior and expanded exemption need automated ShellSpec regression coverage.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Fixes SIG image-version garbage collection to prevent deletion of recent or protected images.
Changes:
- Uses
publishedDatewith null handling for age checks. - Protects all GB image versions regardless of version prefix.
File summaries
| File | Description |
|---|---|
vhdbuilder/packer/cleanup.sh |
Corrects SIG age filtering and GB exemptions. |
Review details
Suppressed comments (1)
vhdbuilder/packer/cleanup.sh:183
- 🟡 Medium Risk — 🧪 Test Coverage: Removing the version condition materially broadens a deletion exemption, but no automated case locks in that both legacy
1.1.xand current1.2.xGB versions remain protected. Please cover those versions (and a non-GB definition) in ShellSpec so the exemption cannot silently become dead or over-broad again.
if [ "${image_definition,,}" = "2404gen2arm64gbcontainerd" ]; then
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| set +x | ||
| for image_definition in $(az sig image-definition list -g ${AZURE_RESOURCE_GROUP_NAME} -r ${SIG_GALLERY_NAME} | jq '.[].name' | tr -d '\"' || ""); do | ||
| for image_version in $(az sig image-version list -g ${AZURE_RESOURCE_GROUP_NAME} -r ${SIG_GALLERY_NAME} -i ${image_definition} | jq --arg dl $deadline '.[] | select(.tags.now < $dl).name' | head -n 15 | tr -d '\"' || ""); do | ||
| for image_version in $(az sig image-version list -g ${AZURE_RESOURCE_GROUP_NAME} -r ${SIG_GALLERY_NAME} -i ${image_definition} | jq --arg dl "$publishedDateDeadline" '.[] | select(.publishingProfile.publishedDate != null) | select(.publishingProfile.publishedDate < $dl).name' | head -n 15 | tr -d '\"' || ""); do |
| # NOTE: this deliberately matches the whole image definition. It previously also required the | ||
| # version to start with "1.1.", which silently stopped protecting anything once GB builds moved | ||
| # to 1.2.x, and 1.2.103-1.2.106 were garbage collected as a result. | ||
| if [ "${image_definition,,}" = "2404gen2arm64gbcontainerd" ]; then |
There was a problem hiding this comment.
This will never cleanup anything filling up the gallery which is already full of use 1.X at a minimum and add a logic that forces 1.X for the version. Blocks someone from creating 2.x
ADO build 179633029 deleted 39 SIG image versions — including
2404gen2arm64gbcontainerd1.2.103–1.2.106 (the GB200/GB300 images), 30 Flatcar versions, and five Windows definitions — from a failedAzureLinuxV3gen1build that never produced an image.Root cause
vhdbuilder/packer/cleanup.shages off SIG image versions with:SIG image versions never carry a
nowtag. Packer appliesazure_tags(which is wherenowcomes from) to the managed image; theshared_image_gallery_destinationblock has no tags at all — seevhd-image-builder-arm64-gb.jsonand every other template.So
.tags.nowisnullfor every version, and in jqnullsorts below every string:The filter is therefore unconditionally true. The "delete versions older than 168 hours" pass actually deletes the first 15 versions of every image definition in the gallery, on every
linuxVhdModebuild, regardless of age — including versions created minutes earlier. Only the resource-lock check limited the blast radius.Reproduced against a fixture (deadline
2026-08-27):1.2.1031.2.9991.1755629795.32733260819.045326.24524Fix
Age SIG versions off
publishingProfile.publishedDate, which ARM always populates, with a null guard so anything lacking it is skipped rather than swept.Two existing precedents in this repo confirm the shape of the fix:
select(.tags.now != null)— and managed images genuinely do carry the tag (packerazure_tags), so that loop is correct as-is and is left alone;.pipelines/scripts/windows-sub-cleanup.sh:105already ages SIG versions offpublishingProfile.publishedDate.This aligns
cleanup.shwith both.Second defect: the GB exemption was dead
The exemption also required the version to start with
1.1.. GB builds moved to1.2.x, so it silently stopped protecting anything, which is why1.2.103–1.2.106were collected despite the guard being present. It now matches on the image definition, per the existingTODO(protect GB until it is released to official production galleries).1.1.991.2.103–1.2.107Testing
bash -nclean.shellcheckrun exactly asverify_shell.shinvokes it (bash mode, repo ignore list): exit 0 before and after; no new findings.SC3014count actually drops 5 → 4 since a[[ ]]is removed.az sig image-version listoutput (table above).date -u -d "@1787873664" +%Y-%m-%dT%H:%M:%SZ→2026-08-27T23:34:24Z, verified with GNU date, matching the deadline in the failing run. ISO-8601 UTC compares correctly against ARM's...+00:00form.Note on scope
This does not change the behaviour of the managed-image loop, the resource-group loops, or the storage-account loop; those operate on resources that really are tagged with
now.