ProxmoxVE/misc/api.func
CanbiZ a826769899
Three-tier defaults system | security improvements | error_handler | improved logging | improved container creation | improved architecture (#9540)
* Refactor Core

Refactored misc/alpine-install.func to improve error handling, network checks, and MOTD setup. Added misc/alpine-tools.func and misc/error_handler.func for modular tool installation and error management. Enhanced misc/api.func with detailed exit code explanations and telemetry functions. Updated misc/core.func for better initialization, validation, and execution helpers. Removed misc/create_lxc.sh as part of cleanup.

* Delete config-file.func

* Update install.func

* Refactor stop_all_services function and variable names

Refactor service stopping logic and improve variable handling

* Refactor installation script and update copyright

Updated copyright information and adjusted package installation commands. Enhanced IPv6 disabling logic and improved container customization process.

* Update install.func

* Update license comment format in install.func

* Refactor IPv6 handling and enhance MOTD and SSH

Refactor IPv6 handling and update OS function. Enhance MOTD with additional details and configure SSH settings.

* big core refactor

* Enhance IPv6 configuration menu options

Updated IPv6 Address Management menu options for clarity and added a new option for fully disabling IPv6.

* Update default Node.js version to 24 LTS

* Update misc/alpine-tools.func

Co-authored-by: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com>

* indention

* remove debugf and duplicate codes

* Update whiptail backtitles and error codes

Removed '[dev]' from whiptail --backtitle strings for consistency. Refactored custom exit codes in build.func and error_handler.func: updated Proxmox error codes, shifted MySQL/MariaDB codes to 260-263, and removed unused MongoDB code. Updated error descriptions to match new codes.

* comments

* Refactor error handling and clean up debug comments

Standardized bash variable checks, removed unnecessary debug and commented code, and clarified error handling logic in container build and setup scripts. These changes improve code readability and maintainability without altering functional behavior.

* Update build.func

* feat: Improve LXC network checks and LINSTOR storage handling

Enhanced LXC container network setup to check for both IPv4 and IPv6 addresses, added connectivity (ping) tests, and provided troubleshooting tips on failure. Updated storage validation to support LINSTOR, including cluster connectivity checks and special handling for LINSTOR template storage.

---------

Co-authored-by: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com>
2025-12-04 07:52:18 +01:00

323 lines
11 KiB
Bash

# Copyright (c) 2021-2025 community-scripts ORG
# Author: michelroegl-brunner
# License: MIT | https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/LICENSE
# ==============================================================================
# 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: ERROR CODE DESCRIPTIONS
# ==============================================================================
# ------------------------------------------------------------------------------
# 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
# - Shared function with error_handler.func for consistency
# ------------------------------------------------------------------------------
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)" ;;
206) echo "Custom: CTID already in use (check 'pct list' and /etc/pve/lxc/)" ;;
207) echo "Custom: Password contains unescaped special characters (-, /, \\, *, etc.)" ;;
208) echo "Custom: Invalid configuration (DNS/MAC/Network format error)" ;;
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
}
# ==============================================================================
# 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 [ "$DIAGNOSTICS" = "no" ]; then
return
fi
if [ -z "$RANDOM_UUID" ]; then
return
fi
local API_URL="http://api.community-scripts.org/upload"
local pve_version="not found"
pve_version=$(pveversion | awk -F'[/ ]' '{print $2}')
JSON_PAYLOAD=$(
cat <<EOF
{
"ct_type": $CT_TYPE,
"type":"lxc",
"disk_size": $DISK_SIZE,
"core_count": $CORE_COUNT,
"ram_size": $RAM_SIZE,
"os_type": "$var_os",
"os_version": "$var_version",
"nsapp": "$NSAPP",
"method": "$METHOD",
"pve_version": "$pve_version",
"status": "installing",
"random_id": "$RANDOM_UUID"
}
EOF
)
if [[ "$DIAGNOSTICS" == "yes" ]]; then
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
fi
}
# ------------------------------------------------------------------------------
# post_to_api_vm()
#
# - Sends VM creation statistics to Community-Scripts API
# - Similar to post_to_api() but for virtual machines (not containers)
# - Reads DIAGNOSTICS from /usr/local/community-scripts/diagnostics file
# - Payload differences:
# * ct_type=2 (VM instead of LXC)
# * type="vm"
# * Disk size without 'G' suffix (parsed from DISK_SIZE variable)
# - Only executes if DIAGNOSTICS=yes and RANDOM_UUID is set
# ------------------------------------------------------------------------------
post_to_api_vm() {
if [[ ! -f /usr/local/community-scripts/diagnostics ]]; then
return
fi
DIAGNOSTICS=$(grep -i "^DIAGNOSTICS=" /usr/local/community-scripts/diagnostics | awk -F'=' '{print $2}')
if ! command -v curl &>/dev/null; then
return
fi
if [ "$DIAGNOSTICS" = "no" ]; then
return
fi
if [ -z "$RANDOM_UUID" ]; then
return
fi
local API_URL="http://api.community-scripts.org/upload"
local pve_version="not found"
pve_version=$(pveversion | awk -F'[/ ]' '{print $2}')
DISK_SIZE_API=${DISK_SIZE%G}
JSON_PAYLOAD=$(
cat <<EOF
{
"ct_type": 2,
"type":"vm",
"disk_size": $DISK_SIZE_API,
"core_count": $CORE_COUNT,
"ram_size": $RAM_SIZE,
"os_type": "$var_os",
"os_version": "$var_version",
"nsapp": "$NSAPP",
"method": "$METHOD",
"pve_version": "$pve_version",
"status": "installing",
"random_id": "$RANDOM_UUID"
}
EOF
)
if [[ "$DIAGNOSTICS" == "yes" ]]; then
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
fi
}
# ------------------------------------------------------------------------------
# post_update_to_api()
#
# - Reports installation completion status to API
# - Prevents duplicate submissions via POST_UPDATE_DONE flag
# - Arguments:
# * $1: status ("success" or "failed")
# * $2: exit_code (default: 1 for failed, 0 for success)
# - Payload includes:
# * Final status (success/failed)
# * Error description via get_error_description()
# * Random UUID for session correlation
# - Only executes once per session
# - Silently returns if:
# * curl not available
# * Already reported (POST_UPDATE_DONE=true)
# * DIAGNOSTICS=no
# ------------------------------------------------------------------------------
post_update_to_api() {
if ! command -v curl &>/dev/null; then
return
fi
# Initialize flag if not set (prevents 'unbound variable' error with set -u)
POST_UPDATE_DONE=${POST_UPDATE_DONE:-false}
if [ "$POST_UPDATE_DONE" = true ]; then
return 0
fi
exit_code=${2:-1}
local API_URL="http://api.community-scripts.org/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
error=$(explain_exit_code "$exit_code")
if [ -z "$error" ]; then
error="Unknown error"
fi
JSON_PAYLOAD=$(
cat <<EOF
{
"status": "$status",
"error": "$error",
"random_id": "$RANDOM_UUID"
}
EOF
)
if [[ "$DIAGNOSTICS" == "yes" ]]; then
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
fi
POST_UPDATE_DONE=true
}