Skip to content

OCI: AlmaLinux 9 Build, Release to Compute, Test, Publish to Listings #5

OCI: AlmaLinux 9 Build, Release to Compute, Test, Publish to Listings

OCI: AlmaLinux 9 Build, Release to Compute, Test, Publish to Listings #5

name: "OCI: Build, Release to Compute, Test, Publish to Listings"
run-name: >-
OCI: AlmaLinux ${{ inputs.version_major }} Build, Release to Compute, Test, Publish to Listings
# Unified OCI pipeline: build the qcow2 images with Packer, create a
# Compute Custom Image from each one directly on the build runner (upload to
# Object Storage + import + capability schema + shape compatibility, no S3
# round-trip), boot-test every Compute Image, and publish every image that
# passed its test to the Oracle Cloud Marketplace as a draft revision.
#
# The pipeline is two INDEPENDENT per-image chains
#
# build-x86_64 -> test-x86_64 -> publish-x86_64
# build-aarch64 -> test-aarch64 -> publish-aarch64
#
# rather than build-matrix -> collect -> test-matrix -> collect -> publish:
# with per-image chains, "Re-run failed jobs" re-runs ONLY the failed
# image's own downstream jobs - a sibling image that already tested and
# published is not re-tested and, above all, not re-published. Each build
# leg's compute-image stage uploads an oci-manifest-<arch>.json artifact;
# the image's test job downloads it (artifacts survive re-run attempts, so
# a re-run test needs no re-build) and exposes its fields as job outputs
# for the publish job. The two publishes run in parallel: each arch has
# its own Marketplace listing ("AlmaLinux OS <major> (<arch>)"), so draft
# revisions never collide.
#
# Stage gating:
# create_compute_image=false -> build-only run (compute-image / test / publish skip)
# release_to_marketplace=false -> build + compute-image + test (publish skips)
#
# Test runs for every Compute Image; there is no separate run_test input.
# Publishing covers exactly the images that passed their test - a failed
# sibling test does not block the images that passed.
#
# Stage implementations live in composite actions:
# .github/actions/shared-steps - Packer build (all clouds)
# .github/actions/oci-compute-image-steps - Object Storage upload + image import
# .github/actions/oci-test-steps - Compute Image boot test
# .github/actions/oci-marketplace-steps - Marketplace draft publish
on:
workflow_dispatch:
inputs:
date_time_stamp:
description: 'Custom date+time stamp, YYYYMMDDhhmmss'
required: false
default: ''
version_major:
description: 'AlmaLinux major version'
required: true
default: '10'
type: choice
options:
- 10
- 9
- 8
self-hosted:
description: "Build aarch64 image on self-hosted runner"
required: true
type: boolean
default: true
store_as_artifact:
description: "Store images to the workflow Artifacts"
required: true
type: boolean
default: false
upload_to_s3:
description: "Upload to S3 Bucket"
required: true
type: boolean
default: true
create_compute_image:
description: "Create OCI Compute Image (gates test and publish)"
required: true
type: boolean
default: true
release_to_marketplace:
description: "Release the image to Marketplace listing"
required: true
type: boolean
default: true
notify_mattermost:
description: "Send notification to Mattermost"
required: true
type: boolean
default: true
env:
PACKER_GITHUB_API_TOKEN: ${{ secrets.GIT_HUB_TOKEN }}
jobs:
init-data:
name: Initialize common data
runs-on: ubuntu-24.04
outputs:
time_stamp: ${{ steps.date-time-stamp.outputs.time_stamp }}
date_stamp: ${{ steps.date-time-stamp.outputs.date_stamp }}
steps:
- name: Date+time stamp
id: date-time-stamp
run: |
# date+time stamp, YYYYMMDDhhmmss
if [ "${{ inputs.date_time_stamp }}" != "" ]; then
date_time_stamp="${{ inputs.date_time_stamp }}"
else
date_time_stamp=$(date -u '+%Y%m%d%H%M%S')
fi
echo "time_stamp=${date_time_stamp}" >> $GITHUB_OUTPUT
# date stamp, YYYYMMDD
date_stamp=${date_time_stamp:0:-6}
echo "date_stamp=${date_stamp}" >> "$GITHUB_OUTPUT"
build-x86_64:
name: Build and release x86_64
permissions:
id-token: write
contents: read
needs: [init-data]
# use runs-on runners if within the almalinux org, otherwise GH runners
runs-on: >-
${{
github.repository_owner == 'AlmaLinux' &&
format('runs-on={0}/family=c7i.metal-24xl+c7a.metal-48xl+*8gd.metal*/image=ubuntu24-full-x64/spot=false', github.run_id)
||
'ubuntu-24.04'
}}
env:
TIME_STAMP: ${{ needs.init-data.outputs.time_stamp }}
DATE_STAMP: ${{ needs.init-data.outputs.date_stamp }}
steps:
- name: Checkout ${{ github.action_repository }}
uses: actions/checkout@v6
- uses: ./.github/actions/shared-steps
name: ${{ inputs.version_major }} oci-x86_64 image
with:
type: oci
variant: ${{ inputs.version_major }}
arch: x86_64
S3_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
S3_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ vars.AWS_REGION }}
AWS_S3_BUCKET: ${{ vars.AWS_S3_BUCKET }}
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
MATTERMOST_CHANNEL: ${{ vars.MATTERMOST_CHANNEL }}
store_as_artifact: ${{ inputs.store_as_artifact }}
upload_to_s3: ${{ inputs.upload_to_s3 }}
notify_mattermost: ${{ inputs.notify_mattermost }}
run_test: 'false'
runner: ${{ github.repository_owner == 'AlmaLinux' && 'aws-ec2' || 'gh_hosted' }}
env:
PACKER_GITHUB_API_TOKEN: ${{ secrets.GIT_HUB_TOKEN }}
- uses: ./.github/actions/oci-compute-image-steps
name: Create ${{ inputs.version_major }} oci-x86_64 Compute Image
if: ${{ inputs.create_compute_image }}
with:
arch: x86_64
notify_mattermost: ${{ inputs.notify_mattermost }}
OCI_CLI_USER: ${{ secrets.OCI_CLI_USER }}
OCI_CLI_TENANCY: ${{ secrets.OCI_CLI_TENANCY }}
OCI_CLI_FINGERPRINT: ${{ secrets.OCI_CLI_FINGERPRINT }}
OCI_CLI_KEY_CONTENT: ${{ secrets.OCI_CLI_KEY_CONTENT }}
OCI_CLI_REGION: ${{ vars.OCI_CLI_REGION }}
OCI_COMPARTMENT_ID: ${{ secrets.OCI_COMPARTMENT_ID }}
OCI_OBJECT_STORAGE_BUCKET: ${{ vars.OCI_OBJECT_STORAGE_BUCKET }}
OCI_OBJECT_STORAGE_NAMESPACE: ${{ secrets.OCI_OBJECT_STORAGE_NAMESPACE }}
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
MATTERMOST_CHANNEL: ${{ vars.MATTERMOST_CHANNEL }}
# The job is to start self-hosted runner on AWS EC2 instance if not in the almalinux org
# It does nothing if in the almalinux org, so 'Setup and start runner' step is skipped
start-self-hosted-runner:
name: Start self-hosted runner
if: ${{ inputs.self-hosted }}
runs-on: ubuntu-24.04
needs: [init-data]
steps:
- name: Setup and start runner
if: github.repository_owner != 'AlmaLinux'
uses: unblocked/ec2-action-builder@v1.12
with:
github_token: ${{ secrets.GIT_HUB_TOKEN }}
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws_region: ${{ vars.AWS_REGION }}
ec2_ami_id: ${{ secrets.EC2_AMI_ID_AL9_AARCH64 }}
ec2_subnet_id: ${{ secrets.EC2_SUBNET_ID}} # Subnet and Security Group should match
ec2_security_group_id: ${{ secrets.EC2_SECURITY_GROUP_ID }} # Availability Zones list for 'a1.metal' Instance Type
ec2_instance_type: a1.metal
ec2_root_disk_size_gb: "16" # override default size which is too small for actions and tests stuff
ec2_root_disk_ebs_class: "gp3" # use faster and cheeper storage instead of default 'gp2'
ec2_instance_ttl: 30 # Optional (default is 60 minutes)
ec2_spot_instance_strategy: None # Other options are: SpotOnly, BestEffort, MaxPerformance
ec2_instance_tags: > # Required for IAM role resource permission scoping
[
{"Key": "Project", "Value": "GitHub Actions Self-hosted Runners"}
]
build-aarch64:
name: Build and release aarch64
permissions:
id-token: write
contents: read
if: ${{ inputs.self-hosted }}
needs: [init-data, start-self-hosted-runner]
# If almalinux org, use RunsOn with almalinux-9-aarch64 on a1.metal
#
# Otherwise use AWS EC2 Self-Hosted aarch64 runner set up with the 'start-self-hosted-runner' job above
runs-on: >-
${{
github.repository_owner == 'AlmaLinux' &&
format('runs-on={0}/family=a1.metal/image=almalinux-9-aarch64/volume=40g/spot=false', github.run_id)
||
github.run_id
}}
env:
TIME_STAMP: ${{ needs.init-data.outputs.time_stamp }}
DATE_STAMP: ${{ needs.init-data.outputs.date_stamp }}
steps:
- name: Checkout ${{ github.action_repository }}
uses: actions/checkout@v6
- uses: ./.github/actions/shared-steps
name: ${{ inputs.version_major }} oci-aarch64 image
with:
type: oci
variant: ${{ inputs.version_major }}
arch: aarch64
S3_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
S3_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ vars.AWS_REGION }}
AWS_S3_BUCKET: ${{ vars.AWS_S3_BUCKET }}
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
MATTERMOST_CHANNEL: ${{ vars.MATTERMOST_CHANNEL }}
store_as_artifact: ${{ inputs.store_as_artifact }}
upload_to_s3: ${{ inputs.upload_to_s3 }}
notify_mattermost: ${{ inputs.notify_mattermost }}
run_test: 'false'
runner: aws-ec2
env:
PACKER_GITHUB_API_TOKEN: ${{ secrets.GIT_HUB_TOKEN }}
- uses: ./.github/actions/oci-compute-image-steps
name: Create ${{ inputs.version_major }} oci-aarch64 Compute Image
if: ${{ inputs.create_compute_image }}
with:
arch: aarch64
notify_mattermost: ${{ inputs.notify_mattermost }}
OCI_CLI_USER: ${{ secrets.OCI_CLI_USER }}
OCI_CLI_TENANCY: ${{ secrets.OCI_CLI_TENANCY }}
OCI_CLI_FINGERPRINT: ${{ secrets.OCI_CLI_FINGERPRINT }}
OCI_CLI_KEY_CONTENT: ${{ secrets.OCI_CLI_KEY_CONTENT }}
OCI_CLI_REGION: ${{ vars.OCI_CLI_REGION }}
OCI_COMPARTMENT_ID: ${{ secrets.OCI_COMPARTMENT_ID }}
OCI_OBJECT_STORAGE_BUCKET: ${{ vars.OCI_OBJECT_STORAGE_BUCKET }}
OCI_OBJECT_STORAGE_NAMESPACE: ${{ secrets.OCI_OBJECT_STORAGE_NAMESPACE }}
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
MATTERMOST_CHANNEL: ${{ vars.MATTERMOST_CHANNEL }}
# Per-image test jobs. Each downloads its build leg's compute-image
# manifest artifact (artifacts survive "Re-run failed jobs", so a re-run
# test needs no re-build) and exposes the manifest fields as job outputs
# for the matching publish job.
test-x86_64:
name: Test x86_64
permissions:
id-token: write
contents: read
runs-on: ubuntu-24.04
needs: [build-x86_64]
if: ${{ inputs.create_compute_image }}
outputs:
compute_image_ocid: ${{ steps.manifest.outputs.compute_image_ocid }}
custom_image_name: ${{ steps.manifest.outputs.custom_image_name }}
object_name: ${{ steps.manifest.outputs.object_name }}
alma_major: ${{ steps.manifest.outputs.alma_major }}
alma_version: ${{ steps.manifest.outputs.alma_version }}
alma_date: ${{ steps.manifest.outputs.alma_date }}
alma_release: ${{ steps.manifest.outputs.alma_release }}
alma_code_name: ${{ steps.manifest.outputs.alma_code_name }}
arch: ${{ steps.manifest.outputs.arch }}
display_arch: ${{ steps.manifest.outputs.display_arch }}
image_display_name: ${{ steps.manifest.outputs.image_display_name }}
steps:
- name: Checkout ${{ github.action_repository }}
uses: actions/checkout@v6
- name: Download compute-image manifest
uses: actions/download-artifact@v7
with:
name: oci-manifest-x86_64.json
path: manifest
- name: Read compute-image manifest
id: manifest
run: |
# Read compute-image manifest
f=$(ls manifest/oci-manifest-*.json)
jq '.' "${f}"
for key in compute_image_ocid custom_image_name object_name \
alma_major alma_version alma_date alma_release \
alma_code_name arch display_arch image_display_name; do
echo "${key}=$(jq -r ".${key}" "${f}")" >> "$GITHUB_OUTPUT"
done
- uses: ./.github/actions/oci-test-steps
name: Test ${{ steps.manifest.outputs.compute_image_ocid }}
with:
image_ocid: ${{ steps.manifest.outputs.compute_image_ocid }}
notify_mattermost: ${{ inputs.notify_mattermost }}
OCI_CLI_USER: ${{ secrets.OCI_CLI_USER }}
OCI_CLI_TENANCY: ${{ secrets.OCI_CLI_TENANCY }}
OCI_CLI_FINGERPRINT: ${{ secrets.OCI_CLI_FINGERPRINT }}
OCI_CLI_KEY_CONTENT: ${{ secrets.OCI_CLI_KEY_CONTENT }}
OCI_CLI_REGION: ${{ vars.OCI_CLI_REGION }}
OCI_COMPARTMENT_ID: ${{ secrets.OCI_COMPARTMENT_ID }}
OCI_SUBNET_ID: ${{ secrets.OCI_SUBNET_ID }}
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
MATTERMOST_CHANNEL: ${{ vars.MATTERMOST_CHANNEL }}
test-aarch64:
name: Test aarch64
permissions:
id-token: write
contents: read
runs-on: ubuntu-24.04
needs: [build-aarch64]
if: ${{ inputs.create_compute_image }}
outputs:
compute_image_ocid: ${{ steps.manifest.outputs.compute_image_ocid }}
custom_image_name: ${{ steps.manifest.outputs.custom_image_name }}
object_name: ${{ steps.manifest.outputs.object_name }}
alma_major: ${{ steps.manifest.outputs.alma_major }}
alma_version: ${{ steps.manifest.outputs.alma_version }}
alma_date: ${{ steps.manifest.outputs.alma_date }}
alma_release: ${{ steps.manifest.outputs.alma_release }}
alma_code_name: ${{ steps.manifest.outputs.alma_code_name }}
arch: ${{ steps.manifest.outputs.arch }}
display_arch: ${{ steps.manifest.outputs.display_arch }}
image_display_name: ${{ steps.manifest.outputs.image_display_name }}
steps:
- name: Checkout ${{ github.action_repository }}
uses: actions/checkout@v6
- name: Download compute-image manifest
uses: actions/download-artifact@v7
with:
name: oci-manifest-aarch64.json
path: manifest
- name: Read compute-image manifest
id: manifest
run: |
# Read compute-image manifest
f=$(ls manifest/oci-manifest-*.json)
jq '.' "${f}"
for key in compute_image_ocid custom_image_name object_name \
alma_major alma_version alma_date alma_release \
alma_code_name arch display_arch image_display_name; do
echo "${key}=$(jq -r ".${key}" "${f}")" >> "$GITHUB_OUTPUT"
done
- uses: ./.github/actions/oci-test-steps
name: Test ${{ steps.manifest.outputs.compute_image_ocid }}
with:
image_ocid: ${{ steps.manifest.outputs.compute_image_ocid }}
notify_mattermost: ${{ inputs.notify_mattermost }}
OCI_CLI_USER: ${{ secrets.OCI_CLI_USER }}
OCI_CLI_TENANCY: ${{ secrets.OCI_CLI_TENANCY }}
OCI_CLI_FINGERPRINT: ${{ secrets.OCI_CLI_FINGERPRINT }}
OCI_CLI_KEY_CONTENT: ${{ secrets.OCI_CLI_KEY_CONTENT }}
OCI_CLI_REGION: ${{ vars.OCI_CLI_REGION }}
OCI_COMPARTMENT_ID: ${{ secrets.OCI_COMPARTMENT_ID }}
OCI_SUBNET_ID: ${{ secrets.OCI_SUBNET_ID }}
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
MATTERMOST_CHANNEL: ${{ vars.MATTERMOST_CHANNEL }}
# Per-image publish jobs: each is gated on its OWN image's test succeeding.
# The two publishes run in parallel - each arch has its own Marketplace
# listing ("AlmaLinux OS <major> (<arch>)"), so draft revisions never
# collide.
publish-x86_64:
name: Publish to marketplace x86_64
permissions:
id-token: write
contents: read
runs-on: ubuntu-24.04
needs: [test-x86_64]
if: ${{ inputs.release_to_marketplace }}
steps:
- name: Checkout ${{ github.action_repository }}
uses: actions/checkout@v6
- uses: ./.github/actions/oci-marketplace-steps
name: Publish ${{ needs.test-x86_64.outputs.custom_image_name }} to Marketplace
with:
compute_image_ocid: ${{ needs.test-x86_64.outputs.compute_image_ocid }}
custom_image_name: ${{ needs.test-x86_64.outputs.custom_image_name }}
object_name: ${{ needs.test-x86_64.outputs.object_name }}
alma_major: ${{ needs.test-x86_64.outputs.alma_major }}
alma_version: ${{ needs.test-x86_64.outputs.alma_version }}
alma_date: ${{ needs.test-x86_64.outputs.alma_date }}
alma_release: ${{ needs.test-x86_64.outputs.alma_release }}
alma_code_name: ${{ needs.test-x86_64.outputs.alma_code_name }}
alma_arch: ${{ needs.test-x86_64.outputs.arch }}
display_arch: ${{ needs.test-x86_64.outputs.display_arch }}
image_display_name: ${{ needs.test-x86_64.outputs.image_display_name }}
notify_mattermost: ${{ inputs.notify_mattermost }}
OCI_CLI_USER: ${{ secrets.OCI_CLI_USER }}
OCI_CLI_TENANCY: ${{ secrets.OCI_CLI_TENANCY }}
OCI_CLI_FINGERPRINT: ${{ secrets.OCI_CLI_FINGERPRINT }}
OCI_CLI_KEY_CONTENT: ${{ secrets.OCI_CLI_KEY_CONTENT }}
OCI_CLI_REGION: ${{ vars.OCI_CLI_REGION }}
OCI_COMPARTMENT_ID: ${{ secrets.OCI_COMPARTMENT_ID }}
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
MATTERMOST_CHANNEL: ${{ vars.MATTERMOST_CHANNEL }}
publish-aarch64:
name: Publish to marketplace aarch64
permissions:
id-token: write
contents: read
runs-on: ubuntu-24.04
needs: [test-aarch64]
if: ${{ inputs.release_to_marketplace }}
steps:
- name: Checkout ${{ github.action_repository }}
uses: actions/checkout@v6
- uses: ./.github/actions/oci-marketplace-steps
name: Publish ${{ needs.test-aarch64.outputs.custom_image_name }} to Marketplace
with:
compute_image_ocid: ${{ needs.test-aarch64.outputs.compute_image_ocid }}
custom_image_name: ${{ needs.test-aarch64.outputs.custom_image_name }}
object_name: ${{ needs.test-aarch64.outputs.object_name }}
alma_major: ${{ needs.test-aarch64.outputs.alma_major }}
alma_version: ${{ needs.test-aarch64.outputs.alma_version }}
alma_date: ${{ needs.test-aarch64.outputs.alma_date }}
alma_release: ${{ needs.test-aarch64.outputs.alma_release }}
alma_code_name: ${{ needs.test-aarch64.outputs.alma_code_name }}
alma_arch: ${{ needs.test-aarch64.outputs.arch }}
display_arch: ${{ needs.test-aarch64.outputs.display_arch }}
image_display_name: ${{ needs.test-aarch64.outputs.image_display_name }}
notify_mattermost: ${{ inputs.notify_mattermost }}
OCI_CLI_USER: ${{ secrets.OCI_CLI_USER }}
OCI_CLI_TENANCY: ${{ secrets.OCI_CLI_TENANCY }}
OCI_CLI_FINGERPRINT: ${{ secrets.OCI_CLI_FINGERPRINT }}
OCI_CLI_KEY_CONTENT: ${{ secrets.OCI_CLI_KEY_CONTENT }}
OCI_CLI_REGION: ${{ vars.OCI_CLI_REGION }}
OCI_COMPARTMENT_ID: ${{ secrets.OCI_COMPARTMENT_ID }}
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
MATTERMOST_CHANNEL: ${{ vars.MATTERMOST_CHANNEL }}