From 400905e533c211dd0e8286acc7a803abe3773de3 Mon Sep 17 00:00:00 2001 From: MickLesk <47820557+MickLesk@users.noreply.github.com> Date: Fri, 4 Sep 2026 09:19:53 +0200 Subject: [PATCH 1/3] Ask Proxmox for a template before reaching for linuxcontainers.org Every ARM64 container took the custom-template path, so pveam was never consulted on that architecture. For Debian that path resolved its URL from community-scripts/debian-arm64-lxc, a repository that does not exist: the releases endpoint answers 404, so ARM64 Debian could not be created at all through the split core. Template lookup now runs the same way on both architectures. Local templates first, then the catalog, both matched on OS, version and exact architecture. Only when Proxmox has nothing does the linuxcontainers.org build step in, which is still the only source for Ubuntu, Fedora and the rest on ARM64. Against a live catalog this routes debian 13 and alpine 3.24 through pveam on ARM64 -- Proxmox ships both -- while debian 12, ubuntu and fedora keep the old path. A local template short-circuits before any catalog read. The interactive "pick another version" fallback filtered by name only. On a host whose catalog carries both architectures, which is now the normal case, it could offer an amd64 template to an ARM64 host and fail later at creation. Supersedes the Debian-only routing in #5. --- pve/backend.func | 53 ++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/pve/backend.func b/pve/backend.func index ce3718a..d64d9f7 100644 --- a/pve/backend.func +++ b/pve/backend.func @@ -2367,8 +2367,31 @@ create_lxc_container() { } # Downloads an ARM64 LXC rootfs template to $1. - # Debian: fetches latest release from community-scripts/debian-arm64-lxc on GitHub. - # Others: fetches from jenkins.linuxcontainers.org. + # Does Proxmox offer this OS/version/arch? Local first, then the catalog. + _pveam_offers_template() { + local search pattern + search="${PCT_OSTYPE}-${PCT_OSVERSION:-}" + case "$PCT_OSTYPE" in + debian | ubuntu) pattern="-standard_" ;; + alpine | fedora | rocky | centos) pattern="-default_" ;; + *) pattern="" ;; + esac + + if pveam list "$TEMPLATE_STORAGE" 2>/dev/null | + awk -v s="$search" -v p="$pattern" -v a="$ARCH" \ + '$1 ~ s && $1 ~ p && $1 ~ ("_" a "\\.(tar\\.zst|tar\\.xz|tar\\.gz)$") {found=1} + END {exit !found}'; then + return 0 + fi + + _pveam_update >/dev/null 2>&1 || true + _pveam_available | + grep -E "_${ARCH}\.(tar\.zst|tar\.xz|tar\.gz)([[:space:]]|$)" | + awk '{print $2}' | + grep -qE "^${search}.*${pattern}" + } + + # Only reached when pveam has nothing for this arch. download_arm64_template() { local dest="$1" url @@ -2377,21 +2400,7 @@ create_lxc_container() { exit 217 } - if [[ "$PCT_OSTYPE" == "debian" ]]; then - url=$( - curl -fsSL "https://api.github.com/repos/community-scripts/debian-arm64-lxc/releases/latest" | - jq -r --arg v "$CUSTOM_TEMPLATE_VARIANT" \ - '.assets[].browser_download_url | select(test("debian-" + $v + "-arm64-rootfs\\.tar\\.xz$"))' | - head -n1 - ) - - [[ -n "$url" ]] || { - msg_error "Could not find Debian ${CUSTOM_TEMPLATE_VARIANT} ARM64 template URL." - exit 225 - } - else - url="https://jenkins.linuxcontainers.org/job/image-${PCT_OSTYPE}/architecture=arm64,release=${CUSTOM_TEMPLATE_VARIANT},variant=default/lastStableBuild/artifact/rootfs.tar.xz" - fi + url="https://jenkins.linuxcontainers.org/job/image-${PCT_OSTYPE}/architecture=arm64,release=${CUSTOM_TEMPLATE_VARIANT},variant=default/lastStableBuild/artifact/rootfs.tar.xz" msg_info "Downloading ${PCT_OSTYPE^} ${CUSTOM_TEMPLATE_VARIANT} ARM64 template" local patched="${dest%/*}/.${dest##*/}.patched" @@ -2603,9 +2612,8 @@ create_lxc_container() { # ------------------------------------------------------------------------------ CUSTOM_TEMPLATE_VARIANT="" - if [[ "$ARCH" == "arm64" ]]; then - # ARM64: use custom template download from linuxcontainers.org / GitHub - msg_info "Preparing ARM64 template" + if [[ "$ARCH" == "arm64" ]] && ! _pveam_offers_template; then + msg_info "No Proxmox template for ${PCT_OSTYPE} on ${ARCH}, using linuxcontainers.org" CUSTOM_TEMPLATE_VARIANT=$(arm64_template_variant "$PCT_OSTYPE" "${PCT_OSVERSION:-}") || { msg_error "No ARM64 template mapping for ${PCT_OSTYPE} ${PCT_OSVERSION:-latest}" @@ -2730,12 +2738,13 @@ create_lxc_container() { mapfile -t LOCAL_TEMPLATES < <( pveam list "$TEMPLATE_STORAGE" 2>/dev/null | - awk -v search="${TEMPLATE_SEARCH}-" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' | + awk -v search="${TEMPLATE_SEARCH}-" -v pattern="${TEMPLATE_PATTERN}" -v arch="${ARCH}" \ + '$1 ~ search && $1 ~ pattern && $1 ~ ("_" arch "\\.(tar\\.zst|tar\\.xz|tar\\.gz)$") {print $1}' | sed 's|.*/||' | sort -t - -k 2 -V || true ) mapfile -t ONLINE_TEMPLATES < <( _pveam_available | - grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' | + grep -E "_${ARCH}\.(tar\.zst|tar\.xz|tar\.gz)([[:space:]]|$)" | awk '{print $2}' | grep -E "^${TEMPLATE_SEARCH}-.*${TEMPLATE_PATTERN}" | sort -t - -k 2 -V 2>/dev/null || true From 5df7aa7d00c0f18983f7984265963ee8dbf2e5e2 Mon Sep 17 00:00:00 2001 From: MickLesk <47820557+MickLesk@users.noreply.github.com> Date: Fri, 4 Sep 2026 09:28:01 +0200 Subject: [PATCH 2/3] incus: check the local image cache before asking the remote Image resolution tried up to six images: candidates over the network before looking at what was already copied locally, so an image on disk still cost round-trips and resolution failed outright on a host without internet. The local match was also a substring search over the whole CSV row: asking for debian/12 matched a debian/13 row uploaded on 2026/12/01, because the row contains "debian" and the date contains "12". That launched the wrong release with no error. It now compares the alias field whole. --- incus/backend.func | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/incus/backend.func b/incus/backend.func index 17b220a..10b5651 100644 --- a/incus/backend.func +++ b/incus/backend.func @@ -90,7 +90,22 @@ _incus_resolve_launch_image() { candidates+=("images:ubuntu/${ver}.04" "images:ubuntu/${ver}.04/cloud") fi - local cand local_match + local cand local_aliases + + # Local first: a copied image needs no round-trip, and this keeps working on a + # host without internet. + local_aliases=$(incus image list -f csv,noheader -c l 2>/dev/null || true) + for cand in "${candidates[@]}"; do + # Match the alias field whole. The previous substring search ran over the + # entire row, so a version matched any digits in a date or size. + if [[ -n "$local_aliases" ]] && + grep -qxF "${cand#images:}" <<<"$local_aliases" && + incus image info "${cand#images:}" &>/dev/null; then + INCUS_LAUNCH_IMAGE="${cand#images:}" + return 0 + fi + done + for cand in "${candidates[@]}"; do if incus image info "$cand" &>/dev/null; then INCUS_LAUNCH_IMAGE="$cand" @@ -98,16 +113,6 @@ _incus_resolve_launch_image() { fi done - # Local image fingerprint/alias match (already copied) - local_match=$(incus image list -f csv,noheader 2>/dev/null | - awk -F, -v os="$os" -v ver="$ver" ' - tolower($0) ~ os && $0 ~ ver { print $1; exit } - ' || true) - if [[ -n "$local_match" ]] && incus image info "$local_match" &>/dev/null; then - INCUS_LAUNCH_IMAGE="$local_match" - return 0 - fi - # Last resort: try remote launch of primary (incus may pull on demand) INCUS_LAUNCH_IMAGE="images:${os}/${ver}" return 1 From 314726bd1ca9caad2d79e553ca9137f2a2d89cbd Mon Sep 17 00:00:00 2001 From: MickLesk <47820557+MickLesk@users.noreply.github.com> Date: Fri, 4 Sep 2026 09:30:16 +0200 Subject: [PATCH 3/3] incus: trim comment --- incus/backend.func | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/incus/backend.func b/incus/backend.func index 10b5651..55868cb 100644 --- a/incus/backend.func +++ b/incus/backend.func @@ -92,12 +92,9 @@ _incus_resolve_launch_image() { local cand local_aliases - # Local first: a copied image needs no round-trip, and this keeps working on a - # host without internet. + # Local first: no round-trip, and works without internet. local_aliases=$(incus image list -f csv,noheader -c l 2>/dev/null || true) for cand in "${candidates[@]}"; do - # Match the alias field whole. The previous substring search ran over the - # entire row, so a version matched any digits in a date or size. if [[ -n "$local_aliases" ]] && grep -qxF "${cand#images:}" <<<"$local_aliases" && incus image info "${cand#images:}" &>/dev/null; then