Refactor storage validation and error codes for containers

Simplifies and streamlines storage validation logic in create_lxc_container, removing redundant content checks and using direct exit codes for unsupported storage types. Updates error_handler.func with clearer, more specific Proxmox exit code explanations and improves code consistency and readability throughout error handling functions.
This commit is contained in:
CanbiZ 2025-12-04 14:06:16 +01:00
parent 9307060c45
commit d677488b29
2 changed files with 193 additions and 231 deletions

View File

@ -3336,43 +3336,25 @@ create_lxc_container() {
fi fi
msg_info "Validating storage '$CONTAINER_STORAGE'" msg_info "Validating storage '$CONTAINER_STORAGE'"
STORAGE_CONTENT=$(grep -A10 -E "^(dir|nfs|cifs|btrfs|cephfs|lvm|lvmthin|zfspool|rbd|iscsi|iscsidirect|zfs|linstor|pbs): $CONTAINER_STORAGE$" /etc/pve/storage.cfg | grep -m1 content | awk '{$1=""; print $0}' | xargs)
if [[ -z "$STORAGE_CONTENT" ]]; then
if pvesm status -content rootdir 2>/dev/null | awk 'NR>1{print $1}' | grep -qx "$CONTAINER_STORAGE"; then
STORAGE_CONTENT="rootdir"
fi
fi
STORAGE_TYPE=$(grep -E "^[^:]+: $CONTAINER_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1 | head -1) STORAGE_TYPE=$(grep -E "^[^:]+: $CONTAINER_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1 | head -1)
case "$STORAGE_TYPE" in case "$STORAGE_TYPE" in
linstor | rbd | cephfs | iscsi | iscsidirect | nfs | cifs) iscsidirect) exit 212 ;;
if ! pvesm status -storage "$CONTAINER_STORAGE" &>/dev/null; then iscsi | zfs) exit 213 ;;
msg_error "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) not accessible" cephfs) exit 219 ;;
exit 217 pbs) exit 224 ;;
fi linstor | rbd | nfs | cifs)
pvesm status -storage "$CONTAINER_STORAGE" &>/dev/null || exit 217
;; ;;
esac esac
if ! pvesm status -content rootdir 2>/dev/null | awk 'NR>1{print $1}' | grep -qx "$CONTAINER_STORAGE"; then pvesm status -content rootdir 2>/dev/null | awk 'NR>1{print $1}' | grep -qx "$CONTAINER_STORAGE" || exit 213
if ! grep -qw "rootdir" <<<"$STORAGE_CONTENT"; then
msg_error "Storage '$CONTAINER_STORAGE' does not support 'rootdir'"
exit 217
fi
fi
msg_ok "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) validated" msg_ok "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) validated"
msg_info "Validating template storage '$TEMPLATE_STORAGE'" msg_info "Validating template storage '$TEMPLATE_STORAGE'"
TEMPLATE_CONTENT=$(grep -A10 -E "^(dir|nfs|cifs|btrfs|cephfs|lvm|lvmthin|zfspool|rbd|iscsi|iscsidirect|zfs|linstor|pbs): $TEMPLATE_STORAGE$" /etc/pve/storage.cfg | grep -m1 content | awk '{$1=""; print $0}' | xargs)
if [[ -z "$TEMPLATE_CONTENT" ]]; then
if pvesm status -content vztmpl 2>/dev/null | awk 'NR>1{print $1}' | grep -qx "$TEMPLATE_STORAGE"; then
TEMPLATE_CONTENT="vztmpl"
fi
fi
TEMPLATE_TYPE=$(grep -E "^[^:]+: $TEMPLATE_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1) TEMPLATE_TYPE=$(grep -E "^[^:]+: $TEMPLATE_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1)
if ! grep -qw "vztmpl" <<<"$TEMPLATE_CONTENT"; then if ! pvesm status -content vztmpl 2>/dev/null | awk 'NR>1{print $1}' | grep -qx "$TEMPLATE_STORAGE"; then
msg_warn "Template storage '$TEMPLATE_STORAGE' may not support 'vztmpl'" msg_warn "Template storage '$TEMPLATE_STORAGE' may not support 'vztmpl'"
fi fi
msg_ok "Template storage '$TEMPLATE_STORAGE' validated" msg_ok "Template storage '$TEMPLATE_STORAGE' validated"

View File

@ -40,106 +40,86 @@
# - Returns description string for given exit code # - Returns description string for given exit code
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
explain_exit_code() { explain_exit_code() {
local code="$1" local code="$1"
case "$code" in case "$code" in
# --- Generic / Shell --- # --- Generic / Shell ---
1) echo "General error / Operation not permitted" ;; 1) echo "General error / Operation not permitted" ;;
2) echo "Misuse of shell builtins (e.g. syntax error)" ;; 2) echo "Misuse of shell builtins (e.g. syntax error)" ;;
126) echo "Command invoked cannot execute (permission problem?)" ;; 126) echo "Command invoked cannot execute (permission problem?)" ;;
127) echo "Command not found" ;; 127) echo "Command not found" ;;
128) echo "Invalid argument to exit" ;; 128) echo "Invalid argument to exit" ;;
130) echo "Terminated by Ctrl+C (SIGINT)" ;; 130) echo "Terminated by Ctrl+C (SIGINT)" ;;
137) echo "Killed (SIGKILL / Out of memory?)" ;; 137) echo "Killed (SIGKILL / Out of memory?)" ;;
139) echo "Segmentation fault (core dumped)" ;; 139) echo "Segmentation fault (core dumped)" ;;
143) echo "Terminated (SIGTERM)" ;; 143) echo "Terminated (SIGTERM)" ;;
# --- Package manager / APT / DPKG --- # --- Package manager / APT / DPKG ---
100) echo "APT: Package manager error (broken packages / dependency problems)" ;; 100) echo "APT: Package manager error (broken packages / dependency problems)" ;;
101) echo "APT: Configuration error (bad sources.list, malformed config)" ;; 101) echo "APT: Configuration error (bad sources.list, malformed config)" ;;
255) echo "DPKG: Fatal internal error" ;; 255) echo "DPKG: Fatal internal error" ;;
# --- Node.js / npm / pnpm / yarn --- # --- Node.js / npm / pnpm / yarn ---
243) echo "Node.js: Out of memory (JavaScript heap out of memory)" ;; 243) echo "Node.js: Out of memory (JavaScript heap out of memory)" ;;
245) echo "Node.js: Invalid command-line option" ;; 245) echo "Node.js: Invalid command-line option" ;;
246) echo "Node.js: Internal JavaScript Parse Error" ;; 246) echo "Node.js: Internal JavaScript Parse Error" ;;
247) echo "Node.js: Fatal internal error" ;; 247) echo "Node.js: Fatal internal error" ;;
248) echo "Node.js: Invalid C++ addon / N-API failure" ;; 248) echo "Node.js: Invalid C++ addon / N-API failure" ;;
249) echo "Node.js: Inspector error" ;; 249) echo "Node.js: Inspector error" ;;
254) echo "npm/pnpm/yarn: Unknown fatal error" ;; 254) echo "npm/pnpm/yarn: Unknown fatal error" ;;
# --- Python / pip / uv --- # --- Python / pip / uv ---
210) echo "Python: Virtualenv / uv environment missing or broken" ;; 210) echo "Python: Virtualenv / uv environment missing or broken" ;;
211) echo "Python: Dependency resolution failed" ;; 211) echo "Python: Dependency resolution failed" ;;
212) echo "Python: Installation aborted (permissions or EXTERNALLY-MANAGED)" ;; 212) echo "Python: Installation aborted (permissions or EXTERNALLY-MANAGED)" ;;
# --- PostgreSQL --- # --- PostgreSQL ---
231) echo "PostgreSQL: Connection failed (server not running / wrong socket)" ;; 231) echo "PostgreSQL: Connection failed (server not running / wrong socket)" ;;
232) echo "PostgreSQL: Authentication failed (bad user/password)" ;; 232) echo "PostgreSQL: Authentication failed (bad user/password)" ;;
233) echo "PostgreSQL: Database does not exist" ;; 233) echo "PostgreSQL: Database does not exist" ;;
234) echo "PostgreSQL: Fatal error in query / syntax" ;; 234) echo "PostgreSQL: Fatal error in query / syntax" ;;
# --- MySQL / MariaDB --- # --- MySQL / MariaDB ---
241) echo "MySQL/MariaDB: Connection failed (server not running / wrong socket)" ;; 241) echo "MySQL/MariaDB: Connection failed (server not running / wrong socket)" ;;
242) echo "MySQL/MariaDB: Authentication failed (bad user/password)" ;; 242) echo "MySQL/MariaDB: Authentication failed (bad user/password)" ;;
243) echo "MySQL/MariaDB: Database does not exist" ;; 243) echo "MySQL/MariaDB: Database does not exist" ;;
244) echo "MySQL/MariaDB: Fatal error in query / syntax" ;; 244) echo "MySQL/MariaDB: Fatal error in query / syntax" ;;
# --- MongoDB --- # --- MongoDB ---
251) echo "MongoDB: Connection failed (server not running)" ;; 251) echo "MongoDB: Connection failed (server not running)" ;;
252) echo "MongoDB: Authentication failed (bad user/password)" ;; 252) echo "MongoDB: Authentication failed (bad user/password)" ;;
253) echo "MongoDB: Database not found" ;; 253) echo "MongoDB: Database not found" ;;
254) echo "MongoDB: Fatal query error" ;; 254) echo "MongoDB: Fatal query error" ;;
# --- Proxmox Custom Codes --- # --- Proxmox Custom Codes ---
200) echo "Custom: Failed to create lock file" ;; 200) echo "Proxmox: Failed to create lock file" ;;
203) echo "Custom: Missing CTID variable" ;; 203) echo "Proxmox: Missing CTID variable" ;;
204) echo "Custom: Missing PCT_OSTYPE variable" ;; 204) echo "Proxmox: Missing PCT_OSTYPE variable" ;;
205) echo "Custom: Invalid CTID (<100)" ;; 205) echo "Proxmox: Invalid CTID (<100)" ;;
206) echo "Custom: CTID already in use (check 'pct list' and /etc/pve/lxc/)" ;; 206) echo "Proxmox: CTID already in use" ;;
# --- Proxmox Custom Codes --- 207) echo "Proxmox: Password contains unescaped special characters" ;;
200) echo "Custom: Failed to create lock file" ;; 208) echo "Proxmox: Invalid configuration (DNS/MAC/Network format)" ;;
203) echo "Custom: Missing CTID variable" ;; 209) echo "Proxmox: Container creation failed" ;;
204) echo "Custom: Missing PCT_OSTYPE variable" ;; 210) echo "Proxmox: Cluster not quorate" ;;
205) echo "Custom: Invalid CTID (<100)" ;; 211) echo "Proxmox: Timeout waiting for template lock" ;;
206) echo "Custom: CTID already in use (check 'pct list' and /etc/pve/lxc/)" ;; 212) echo "Proxmox: Storage type 'iscsidirect' does not support containers (VMs only)" ;;
207) echo "Custom: Password contains unescaped special characters (-, /, \\, *, etc.)" ;; 213) echo "Proxmox: Storage type does not support 'rootdir' content" ;;
208) echo "Custom: Invalid configuration (DNS/MAC/Network format error)" ;; 214) echo "Proxmox: Not enough storage space" ;;
209) echo "Custom: Container creation failed (check logs for pct create output)" ;; 215) echo "Proxmox: Container created but not listed (ghost state)" ;;
210) echo "Custom: Cluster not quorate" ;; 216) echo "Proxmox: RootFS entry missing in config" ;;
211) echo "Custom: Timeout waiting for template lock (concurrent download in progress)" ;; 217) echo "Proxmox: Storage not accessible" ;;
214) echo "Custom: Not enough storage space" ;; 219) echo "Proxmox: CephFS does not support containers - use RBD" ;;
215) echo "Custom: Container created but not listed (ghost state - check /etc/pve/lxc/)" ;; 224) echo "Proxmox: PBS storage is for backups only" ;;
216) echo "Custom: RootFS entry missing in config (incomplete creation)" ;; 218) echo "Proxmox: Template file corrupted or incomplete" ;;
217) echo "Custom: Storage does not support rootdir (check storage capabilities)" ;; 220) echo "Proxmox: Unable to resolve template path" ;;
218) echo "Custom: Template file corrupted or incomplete download (size <1MB or invalid archive)" ;; 221) echo "Proxmox: Template file not readable" ;;
220) echo "Custom: Unable to resolve template path" ;; 222) echo "Proxmox: Template download failed" ;;
221) echo "Custom: Template file exists but not readable (check file permissions)" ;; 223) echo "Proxmox: Template not available after download" ;;
222) echo "Custom: Template download failed after 3 attempts (network/storage issue)" ;; 225) echo "Proxmox: No template available for OS/Version" ;;
223) echo "Custom: Template not available after download (storage sync issue)" ;; 231) echo "Proxmox: LXC stack upgrade failed" ;;
225) echo "Custom: No template available for OS/Version (check 'pveam available')" ;;
231) echo "Custom: LXC stack upgrade/retry failed (outdated pve-container - check https://github.com/community-scripts/ProxmoxVE/discussions/8126)" ;;
# --- Default --- # --- Default ---
*) echo "Unknown error" ;; *) echo "Unknown error" ;;
208) echo "Custom: Invalid configuration (DNS/MAC/Network format error)" ;; esac
209) echo "Custom: Container creation failed (check logs for pct create output)" ;;
210) echo "Custom: Cluster not quorate" ;;
211) echo "Custom: Timeout waiting for template lock (concurrent download in progress)" ;;
214) echo "Custom: Not enough storage space" ;;
215) echo "Custom: Container created but not listed (ghost state - check /etc/pve/lxc/)" ;;
216) echo "Custom: RootFS entry missing in config (incomplete creation)" ;;
217) echo "Custom: Storage does not support rootdir (check storage capabilities)" ;;
218) echo "Custom: Template file corrupted or incomplete download (size <1MB or invalid archive)" ;;
220) echo "Custom: Unable to resolve template path" ;;
221) echo "Custom: Template file exists but not readable (check file permissions)" ;;
222) echo "Custom: Template download failed after 3 attempts (network/storage issue)" ;;
223) echo "Custom: Template not available after download (storage sync issue)" ;;
225) echo "Custom: No template available for OS/Version (check 'pveam available')" ;;
231) echo "Custom: LXC stack upgrade/retry failed (outdated pve-container - check https://github.com/community-scripts/ProxmoxVE/discussions/8126)" ;;
# --- Default ---
*) echo "Unknown error" ;;
esac
} }
# ============================================================================== # ==============================================================================
@ -163,100 +143,100 @@ explain_exit_code() {
# * Exits with original exit code # * Exits with original exit code
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
error_handler() { error_handler() {
local exit_code=${1:-$?} local exit_code=${1:-$?}
local command=${2:-${BASH_COMMAND:-unknown}} local command=${2:-${BASH_COMMAND:-unknown}}
local line_number=${BASH_LINENO[0]:-unknown} local line_number=${BASH_LINENO[0]:-unknown}
command="${command//\$STD/}" command="${command//\$STD/}"
if [[ "$exit_code" -eq 0 ]]; then if [[ "$exit_code" -eq 0 ]]; then
return 0 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
# Get active log file (BUILD_LOG or INSTALL_LOG)
local active_log=""
if declare -f get_active_logfile >/dev/null 2>&1; then
active_log="$(get_active_logfile)"
elif [[ -n "${SILENT_LOGFILE:-}" ]]; then
active_log="$SILENT_LOGFILE"
fi
if [[ -n "$active_log" && -s "$active_log" ]]; then
echo "--- Last 20 lines of silent log ---"
tail -n 20 "$active_log"
echo "-----------------------------------"
# Detect context: Container (INSTALL_LOG set + /root exists) vs Host (BUILD_LOG)
if [[ -n "${INSTALL_LOG:-}" && -d /root ]]; then
# CONTAINER CONTEXT: Copy log and create flag file for host
local container_log="/root/.install-${SESSION_ID:-error}.log"
cp "$active_log" "$container_log" 2>/dev/null || true
# Create error flag file with exit code for host detection
echo "$exit_code" >"/root/.install-${SESSION_ID:-error}.failed" 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
# HOST CONTEXT: Show local log path and offer container cleanup
if declare -f msg_custom >/dev/null 2>&1; then
msg_custom "📋" "${YW}" "Full log: ${active_log}"
else
echo -e "${YW}Full log:${CL} ${BL}${active_log}${CL}"
fi
# Offer to remove container if it exists (build errors after container creation)
if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null && pct status "$CTID" &>/dev/null; then
echo ""
echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
if read -t 60 -r response; then
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
echo -e "\n${YW}Removing container ${CTID}${CL}"
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
echo -e "${GN}✔${CL} Container ${CTID} removed"
elif [[ "$response" =~ ^[Nn]$ ]]; then
echo -e "\n${YW}Container ${CTID} kept for debugging${CL}"
fi
else
# Timeout - auto-remove
echo -e "\n${YW}No response - auto-removing container${CL}"
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
echo -e "${GN}✔${CL} Container ${CTID} removed"
fi
fi
fi fi
fi
exit "$exit_code" 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
# Get active log file (BUILD_LOG or INSTALL_LOG)
local active_log=""
if declare -f get_active_logfile >/dev/null 2>&1; then
active_log="$(get_active_logfile)"
elif [[ -n "${SILENT_LOGFILE:-}" ]]; then
active_log="$SILENT_LOGFILE"
fi
if [[ -n "$active_log" && -s "$active_log" ]]; then
echo "--- Last 20 lines of silent log ---"
tail -n 20 "$active_log"
echo "-----------------------------------"
# Detect context: Container (INSTALL_LOG set + /root exists) vs Host (BUILD_LOG)
if [[ -n "${INSTALL_LOG:-}" && -d /root ]]; then
# CONTAINER CONTEXT: Copy log and create flag file for host
local container_log="/root/.install-${SESSION_ID:-error}.log"
cp "$active_log" "$container_log" 2>/dev/null || true
# Create error flag file with exit code for host detection
echo "$exit_code" >"/root/.install-${SESSION_ID:-error}.failed" 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
# HOST CONTEXT: Show local log path and offer container cleanup
if declare -f msg_custom >/dev/null 2>&1; then
msg_custom "📋" "${YW}" "Full log: ${active_log}"
else
echo -e "${YW}Full log:${CL} ${BL}${active_log}${CL}"
fi
# Offer to remove container if it exists (build errors after container creation)
if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null && pct status "$CTID" &>/dev/null; then
echo ""
echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
if read -t 60 -r response; then
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
echo -e "\n${YW}Removing container ${CTID}${CL}"
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
echo -e "${GN}✔${CL} Container ${CTID} removed"
elif [[ "$response" =~ ^[Nn]$ ]]; then
echo -e "\n${YW}Container ${CTID} kept for debugging${CL}"
fi
else
# Timeout - auto-remove
echo -e "\n${YW}No response - auto-removing container${CL}"
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
echo -e "${GN}✔${CL} Container ${CTID} removed"
fi
fi
fi
fi
exit "$exit_code"
} }
# ============================================================================== # ==============================================================================
@ -272,9 +252,9 @@ error_handler() {
# - Always runs on script termination (success or failure) # - Always runs on script termination (success or failure)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
on_exit() { on_exit() {
local exit_code=$? local exit_code=$?
[[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile" [[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
exit "$exit_code" exit "$exit_code"
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -285,12 +265,12 @@ on_exit() {
# - Exits with code 130 (128 + SIGINT=2) # - Exits with code 130 (128 + SIGINT=2)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
on_interrupt() { on_interrupt() {
if declare -f msg_error >/dev/null 2>&1; then if declare -f msg_error >/dev/null 2>&1; then
msg_error "Interrupted by user (SIGINT)" msg_error "Interrupted by user (SIGINT)"
else else
echo -e "\n${RD}Interrupted by user (SIGINT)${CL}" echo -e "\n${RD}Interrupted by user (SIGINT)${CL}"
fi fi
exit 130 exit 130
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -302,12 +282,12 @@ on_interrupt() {
# - Triggered by external process termination # - Triggered by external process termination
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
on_terminate() { on_terminate() {
if declare -f msg_error >/dev/null 2>&1; then if declare -f msg_error >/dev/null 2>&1; then
msg_error "Terminated by signal (SIGTERM)" msg_error "Terminated by signal (SIGTERM)"
else else
echo -e "\n${RD}Terminated by signal (SIGTERM)${CL}" echo -e "\n${RD}Terminated by signal (SIGTERM)${CL}"
fi fi
exit 143 exit 143
} }
# ============================================================================== # ==============================================================================
@ -330,13 +310,13 @@ on_terminate() {
# - Call this function early in every script # - Call this function early in every script
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
catch_errors() { catch_errors() {
set -Ee -o pipefail set -Ee -o pipefail
if [ "${STRICT_UNSET:-0}" = "1" ]; then if [ "${STRICT_UNSET:-0}" = "1" ]; then
set -u set -u
fi fi
trap 'error_handler' ERR trap 'error_handler' ERR
trap on_exit EXIT trap on_exit EXIT
trap on_interrupt INT trap on_interrupt INT
trap on_terminate TERM trap on_terminate TERM
} }