@@ -4,14 +4,25 @@ set -euo pipefail
44export LC_ALL=C.UTF-8
55export 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"
812PULL_SECRET=${PULL_SECRET:- ~/ .pull-secret.json}
913
1014WORKDIR=$( mktemp -d /tmp/okd-build-images-XXXXXX)
1115trap ' cd ; rm -rf "${WORKDIR}"' EXIT
1216
1317usage () {
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
328480fi
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
336494case " ${TARGET_ARCH} " in
@@ -346,6 +504,15 @@ case "${TARGET_ARCH}" in
346504 ;;
347505esac
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
350517declare -A images
351518declare -A images_sha
@@ -368,10 +535,11 @@ images=(
368535
369536# Check the prerequisites
370537check_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