Skip to content

Commit 18a3542

Browse files
Kasturi NarraKasturi Narra
authored andcommitted
Separate OKD build and push phases
1 parent dfa6c32 commit 18a3542

File tree

2 files changed

+225
-17
lines changed

2 files changed

+225
-17
lines changed

.github/actions/build-okd/action.yaml

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,30 @@ runs:
5151
set -euo pipefail
5252
5353
cd ${GITHUB_WORKSPACE}/
54+
# The 'staging' mode builds images locally AND pushes them to staging registry
55+
# Staging registry is automatically derived as: $(dirname target-registry)/okd-staging
56+
# This allows testing before promoting to production
5457
TARGET_REGISTRY="${{ inputs.target-registry }}" ./src/okd/build_images.sh \
58+
staging \
5559
"${{ inputs.okd-version-tag }}" \
5660
"${{ inputs.ushift-gitref }}" \
5761
"${{ inputs.target-arch }}"
5862
59-
- name: Build MicroShift RPMs
63+
- name: Build MicroShift RPMs using staging OKD images
6064
shell: bash
6165
run: |
6266
# See https://github.com/microshift-io/microshift/blob/main/docs/build.md
6367
# for more information about the build process.
6468
65-
# Run the RPM build process.
69+
# Run the RPM build process using images from staging registry
70+
# Staging registry is derived as: $(dirname target-registry)/okd-staging
6671
cd ${GITHUB_WORKSPACE}/
72+
PRODUCTION_REGISTRY="${{ inputs.target-registry }}"
73+
STAGING_REGISTRY="$(dirname "${PRODUCTION_REGISTRY}")/okd-staging"
6774
make rpm \
6875
USHIFT_GITREF="${{ inputs.ushift-gitref }}" \
6976
OKD_VERSION_TAG="${{ inputs.okd-version-tag }}" \
70-
OKD_RELEASE_IMAGE="${{ inputs.target-registry }}/okd-release-${{ steps.detect-cpu-arch.outputs.go_arch }}" \
77+
OKD_RELEASE_IMAGE_AARCH64="${STAGING_REGISTRY}/okd-release-arm64" \
7178
RPM_OUTDIR=/mnt/rpms
7279
7380
- name: Build MicroShift bootc container image
@@ -97,6 +104,39 @@ runs:
97104
make run-healthy
98105
make stop
99106
107+
- name: Push OKD images to production registry
108+
if: success()
109+
shell: bash
110+
run: |
111+
set -euo pipefail
112+
113+
cd ${GITHUB_WORKSPACE}/
114+
# Only push to production if all tests passed
115+
# This ensures we don't publish broken OKD images to production
116+
TARGET_REGISTRY="${{ inputs.target-registry }}" ./src/okd/build_images.sh \
117+
production \
118+
"${{ inputs.okd-version-tag }}" \
119+
"${{ inputs.ushift-gitref }}" \
120+
"${{ inputs.target-arch }}"
121+
122+
- name: Cleanup staging registry
123+
if: always()
124+
shell: bash
125+
continue-on-error: true
126+
env:
127+
GH_TOKEN: ${{ inputs.token }}
128+
run: |
129+
set -euo pipefail
130+
131+
cd ${GITHUB_WORKSPACE}/
132+
# Cleanup staging registry using the script's cleanup mode
133+
# This runs on both success and failure to keep the staging registry clean
134+
TARGET_REGISTRY="${{ inputs.target-registry }}" ./src/okd/build_images.sh \
135+
cleanup \
136+
"${{ inputs.okd-version-tag }}" \
137+
"${{ inputs.ushift-gitref }}" \
138+
"${{ inputs.target-arch }}"
139+
100140
# Uncomment this to enable tmate-debug on failure
101141
# - name: Pause and open tmate debug session
102142
# if: failure()

src/okd/build_images.sh

Lines changed: 182 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,25 @@ set -euo pipefail
44
export LC_ALL=C.UTF-8
55
export LANG=C.UTF-8
66

7-
TARGET_REGISTRY=${TARGET_REGISTRY:-ghcr.io/microshift-io/okd}
7+
# Production registry - must be provided via TARGET_REGISTRY environment variable
8+
# or defaults to the upstream registry if not specified
9+
PRODUCTION_REGISTRY="${TARGET_REGISTRY:-ghcr.io/microshift-io/okd}"
10+
# Automatically derive staging registry by appending '/okd-staging' subpath
11+
STAGING_REGISTRY="$(dirname "${PRODUCTION_REGISTRY}")/okd-staging"
812
PULL_SECRET=${PULL_SECRET:-~/.pull-secret.json}
913

1014
WORKDIR=$(mktemp -d /tmp/okd-build-images-XXXXXX)
1115
trap 'cd ; rm -rf "${WORKDIR}"' EXIT
1216

1317
usage() {
14-
echo "Usage: $(basename "$0") <okd-version> <ocp-branch> <target-arch>"
18+
echo "Usage: $(basename "$0") <mode> <okd-version> <ocp-branch> <target-arch>"
19+
echo " mode: Operation mode - 'staging', 'production', or 'cleanup'"
20+
echo " 'staging' - Build OKD images locally and push to staging registry"
21+
echo " (${STAGING_REGISTRY})"
22+
echo " 'production' - Push previously built images to production registry"
23+
echo " (${PRODUCTION_REGISTRY})"
24+
echo " 'cleanup' - Delete images from staging registry"
25+
echo " (${STAGING_REGISTRY})"
1526
echo " okd-version: The version of OKD to build (see https://amd64.origin.releases.ci.openshift.org/)"
1627
echo " ocp-branch: The branch of OCP to build (e.g. release-4.19)"
1728
echo " target-arch: The architecture of the target images (amd64 or arm64)"
@@ -320,17 +331,164 @@ create_new_okd_release() {
320331
# "ovn-kubernetes-microshift=${images_sha[ovn-kubernetes-microshift]}" \
321332
}
322333

334+
# Build OKD images locally and populate images_sha array
335+
build_okd_images() {
336+
echo "Building OKD images locally..."
337+
create_images
338+
339+
for key in "${!images[@]}" ; do
340+
# Skip haproxy-router for non-ARM64 architectures (see TODO at line 99)
341+
# haproxy28 package implementation for amd64 is not yet available
342+
if [ "${TARGET_ARCH}" != "arm64" ] && [ "${key}" = "haproxy-router" ] ; then
343+
continue
344+
fi
345+
images_sha["${key}"]="${images[$key]}"
346+
done
347+
348+
echo "Build completed successfully"
349+
}
350+
351+
# Push images and manifests to registry, then create OKD release
352+
push_okd_images() {
353+
echo "Pushing images to registry: ${TARGET_REGISTRY}"
354+
push_image_manifests
355+
create_new_okd_release
356+
echo "Push completed successfully"
357+
echo "OKD release image published to: ${OKD_RELEASE_IMAGE}"
358+
}
359+
360+
# Retag staging images to production names
361+
retag_staging_to_production() {
362+
local staging_image
363+
local production_image
364+
365+
echo "Re-tagging staging images to production names..."
366+
367+
for key in "${!images[@]}" ; do
368+
# Skip haproxy-router for non-ARM64 architectures (see TODO at line 99)
369+
# haproxy28 package implementation for amd64 is not yet available
370+
if [ "${TARGET_ARCH}" != "arm64" ] && [ "${key}" = "haproxy-router" ] ; then
371+
continue
372+
fi
373+
374+
production_image="${images[$key]}"
375+
staging_image="${production_image/${PRODUCTION_REGISTRY}/${STAGING_REGISTRY}}"
376+
377+
if ! podman image exists "${staging_image}" ; then
378+
echo "ERROR: Local staging image ${staging_image} not found."
379+
echo "Run staging build first: $0 staging ${OKD_VERSION} ${OCP_BRANCH} ${TARGET_ARCH}"
380+
exit 1
381+
fi
382+
383+
echo "Re-tagging ${staging_image} to ${production_image}"
384+
podman tag "${staging_image}" "${production_image}"
385+
images_sha["${key}"]="${production_image}"
386+
done
387+
}
388+
389+
# Staging mode: build images locally and push to staging registry
390+
push_staging() {
391+
check_podman_login
392+
check_release_image_exists
393+
build_okd_images
394+
push_okd_images
395+
echo ""
396+
echo "Images built and pushed to staging registry: ${STAGING_REGISTRY}"
397+
echo "OKD release image available at: ${OKD_RELEASE_IMAGE}"
398+
echo "After successful testing, push to production with:"
399+
echo " $0 production ${OKD_VERSION} ${OCP_BRANCH} ${TARGET_ARCH}"
400+
}
401+
402+
# Production mode: retag staging images and push to production registry
403+
push_production() {
404+
check_podman_login
405+
check_release_image_exists
406+
retag_staging_to_production
407+
push_okd_images
408+
}
409+
410+
# Delete entire package from GHCR using GitHub CLI
411+
delete_ghcr_package() {
412+
local image="$1"
413+
local owner package
414+
415+
# Parse: ghcr.io/owner/package/subpath:tag -> extract owner and package (without tag)
416+
owner=$(echo "${image}" | cut -d'/' -f2)
417+
package=$(echo "${image}" | cut -d'/' -f3- | cut -d':' -f1)
418+
419+
# URL-encode package path (replace / with %2F)
420+
package="${package//\//%2F}"
421+
422+
echo " Deleting package: ${owner}/${package//%2F//}"
423+
424+
# Delete the entire package (all versions)
425+
local error_msg
426+
if error_msg=$(gh api --method DELETE "/users/${owner}/packages/container/${package}" -H "Accept: application/vnd.github+json" 2>&1); then
427+
echo " ✓ Package deleted"
428+
else
429+
# Handle known errors
430+
if echo "${error_msg}" | grep -q "Not Found"; then
431+
echo " ✓ Already deleted"
432+
else
433+
echo " WARNING: Failed to delete package"
434+
echo " Error: ${error_msg}"
435+
fi
436+
fi
437+
}
438+
439+
# Cleanup mode: delete images from staging registry
440+
cleanup_staging() {
441+
echo "Cleaning up staging registry images for version ${OKD_VERSION}..."
442+
443+
# Track deleted packages to avoid duplicates
444+
declare -A deleted_packages
445+
446+
for key in "${!images[@]}" ; do
447+
# Skip haproxy-router for non-ARM64 architectures (see TODO at line 99)
448+
if [ "${TARGET_ARCH}" != "arm64" ] && [ "${key}" = "haproxy-router" ] ; then
449+
continue
450+
fi
451+
452+
# Extract package name (without tag)
453+
local package_name="${images[$key]%%:*}"
454+
455+
# Skip if already deleted
456+
if [ -n "${deleted_packages[$package_name]:-}" ]; then
457+
echo " Skipping ${package_name} (already deleted)"
458+
continue
459+
fi
460+
461+
# Delete the entire package (all versions including manifest and arch-specific)
462+
delete_ghcr_package "${images[$key]}"
463+
deleted_packages[$package_name]=1
464+
done
465+
466+
# Delete the OKD release image package
467+
local release_package="${OKD_RELEASE_IMAGE%%:*}"
468+
if [ -z "${deleted_packages[$release_package]:-}" ]; then
469+
delete_ghcr_package "${OKD_RELEASE_IMAGE}"
470+
fi
471+
472+
echo "Staging registry cleanup completed"
473+
}
474+
323475
#
324476
# Main
325477
#
326-
if [[ $# -ne 3 ]]; then
478+
if [[ $# -ne 4 ]]; then
327479
usage
328480
fi
329481

330-
OKD_VERSION="$1"
331-
OCP_BRANCH="$2"
332-
TARGET_ARCH="$3"
333-
OKD_RELEASE_IMAGE="${TARGET_REGISTRY}/okd-release-${TARGET_ARCH}:${OKD_VERSION}"
482+
MODE="$1"
483+
OKD_VERSION="$2"
484+
OCP_BRANCH="$3"
485+
TARGET_ARCH="$4"
486+
487+
# Validate mode
488+
if [[ "${MODE}" != "staging" ]] && [[ "${MODE}" != "production" ]] && [[ "${MODE}" != "cleanup" ]]; then
489+
echo "ERROR: Invalid mode '${MODE}'. Must be 'staging', 'production', or 'cleanup'"
490+
usage
491+
fi
334492

335493
# Determine the alternate architecture
336494
case "${TARGET_ARCH}" in
@@ -346,6 +504,15 @@ case "${TARGET_ARCH}" in
346504
;;
347505
esac
348506

507+
# Set target registry based on mode
508+
if [[ "${MODE}" == "staging" ]] || [[ "${MODE}" == "cleanup" ]]; then
509+
TARGET_REGISTRY="${STAGING_REGISTRY}"
510+
elif [[ "${MODE}" == "production" ]]; then
511+
TARGET_REGISTRY="${PRODUCTION_REGISTRY}"
512+
fi
513+
514+
OKD_RELEASE_IMAGE="${TARGET_REGISTRY}/okd-release-${TARGET_ARCH}:${OKD_VERSION}"
515+
349516
# Populate associative arrays with image names and tags
350517
declare -A images
351518
declare -A images_sha
@@ -368,10 +535,11 @@ images=(
368535

369536
# Check the prerequisites
370537
check_prereqs
371-
check_podman_login
372-
check_release_image_exists
373-
# Create and push images
374-
create_images
375-
push_image_manifests
376-
# Create a new OKD release
377-
create_new_okd_release
538+
# Execute based on mode
539+
if [[ "${MODE}" == "staging" ]]; then
540+
push_staging
541+
elif [[ "${MODE}" == "production" ]]; then
542+
push_production
543+
elif [[ "${MODE}" == "cleanup" ]]; then
544+
cleanup_staging
545+
fi

0 commit comments

Comments
 (0)