diff --git a/misc/api.func b/misc/api.func index 08bdc914b..17f9cd9e8 100644 --- a/misc/api.func +++ b/misc/api.func @@ -2,77 +2,91 @@ # Author: michelroegl-brunner # License: MIT | https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/LICENSE -get_error_description() { - local exit_code="$1" - case "$exit_code" in - 0) echo " " ;; - 1) echo "General error: An unspecified error occurred." ;; - 2) echo "Incorrect shell usage or invalid command arguments." ;; - 3) echo "Unexecuted function or invalid shell condition." ;; - 4) echo "Error opening a file or invalid path." ;; - 5) echo "I/O error: An input/output failure occurred." ;; - 6) echo "No such device or address." ;; - 7) echo "Insufficient memory or resource exhaustion." ;; - 8) echo "Non-executable file or invalid file format." ;; - 9) echo "Failed child process execution." ;; - 18) echo "Connection to a remote server failed." ;; - 22) echo "Invalid argument or faulty network connection." ;; - 28) echo "No space left on device." ;; - 35) echo "Timeout while establishing a connection." ;; - 56) echo "Faulty TLS connection." ;; - 60) echo "SSL certificate error." ;; - 100) echo "LXC install error: Unexpected error in create_lxc.sh." ;; - 101) echo "LXC install error: No network connection detected." ;; - 200) echo "LXC creation failed." ;; - 201) echo "LXC error: Invalid Storage class." ;; - 202) echo "User aborted menu in create_lxc.sh." ;; - 203) echo "CTID not set in create_lxc.sh." ;; - 204) echo "PCT_OSTYPE not set in create_lxc.sh." ;; - 205) echo "CTID cannot be less than 100 in create_lxc.sh." ;; - 206) echo "CTID already in use in create_lxc.sh." ;; - 207) echo "Template not found in create_lxc.sh." ;; - 208) echo "Error downloading template in create_lxc.sh." ;; - 209) echo "Container creation failed, but template is intact in create_lxc.sh." ;; - 125) echo "Docker error: Container could not start." ;; - 126) echo "Command not executable: Incorrect permissions or missing dependencies." ;; - 127) echo "Command not found: Incorrect path or missing dependency." ;; - 128) echo "Invalid exit signal, e.g., incorrect Git command." ;; - 129) echo "Signal 1 (SIGHUP): Process terminated due to hangup." ;; - 130) echo "Signal 2 (SIGINT): Manual termination via Ctrl+C." ;; - 132) echo "Signal 4 (SIGILL): Illegal machine instruction." ;; - 133) echo "Signal 5 (SIGTRAP): Debugging error or invalid breakpoint signal." ;; - 134) echo "Signal 6 (SIGABRT): Program aborted itself." ;; - 135) echo "Signal 7 (SIGBUS): Memory error, invalid memory address." ;; - 137) echo "Signal 9 (SIGKILL): Process forcibly terminated (OOM-killer or 'kill -9')." ;; - 139) echo "Signal 11 (SIGSEGV): Segmentation fault, possibly due to invalid pointer access." ;; - 141) echo "Signal 13 (SIGPIPE): Pipe closed unexpectedly." ;; - 143) echo "Signal 15 (SIGTERM): Process terminated normally." ;; - 152) echo "Signal 24 (SIGXCPU): CPU time limit exceeded." ;; - 255) echo "Unknown critical error, often due to missing permissions or broken scripts." ;; - *) echo "Unknown error code ($exit_code)." ;; - esac -} +# ============================================================================== +# API.FUNC - TELEMETRY & DIAGNOSTICS API +# ============================================================================== +# +# Provides functions for sending anonymous telemetry data to Community-Scripts +# API for analytics and diagnostics purposes. +# +# Features: +# - Container/VM creation statistics +# - Installation success/failure tracking +# - Error code mapping and reporting +# - Privacy-respecting anonymous telemetry +# +# Usage: +# source <(curl -fsSL .../api.func) +# post_to_api # Report container creation +# post_update_to_api # Report installation status +# +# Privacy: +# - Only anonymous statistics (no personal data) +# - User can opt-out via diagnostics settings +# - Random UUID for session tracking only +# +# ============================================================================== +# ============================================================================== +# SECTION 1: DEPENDENCY LOADING +# ============================================================================== + +# Load error_handler.func for explain_exit_code() function +# This provides centralized error code descriptions (exit codes 1-255, shell, package managers, databases, custom Proxmox codes) +if [[ -z "${COMMUNITY_SCRIPTS_BASE_URL:-}" ]]; then + COMMUNITY_SCRIPTS_BASE_URL="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main" +fi + +if ! declare -f explain_exit_code >/dev/null 2>&1; then + source <(curl -fsSL "${COMMUNITY_SCRIPTS_BASE_URL}/misc/error_handler.func") || { + echo "Failed to load error_handler.func" >&2 + return 1 + } +fi + +# ============================================================================== +# SECTION 2: TELEMETRY FUNCTIONS +# ============================================================================== + +# ------------------------------------------------------------------------------ +# post_to_api() +# +# - Sends LXC container creation statistics to Community-Scripts API +# - Only executes if: +# * curl is available +# * DIAGNOSTICS=yes +# * RANDOM_UUID is set +# - Payload includes: +# * Container type, disk size, CPU cores, RAM +# * OS type and version +# * IPv6 disable status +# * Application name (NSAPP) +# * Installation method +# * PVE version +# * Status: "installing" +# * Random UUID for session tracking +# - Anonymous telemetry (no personal data) +# ------------------------------------------------------------------------------ post_to_api() { - if ! command -v curl &>/dev/null; then - return - fi + if ! command -v curl &>/dev/null; then + return + fi - if [ "$DIAGNOSTICS" = "no" ]; then - return - fi + if [ "$DIAGNOSTICS" = "no" ]; then + return + fi - if [ -z "$RANDOM_UUID" ]; then - return - fi + if [ -z "$RANDOM_UUID" ]; then + return + fi - local API_URL="http://api.community-scripts.org/dev/upload" - local pve_version="not found" - pve_version=$(pveversion | awk -F'[/ ]' '{print $2}') + local API_URL="http://api.community-scripts.org/dev/upload" + local pve_version="not found" + pve_version=$(pveversion | awk -F'[/ ]' '{print $2}') - JSON_PAYLOAD=$( - cat </dev/null; then - return - fi + if ! command -v curl &>/dev/null; then + return + fi - if [ "$POST_UPDATE_DONE" = true ]; then - return 0 - fi - exit_code=${2:-1} - local API_URL="http://api.community-scripts.org/dev/upload/updatestatus" - local status="${1:-failed}" - if [[ "$status" == "failed" ]]; then - local exit_code="${2:-1}" - elif [[ "$status" == "success" ]]; then - local exit_code="${2:-0}" - fi + if [ "$POST_UPDATE_DONE" = true ]; then + return 0 + fi + exit_code=${2:-1} + local API_URL="http://api.community-scripts.org/dev/upload/updatestatus" + local status="${1:-failed}" + if [[ "$status" == "failed" ]]; then + local exit_code="${2:-1}" + elif [[ "$status" == "success" ]]; then + local exit_code="${2:-0}" + fi - if [[ -z "$exit_code" ]]; then - exit_code=1 - fi + if [[ -z "$exit_code" ]]; then + exit_code=1 + fi - error=$(get_error_description "$exit_code") + error=$(explain_exit_code "$exit_code") - if [ -z "$error" ]; then - error="Unknown error" - fi + if [ -z "$error" ]; then + error="Unknown error" + fi - JSON_PAYLOAD=$( - cat </dev/null 2>&1; then #echo "(build.func) Loaded core.func via wget" fi +# ============================================================================== +# SECTION 2: PRE-FLIGHT CHECKS & SYSTEM VALIDATION +# ============================================================================== + # ------------------------------------------------------------------------------ # maxkeys_check() # @@ -224,12 +247,17 @@ maxkeys_check() { # Silent success - only show errors if they exist } +# ============================================================================== +# SECTION 3: CONTAINER SETUP UTILITIES +# ============================================================================== + # ------------------------------------------------------------------------------ # get_current_ip() # # - Returns current container IP depending on OS type # - Debian/Ubuntu: uses `hostname -I` # - Alpine: parses eth0 via `ip -4 addr` +# - Returns "Unknown" if OS type cannot be determined # ------------------------------------------------------------------------------ get_current_ip() { if [ -f /etc/os-release ]; then @@ -356,7 +384,17 @@ find_host_ssh_keys() { ) } -# ===== Unified storage selection & writing to vars files ===== +# ============================================================================== +# SECTION 4: STORAGE & RESOURCE MANAGEMENT +# ============================================================================== + +# ------------------------------------------------------------------------------ +# _write_storage_to_vars() +# +# - Writes storage selection to vars file +# - Removes old entries (commented and uncommented) to avoid duplicates +# - Arguments: vars_file, key (var_container_storage/var_template_storage), value +# ------------------------------------------------------------------------------ _write_storage_to_vars() { # $1 = vars_file, $2 = key (var_container_storage / var_template_storage), $3 = value local vf="$1" key="$2" val="$3" @@ -407,6 +445,10 @@ choose_and_set_storage_for_file() { # Silent operation - no output message } +# ============================================================================== +# SECTION 5: CONFIGURATION & DEFAULTS MANAGEMENT +# ============================================================================== + # ------------------------------------------------------------------------------ # base_settings() # @@ -414,6 +456,7 @@ choose_and_set_storage_for_file() { # - Reads from environment variables (var_*) # - Provides fallback defaults for OS type/version # - App-specific values take precedence when they are HIGHER (for CPU, RAM, DISK) +# - Sets up container type, resources, network, SSH, features, and tags # ------------------------------------------------------------------------------ base_settings() { # Default Settings @@ -1014,13 +1057,27 @@ ensure_global_default_vars_file() { echo "$vars_path" } +# ============================================================================== +# SECTION 6: ADVANCED INTERACTIVE CONFIGURATION +# ============================================================================== + # ------------------------------------------------------------------------------ # advanced_settings() # -# - Interactive whiptail menu for advanced configuration -# - Lets user set container type, password, CT ID, hostname, disk, CPU, RAM -# - Supports IPv4/IPv6, DNS, MAC, VLAN, tags, SSH keys, FUSE, verbose mode -# - Ends with confirmation or re-entry if cancelled +# - Interactive whiptail menu for comprehensive container configuration +# - Allows user to customize: +# * Container type (privileged/unprivileged) +# * Root password +# * Container ID (CTID) +# * Hostname +# * Resources (disk size, CPU cores, RAM) +# * Network (IPv4/IPv6, gateway, DNS, MAC, VLAN, MTU) +# * SSH settings and key injection +# * Advanced features (FUSE, TUN, keyctl) +# * Tags for organization +# * Verbose/debug mode +# - Loops until user confirms or cancels +# - Validates all input and shows current selections # ------------------------------------------------------------------------------ advanced_settings() { whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --msgbox --title "Here is an instructional tip:" "To make a selection, use the Spacebar." 8 58 @@ -1487,10 +1544,19 @@ advanced_settings() { fi } +# ============================================================================== +# SECTION 7: USER INTERFACE & DIAGNOSTICS +# ============================================================================== + # ------------------------------------------------------------------------------ # diagnostics_check() # # - Ensures diagnostics config file exists at /usr/local/community-scripts/diagnostics +# - Creates file if missing with default DIAGNOSTICS=yes +# - Reads current diagnostics setting from file +# - Sets global DIAGNOSTICS variable for API telemetry opt-in/out +# ------------------------------------------------------------------------------ +diagnostics_check() { # - Asks user whether to send anonymous diagnostic data # - Saves DIAGNOSTICS=yes/no in the config file # ------------------------------------------------------------------------------ @@ -2054,13 +2120,22 @@ start() { fi } +# ============================================================================== +# SECTION 8: CONTAINER CREATION & DEPLOYMENT +# ============================================================================== + # ------------------------------------------------------------------------------ # build_container() # -# - Creates and configures the LXC container -# - Builds network string and applies features (FUSE, TUN, VAAPI passthrough) +# - Main function for creating and configuring LXC container +# - Builds network configuration string (IP, gateway, VLAN, MTU, MAC, IPv6) +# - Creates container via pct create with all specified settings +# - Applies features: FUSE, TUN, keyctl, VAAPI passthrough # - Starts container and waits for network connectivity -# - Installs base packages, SSH keys, and runs -install.sh +# - Installs base packages (curl, sudo, etc.) +# - Injects SSH keys if configured +# - Executes -install.sh inside container +# - Posts installation telemetry to API if diagnostics enabled # ------------------------------------------------------------------------------ build_container() { # if [ "$VERBOSE" == "yes" ]; then set -x; fi @@ -3389,12 +3464,21 @@ create_lxc_container() { msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created." } +# ============================================================================== +# SECTION 9: POST-INSTALLATION & FINALIZATION +# ============================================================================== + # ------------------------------------------------------------------------------ # description() # -# - Sets container description with HTML content (logo, links, badges) -# - Restarts ping-instances.service if present -# - Posts status "done" to API +# - Sets container description with formatted HTML content +# - Includes: +# * Community-Scripts logo +# * Application name +# * Links to GitHub, Discussions, Issues +# * Ko-fi donation badge +# - Restarts ping-instances.service if present (monitoring) +# - Posts final "done" status to API telemetry # ------------------------------------------------------------------------------ description() { IP=$(pct exec "$CTID" ip a s dev eth0 | awk '/inet / {print $2}' | cut -d/ -f1) @@ -3439,31 +3523,23 @@ EOF post_update_to_api "done" "none" } +# ============================================================================== +# SECTION 10: ERROR HANDLING & EXIT TRAPS +# ============================================================================== + # ------------------------------------------------------------------------------ # api_exit_script() # -# - Exit trap handler -# - Reports exit codes to API with detailed reason -# - Handles known codes (100–209) and maps them to errors +# - Exit trap handler for reporting to API telemetry +# - Captures exit code and reports to API using centralized error descriptions +# - Uses explain_exit_code() from error_handler.func for consistent error messages +# - Posts failure status with exit code to API (error description added automatically) +# - Only executes on non-zero exit codes # ------------------------------------------------------------------------------ api_exit_script() { exit_code=$? if [ $exit_code -ne 0 ]; then - case $exit_code in - 100) post_update_to_api "failed" "100: Unexpected error in create_lxc.sh" ;; - 101) post_update_to_api "failed" "101: No network connection detected in create_lxc.sh" ;; - 200) post_update_to_api "failed" "200: LXC creation failed in create_lxc.sh" ;; - 201) post_update_to_api "failed" "201: Invalid Storage class in create_lxc.sh" ;; - 202) post_update_to_api "failed" "202: User aborted menu in create_lxc.sh" ;; - 203) post_update_to_api "failed" "203: CTID not set in create_lxc.sh" ;; - 204) post_update_to_api "failed" "204: PCT_OSTYPE not set in create_lxc.sh" ;; - 205) post_update_to_api "failed" "205: CTID cannot be less than 100 in create_lxc.sh" ;; - 206) post_update_to_api "failed" "206: CTID already in use in create_lxc.sh" ;; - 207) post_update_to_api "failed" "207: Template not found in create_lxc.sh" ;; - 208) post_update_to_api "failed" "208: Error downloading template in create_lxc.sh" ;; - 209) post_update_to_api "failed" "209: Container creation failed, but template is intact in create_lxc.sh" ;; - *) post_update_to_api "failed" "Unknown error, exit code: $exit_code in create_lxc.sh" ;; - esac + post_update_to_api "failed" "$exit_code" fi } diff --git a/misc/core.func b/misc/core.func index aef2b6e79..a3c4ac51f 100644 --- a/misc/core.func +++ b/misc/core.func @@ -2,13 +2,34 @@ # Copyright (c) 2021-2025 community-scripts ORG # License: MIT | https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/LICENSE -# ------------------------------------------------------------------------------ -# Loads core utility groups once (colors, formatting, icons, defaults). -# ------------------------------------------------------------------------------ +# ============================================================================== +# CORE FUNCTIONS - LXC CONTAINER UTILITIES +# ============================================================================== +# +# This file provides core utility functions for LXC container management +# including colors, formatting, validation checks, message output, and +# execution helpers used throughout the Community-Scripts ecosystem. +# +# Usage: +# source <(curl -fsSL https://git.community-scripts.org/.../core.func) +# load_functions +# +# ============================================================================== [[ -n "${_CORE_FUNC_LOADED:-}" ]] && return _CORE_FUNC_LOADED=1 +# ============================================================================== +# SECTION 1: INITIALIZATION & SETUP +# ============================================================================== + +# ------------------------------------------------------------------------------ +# load_functions() +# +# - Initializes all core utility groups (colors, formatting, icons, defaults) +# - Ensures functions are loaded only once via __FUNCTIONS_LOADED flag +# - Must be called at start of any script using these utilities +# ------------------------------------------------------------------------------ load_functions() { [[ -n "${__FUNCTIONS_LOADED:-}" ]] && return __FUNCTIONS_LOADED=1 @@ -17,11 +38,14 @@ load_functions() { icons default_vars set_std_mode - # add more } # ------------------------------------------------------------------------------ -# Sets ANSI color codes used for styled terminal output. +# color() +# +# - Sets ANSI color codes for styled terminal output +# - Variables: YW (yellow), YWB (yellow bright), BL (blue), RD (red) +# GN (green), DGN (dark green), BGN (background green), CL (clear) # ------------------------------------------------------------------------------ color() { YW=$(echo "\033[33m") @@ -34,7 +58,14 @@ color() { CL=$(echo "\033[m") } -# Special for spinner and colorized output via printf +# ------------------------------------------------------------------------------ +# color_spinner() +# +# - Sets ANSI color codes specifically for spinner animation +# - Variables: CS_YW (spinner yellow), CS_YWB (spinner yellow bright), +# CS_CL (spinner clear) +# - Used by spinner() function to avoid color conflicts +# ------------------------------------------------------------------------------ color_spinner() { CS_YW=$'\033[33m' CS_YWB=$'\033[93m' @@ -42,7 +73,12 @@ color_spinner() { } # ------------------------------------------------------------------------------ -# Defines formatting helpers like tab, bold, and line reset sequences. +# formatting() +# +# - Defines formatting helpers for terminal output +# - BFR: Backspace and clear line sequence +# - BOLD: Bold text escape code +# - TAB/TAB3: Indentation spacing # ------------------------------------------------------------------------------ formatting() { BFR="\\r\\033[K" @@ -53,7 +89,11 @@ formatting() { } # ------------------------------------------------------------------------------ -# Sets symbolic icons used throughout user feedback and prompts. +# icons() +# +# - Sets symbolic emoji icons used throughout user feedback +# - Provides consistent visual indicators for success, error, info, etc. +# - Icons: CM (checkmark), CROSS (error), INFO (info), HOURGLASS (wait), etc. # ------------------------------------------------------------------------------ icons() { CM="${TAB}✔️${TAB}" @@ -84,21 +124,28 @@ icons() { ADVANCED="${TAB}🧩${TAB}${CL}" FUSE="${TAB}🗂️${TAB}${CL}" HOURGLASS="${TAB}⏳${TAB}" - } # ------------------------------------------------------------------------------ -# Sets default retry and wait variables used for system actions. +# default_vars() +# +# - Sets default retry and wait variables used for system actions +# - RETRY_NUM: Maximum number of retry attempts (default: 10) +# - RETRY_EVERY: Seconds to wait between retries (default: 3) +# - i: Counter variable initialized to RETRY_NUM # ------------------------------------------------------------------------------ default_vars() { RETRY_NUM=10 RETRY_EVERY=3 i=$RETRY_NUM - #[[ "${VAR_OS:-}" == "unknown" ]] } # ------------------------------------------------------------------------------ -# Sets default verbose mode for script and os execution. +# set_std_mode() +# +# - Sets default verbose mode for script and OS execution +# - If VERBOSE=yes: STD="" (show all output) +# - If VERBOSE=no: STD="silent" (suppress output via silent() wrapper) # ------------------------------------------------------------------------------ set_std_mode() { if [ "${VERBOSE:-no}" = "yes" ]; then @@ -108,8 +155,148 @@ set_std_mode() { fi } +# ============================================================================== +# SECTION 2: VALIDATION CHECKS +# ============================================================================== + +# ------------------------------------------------------------------------------ +# shell_check() +# +# - Verifies that the script is running under Bash shell +# - Exits with error message if different shell is detected +# - Required because scripts use Bash-specific features +# ------------------------------------------------------------------------------ +shell_check() { + if [[ "$(ps -p $$ -o comm=)" != "bash" ]]; then + clear + msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell." + echo -e "\nExiting..." + sleep 2 + exit + fi +} + +# ------------------------------------------------------------------------------ +# root_check() +# +# - Verifies script is running with root privileges +# - Detects if executed via sudo (which can cause issues) +# - Exits with error if not running as root directly +# ------------------------------------------------------------------------------ +root_check() { + if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then + clear + msg_error "Please run this script as root." + echo -e "\nExiting..." + sleep 2 + exit + fi +} + +# ------------------------------------------------------------------------------ +# pve_check() +# +# - Validates Proxmox VE version compatibility +# - Supported: PVE 8.0-8.9 and PVE 9.0 only +# - Exits with error message if unsupported version detected +# ------------------------------------------------------------------------------ +pve_check() { + local PVE_VER + PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')" + + # Check for Proxmox VE 8.x: allow 8.0–8.9 + if [[ "$PVE_VER" =~ ^8\.([0-9]+) ]]; then + local MINOR="${BASH_REMATCH[1]}" + if ((MINOR < 0 || MINOR > 9)); then + msg_error "This version of Proxmox VE is not supported." + msg_error "Supported: Proxmox VE version 8.0 – 8.9" + exit 1 + fi + return 0 + fi + + # Check for Proxmox VE 9.x: allow ONLY 9.0 + if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then + local MINOR="${BASH_REMATCH[1]}" + if ((MINOR != 0)); then + msg_error "This version of Proxmox VE is not yet supported." + msg_error "Supported: Proxmox VE version 9.0" + exit 1 + fi + return 0 + fi + + # All other unsupported versions + msg_error "This version of Proxmox VE is not supported." + msg_error "Supported versions: Proxmox VE 8.0 – 8.x or 9.0" + exit 1 +} + +# ------------------------------------------------------------------------------ +# arch_check() +# +# - Validates system architecture is amd64/x86_64 +# - Exits with error message for unsupported architectures (e.g., ARM/PiMox) +# - Provides link to ARM64-compatible scripts +# ------------------------------------------------------------------------------ +arch_check() { + if [ "$(dpkg --print-architecture)" != "amd64" ]; then + echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n" + echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n" + echo -e "Exiting..." + sleep 2 + exit + fi +} + +# ------------------------------------------------------------------------------ +# ssh_check() +# +# - Detects if script is running over SSH connection +# - Warns user for external SSH connections (recommends Proxmox shell) +# - Skips warning for local/same-subnet connections +# - Does not abort execution, only warns +# ------------------------------------------------------------------------------ +ssh_check() { + if [ -n "$SSH_CLIENT" ]; then + local client_ip=$(awk '{print $1}' <<<"$SSH_CLIENT") + local host_ip=$(hostname -I | awk '{print $1}') + + # Check if connection is local (Proxmox WebUI or same machine) + # - localhost (127.0.0.1, ::1) + # - same IP as host + # - local network range (10.x, 172.16-31.x, 192.168.x) + if [[ "$client_ip" == "127.0.0.1" || "$client_ip" == "::1" || "$client_ip" == "$host_ip" ]]; then + return + fi + + # Check if client is in same local network (optional, safer approach) + local host_subnet=$(echo "$host_ip" | cut -d. -f1-3) + local client_subnet=$(echo "$client_ip" | cut -d. -f1-3) + if [[ "$host_subnet" == "$client_subnet" ]]; then + return + fi + + # Only warn for truly external connections + msg_warn "Running via external SSH (client: $client_ip)." + msg_warn "For better stability, consider using the Proxmox Shell (Console) instead." + fi +} + +# ============================================================================== +# SECTION 3: EXECUTION HELPERS +# ============================================================================== + SILENT_LOGFILE="/tmp/install-$(date +%Y%m%d_%H%M%S)_${SESSION_ID:-$(date +%s)}.log" +# ------------------------------------------------------------------------------ +# silent() +# +# - Executes command with output redirected to SILENT_LOGFILE +# - On error: displays last 10 lines of log and exits with original exit code +# - Temporarily disables error trap to capture exit code correctly +# - Sources explain_exit_code() for detailed error messages +# ------------------------------------------------------------------------------ silent() { local cmd="$*" local caller_line="${BASH_LINENO[0]:-unknown}" @@ -152,206 +339,47 @@ silent() { fi } -# Check if the shell is using bash -shell_check() { - if [[ "$(ps -p $$ -o comm=)" != "bash" ]]; then - clear - msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell." - echo -e "\nExiting..." - sleep 2 - exit - fi -} - -# Run as root only -root_check() { - if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then - clear - msg_error "Please run this script as root." - echo -e "\nExiting..." - sleep 2 - exit - fi -} - -# This function checks the version of Proxmox Virtual Environment (PVE) and exits if the version is not supported. -# Supported: Proxmox VE 8.0.x – 8.9.x and 9.0 (NOT 9.1+) -pve_check() { - local PVE_VER - PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')" - - # Check for Proxmox VE 8.x: allow 8.0–8.9 - if [[ "$PVE_VER" =~ ^8\.([0-9]+) ]]; then - local MINOR="${BASH_REMATCH[1]}" - if ((MINOR < 0 || MINOR > 9)); then - msg_error "This version of Proxmox VE is not supported." - msg_error "Supported: Proxmox VE version 8.0 – 8.9" - exit 1 - fi - return 0 - fi - - # Check for Proxmox VE 9.x: allow ONLY 9.0 - if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then - local MINOR="${BASH_REMATCH[1]}" - if ((MINOR != 0)); then - msg_error "This version of Proxmox VE is not yet supported." - msg_error "Supported: Proxmox VE version 9.0" - exit 1 - fi - return 0 - fi - - # All other unsupported versions - msg_error "This version of Proxmox VE is not supported." - msg_error "Supported versions: Proxmox VE 8.0 – 8.x or 9.0" - exit 1 -} - -# This function checks the system architecture and exits if it's not "amd64". -arch_check() { - if [ "$(dpkg --print-architecture)" != "amd64" ]; then - echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n" - echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n" - echo -e "Exiting..." - sleep 2 - exit - fi -} - # ------------------------------------------------------------------------------ -# ssh_check() +# spinner() # -# - Detects if script is running over SSH -# - Warns user and recommends using Proxmox shell -# - User can choose to continue or abort +# - Displays animated spinner with rotating characters (⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏) +# - Shows SPINNER_MSG alongside animation +# - Runs in infinite loop until killed by stop_spinner() +# - Uses color_spinner() colors for output # ------------------------------------------------------------------------------ -ssh_check() { - if [ -n "$SSH_CLIENT" ]; then - local client_ip=$(awk '{print $1}' <<<"$SSH_CLIENT") - local host_ip=$(hostname -I | awk '{print $1}') - - # Check if connection is local (Proxmox WebUI or same machine) - # - localhost (127.0.0.1, ::1) - # - same IP as host - # - local network range (10.x, 172.16-31.x, 192.168.x) - if [[ "$client_ip" == "127.0.0.1" || "$client_ip" == "::1" || "$client_ip" == "$host_ip" ]]; then - return - fi - - # Check if client is in same local network (optional, safer approach) - local host_subnet=$(echo "$host_ip" | cut -d. -f1-3) - local client_subnet=$(echo "$client_ip" | cut -d. -f1-3) - if [[ "$host_subnet" == "$client_subnet" ]]; then - return - fi - - # Only warn for truly external connections - msg_warn "Running via external SSH (client: $client_ip)." - msg_warn "For better stability, consider using the Proxmox Shell (Console) instead." - fi -} - -# ------------------------------------------------------------------------------ -# exit_script() -# -# - Called when user cancels an action -# - Clears screen and exits gracefully -# ------------------------------------------------------------------------------ -exit_script() { - clear - echo -e "\n${CROSS}${RD}User exited script${CL}\n" - exit -} - -# Function to download & save header files -get_header() { - local app_name=$(echo "${APP,,}" | tr -d ' ') - local app_type=${APP_TYPE:-ct} # Default zu 'ct' falls nicht gesetzt - local header_url="https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/${app_type}/headers/${app_name}" - local local_header_path="/usr/local/community-scripts/headers/${app_type}/${app_name}" - - mkdir -p "$(dirname "$local_header_path")" - - if [ ! -s "$local_header_path" ]; then - if ! curl -fsSL "$header_url" -o "$local_header_path"; then - return 1 - fi - fi - - cat "$local_header_path" 2>/dev/null || true -} - -header_info() { - local app_name=$(echo "${APP,,}" | tr -d ' ') - local header_content - - header_content=$(get_header "$app_name") || header_content="" - - clear - local term_width - term_width=$(tput cols 2>/dev/null || echo 120) - - if [ -n "$header_content" ]; then - echo "$header_content" - fi -} - -ensure_tput() { - if ! command -v tput >/dev/null 2>&1; then - if grep -qi 'alpine' /etc/os-release; then - apk add --no-cache ncurses >/dev/null 2>&1 - elif command -v apt-get >/dev/null 2>&1; then - apt-get update -qq >/dev/null - apt-get install -y -qq ncurses-bin >/dev/null 2>&1 - fi - fi -} - -is_alpine() { - local os_id="${var_os:-${PCT_OSTYPE:-}}" - - if [[ -z "$os_id" && -f /etc/os-release ]]; then - os_id="$( - . /etc/os-release 2>/dev/null - echo "${ID:-}" - )" - fi - - [[ "$os_id" == "alpine" ]] -} - -is_verbose_mode() { - local verbose="${VERBOSE:-${var_verbose:-no}}" - local tty_status - if [[ -t 2 ]]; then - tty_status="interactive" - else - tty_status="not-a-tty" - fi - [[ "$verbose" != "no" || ! -t 2 ]] -} - -fatal() { - msg_error "$1" - kill -INT $$ -} - spinner() { local chars=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏) + local msg="${SPINNER_MSG:-Processing...}" local i=0 while true; do local index=$((i++ % ${#chars[@]})) - printf "\r\033[2K%s %b" "${CS_YWB}${chars[$index]}${CS_CL}" "${CS_YWB}${SPINNER_MSG:-}${CS_CL}" + printf "\r\033[2K%s %b" "${CS_YWB}${chars[$index]}${CS_CL}" "${CS_YWB}${msg}${CS_CL}" sleep 0.1 done } +# ------------------------------------------------------------------------------ +# clear_line() +# +# - Clears current terminal line using tput or ANSI escape codes +# - Moves cursor to beginning of line (carriage return) +# - Erases from cursor to end of line +# - Fallback to ANSI codes if tput not available +# ------------------------------------------------------------------------------ clear_line() { tput cr 2>/dev/null || echo -en "\r" tput el 2>/dev/null || echo -en "\033[K" } +# ------------------------------------------------------------------------------ +# stop_spinner() +# +# - Stops running spinner process by PID +# - Reads PID from SPINNER_PID variable or /tmp/.spinner.pid file +# - Attempts graceful kill, then forced kill if needed +# - Cleans up temp file and resets terminal state +# - Unsets SPINNER_PID and SPINNER_MSG variables +# ------------------------------------------------------------------------------ stop_spinner() { local pid="${SPINNER_PID:-}" [[ -z "$pid" && -f /tmp/.spinner.pid ]] && pid=$(/dev/null || true } +# ============================================================================== +# SECTION 4: MESSAGE OUTPUT +# ============================================================================== + +# ------------------------------------------------------------------------------ +# msg_info() +# +# - Displays informational message with spinner animation +# - Shows each unique message only once (tracked via MSG_INFO_SHOWN) +# - In verbose/Alpine mode: shows hourglass icon instead of spinner +# - Stops any existing spinner before starting new one +# - Backgrounds spinner process and stores PID for later cleanup +# ------------------------------------------------------------------------------ msg_info() { local msg="$1" [[ -z "$msg" ]] && return @@ -395,6 +436,14 @@ msg_info() { disown "$SPINNER_PID" 2>/dev/null || true } +# ------------------------------------------------------------------------------ +# msg_ok() +# +# - Displays success message with checkmark icon +# - Stops spinner and clears line before output +# - Removes message from MSG_INFO_SHOWN to allow re-display +# - Uses green color for success indication +# ------------------------------------------------------------------------------ msg_ok() { local msg="$1" [[ -z "$msg" ]] && return @@ -404,18 +453,42 @@ msg_ok() { unset MSG_INFO_SHOWN["$msg"] } +# ------------------------------------------------------------------------------ +# msg_error() +# +# - Displays error message with cross/X icon +# - Stops spinner before output +# - Uses red color for error indication +# - Outputs to stderr +# ------------------------------------------------------------------------------ msg_error() { stop_spinner local msg="$1" echo -e "${BFR:-}${CROSS:-✖️} ${RD}${msg}${CL}" >&2 } +# ------------------------------------------------------------------------------ +# msg_warn() +# +# - Displays warning message with info/lightbulb icon +# - Stops spinner before output +# - Uses bright yellow color for warning indication +# - Outputs to stderr +# ------------------------------------------------------------------------------ msg_warn() { stop_spinner local msg="$1" echo -e "${BFR:-}${INFO:-ℹ️} ${YWB}${msg}${CL}" >&2 } +# ------------------------------------------------------------------------------ +# msg_custom() +# +# - Displays custom message with user-defined symbol and color +# - Arguments: symbol, color code, message text +# - Stops spinner before output +# - Useful for specialized status messages +# ------------------------------------------------------------------------------ msg_custom() { local symbol="${1:-"[*]"}" local color="${2:-"\e[36m"}" @@ -425,13 +498,169 @@ msg_custom() { echo -e "${BFR:-} ${symbol} ${color}${msg}${CL:-\e[0m}" } -function msg_debug() { +# ------------------------------------------------------------------------------ +# msg_debug() +# +# - Displays debug message with timestamp when var_full_verbose=1 +# - Automatically enables var_verbose if not already set +# - Shows date/time prefix for log correlation +# - Uses bright yellow color for debug output +# ------------------------------------------------------------------------------ +msg_debug() { if [[ "${var_full_verbose:-0}" == "1" ]]; then [[ "${var_verbose:-0}" != "1" ]] && var_verbose=1 echo -e "${YWB}[$(date '+%F %T')] [DEBUG]${CL} $*" fi } +# ------------------------------------------------------------------------------ +# fatal() +# +# - Displays error message and immediately terminates script +# - Sends SIGINT to current process to trigger error handler +# - Use for unrecoverable errors that require immediate exit +# ------------------------------------------------------------------------------ +fatal() { + msg_error "$1" + kill -INT $$ +} + +# ============================================================================== +# SECTION 5: UTILITY FUNCTIONS +# ============================================================================== + +# ------------------------------------------------------------------------------ +# exit_script() +# +# - Called when user cancels an action +# - Clears screen and displays exit message +# - Exits with default exit code +# ------------------------------------------------------------------------------ +exit_script() { + clear + echo -e "\n${CROSS}${RD}User exited script${CL}\n" + exit +} + +# ------------------------------------------------------------------------------ +# get_header() +# +# - Downloads and caches application header ASCII art +# - Falls back to local cache if already downloaded +# - Determines app type (ct/vm) from APP_TYPE variable +# - Returns header content or empty string on failure +# ------------------------------------------------------------------------------ +get_header() { + local app_name=$(echo "${APP,,}" | tr -d ' ') + local app_type=${APP_TYPE:-ct} # Default zu 'ct' falls nicht gesetzt + local header_url="https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/${app_type}/headers/${app_name}" + local local_header_path="/usr/local/community-scripts/headers/${app_type}/${app_name}" + + mkdir -p "$(dirname "$local_header_path")" + + if [ ! -s "$local_header_path" ]; then + if ! curl -fsSL "$header_url" -o "$local_header_path"; then + return 1 + fi + fi + + cat "$local_header_path" 2>/dev/null || true +} + +# ------------------------------------------------------------------------------ +# header_info() +# +# - Displays application header ASCII art at top of screen +# - Clears screen before displaying header +# - Detects terminal width for formatting +# - Returns silently if header not available +# ------------------------------------------------------------------------------ +header_info() { + local app_name=$(echo "${APP,,}" | tr -d ' ') + local header_content + + header_content=$(get_header "$app_name") || header_content="" + + clear + local term_width + term_width=$(tput cols 2>/dev/null || echo 120) + + if [ -n "$header_content" ]; then + echo "$header_content" + fi +} + +# ------------------------------------------------------------------------------ +# ensure_tput() +# +# - Ensures tput command is available for terminal control +# - Installs ncurses-bin on Debian/Ubuntu or ncurses on Alpine +# - Required for clear_line() and terminal width detection +# ------------------------------------------------------------------------------ +ensure_tput() { + if ! command -v tput >/dev/null 2>&1; then + if grep -qi 'alpine' /etc/os-release; then + apk add --no-cache ncurses >/dev/null 2>&1 + elif command -v apt-get >/dev/null 2>&1; then + apt-get update -qq >/dev/null + apt-get install -y -qq ncurses-bin >/dev/null 2>&1 + fi + fi +} + +# ------------------------------------------------------------------------------ +# is_alpine() +# +# - Detects if running on Alpine Linux +# - Checks var_os, PCT_OSTYPE, or /etc/os-release +# - Returns 0 if Alpine, 1 otherwise +# - Used to adjust behavior for Alpine-specific commands +# ------------------------------------------------------------------------------ +is_alpine() { + local os_id="${var_os:-${PCT_OSTYPE:-}}" + + if [[ -z "$os_id" && -f /etc/os-release ]]; then + os_id="$( + . /etc/os-release 2>/dev/null + echo "${ID:-}" + )" + fi + + [[ "$os_id" == "alpine" ]] +} + +# ------------------------------------------------------------------------------ +# is_verbose_mode() +# +# - Determines if script should run in verbose mode +# - Checks VERBOSE and var_verbose variables +# - Also returns true if not running in TTY (pipe/redirect scenario) +# - Used by msg_info() to decide between spinner and static output +# ------------------------------------------------------------------------------ +is_verbose_mode() { + local verbose="${VERBOSE:-${var_verbose:-no}}" + local tty_status + if [[ -t 2 ]]; then + tty_status="interactive" + else + tty_status="not-a-tty" + fi + [[ "$verbose" != "no" || ! -t 2 ]] +} + +# ============================================================================== +# SECTION 6: CLEANUP & MAINTENANCE +# ============================================================================== + +# ------------------------------------------------------------------------------ +# cleanup_lxc() +# +# - Comprehensive cleanup of package managers, caches, and logs +# - Supports Alpine (apk), Debian/Ubuntu (apt), and language package managers +# - Cleans: Python (pip/uv), Node.js (npm/yarn/pnpm), Go, Rust, Ruby, PHP +# - Truncates log files and vacuums systemd journal +# - Run at end of container creation to minimize disk usage +# ------------------------------------------------------------------------------ cleanup_lxc() { msg_info "Cleaning up" @@ -480,6 +709,16 @@ cleanup_lxc() { msg_ok "Cleaned" } +# ------------------------------------------------------------------------------ +# check_or_create_swap() +# +# - Checks if swap is active on system +# - Offers to create swap file if none exists +# - Prompts user for swap size in MB +# - Creates /swapfile with specified size +# - Activates swap immediately +# - Returns 0 if swap active or successfully created, 1 if declined/failed +# ------------------------------------------------------------------------------ check_or_create_swap() { msg_info "Checking for active swap" @@ -518,4 +757,8 @@ check_or_create_swap() { fi } +# ============================================================================== +# SIGNAL TRAPS +# ============================================================================== + trap 'stop_spinner' EXIT INT TERM diff --git a/misc/error_handler.func b/misc/error_handler.func index 5aa38e5e1..ef2c1a99e 100644 --- a/misc/error_handler.func +++ b/misc/error_handler.func @@ -1,12 +1,44 @@ #!/usr/bin/env bash # ------------------------------------------------------------------------------ -# Error & Signal Handling for ProxmoxVED Scripts +# ERROR HANDLER - ERROR & SIGNAL MANAGEMENT # ------------------------------------------------------------------------------ # Copyright (c) 2021-2025 community-scripts ORG # Author: MickLesk (CanbiZ) # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # ------------------------------------------------------------------------------ +# +# Provides comprehensive error handling and signal management for all scripts. +# Includes: +# - Exit code explanations (shell, package managers, databases, custom codes) +# - Error handler with detailed logging +# - Signal handlers (EXIT, INT, TERM) +# - Initialization function for trap setup +# +# Usage: +# source <(curl -fsSL .../error_handler.func) +# catch_errors +# +# ------------------------------------------------------------------------------ +# ============================================================================== +# SECTION 1: EXIT CODE EXPLANATIONS +# ============================================================================== + +# ------------------------------------------------------------------------------ +# explain_exit_code() +# +# - Maps numeric exit codes to human-readable error descriptions +# - Supports: +# * Generic/Shell errors (1, 2, 126, 127, 128, 130, 137, 139, 143) +# * Package manager errors (APT, DPKG: 100, 101, 255) +# * Node.js/npm errors (243-249, 254) +# * Python/pip/uv errors (210-212) +# * PostgreSQL errors (231-234) +# * MySQL/MariaDB errors (241-244) +# * MongoDB errors (251-254) +# * Proxmox custom codes (200-231) +# - Returns description string for given exit code +# ------------------------------------------------------------------------------ explain_exit_code() { local code="$1" case "$code" in @@ -79,7 +111,26 @@ explain_exit_code() { esac } -# === Error handler ============================================================ +# ============================================================================== +# SECTION 2: ERROR HANDLERS +# ============================================================================== + +# ------------------------------------------------------------------------------ +# error_handler() +# +# - Main error handler triggered by ERR trap +# - Arguments: exit_code, command, line_number +# - Behavior: +# * Returns silently if exit_code is 0 (success) +# * Sources explain_exit_code() for detailed error description +# * Displays error message with: +# - Line number where error occurred +# - Exit code with explanation +# - Command that failed +# * Shows last 20 lines of SILENT_LOGFILE if available +# * Copies log to container /root for later inspection +# * Exits with original exit code +# ------------------------------------------------------------------------------ error_handler() { local exit_code=${1:-$?} local command=${2:-${BASH_COMMAND:-unknown}} @@ -141,14 +192,31 @@ error_handler() { exit "$exit_code" } -# === Exit handler ============================================================= +# ============================================================================== +# SECTION 3: SIGNAL HANDLERS +# ============================================================================== + +# ------------------------------------------------------------------------------ +# on_exit() +# +# - EXIT trap handler +# - Cleans up lock files if lockfile variable is set +# - Exits with captured exit code +# - Always runs on script termination (success or failure) +# ------------------------------------------------------------------------------ on_exit() { local exit_code=$? [[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile" exit "$exit_code" } -# === Signal handlers ========================================================== +# ------------------------------------------------------------------------------ +# on_interrupt() +# +# - SIGINT (Ctrl+C) trap handler +# - Displays "Interrupted by user" message +# - Exits with code 130 (128 + SIGINT=2) +# ------------------------------------------------------------------------------ on_interrupt() { if declare -f msg_error >/dev/null 2>&1; then msg_error "Interrupted by user (SIGINT)" @@ -158,6 +226,14 @@ on_interrupt() { exit 130 } +# ------------------------------------------------------------------------------ +# on_terminate() +# +# - SIGTERM trap handler +# - Displays "Terminated by signal" message +# - Exits with code 143 (128 + SIGTERM=15) +# - Triggered by external process termination +# ------------------------------------------------------------------------------ on_terminate() { if declare -f msg_error >/dev/null 2>&1; then msg_error "Terminated by signal (SIGTERM)" @@ -167,7 +243,25 @@ on_terminate() { exit 143 } -# === Init traps =============================================================== +# ============================================================================== +# SECTION 4: INITIALIZATION +# ============================================================================== + +# ------------------------------------------------------------------------------ +# catch_errors() +# +# - Initializes error handling and signal traps +# - Enables strict error handling: +# * set -Ee: Exit on error, inherit ERR trap in functions +# * set -o pipefail: Pipeline fails if any command fails +# * set -u: (optional) Exit on undefined variable (if STRICT_UNSET=1) +# - Sets up traps: +# * ERR → error_handler +# * EXIT → on_exit +# * INT → on_interrupt +# * TERM → on_terminate +# - Call this function early in every script +# ------------------------------------------------------------------------------ catch_errors() { set -Ee -o pipefail if [ "${STRICT_UNSET:-0}" = "1" ]; then diff --git a/misc/install.func b/misc/install.func index f741b921d..3d0a08d33 100644 --- a/misc/install.func +++ b/misc/install.func @@ -4,6 +4,30 @@ # Co-Author: michelroegl-brunner # License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# ============================================================================== +# INSTALL.FUNC - CONTAINER INSTALLATION & SETUP +# ============================================================================== +# +# This file provides installation functions executed inside LXC containers +# after creation. Handles: +# +# - Network connectivity verification (IPv4/IPv6) +# - OS updates and package installation +# - DNS resolution checks +# - MOTD and SSH configuration +# - Container customization and auto-login +# +# Usage: +# - Sourced by -install.sh scripts +# - Executes via pct exec inside container +# - Requires internet connectivity +# +# ============================================================================== + +# ============================================================================== +# SECTION 1: INITIALIZATION +# ============================================================================== + if ! command -v curl >/dev/null 2>&1; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 apt-get update >/dev/null 2>&1 @@ -14,7 +38,17 @@ source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxV load_functions catch_errors -# This function enables IPv6 if it's not disabled and sets verbose mode +# ============================================================================== +# SECTION 2: NETWORK & CONNECTIVITY +# ============================================================================== + +# ------------------------------------------------------------------------------ +# verb_ip6() +# +# - Configures IPv6 based on DISABLEIPV6 variable +# - If DISABLEIPV6=yes: disables IPv6 via sysctl +# - Sets verbose mode via set_std_mode() +# ------------------------------------------------------------------------------ verb_ip6() { set_std_mode # Set STD mode based on VERBOSE @@ -24,29 +58,15 @@ verb_ip6() { fi } -# # This function sets error handling options and defines the error_handler function to handle errors -# catch_errors() { -# set -Eeuo pipefail -# trap 'error_handler $LINENO "$BASH_COMMAND"' ERR -# } - -# # This function handles errors -# error_handler() { -# source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/api.func) -# local exit_code="$1" -# local line_number="$2" -# local command="${3:-}" - -# if [[ "$exit_code" -eq 0 ]]; then -# return 0 -# fi - -# printf "\e[?25h" -# echo -e "\n${RD}[ERROR]${CL} in line ${RD}${line_number}${CL}: exit code ${RD}${exit_code}${CL}: while executing command ${YW}${command}${CL}\n" -# exit "$exit_code" -#} - -# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection +# ------------------------------------------------------------------------------ +# setting_up_container() +# +# - Verifies network connectivity via hostname -I +# - Retries up to RETRY_NUM times with RETRY_EVERY seconds delay +# - Removes Python EXTERNALLY-MANAGED restrictions +# - Disables systemd-networkd-wait-online.service for faster boot +# - Exits with error if network unavailable after retries +# ------------------------------------------------------------------------------ setting_up_container() { msg_info "Setting up Container OS" for ((i = RETRY_NUM; i > 0; i--)); do @@ -68,7 +88,17 @@ setting_up_container() { msg_ok "Network Connected: ${BL}$(hostname -I)" } -# This function checks the network connection by pinging a known IP address and prompts the user to continue if the internet is not connected +# ------------------------------------------------------------------------------ +# network_check() +# +# - Comprehensive network connectivity check for IPv4 and IPv6 +# - Tests connectivity to multiple DNS servers: +# * IPv4: 1.1.1.1 (Cloudflare), 8.8.8.8 (Google), 9.9.9.9 (Quad9) +# * IPv6: 2606:4700:4700::1111, 2001:4860:4860::8888, 2620:fe::fe +# - Verifies DNS resolution for GitHub and Community-Scripts domains +# - Prompts user to continue if no internet detected +# - Uses fatal() on DNS resolution failure for critical hosts +# ------------------------------------------------------------------------------ network_check() { set +e trap - ERR @@ -128,7 +158,19 @@ network_check() { trap 'error_handler $LINENO "$BASH_COMMAND"' ERR } -# This function updates the Container OS by running apt-get update and upgrade +# ============================================================================== +# SECTION 3: OS UPDATE & PACKAGE MANAGEMENT +# ============================================================================== + +# ------------------------------------------------------------------------------ +# update_os() +# +# - Updates container OS via apt-get update and dist-upgrade +# - Configures APT cacher proxy if CACHER=yes (accelerates package downloads) +# - Removes Python EXTERNALLY-MANAGED restrictions for pip +# - Sources tools.func for additional setup functions after update +# - Uses $STD wrapper to suppress output unless VERBOSE=yes +# ------------------------------------------------------------------------------ update_os() { msg_info "Updating Container OS" if [[ "$CACHER" == "yes" ]]; then @@ -150,7 +192,24 @@ EOF source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/tools.func) } -# This function modifies the message of the day (motd) and SSH settings +# ============================================================================== +# SECTION 4: MOTD & SSH CONFIGURATION +# ============================================================================== + +# ------------------------------------------------------------------------------ +# motd_ssh() +# +# - Configures Message of the Day (MOTD) with container information +# - Creates /etc/profile.d/00_lxc-details.sh with: +# * Application name +# * Warning banner (DEV repository) +# * OS name and version +# * Hostname and IP address +# * GitHub repository link +# - Disables executable flag on /etc/update-motd.d/* scripts +# - Enables root SSH access if SSH_ROOT=yes +# - Configures TERM environment variable for better terminal support +# ------------------------------------------------------------------------------ motd_ssh() { grep -qxF "export TERM='xterm-256color'" /root/.bashrc || echo "export TERM='xterm-256color'" >>/root/.bashrc @@ -180,7 +239,19 @@ motd_ssh() { fi } -# This function customizes the container by modifying the getty service and enabling auto-login for the root user +# ============================================================================== +# SECTION 5: CONTAINER CUSTOMIZATION +# ============================================================================== + +# ------------------------------------------------------------------------------ +# customize() +# +# - Customizes container for passwordless root login if PASSWORD is empty +# - Configures getty for auto-login via /etc/systemd/system/container-getty@1.service.d/override.conf +# - Creates /usr/bin/update script for easy application updates +# - Injects SSH authorized keys if SSH_AUTHORIZED_KEY variable is set +# - Sets proper permissions on SSH directories and key files +# ------------------------------------------------------------------------------ customize() { if [[ "$PASSWORD" == "" ]]; then msg_info "Customizing Container"