diff --git a/misc/build.func b/misc/build.func index 29c88ed88..9b12cc564 100644 --- a/misc/build.func +++ b/misc/build.func @@ -3831,6 +3831,78 @@ runtime_script_status_guard() { return 0 } +# ------------------------------------------------------------------------------ +# check_container_os_guard() +# +# - Compares the container OS (/etc/os-release) with the script's recommended +# var_os/var_version before running update_script +# - On mismatch: interactive runs ask whether to continue (default: no); +# headless runs (PHS_SILENT=1 / no tty) abort instead of updating on an +# unsupported base and leaving the app broken mid-update +# - Bypass via var_ignore_os_mismatch=1|yes|true|on (still warns, but continues) +# ------------------------------------------------------------------------------ +check_container_os_guard() { + local rec_os="${var_os:-}" rec_ver="${var_version:-}" + rec_os="${rec_os,,}" + [[ -z "$rec_os" || -z "$rec_ver" ]] && return 0 + [[ -r /etc/os-release ]] || return 0 + + local cur_os cur_ver + cur_os="$(. /etc/os-release 2>/dev/null; echo "${ID:-}")" + cur_ver="$(. /etc/os-release 2>/dev/null; echo "${VERSION_ID:-}")" + cur_os="${cur_os,,}" + [[ -z "$cur_os" || -z "$cur_ver" ]] && return 0 + + # Exact version or prefix on a dot boundary (e.g. alpine 3.22 matches 3.22.1) + if [[ "$cur_os" == "$rec_os" ]] && [[ "$cur_ver" == "$rec_ver" || "$cur_ver" == "$rec_ver".* ]]; then + return 0 + fi + + case "${var_ignore_os_mismatch:-}" in + 1 | yes | true | on) + msg_warn "Container OS is ${cur_os} ${cur_ver} but the script recommends ${rec_os} ${rec_ver} — continuing via var_ignore_os_mismatch (may break, no support)." + return 0 + ;; + esac + + # Persistent opt-out: stores the ignored target version, so the question + # comes back once the script targets a newer OS again + local ignore_file="/usr/local/community-scripts/ignore-os-mismatch" + if [[ -f "$ignore_file" && "$(cat "$ignore_file" 2>/dev/null)" == "${rec_os} ${rec_ver}" ]]; then + msg_warn "Container OS is ${cur_os} ${cur_ver} but the script recommends ${rec_os} ${rec_ver} — continuing (previously ignored via ${ignore_file}, may break, no support)." + return 0 + fi + + if [[ "${PHS_SILENT:-0}" != "1" ]] && command -v whiptail &>/dev/null && [ -t 0 ] && [[ "$TERM" != "dumb" ]]; then + local choice + choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "OS VERSION MISMATCH" --menu \ + "This container runs ${cur_os} ${cur_ver}, but this script now targets ${rec_os} ${rec_ver}.\n\nUpdating on the older base OS may fail or leave ${APP:-the application} broken (e.g. required runtime versions are not available).\n\nRecommended: upgrade the container OS to ${rec_os} ${rec_ver} first, then run this update again.\n\nIf you continue anyway, it may break — no support is provided in that case.\n\nContinue anyway?" \ + 20 70 3 \ + "1" "No (cancel update)" \ + "2" "Yes (continue this time)" \ + "3" "Yes (continue and don't ask again)" \ + --nocancel --default-item "1" 3>&1 1>&2 2>&3) + case "$choice" in + 2) + msg_warn "Continuing update on ${cur_os} ${cur_ver} despite recommended ${rec_os} ${rec_ver} — may break, no support." + return 0 + ;; + 3) + mkdir -p "${ignore_file%/*}" + echo "${rec_os} ${rec_ver}" >"$ignore_file" + msg_warn "Continuing update on ${cur_os} ${cur_ver}; OS check for ${rec_os} ${rec_ver} disabled via ${ignore_file} — may break, no support." + return 0 + ;; + esac + msg_error "Update cancelled: container OS ${cur_os} ${cur_ver} does not match the recommended ${rec_os} ${rec_ver}." + return 1 + fi + + msg_error "Container OS ${cur_os} ${cur_ver} does not match the recommended ${rec_os} ${rec_ver} — skipping update." + msg_error "Upgrade the container OS to ${rec_os} ${rec_ver} first, then run this update again — or bypass this check (may break, no support) with: echo \"${rec_os} ${rec_ver}\" > ${ignore_file}" + return 1 +} + # ------------------------------------------------------------------------------ # start() # @@ -3852,6 +3924,7 @@ start() { ensure_profile_loaded get_lxc_ip runtime_script_status_guard update || return 0 + check_container_os_guard || return 0 update_script run_addon_updates update_motd_ip @@ -3863,6 +3936,7 @@ start() { ensure_profile_loaded get_lxc_ip runtime_script_status_guard update || return 0 + check_container_os_guard || return 0 update_script run_addon_updates update_motd_ip @@ -3893,6 +3967,7 @@ start() { ensure_profile_loaded get_lxc_ip runtime_script_status_guard update || return 0 + check_container_os_guard || return 0 update_script run_addon_updates update_motd_ip