mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-05-25 18:04:58 +02:00
fix(tools): improve error diagnostics and actionable hints across install functions
- Add _diagnose_deb_failure() helper: extracts package metadata from failed .deb installs,
detects PostgreSQL version conflicts (e.g., postgresql-16-vchord with PG17 active),
lists unmet dependencies, and provides specific actionable hints
- Replace all 4 generic 'Both apt and dpkg installation failed' messages in
fetch_and_deploy_{codeberg,gh,gl}_release and fetch_and_deploy_from_url with
_diagnose_deb_failure() for targeted diagnostics
- install_packages_with_retry: on failure, check which packages are missing from
configured repos and name them with a distribution-specific hint
- upgrade_packages_with_retry: add hint about held-back packages / apt-cache policy
- setup_postgresql: when PGDG repo is unavailable for trixie/forky/sid, show which
distro PG version will be installed and warn that extension packages must match
- setup_deb822_repo: include GPG key URL and firewall hint in download failure message
- curl_download: add network/DNS hint to the failure message
- error_handler: add log-pattern analysis block after Node.js OOM detection that
scans the last 60 log lines for 5 common failure patterns and emits msg_warn hints:
* APT/dpkg dependency conflict (generic + PostgreSQL version mismatch)
* APT GPG/signature verification failure (sqv, KEYEXPIRED, NO_PUBKEY)
* Network/DNS failure (Could not resolve, Failed to fetch)
* APT lock held by another process
* Disk space exhaustion (ENOSPC)
This commit is contained in:
@@ -358,6 +358,55 @@ error_handler() {
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Log-pattern analysis: detect common failure causes and emit actionable hints ──
|
||||
if [[ -n "$active_log" && -s "$active_log" ]]; then
|
||||
local _log_tail
|
||||
_log_tail=$(tail -n 60 "$active_log" 2>/dev/null || true)
|
||||
|
||||
# 1. APT/dpkg dependency conflict
|
||||
if echo "$_log_tail" | grep -qE "Depends:|depends on.*but.*not installed|broken packages|unmet dep|dependency problems"; then
|
||||
# Check for PostgreSQL-specific version mismatch (most actionable)
|
||||
local _pg_conflict
|
||||
_pg_conflict=$(echo "$_log_tail" | grep -oE 'postgresql-[0-9]+ but.*installed' | head -1 || true)
|
||||
if [[ -n "$_pg_conflict" ]]; then
|
||||
if declare -f msg_warn >/dev/null 2>&1; then
|
||||
msg_warn "PostgreSQL version conflict: ${_pg_conflict}"
|
||||
msg_warn "Hint: A package requires a specific PostgreSQL version that is not installed. Your distribution may have installed a different PG version than expected."
|
||||
fi
|
||||
else
|
||||
if declare -f msg_warn >/dev/null 2>&1; then
|
||||
msg_warn "APT dependency conflict detected. A required package is not available or is the wrong version for this system."
|
||||
msg_warn "Hint: Run 'apt-get install -f' inside the container or check that all required repositories are configured for your distribution."
|
||||
fi
|
||||
fi
|
||||
# 2. APT/GPG signature verification failure
|
||||
elif echo "$_log_tail" | grep -qE "sqv|KEYEXPIRED|NO_PUBKEY|key is not certified|signature verification failed|is not signed|Sub-process.*sqv"; then
|
||||
if declare -f msg_warn >/dev/null 2>&1; then
|
||||
msg_warn "APT repository signature error detected."
|
||||
msg_warn "Hint: A repository GPG key may be missing, expired, or the keyring file is not yet present (/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc etc.)."
|
||||
msg_warn "Hint: Install the 'postgresql-common' package first, or re-add the repository with its correct signing key."
|
||||
fi
|
||||
# 3. Network / DNS failure during apt-get or curl
|
||||
elif echo "$_log_tail" | grep -qE "Could not resolve|Failed to fetch|Unable to connect|Name or service not known|Network is unreachable|curl.*resolve"; then
|
||||
if declare -f msg_warn >/dev/null 2>&1; then
|
||||
msg_warn "Network or DNS failure detected."
|
||||
msg_warn "Hint: Check the container's network connectivity, DNS settings, and whether any firewall or ad-blocker is intercepting traffic."
|
||||
fi
|
||||
# 4. APT lock held by another process
|
||||
elif echo "$_log_tail" | grep -qE "Could not get lock|dpkg frontend lock|waiting for it to exit|E: Unable to lock"; then
|
||||
if declare -f msg_warn >/dev/null 2>&1; then
|
||||
msg_warn "APT or dpkg lock conflict detected."
|
||||
msg_warn "Hint: Another package manager process may be running. Try 'rm /var/lib/dpkg/lock-frontend && dpkg --configure -a' inside the container."
|
||||
fi
|
||||
# 5. Disk space exhaustion
|
||||
elif echo "$_log_tail" | grep -qE "No space left on device|disk quota exceeded|ENOSPC"; then
|
||||
if declare -f msg_warn >/dev/null 2>&1; then
|
||||
msg_warn "Disk space exhausted during installation."
|
||||
msg_warn "Hint: Increase the container's disk size (pct resize <ctid> rootfs +2G) or clean up space first."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Detect context: Container (INSTALL_LOG set + inside container /root) vs Host
|
||||
if [[ -n "${INSTALL_LOG:-}" && -f "${INSTALL_LOG:-}" && -d /root ]]; then
|
||||
# CONTAINER CONTEXT: Copy log and create flag file for host
|
||||
|
||||
@@ -477,6 +477,21 @@ install_packages_with_retry() {
|
||||
done
|
||||
|
||||
msg_error "Failed to install packages after $((max_retries + 1)) attempts: ${packages[*]}"
|
||||
# Provide a quick diagnostic: check if package exists in any configured repo
|
||||
local _os_codename
|
||||
_os_codename=$(awk -F= '/^VERSION_CODENAME=/{gsub(/"/, "", $2); print $2}' /etc/os-release 2>/dev/null || echo "unknown")
|
||||
local _unavailable=()
|
||||
for _pkg in "${packages[@]}"; do
|
||||
if ! apt-cache show "$_pkg" &>/dev/null; then
|
||||
_unavailable+=("$_pkg")
|
||||
fi
|
||||
done
|
||||
if [[ ${#_unavailable[@]} -gt 0 ]]; then
|
||||
msg_error "Package(s) not found in any configured repository: ${_unavailable[*]}"
|
||||
msg_error "Hint: These packages may not be available for '${_os_codename}'. Check repository configuration or package names."
|
||||
else
|
||||
msg_error "Hint: Package(s) exist in the repo but could not be installed — run 'apt-get install -f' inside the container or check for dependency conflicts."
|
||||
fi
|
||||
return 100
|
||||
}
|
||||
|
||||
@@ -508,6 +523,7 @@ upgrade_packages_with_retry() {
|
||||
done
|
||||
|
||||
msg_error "Failed to upgrade packages after $((max_retries + 1)) attempts: ${packages[*]}"
|
||||
msg_error "Hint: The package may be held back, have conflicting dependencies, or the repository is unreachable. Check 'apt-cache policy ${packages[*]}' inside the container."
|
||||
return 100
|
||||
}
|
||||
|
||||
@@ -1468,6 +1484,7 @@ download_file() {
|
||||
done
|
||||
|
||||
msg_error "Failed to download: $url"
|
||||
msg_error "Hint: Check network connectivity or DNS resolution. The server may be unreachable or the URL may have changed."
|
||||
return 250
|
||||
}
|
||||
|
||||
@@ -1896,7 +1913,8 @@ setup_deb822_repo() {
|
||||
local tmp_gpg
|
||||
tmp_gpg=$(mktemp) || return 252
|
||||
curl -fsSL "$gpg_url" -o "$tmp_gpg" || {
|
||||
msg_error "Failed to download GPG key for ${name}"
|
||||
msg_error "Failed to download GPG key for ${name} from: ${gpg_url}"
|
||||
msg_error "Hint: Check network connectivity. If behind a proxy or firewall, ensure HTTPS access to $(echo "$gpg_url" | grep -oE 'https?://[^/]+') is allowed."
|
||||
rm -f "$tmp_gpg"
|
||||
return 7
|
||||
}
|
||||
@@ -2873,6 +2891,66 @@ function curl_download() {
|
||||
# fetch_and_deploy_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb" "tag" "v0.11.3" "/opt/autocaliweb"
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# _diagnose_deb_failure()
|
||||
#
|
||||
# - Called when both apt and dpkg fail to install a .deb package
|
||||
# - Extracts package metadata and detects common failure patterns
|
||||
# - Outputs enhanced error messages with actionable hints:
|
||||
# * PostgreSQL version conflicts (e.g., postgresql-16-foo with pg17 active)
|
||||
# * Missing declared dependencies
|
||||
# * Generic fallback hint pointing to the log
|
||||
#
|
||||
# Usage: _diagnose_deb_failure "/path/to/file.deb"
|
||||
# Returns: always 0 (diagnostic only — caller must return the error code)
|
||||
# ------------------------------------------------------------------------------
|
||||
_diagnose_deb_failure() {
|
||||
local deb_path="$1"
|
||||
local filename="${deb_path##*/}"
|
||||
local pkg_name pkg_deps pkg_version
|
||||
|
||||
pkg_name=$(dpkg-deb -f "$deb_path" Package 2>/dev/null || echo "${filename%%_*}")
|
||||
pkg_version=$(dpkg-deb -f "$deb_path" Version 2>/dev/null || true)
|
||||
pkg_deps=$(dpkg-deb -f "$deb_path" Depends 2>/dev/null || true)
|
||||
|
||||
msg_error "Failed to install '${pkg_name}${pkg_version:+ (${pkg_version})}' — both apt and dpkg reported errors"
|
||||
|
||||
# Detect PostgreSQL version conflict (e.g., postgresql-16-vchord while pg17 is active)
|
||||
local pg_ver_needed pg_ver_installed
|
||||
pg_ver_needed=$(echo "$filename" | grep -oP '(?<=postgresql-)[0-9]+(?=-)' | head -1 || true)
|
||||
if [[ -n "$pg_ver_needed" ]]; then
|
||||
pg_ver_installed=$(psql -V 2>/dev/null | awk '{print $3}' | cut -d. -f1 || true)
|
||||
if [[ -n "$pg_ver_installed" && "$pg_ver_needed" != "$pg_ver_installed" ]]; then
|
||||
msg_error "Version conflict: '${pkg_name}' is built for PostgreSQL ${pg_ver_needed}, but PostgreSQL ${pg_ver_installed} is installed on this system."
|
||||
msg_error "Hint: Your distribution installed a different PostgreSQL version than expected. The script may need updating to use postgresql-${pg_ver_installed}-* packages."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Show which declared dependencies are not satisfied
|
||||
if [[ -n "$pkg_deps" ]]; then
|
||||
local missing_deps=()
|
||||
while IFS=',' read -ra dep_list; do
|
||||
for dep_entry in "${dep_list[@]}"; do
|
||||
local dep_pkg
|
||||
dep_pkg=$(echo "$dep_entry" | awk '{print $1}' | tr -d ' ')
|
||||
[[ -z "$dep_pkg" || "$dep_pkg" == "("* ]] && continue
|
||||
if ! dpkg-query -W -f='${Status}' "$dep_pkg" 2>/dev/null | grep -q "install ok installed"; then
|
||||
missing_deps+=("$dep_pkg")
|
||||
fi
|
||||
done
|
||||
done <<<"$pkg_deps"
|
||||
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
||||
msg_error "Unmet dependencies: ${missing_deps[*]}"
|
||||
msg_error "Hint: Run 'apt-get install -f' inside the container to attempt automatic dependency resolution."
|
||||
else
|
||||
msg_error "Hint: Declared dependencies appear present but installation still failed. Check the log above for the exact error."
|
||||
fi
|
||||
else
|
||||
msg_error "Hint: Check the installation log above for the exact dependency or configuration error."
|
||||
fi
|
||||
}
|
||||
|
||||
function fetch_and_deploy_codeberg_release() {
|
||||
local app="$1"
|
||||
local repo="$2"
|
||||
@@ -3106,7 +3184,7 @@ function fetch_and_deploy_codeberg_release() {
|
||||
chmod 644 "$tmpdir/$filename"
|
||||
$STD apt install -y "$tmpdir/$filename" || {
|
||||
$STD dpkg -i "$tmpdir/$filename" || {
|
||||
msg_error "Both apt and dpkg installation failed"
|
||||
_diagnose_deb_failure "$tmpdir/$filename"
|
||||
rm -rf "$tmpdir"
|
||||
return 100
|
||||
}
|
||||
@@ -3651,7 +3729,7 @@ function fetch_and_deploy_gh_release() {
|
||||
[[ "${DPKG_FORCE_CONFNEW:-}" == "1" ]] && dpkg_opts="-o Dpkg::Options::=--force-confnew"
|
||||
DEBIAN_FRONTEND=noninteractive SYSTEMD_OFFLINE=1 $STD apt install -y $dpkg_opts "$tmpdir/$filename" || {
|
||||
SYSTEMD_OFFLINE=1 $STD dpkg -i "$tmpdir/$filename" || {
|
||||
msg_error "Both apt and dpkg installation failed"
|
||||
_diagnose_deb_failure "$tmpdir/$filename"
|
||||
rm -rf "$tmpdir"
|
||||
return 100
|
||||
}
|
||||
@@ -7040,7 +7118,13 @@ setup_postgresql() {
|
||||
SUITE="trixie-pgdg"
|
||||
|
||||
else
|
||||
msg_warn "PGDG repo not available for ${DISTRO_CODENAME}, falling back to distro packages"
|
||||
local _distro_pg_ver
|
||||
_distro_pg_ver=$(apt-cache show postgresql 2>/dev/null | awk '/^Version:/{print $2; exit}' | grep -oE '^[0-9]+' || true)
|
||||
msg_warn "PGDG repository not available for ${DISTRO_CODENAME} — falling back to distro-provided PostgreSQL packages"
|
||||
if [[ -n "$_distro_pg_ver" ]]; then
|
||||
msg_warn "Distro will install PostgreSQL ${_distro_pg_ver} (not the requested ${PG_VERSION})."
|
||||
msg_warn "Any PostgreSQL extension packages (e.g. vchord, pgvector) must be built for PostgreSQL ${_distro_pg_ver} on ${DISTRO_CODENAME}."
|
||||
fi
|
||||
USE_PGDG_REPO=false setup_postgresql
|
||||
return $?
|
||||
fi
|
||||
@@ -8558,7 +8642,7 @@ function fetch_and_deploy_from_url() {
|
||||
chmod 644 "$tmpdir/$filename"
|
||||
$STD apt install -y "$tmpdir/$filename" || {
|
||||
$STD dpkg -i "$tmpdir/$filename" || {
|
||||
msg_error "Both apt and dpkg installation failed"
|
||||
_diagnose_deb_failure "$tmpdir/$filename"
|
||||
rm -rf "$tmpdir"
|
||||
return 100
|
||||
}
|
||||
@@ -9226,7 +9310,7 @@ function fetch_and_deploy_gl_release() {
|
||||
[[ "${DPKG_FORCE_CONFNEW:-}" == "1" ]] && dpkg_opts="-o Dpkg::Options::=--force-confnew"
|
||||
DEBIAN_FRONTEND=noninteractive SYSTEMD_OFFLINE=1 $STD apt install -y $dpkg_opts "$tmpdir/$filename" || {
|
||||
SYSTEMD_OFFLINE=1 $STD dpkg -i "$tmpdir/$filename" || {
|
||||
msg_error "Both apt and dpkg installation failed"
|
||||
_diagnose_deb_failure "$tmpdir/$filename"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user