mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
7bcd365549
* ci(eks-ami): build on self-hosted ci-single-1 runner GitHub-hosted ubuntu-24.04 cannot run the libguestfs appliance network: passt fails (PID file denied under its AppArmor confine / privilege drop) and the SLIRP fallback has no outbound, so virt-customize --network dies. The self-hosted ci-single-1 runner has /dev/kvm and real networking, so the existing libguestfs build works unmodified. * fix(build-system-image): add --no-cache, force fresh build on publish The <10min cached-raw skip avoids duplicate work for concurrent e2e jobs, but on the persistent publish runner it could republish a stale image from a prior or concurrent run. Add --no-cache to bypass the skip and have publish-system-image.sh pass it on every build. * ci(eks-ami): target ci-single label (no ci-single-1 label exists) The self-hosted runners are named ci-single/-2/-3 but all share the single label 'ci-single'; runs-on matches labels, not names, so ci-single-1 never schedules. * ci(eks-ami): disable Go cache on self-hosted runner setup-go's cache-save (Post Setup Go) re-uploaded the Go cache to the Actions backend on every run, taking ~2.5min vs the 36s build. The self-hosted runner already keeps the cache on local disk, so cache:false.
150 lines
4.7 KiB
Bash
Executable File
150 lines
4.7 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
# publish-system-image.sh — Publish a built system AMI to Cloudflare R2
|
|
#
|
|
# Converts the raw image produced by build-system-image.sh into a compressed
|
|
# qcow2, writes a .sha256 sidecar (coreutils format, matched by the spx catalog
|
|
# checksum verifier), and uploads both to the R2 bucket that backs
|
|
# iso.mulgadc.com/system-ami/. The matching catalog entry in
|
|
# spinifex/spinifex/utils/images.go then lets operators run:
|
|
#
|
|
# spx admin images import --name <catalog-key>
|
|
#
|
|
# Object name is <AMI_NAME or IMAGE_NAME>-<arch>.qcow2 — this MUST match the
|
|
# basename of the catalog entry's URL.
|
|
#
|
|
# Requirements: qemu-img, sha256sum, aws (CLI; R2 speaks the S3 API)
|
|
# Usage: ./scripts/publish-system-image.sh <manifest.conf> [--build] [--dry-run]
|
|
# --build Run build-system-image.sh first (otherwise reuse the cached raw)
|
|
# --dry-run Print the convert/checksum/upload steps without uploading
|
|
#
|
|
# Env (required unless --dry-run):
|
|
# R2_ENDPOINT https://<account>.r2.cloudflarestorage.com
|
|
# R2_BUCKET defaults to "spinifex-iso" (backs iso.mulgadc.com)
|
|
# AWS_ACCESS_KEY_ID R2 token access key
|
|
# AWS_SECRET_ACCESS_KEY R2 token secret
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
|
usage() {
|
|
echo "Usage: $0 <manifest.conf> [--build] [--dry-run]"
|
|
exit 1
|
|
}
|
|
|
|
if [[ $# -lt 1 || "$1" == "-h" || "$1" == "--help" ]]; then
|
|
usage
|
|
fi
|
|
|
|
MANIFEST="$1"
|
|
shift
|
|
|
|
if [[ ! -f "$MANIFEST" ]]; then
|
|
echo "ERROR: Manifest not found: $MANIFEST"
|
|
exit 1
|
|
fi
|
|
|
|
DO_BUILD=false
|
|
DRY_RUN=false
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--build) DO_BUILD=true ;;
|
|
--dry-run) DRY_RUN=true ;;
|
|
*) echo "ERROR: unknown flag: $arg"; usage ;;
|
|
esac
|
|
done
|
|
|
|
# shellcheck source=/dev/null
|
|
source "$MANIFEST"
|
|
|
|
DISTRO="${DISTRO:-alpine}"
|
|
ARCH="x86_64" # build-system-image.sh builds x86_64 only today
|
|
R2_BUCKET="${R2_BUCKET:-spinifex-iso}" # iso.mulgadc.com is served from this bucket
|
|
|
|
if [[ -z "${IMAGE_NAME:-}" ]]; then
|
|
echo "ERROR: Manifest missing required field: IMAGE_NAME"
|
|
exit 1
|
|
fi
|
|
|
|
# Mirror build-system-image.sh's derived paths so we reuse its cached raw.
|
|
BUILD_DIR="/tmp/${IMAGE_NAME}-image-build"
|
|
RAW_IMAGE="${BUILD_DIR}/${IMAGE_NAME}-${DISTRO}.raw"
|
|
|
|
OBJECT_BASE="${AMI_NAME:-$IMAGE_NAME}-${ARCH}"
|
|
QCOW2_OUT="${BUILD_DIR}/${OBJECT_BASE}.qcow2"
|
|
SHA_OUT="${QCOW2_OUT}.sha256"
|
|
OBJECT_QCOW2="${OBJECT_BASE}.qcow2"
|
|
OBJECT_SHA="${OBJECT_BASE}.qcow2.sha256"
|
|
|
|
for tool in qemu-img sha256sum; do
|
|
if ! command -v "$tool" &>/dev/null; then
|
|
echo "ERROR: $tool not found"
|
|
exit 1
|
|
fi
|
|
done
|
|
if [[ "$DRY_RUN" == false ]] && ! command -v aws &>/dev/null; then
|
|
echo "ERROR: aws CLI not found (required for R2 upload; use --dry-run to skip)"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$DO_BUILD" == true ]]; then
|
|
echo "=== Building ${IMAGE_NAME} ==="
|
|
# --no-cache: publishing must never reuse a stale raw left by a prior or
|
|
# concurrent build on a persistent runner.
|
|
"${SCRIPT_DIR}/build-system-image.sh" "$MANIFEST" --no-cache
|
|
fi
|
|
|
|
if [[ ! -f "$RAW_IMAGE" ]]; then
|
|
echo "ERROR: Raw image not found: $RAW_IMAGE"
|
|
echo " Run with --build, or 'make build-system-image IMAGE=...' first."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$DRY_RUN" == false ]]; then
|
|
for var in R2_ENDPOINT AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY; do
|
|
if [[ -z "${!var:-}" ]]; then
|
|
echo "ERROR: $var must be set (or use --dry-run)"
|
|
exit 1
|
|
fi
|
|
done
|
|
fi
|
|
|
|
echo "=== Publish System Image ==="
|
|
echo " Manifest: ${MANIFEST}"
|
|
echo " Raw: ${RAW_IMAGE}"
|
|
echo " Object: s3://${R2_BUCKET}/system-ami/${OBJECT_QCOW2}"
|
|
echo ""
|
|
|
|
run() {
|
|
echo "+ $*"
|
|
if [[ "$DRY_RUN" == false ]]; then
|
|
"$@"
|
|
fi
|
|
}
|
|
|
|
# Compressed qcow2 keeps the transfer small (consistent with the GPU images).
|
|
run qemu-img convert -c -f raw -O qcow2 "$RAW_IMAGE" "$QCOW2_OUT"
|
|
|
|
# Sidecar in coreutils format: "<hex> <basename>". The spx catalog verifier
|
|
# matches the entry by the downloaded file's basename, so write the basename
|
|
# the catalog URL resolves to, not the local build path.
|
|
if [[ "$DRY_RUN" == false ]]; then
|
|
( cd "$(dirname "$QCOW2_OUT")" && sha256sum "$(basename "$QCOW2_OUT")" > "$(basename "$SHA_OUT")" )
|
|
echo " sha256: $(cut -d' ' -f1 "$SHA_OUT")"
|
|
else
|
|
echo "+ sha256sum ${OBJECT_QCOW2} > ${OBJECT_SHA}"
|
|
fi
|
|
|
|
S3_PREFIX="s3://${R2_BUCKET}/system-ami"
|
|
run aws s3 cp --endpoint-url "${R2_ENDPOINT:-<R2_ENDPOINT>}" "$QCOW2_OUT" "${S3_PREFIX}/${OBJECT_QCOW2}"
|
|
run aws s3 cp --endpoint-url "${R2_ENDPOINT:-<R2_ENDPOINT>}" "$SHA_OUT" "${S3_PREFIX}/${OBJECT_SHA}"
|
|
|
|
echo ""
|
|
if [[ "$DRY_RUN" == true ]]; then
|
|
echo "=== Dry run complete (no upload) ==="
|
|
else
|
|
echo "=== Published ==="
|
|
echo " https://iso.mulgadc.com/system-ami/${OBJECT_QCOW2}"
|
|
echo " https://iso.mulgadc.com/system-ami/${OBJECT_SHA}"
|
|
fi
|