feat(release): version live-image, skip rebuild+redownload when unchanged
CI / Lint + build + test (push) Successful in 1m41s
Release / detect (push) Successful in 7s
Release / build-live-image (push) Failing after 3m58s
Release / bundle (push) Has been skipped

Splits the release workflow into three jobs (detect, build-live-image,
bundle) so the ~9 min mkosi build only runs when live-image/VERSION
bumps. The slim bundle (~30 MB: orchestrator + agent + deploy scripts
+ a live-image/VERSION pointer) rebuilds every push; the ~300 MB
vmlinuz+initrd.img are published separately under the immutable
live-image/<version>/ path. install.sh compares the pointer to
/var/lib/vetting/live/VERSION and fetches the files only on mismatch,
cutting repeat-install wall-clock from ~30 s + 300 MB to ~10 s + 0 MB
on the common no-live-image-change release.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-20 21:04:14 -04:00
parent 4c153bb115
commit 211abdf08f
7 changed files with 309 additions and 108 deletions
+86 -10
View File
@@ -18,10 +18,15 @@
# - Fetch TFTP iPXE payloads (that's pxe-setup.sh's job — it also
# writes the pxe: block of vetting.yaml with first-time args).
#
# When a live-image/{vmlinuz,initrd.img} is present next to this script
# (release bundle) or under ../live-image/build/ (repo checkout), it's
# staged into --live-dir automatically. This makes the one-liner
# upgrade loop work end-to-end for PXE-enabled installs.
# Live-image staging has two modes:
# - Release bundle (new format): the bundle carries only a
# live-image/VERSION pointer. We compare it to ${LIVE_DIR}/VERSION
# and, on mismatch, fetch vmlinuz+initrd.img from the Gitea
# generic registry at live-image/<VERSION>/. Matched versions
# skip the fetch (set FORCE_LIVE_IMAGE=1 to override).
# - Repo checkout / legacy bundle: if vmlinuz+initrd.img are present
# next to this script (${SCRIPT_DIR}/live-image/) or under
# ${REPO_ROOT}/live-image/build/, they're copied straight in.
#
# Usage:
# sudo ./install.sh [--binary PATH] [--config-dir /etc/vetting]
@@ -165,6 +170,59 @@ heal_pxe_config() {
mv "${tmp}" "${config}"
}
# refresh_live_image: pull vmlinuz+initrd.img from the Gitea generic
# package registry when the bundle's live-image/VERSION pointer differs
# from ${LIVE_DIR}/VERSION. Skips the fetch when versions match unless
# FORCE_LIVE_IMAGE=1 (useful when on-disk files got corrupted). Set by
# proxmox-install.sh; on a direct `install.sh` invocation the caller
# must export REGISTRY_URL (and optionally PACKAGE_OWNER).
refresh_live_image() {
local pointer="${SCRIPT_DIR}/live-image/VERSION"
local bundle_ver
bundle_ver="$(tr -d '[:space:]' < "${pointer}" 2>/dev/null || true)"
if [[ -z "${bundle_ver}" ]]; then
echo "WARN: bundle's ${pointer} is empty; skipping live-image fetch" >&2
return 0
fi
local installed_ver=""
if [[ -f "${LIVE_DIR}/VERSION" ]]; then
installed_ver="$(tr -d '[:space:]' < "${LIVE_DIR}/VERSION")"
fi
if [[ "${bundle_ver}" == "${installed_ver}" && "${FORCE_LIVE_IMAGE:-0}" != "1" ]]; then
echo "==> live-image already at ${bundle_ver}; skipping fetch (FORCE_LIVE_IMAGE=1 to redownload)"
return 0
fi
if [[ -z "${REGISTRY_URL:-}" ]]; then
echo "WARN: REGISTRY_URL is not set; cannot fetch live-image ${bundle_ver}. Re-run via proxmox-install.sh or export REGISTRY_URL." >&2
return 0
fi
local owner="${PACKAGE_OWNER:-josh}"
local base="${REGISTRY_URL%/}/api/packages/${owner}/generic/live-image/${bundle_ver}"
echo "==> fetching live-image ${bundle_ver} (was '${installed_ver:-none}') from ${base}"
local tmp
tmp="$(mktemp -d)"
# shellcheck disable=SC2064
trap "rm -rf '${tmp}'" RETURN
# Default curl meter shows rate + ETA, which matters for the ~300 MB
# initrd on slow links.
curl -fL -o "${tmp}/vmlinuz" "${base}/vmlinuz"
curl -fL -o "${tmp}/initrd.img" "${base}/initrd.img"
install -d -m 0755 -o "${SERVICE_USER}" -g "${SERVICE_USER}" "${LIVE_DIR}"
install -m 0644 -o "${SERVICE_USER}" -g "${SERVICE_USER}" \
"${tmp}/vmlinuz" "${LIVE_DIR}/vmlinuz"
install -m 0644 -o "${SERVICE_USER}" -g "${SERVICE_USER}" \
"${tmp}/initrd.img" "${LIVE_DIR}/initrd.img"
printf '%s\n' "${bundle_ver}" > "${LIVE_DIR}/VERSION"
chown "${SERVICE_USER}:${SERVICE_USER}" "${LIVE_DIR}/VERSION"
chmod 0644 "${LIVE_DIR}/VERSION"
}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
@@ -244,12 +302,14 @@ if [[ -f "${SCRIPT_DIR}/pxe-setup.sh" && -f "${SCRIPT_DIR}/ipxe-shas.txt" ]]; th
ln -sfn /usr/local/share/vetting/pxe-setup.sh /usr/local/sbin/vetting-pxe-setup
fi
# Stage the live image into LIVE_DIR if we can find one. Two layouts:
# - release bundle: ${SCRIPT_DIR}/live-image/{vmlinuz,initrd.img}
# - repo-tree dev run: ${REPO_ROOT}/live-image/build/{vmlinuz,initrd.img}
# Silently skipped when no source is found — operators without PXE
# don't need it, and dev checkouts that haven't run `make live-image`
# shouldn't fail the install.
# Stage the live image into LIVE_DIR. Preference order:
# 1. --live-image-src explicitly given, or local files found in the
# bundle/repo — copy straight in (dev and legacy bundle layouts).
# 2. Bundle carries only live-image/VERSION — fetch from the Gitea
# generic registry when the pointer differs from ${LIVE_DIR}/VERSION.
# 3. Neither — skip quietly (no-PXE installs don't need a live image,
# and dev checkouts that haven't run `make live-image` shouldn't
# fail the install).
if [[ -z "${LIVE_IMAGE_SRC}" ]]; then
for cand in \
"${SCRIPT_DIR}/live-image" \
@@ -268,6 +328,22 @@ if [[ -n "${LIVE_IMAGE_SRC}" ]]; then
"${LIVE_IMAGE_SRC}/vmlinuz" "${LIVE_DIR}/vmlinuz"
install -m 0644 -o "${SERVICE_USER}" -g "${SERVICE_USER}" \
"${LIVE_IMAGE_SRC}/initrd.img" "${LIVE_DIR}/initrd.img"
# Record the version that produced these files if the source has
# one (bundle with legacy layout carrying VERSION alongside the
# kernel; dev tree has live-image/VERSION at repo root). Lets a
# future bundle-based install decide whether to refetch.
for vcand in \
"${LIVE_IMAGE_SRC}/VERSION" \
"${SCRIPT_DIR}/live-image/VERSION" \
"${REPO_ROOT}/live-image/VERSION"; do
if [[ -f "${vcand}" ]]; then
install -m 0644 -o "${SERVICE_USER}" -g "${SERVICE_USER}" \
"${vcand}" "${LIVE_DIR}/VERSION"
break
fi
done
elif [[ -f "${SCRIPT_DIR}/live-image/VERSION" ]]; then
refresh_live_image
else
echo "==> no live image found (bundle/live-image or ../live-image/build); skipping live-dir staging"
fi