From 2b75214a975be9b9bef4824b78304a23fbe5f078 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 14 Jul 2026 15:30:08 +0200 Subject: image-builder: catch build/push failures, prune cache on --force The main loop runs build_variant in an `if ! (...)` condition, which suppresses set -e inside the subshell, so a failed docker build fell through to push a nonexistent tag and log "Done" (seen live: a transient containerd export lock reported success). Add explicit exit checks on docker build and docker push in all three scripts; return non-zero so the variant is marked failed. Also prune the build cache before a --force full-image build: --force already implies --no-cache, so the stale cache is dead weight that still loads the snapshotter's lock bookkeeping and has raced the layer export. Best-effort, never fails the build. Co-Authored-By: Claude Opus 4.8 --- .extras/image-builder/bootstrap.sh | 13 +++++++++++-- .extras/image-builder/build-full-image.sh | 25 ++++++++++++++++++++++--- .extras/image-builder/build-sbo-testbuild.sh | 13 +++++++++++-- 3 files changed, 44 insertions(+), 7 deletions(-) (limited to '.extras') diff --git a/.extras/image-builder/bootstrap.sh b/.extras/image-builder/bootstrap.sh index e9d9be5..9893e66 100755 --- a/.extras/image-builder/bootstrap.sh +++ b/.extras/image-builder/bootstrap.sh @@ -521,9 +521,18 @@ LABEL slackware.arch="x86_64" CMD ["/bin/bash"] DOCKERFILE + # Explicit exit checks: build_variant runs in an `if ! (...)` condition + # (see Main), which suppresses `set -e` in this subshell, so a failed build + # would otherwise push a nonexistent tag and log "Done". _log "Building and pushing ${TAG}..." - docker build --no-cache -t "${TAG}" "${WORKDIR}" - docker push "${TAG}" + if ! docker build --no-cache -t "${TAG}" "${WORKDIR}"; then + _warn "build failed for ${TAG}; not pushing." + return 1 + fi + if ! docker push "${TAG}"; then + _warn "push failed for ${TAG}." + return 1 + fi _log "=== Done: ${TAG} ===" } diff --git a/.extras/image-builder/build-full-image.sh b/.extras/image-builder/build-full-image.sh index c5f1c36..24cbe1d 100755 --- a/.extras/image-builder/build-full-image.sh +++ b/.extras/image-builder/build-full-image.sh @@ -189,13 +189,23 @@ DOCKERFILE local BUILD_FLAGS=() [[ "${FORCE}" == "true" ]] && BUILD_FLAGS+=(--no-cache) + # Explicit exit checks: build_variant runs in an `if ! (...)` condition + # (see Main), which suppresses `set -e` inside this subshell, so a failed + # docker build would otherwise fall through to push a nonexistent tag and + # log "Done". Check each step and return non-zero on failure. _log " Building ${FULL_TAG}..." - docker build "${BUILD_FLAGS[@]}" \ + if ! docker build "${BUILD_FLAGS[@]}" \ -t "${FULL_TAG}" \ - "${WORKDIR}" + "${WORKDIR}"; then + _warn " build failed for ${FULL_TAG}; not pushing." + return 1 + fi _log " Pushing ${FULL_TAG}..." - docker push "${FULL_TAG}" + if ! docker push "${FULL_TAG}"; then + _warn " push failed for ${FULL_TAG}." + return 1 + fi _log "=== Done: ${FULL_TAG} ===" } @@ -204,6 +214,15 @@ DOCKERFILE # Main # ============================================================================ +# A --force build passes --no-cache, so the stale build cache is dead weight: +# it still loads the containerd snapshotter's lease/lock bookkeeping and has +# raced the layer export ("failed to open writer: ref ... locked ... unavailable"). +# Prune it first to shrink that surface. Best-effort; never fail the build on it. +if [[ "${FORCE}" == "true" ]]; then + _log " --force: pruning build cache before rebuild" + docker builder prune -f >/dev/null 2>&1 || _warn " builder prune failed (ignored)" +fi + rc=0 for VERSION in "${BUILD_VARIANTS[@]}"; do if ! ( build_variant "${VERSION}" ); then diff --git a/.extras/image-builder/build-sbo-testbuild.sh b/.extras/image-builder/build-sbo-testbuild.sh index 4364cd5..d04c426 100755 --- a/.extras/image-builder/build-sbo-testbuild.sh +++ b/.extras/image-builder/build-sbo-testbuild.sh @@ -104,10 +104,19 @@ DOCKERFILE local BUILD_FLAGS=() [[ "${FORCE}" == "true" ]] && BUILD_FLAGS+=(--no-cache) + # Explicit exit checks: build_variant runs in an `if ! (...)` condition + # (see Main), which suppresses `set -e` in this subshell, so a failed build + # would otherwise push a nonexistent tag and log "Done". _log " Building ${TB_TAG}..." - docker build "${BUILD_FLAGS[@]}" -t "${TB_TAG}" "${WORKDIR}" + if ! docker build "${BUILD_FLAGS[@]}" -t "${TB_TAG}" "${WORKDIR}"; then + _warn " build failed for ${TB_TAG}; not pushing." + return 1 + fi _log " Pushing ${TB_TAG}..." - docker push "${TB_TAG}" + if ! docker push "${TB_TAG}"; then + _warn " push failed for ${TB_TAG}." + return 1 + fi _log "=== Done: ${TB_TAG} ===" } -- cgit v1.2.3