Skip to content

feat(acl): convert ACL VHDs to COSI and publish to PMC#8848

Draft
adamsanaglo wants to merge 26 commits into
mainfrom
aa/cosi-pmc-reconcile
Draft

feat(acl): convert ACL VHDs to COSI and publish to PMC#8848
adamsanaglo wants to merge 26 commits into
mainfrom
aa/cosi-pmc-reconcile

Conversation

@adamsanaglo

Copy link
Copy Markdown

What this PR does / why we need it:
Builds on the ACL VHD->COSI conversion work to upload the COSI directly to PMC via its AFD upload endpoint under PMC's service connection.

  • Add cmd/cosi-upload, a Go tool that uploads via the Azure Blob SDK's chunked block-blob upload to avoid the single Put Blob size limit on large COSI images.
  • Add upload-cosi-to-pmc.sh and packer.mk targets.
  • convert-vhd-to-cosi.sh stages the COSI for upload; cosi-publishing-info.json uses the AFD download URL and adds sha1.
  • Wire the release pipeline's "Upload COSI to PMC" step and drop the old azcopy copy-to-immutable step.
  • Add azblob and azidentity dependencies.

Which issue(s) this PR fixes:

Fixes #

bfjelds and others added 23 commits June 29, 2026 20:38
Add a post-build pipeline step that converts AzureContainerLinux (ACL) VHD
images to COSI format using ImageCustomizer's convert command (v1.2.0-2).

Changes:
- New script: convert-vhd-to-cosi.sh downloads ACL VHD from blob storage,
  runs ImageCustomizer convert (VHD -> COSI), and uploads the COSI file
- New make target: convert-vhd-to-cosi in packer.mk
- Pipeline vars: set IMG_CUSTOMIZER_CONTAINER and IMG_CUSTOMIZER_VERSION
  on ACL build jobs in both PR and release pipelines
- Builder template: add Convert ACL VHD to COSI step after SIG->classic
  conversion, conditioned on OS_SKU=AzureContainerLinux
- Immutable copy: updated to also copy/remove .cosi files for ACL builds

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the ACL COSI 'az storage blob copy start' from the VHD immutable
copy task into a dedicated task with its own condition gating on
OS_SKU=AzureContainerLinux, rather than using a bash if-block inside
the VHD copy step.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move 'Convert ACL VHD to COSI' task to after 'Copy to Immutable Storage
Container' so the VHD is safely in immutable storage before conversion.
Revert echo to original 'Successfully copied to immutable container'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move 'Copy to Immutable Storage Container' (VHD) after
'Copy COSI to Immutable Storage Container'. New order:
1. Convert ACL VHD to COSI
2. Copy COSI to Immutable Storage Container
3. Copy to Immutable Storage Container (VHD)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use less specific version tag to pick up patch releases automatically.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SIG_SOURCE_GALLERY_UNIQUE_NAME, SIG_SOURCE_IMAGE_NAME, and
SIG_SOURCE_IMAGE_VERSION are set but never consumed by any script
or template in the repo.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
FIPS jobs were missing IMG_CUSTOMIZER_CONTAINER and IMG_CUSTOMIZER_VERSION,
which are required for the COSI conversion step.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Create generate-cosi-publishing-info.sh that writes cosi-publishing-info.json
with the immutable storage URL and image metadata, paralleling
generate-vhd-publishing-info.sh for VHDs.

Pipeline steps added after 'Copy COSI to Immutable Storage Container':
- Generate COSI Publishing Info (bash, no az-login needed)
- Publish COSI Publishing Info (artifact: cosi-publishing-info-{artifactName})

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Generate cosi-publishing-info.json (with sha256, size, cosi_url, and
image metadata) directly in convert-vhd-to-cosi.sh while the COSI
artifact is still on disk. Remove the standalone script and make target.

Pipeline order: Convert + generate info -> Publish artifact -> Copy to immutable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
OS_NAME was referenced in cosi-publishing-info.json but never set.
ACL COSI artifacts are always Linux, so hardcode it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The container entrypoint is already 'imagecustomizer', so the first
argument should be the subcommand 'convert' directly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add an opt-in fallback to convert-vhd-to-cosi.sh so that when the MCR
ImageCustomizer image for the requested version is unavailable, the
script can pull from a configurable fallback registry
(IMG_CUSTOMIZER_CONTAINER_FALLBACK, e.g. ghcr.io/microsoft/imagecustomizer).
The fallback is gated by a script param defaulting to off, normalizes
major.minor versions to major.minor.0 for GHCR's full semver tags, and
is enabled for the ACL COSI conversion step. Bump IMG_CUSTOMIZER_VERSION
from 1.4 to 1.5 for ACL jobs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Include the tag directly in IMG_CUSTOMIZER_CONTAINER
(mcr.microsoft.com/azurelinux/imagecustomizer:1.5) and
IMG_CUSTOMIZER_CONTAINER_FALLBACK
(ghcr.io/microsoft/imagecustomizer:1.5.0) for the ACL COSI conversion.
Drop the separate IMG_CUSTOMIZER_VERSION variable and the major.minor
to major.minor.0 normalization from convert-vhd-to-cosi.sh, since both
registries now carry fully-qualified tags.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nnection

- convert-vhd-to-cosi.sh: convert+stage only; emit AFD cosi_url + sha1 for aks-rp cosi register
- upload-cosi-to-pmc.sh (new) + make target: upload staged COSI under PMC's SC (no az-login dep)
- pipeline: Upload COSI to PMC task under COSI_PMC_SERVICE_CONNECTION; drop obsolete COSI immutable-copy step
- fix azExitCode masking + set -u guards
…copy

azcopy cannot infer the service type for a custom *.azurefd.net host and
won't send the AAD token to a non-default trusted suffix. Mint a
storage-scoped token and PUT the staged .cosi directly to PMC's AFD
upload endpoint (AFD passthrough-forwards the Bearer token to the blob
origin), matching the proven Nebraska POC. Stream with curl -T to avoid
loading a multi-GB COSI into memory.
A single Blob REST PUT is capped at 5000 MiB, so the real converted COSI
(>5 GiB) failed with HTTP 413 RequestBodyTooLarge. Replace the curl PUT
with a small cmd/cosi-upload Go tool that uses the Azure Blob SDK's
UploadFile (16 MiB blocks, concurrency 8), which chunks via Put Block +
Put Block List and is not subject to the single-PUT limit. Auth is
unchanged (Microsoft Entra via the AzureCLI@2 login); AFD forwards the
bearer token to the blob origin. azblob/azidentity are pinned to the
versions already used by the e2e module.
Copilot AI review requested due to automatic review settings July 7, 2026 16:52
@microsoft-github-policy-service

Copy link
Copy Markdown

@adamsanaglo please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"
Contributor License Agreement

Contribution License Agreement

This Contribution License Agreement (“Agreement”) is agreed to by the party signing below (“You”),
and conveys certain license rights to Microsoft Corporation and its affiliates (“Microsoft”) for Your
contributions to Microsoft open source projects. This Agreement is effective as of the latest signature
date below.

  1. Definitions.
    “Code” means the computer software code, whether in human-readable or machine-executable form,
    that is delivered by You to Microsoft under this Agreement.
    “Project” means any of the projects owned or managed by Microsoft and offered under a license
    approved by the Open Source Initiative (www.opensource.org).
    “Submit” is the act of uploading, submitting, transmitting, or distributing code or other content to any
    Project, including but not limited to communication on electronic mailing lists, source code control
    systems, and issue tracking systems that are managed by, or on behalf of, the Project for the purpose of
    discussing and improving that Project, but excluding communication that is conspicuously marked or
    otherwise designated in writing by You as “Not a Submission.”
    “Submission” means the Code and any other copyrightable material Submitted by You, including any
    associated comments and documentation.
  2. Your Submission. You must agree to the terms of this Agreement before making a Submission to any
    Project. This Agreement covers any and all Submissions that You, now or in the future (except as
    described in Section 4 below), Submit to any Project.
  3. Originality of Work. You represent that each of Your Submissions is entirely Your original work.
    Should You wish to Submit materials that are not Your original work, You may Submit them separately
    to the Project if You (a) retain all copyright and license information that was in the materials as You
    received them, (b) in the description accompanying Your Submission, include the phrase “Submission
    containing materials of a third party:” followed by the names of the third party and any licenses or other
    restrictions of which You are aware, and (c) follow any other instructions in the Project’s written
    guidelines concerning Submissions.
  4. Your Employer. References to “employer” in this Agreement include Your employer or anyone else
    for whom You are acting in making Your Submission, e.g. as a contractor, vendor, or agent. If Your
    Submission is made in the course of Your work for an employer or Your employer has intellectual
    property rights in Your Submission by contract or applicable law, You must secure permission from Your
    employer to make the Submission before signing this Agreement. In that case, the term “You” in this
    Agreement will refer to You and the employer collectively. If You change employers in the future and
    desire to Submit additional Submissions for the new employer, then You agree to sign a new Agreement
    and secure permission from the new employer before Submitting those Submissions.
  5. Licenses.
  • Copyright License. You grant Microsoft, and those who receive the Submission directly or
    indirectly from Microsoft, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license in the
    Submission to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute
    the Submission and such derivative works, and to sublicense any or all of the foregoing rights to third
    parties.
  • Patent License. You grant Microsoft, and those who receive the Submission directly or
    indirectly from Microsoft, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license under
    Your patent claims that are necessarily infringed by the Submission or the combination of the
    Submission with the Project to which it was Submitted to make, have made, use, offer to sell, sell and
    import or otherwise dispose of the Submission alone or with the Project.
  • Other Rights Reserved. Each party reserves all rights not expressly granted in this Agreement.
    No additional licenses or rights whatsoever (including, without limitation, any implied licenses) are
    granted by implication, exhaustion, estoppel or otherwise.
  1. Representations and Warranties. You represent that You are legally entitled to grant the above
    licenses. You represent that each of Your Submissions is entirely Your original work (except as You may
    have disclosed under Section 3). You represent that You have secured permission from Your employer to
    make the Submission in cases where Your Submission is made in the course of Your work for Your
    employer or Your employer has intellectual property rights in Your Submission by contract or applicable
    law. If You are signing this Agreement on behalf of Your employer, You represent and warrant that You
    have the necessary authority to bind the listed employer to the obligations contained in this Agreement.
    You are not expected to provide support for Your Submission, unless You choose to do so. UNLESS
    REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, AND EXCEPT FOR THE WARRANTIES
    EXPRESSLY STATED IN SECTIONS 3, 4, AND 6, THE SUBMISSION PROVIDED UNDER THIS AGREEMENT IS
    PROVIDED WITHOUT WARRANTY OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY OF
    NONINFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
  2. Notice to Microsoft. You agree to notify Microsoft in writing of any facts or circumstances of which
    You later become aware that would make Your representations in this Agreement inaccurate in any
    respect.
  3. Information about Submissions. You agree that contributions to Projects and information about
    contributions may be maintained indefinitely and disclosed publicly, including Your name and other
    information that You submit with Your Submission.
  4. Governing Law/Jurisdiction. This Agreement is governed by the laws of the State of Washington, and
    the parties consent to exclusive jurisdiction and venue in the federal courts sitting in King County,
    Washington, unless no federal subject matter jurisdiction exists, in which case the parties consent to
    exclusive jurisdiction and venue in the Superior Court of King County, Washington. The parties waive all
    defenses of lack of personal jurisdiction and forum non-conveniens.
  5. Entire Agreement/Assignment. This Agreement is the entire agreement between the parties, and
    supersedes any and all prior agreements, understandings or communications, written or oral, between
    the parties relating to the subject matter hereof. This Agreement may be assigned by Microsoft.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the Azure Container Linux (ACL) VHD → COSI flow by adding a dedicated upload path to PMC via an Azure Front Door (AFD) upload endpoint, wiring the new conversion + upload steps into the VHD builder release pipeline, and introducing a small Go-based uploader that uses Azure Blob SDK block uploads to avoid single-request size limits.

Changes:

  • Add an ImageCustomizer-based VHD→COSI conversion script that stages the artifact and emits cosi-publishing-info.json (including sha1).
  • Add a Go CLI (cmd/cosi-upload) plus a wrapper script to upload large COSI artifacts via chunked block-blob upload using Azure CLI (Entra ID) auth.
  • Wire new “Convert ACL VHD to COSI” and “Upload COSI to PMC” steps into the builder release template and set ImageCustomizer image variables in pipeline definitions.

Reviewed changes

Copilot reviewed 8 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
vhdbuilder/packer/imagecustomizer/scripts/convert-vhd-to-cosi.sh Downloads the staged ACL VHD, converts it to COSI via ImageCustomizer, stages the COSI, and generates cosi-publishing-info.json with hashes.
vhdbuilder/packer/imagecustomizer/scripts/upload-cosi-to-pmc.sh Validates expected environment + artifacts and invokes the Go uploader to push to the PMC AFD upload endpoint.
cmd/cosi-upload/main.go Implements block/chunked upload using azblob with Azure CLI credential for pipeline auth.
packer.mk Adds convert-vhd-to-cosi, build-cosi-upload, and upload-cosi-to-pmc targets used by pipeline steps.
.pipelines/templates/.builder-release-template.yaml Adds pipeline tasks to convert ACL VHD to COSI and upload COSI to PMC, and publishes cosi-publishing-info.json.
.pipelines/.vsts-vhd-builder.yaml Sets ImageCustomizer container image variables (primary + GHCR fallback) for relevant stages.
.pipelines/.vsts-vhd-builder-release.yaml Sets ImageCustomizer container image variables (primary + GHCR fallback) for relevant stages.
go.mod Adds Azure Blob SDK + Azure Identity dependencies required by the new uploader tool.
go.sum Updates module checksums for newly introduced Go dependencies.

Comment thread packer.mk
Comment on lines +112 to +113
build-cosi-upload: setup-golang
@go build -o bin/cosi-upload ./cmd/cosi-upload
Comment on lines +421 to +425
- task: AzureCLI@2
inputs:
azureSubscription: $(COSI_PMC_SERVICE_CONNECTION)
scriptType: bash
scriptLocation: inlineScript
Copilot AI review requested due to automatic review settings July 7, 2026 16:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 10 changed files in this pull request and generated 6 comments.

Comment on lines +10 to +22
required_env_vars=(
"CAPTURED_SIG_VERSION"
"AFD_UPLOAD_ENDPOINT"
"COSI_CONTAINER"
)

for v in "${required_env_vars[@]}"
do
if [ -z "${!v:-}" ]; then
echo "$v was not set!"
exit 1
fi
done
Comment on lines +7 to +21
required_env_vars=(
"DESTINATION_STORAGE_CONTAINER"
"CAPTURED_SIG_VERSION"
"IMG_CUSTOMIZER_CONTAINER"
"AFD_DOWNLOAD_HOSTNAME"
"COSI_CONTAINER"
)

for v in "${required_env_vars[@]}"
do
if [ -z "${!v:-}" ]; then
echo "$v was not set!"
exit 1
fi
done
Comment on lines +59 to +69
shopt -s nullglob
for f in "${AZCOPY_LOG_LOCATION}"/*.log; do
echo "Azcopy log file: $f"
echo "##vso[build.uploadlog]$f"
if grep -q '"level":"Error"' "$f"; then
echo "log file $f contains errors"
echo "##vso[task.logissue type=error]Azcopy log file $f contains errors"
cat "$f"
fi
done
shopt -u nullglob

echo "Pulling ImageCustomizer image ${IMG_CUSTOMIZER_REF}"
if ! docker pull "${IMG_CUSTOMIZER_REF}"; then
if [ "${ALLOW_GHCR_FALLBACK,,}" != "true" ]; then
fi

ARCH_LOWER="${ARCHITECTURE:-}"
if [ "${ARCH_LOWER,,}" = "arm64" ]; then
Comment on lines +400 to +407
- task: AzureCLI@2
inputs:
azureSubscription: $(VHD_ARM_SERVICE_CONNECTION)
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
make -f packer.mk convert-vhd-to-cosi
condition: |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants