From c9dbcd73b9c999b6939b86acaa36ce3bb25a6b55 Mon Sep 17 00:00:00 2001 From: MickLesk <47820557+MickLesk@users.noreply.github.com> Date: Thu, 8 Oct 2026 09:57:20 +0200 Subject: [PATCH] Remember a kept cached image until the upstream changes Keep cached was asked on every run once the mirror had rebuilt an image. The answer is now stored in .keep with the upstream checksum, and the question returns only when that checksum changes; a download removes the marker. --- pve/vm-core.func | 16 ++++++++++++++-- tests/vm-helpers.sh | 17 +++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/pve/vm-core.func b/pve/vm-core.func index 85381b2..330c7df 100644 --- a/pve/vm-core.func +++ b/pve/vm-core.func @@ -1678,7 +1678,9 @@ vm_image_cache_path() { # A cached image that no longer matches usually means the upstream was rebuilt, # not that anything is wrong. Offer the choice instead of silently re-downloading -# several hundred MB. Unattended or without a terminal, take the new one. +# several hundred MB. Unattended or without a terminal, take the new one. A +# "Keep cached" answer is remembered in .keep with the upstream checksum +# it was given against, so the question returns only when the upstream changes. _vm_cache_choice() { local file="$1" url="$2" local_size local_date remote_size remote_date head @@ -1742,13 +1744,23 @@ vm_fetch_image() { fi if [[ "$cache" == yes && -e "$target" ]]; then + local keep="${target}.keep" if _vm_image_ok "$target" "$exact_bytes" "$min_bytes" "$sha_tool" "$sha_want" "$xz"; then + rm -f "$keep" msg_ok "Using cached ${CL}${BL}$(basename "$target")${CL}" return 0 fi + if [[ -n "$sha_want" && -f "$keep" && "$(<"$keep")" == "${sha_tool}:${sha_want}" ]]; then + msg_ok "Using cached ${CL}${BL}$(basename "$target")${CL} (kept; the upstream has not changed)" + return 0 + fi if _vm_cache_choice "$target" "$url"; then msg_warn "Replacing the cached $(basename "$target")" - rm -f "$target" + rm -f "$target" "$keep" + elif [[ -n "$sha_want" ]]; then + printf '%s' "${sha_tool}:${sha_want}" >"$keep" + msg_ok "Using cached ${CL}${BL}$(basename "$target")${CL} (kept until the upstream changes)" + return 0 else msg_ok "Using cached ${CL}${BL}$(basename "$target")${CL}" return 0 diff --git a/tests/vm-helpers.sh b/tests/vm-helpers.sh index c6fa09f..7205b71 100644 --- a/tests/vm-helpers.sh +++ b/tests/vm-helpers.sh @@ -182,6 +182,23 @@ vm_fetch_image "https://dl.test/openwrt.img.gz" "$TEST_DIR/cache/nosums.img" --c assert_contains "$WARNINGS" "checking the size only" ok "digest case is ignored; missing checksum list warns and continues" +CHOICE_CALLS="$TEST_DIR/choice-calls" +: >"$CHOICE_CALLS" +_vm_cache_choice() { echo keep >>"$CHOICE_CALLS"; return 1; } +KEPT="$TEST_DIR/cache/kept.img" +mkdir -p "$TEST_DIR/cache" && printf 'old build\n' >"$KEPT" +vm_fetch_image "https://dl.test/openwrt.img.gz" "$KEPT" --cache --sha256 "$IMAGE_SHA256" || fail "keep cached" +[[ -f "$KEPT.keep" ]] || fail "a kept cache gets a marker" +vm_fetch_image "https://dl.test/openwrt.img.gz" "$KEPT" --cache --sha256 "$IMAGE_SHA256" || fail "kept cache reused" +assert_eq "$(grep -c keep "$CHOICE_CALLS")" 1 "asked once while the upstream is unchanged" +vm_fetch_image "https://dl.test/openwrt.img.gz" "$KEPT" --cache --sha256 "$(printf '%064d' 1)" || fail "keep again after a change" +assert_eq "$(grep -c keep "$CHOICE_CALLS")" 2 "asked again once the upstream changed" +_vm_cache_choice() { return 0; } +vm_fetch_image "https://dl.test/openwrt.img.gz" "$KEPT" --cache --sha256 "$IMAGE_SHA256" || fail "replace cached" +[[ ! -f "$KEPT.keep" ]] || fail "the marker goes with the replaced file" +assert_eq "$(sha256sum "$KEPT" | cut -d' ' -f1)" "$IMAGE_SHA256" "fresh download in place" +ok "a kept cache is reused until the upstream checksum changes" + # ── vm_import_disk ────────────────────────────────────────────────────────── VMID=100 QM_MODERN=yes