Enhances the build and error handler scripts to better manage installation logs. On install failure, the log is now copied from the container to the host for easier debugging. The error handler now saves the log inside the container's /root directory for later retrieval, improving traceability and support.
181 lines
6.5 KiB
Bash
181 lines
6.5 KiB
Bash
#!/usr/bin/env bash
|
|
# ------------------------------------------------------------------------------
|
|
# Error & Signal Handling for ProxmoxVED Scripts
|
|
# ------------------------------------------------------------------------------
|
|
# Copyright (c) 2021-2025 community-scripts ORG
|
|
# Author: MickLesk (CanbiZ)
|
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
# ------------------------------------------------------------------------------
|
|
|
|
explain_exit_code() {
|
|
local code="$1"
|
|
case "$code" in
|
|
# --- Generic / Shell ---
|
|
1) echo "General error / Operation not permitted" ;;
|
|
2) echo "Misuse of shell builtins (e.g. syntax error)" ;;
|
|
126) echo "Command invoked cannot execute (permission problem?)" ;;
|
|
127) echo "Command not found" ;;
|
|
128) echo "Invalid argument to exit" ;;
|
|
130) echo "Terminated by Ctrl+C (SIGINT)" ;;
|
|
137) echo "Killed (SIGKILL / Out of memory?)" ;;
|
|
139) echo "Segmentation fault (core dumped)" ;;
|
|
143) echo "Terminated (SIGTERM)" ;;
|
|
|
|
# --- Package manager / APT / DPKG ---
|
|
100) echo "APT: Package manager error (broken packages / dependency problems)" ;;
|
|
101) echo "APT: Configuration error (bad sources.list, malformed config)" ;;
|
|
255) echo "DPKG: Fatal internal error" ;;
|
|
|
|
# --- Node.js / npm / pnpm / yarn ---
|
|
243) echo "Node.js: Out of memory (JavaScript heap out of memory)" ;;
|
|
245) echo "Node.js: Invalid command-line option" ;;
|
|
246) echo "Node.js: Internal JavaScript Parse Error" ;;
|
|
247) echo "Node.js: Fatal internal error" ;;
|
|
248) echo "Node.js: Invalid C++ addon / N-API failure" ;;
|
|
249) echo "Node.js: Inspector error" ;;
|
|
254) echo "npm/pnpm/yarn: Unknown fatal error" ;;
|
|
|
|
# --- Python / pip / uv ---
|
|
210) echo "Python: Virtualenv / uv environment missing or broken" ;;
|
|
211) echo "Python: Dependency resolution failed" ;;
|
|
212) echo "Python: Installation aborted (permissions or EXTERNALLY-MANAGED)" ;;
|
|
|
|
# --- PostgreSQL ---
|
|
231) echo "PostgreSQL: Connection failed (server not running / wrong socket)" ;;
|
|
232) echo "PostgreSQL: Authentication failed (bad user/password)" ;;
|
|
233) echo "PostgreSQL: Database does not exist" ;;
|
|
234) echo "PostgreSQL: Fatal error in query / syntax" ;;
|
|
|
|
# --- MySQL / MariaDB ---
|
|
241) echo "MySQL/MariaDB: Connection failed (server not running / wrong socket)" ;;
|
|
242) echo "MySQL/MariaDB: Authentication failed (bad user/password)" ;;
|
|
243) echo "MySQL/MariaDB: Database does not exist" ;;
|
|
244) echo "MySQL/MariaDB: Fatal error in query / syntax" ;;
|
|
|
|
# --- MongoDB ---
|
|
251) echo "MongoDB: Connection failed (server not running)" ;;
|
|
252) echo "MongoDB: Authentication failed (bad user/password)" ;;
|
|
253) echo "MongoDB: Database not found" ;;
|
|
254) echo "MongoDB: Fatal query error" ;;
|
|
|
|
# --- Proxmox Custom Codes ---
|
|
200) echo "Custom: Failed to create lock file" ;;
|
|
203) echo "Custom: Missing CTID variable" ;;
|
|
204) echo "Custom: Missing PCT_OSTYPE variable" ;;
|
|
205) echo "Custom: Invalid CTID (<100)" ;;
|
|
209) echo "Custom: Container creation failed" ;;
|
|
210) echo "Custom: Cluster not quorate" ;;
|
|
214) echo "Custom: Not enough storage space" ;;
|
|
215) echo "Custom: Container ID not listed" ;;
|
|
216) echo "Custom: RootFS entry missing in config" ;;
|
|
217) echo "Custom: Storage does not support rootdir" ;;
|
|
220) echo "Custom: Unable to resolve template path" ;;
|
|
222) echo "Custom: Template download failed after 3 attempts" ;;
|
|
223) echo "Custom: Template not available after download" ;;
|
|
231) echo "Custom: LXC stack upgrade/retry failed" ;;
|
|
|
|
# --- Default ---
|
|
*) echo "Unknown error" ;;
|
|
esac
|
|
}
|
|
|
|
# === Error handler ============================================================
|
|
error_handler() {
|
|
local exit_code=${1:-$?}
|
|
local command=${2:-${BASH_COMMAND:-unknown}}
|
|
local line_number=${BASH_LINENO[0]:-unknown}
|
|
|
|
command="${command//\$STD/}"
|
|
|
|
if [[ "$exit_code" -eq 0 ]]; then
|
|
return 0
|
|
fi
|
|
|
|
local explanation
|
|
explanation="$(explain_exit_code "$exit_code")"
|
|
|
|
printf "\e[?25h"
|
|
|
|
# Use msg_error if available, fallback to echo
|
|
if declare -f msg_error >/dev/null 2>&1; then
|
|
msg_error "in line ${line_number}: exit code ${exit_code} (${explanation}): while executing command ${command}"
|
|
else
|
|
echo -e "\n${RD}[ERROR]${CL} in line ${RD}${line_number}${CL}: exit code ${RD}${exit_code}${CL} (${explanation}): while executing command ${YWB}${command}${CL}\n"
|
|
fi
|
|
|
|
if [[ -n "${DEBUG_LOGFILE:-}" ]]; then
|
|
{
|
|
echo "------ ERROR ------"
|
|
echo "Timestamp : $(date '+%Y-%m-%d %H:%M:%S')"
|
|
echo "Exit Code : $exit_code ($explanation)"
|
|
echo "Line : $line_number"
|
|
echo "Command : $command"
|
|
echo "-------------------"
|
|
} >>"$DEBUG_LOGFILE"
|
|
fi
|
|
|
|
if [[ -n "${SILENT_LOGFILE:-}" && -s "$SILENT_LOGFILE" ]]; then
|
|
echo "--- Last 20 lines of silent log ---"
|
|
tail -n 20 "$SILENT_LOGFILE"
|
|
echo "-----------------------------------"
|
|
|
|
# Copy log to container home for later retrieval (if running inside container via pct exec)
|
|
if [[ -d /root ]]; then
|
|
local container_log="/root/.install-${SESSION_ID:-error}.log"
|
|
cp "$SILENT_LOGFILE" "$container_log" 2>/dev/null || true
|
|
if declare -f msg_custom >/dev/null 2>&1; then
|
|
msg_custom "📋" "${YW}" "Log saved to: ${container_log}"
|
|
else
|
|
echo -e "${YW}Log saved to:${CL} ${BL}${container_log}${CL}"
|
|
fi
|
|
else
|
|
# Running on host - show local path
|
|
if declare -f msg_custom >/dev/null 2>&1; then
|
|
msg_custom "📋" "${YW}" "Full log: ${SILENT_LOGFILE}"
|
|
else
|
|
echo -e "${YW}Full log:${CL} ${BL}${SILENT_LOGFILE}${CL}"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
exit "$exit_code"
|
|
}
|
|
|
|
# === Exit handler =============================================================
|
|
on_exit() {
|
|
local exit_code=$?
|
|
[[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
|
|
exit "$exit_code"
|
|
}
|
|
|
|
# === Signal handlers ==========================================================
|
|
on_interrupt() {
|
|
if declare -f msg_error >/dev/null 2>&1; then
|
|
msg_error "Interrupted by user (SIGINT)"
|
|
else
|
|
echo -e "\n${RD}Interrupted by user (SIGINT)${CL}"
|
|
fi
|
|
exit 130
|
|
}
|
|
|
|
on_terminate() {
|
|
if declare -f msg_error >/dev/null 2>&1; then
|
|
msg_error "Terminated by signal (SIGTERM)"
|
|
else
|
|
echo -e "\n${RD}Terminated by signal (SIGTERM)${CL}"
|
|
fi
|
|
exit 143
|
|
}
|
|
|
|
# === Init traps ===============================================================
|
|
catch_errors() {
|
|
set -Ee -o pipefail
|
|
if [ "${STRICT_UNSET:-0}" = "1" ]; then
|
|
set -u
|
|
fi
|
|
trap 'error_handler' ERR
|
|
trap on_exit EXIT
|
|
trap on_interrupt INT
|
|
trap on_terminate TERM
|
|
}
|