# Copyright (c) 2021-2026 community-scripts ORG # Author: michelroegl-brunner # License: MIT | https://raw.githubusercontent.com/community-scripts/ProxmoxVED/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, 124, 126-130, 134, 137, 139, 141, 143) # * curl/wget errors (6, 7, 22, 28, 35) # * Package manager errors (APT, DPKG: 100-102, 255) # * Systemd/Service errors (150-154) # * Python/pip/uv errors (160-162) # * PostgreSQL errors (170-173) # * MySQL/MariaDB errors (180-183) # * MongoDB errors (190-193) # * Proxmox custom codes (200-231) # * Node.js/npm errors (243, 245-249) # - 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)" ;; # --- curl / wget errors (commonly seen in downloads) --- 6) echo "curl: DNS resolution failed (could not resolve host)" ;; 7) echo "curl: Failed to connect (network unreachable / host down)" ;; 22) echo "curl: HTTP error returned (404, 429, 500+)" ;; 28) echo "curl: Operation timeout (network slow or server not responding)" ;; 35) echo "curl: SSL/TLS handshake failed (certificate error)" ;; # --- Package manager / APT / DPKG --- 100) echo "APT: Package manager error (broken packages / dependency problems)" ;; 101) echo "APT: Configuration error (bad sources.list, malformed config)" ;; 102) echo "APT: Lock held by another process (dpkg/apt still running)" ;; # --- Common shell/system errors --- 124) echo "Command timed out (timeout command)" ;; 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)" ;; 134) echo "Process aborted (SIGABRT - possibly Node.js heap overflow)" ;; 137) echo "Killed (SIGKILL / Out of memory?)" ;; 139) echo "Segmentation fault (core dumped)" ;; 141) echo "Broken pipe (SIGPIPE - output closed prematurely)" ;; 143) echo "Terminated (SIGTERM)" ;; # --- Systemd / Service errors (150-154) --- 150) echo "Systemd: Service failed to start" ;; 151) echo "Systemd: Service unit not found" ;; 152) echo "Permission denied (EACCES)" ;; 153) echo "Build/compile failed (make/gcc/cmake)" ;; 154) echo "Node.js: Native addon build failed (node-gyp)" ;; # --- Python / pip / uv (160-162) --- 160) echo "Python: Virtualenv / uv environment missing or broken" ;; 161) echo "Python: Dependency resolution failed" ;; 162) echo "Python: Installation aborted (permissions or EXTERNALLY-MANAGED)" ;; # --- PostgreSQL (170-173) --- 170) echo "PostgreSQL: Connection failed (server not running / wrong socket)" ;; 171) echo "PostgreSQL: Authentication failed (bad user/password)" ;; 172) echo "PostgreSQL: Database does not exist" ;; 173) echo "PostgreSQL: Fatal error in query / syntax" ;; # --- MySQL / MariaDB (180-183) --- 180) echo "MySQL/MariaDB: Connection failed (server not running / wrong socket)" ;; 181) echo "MySQL/MariaDB: Authentication failed (bad user/password)" ;; 182) echo "MySQL/MariaDB: Database does not exist" ;; 183) echo "MySQL/MariaDB: Fatal error in query / syntax" ;; # --- MongoDB (190-193) --- 190) echo "MongoDB: Connection failed (server not running)" ;; 191) echo "MongoDB: Authentication failed (bad user/password)" ;; 192) echo "MongoDB: Database not found" ;; 193) echo "MongoDB: Fatal query error" ;; # --- Proxmox Custom Codes (200-231) --- 200) echo "Proxmox: Failed to create lock file" ;; 203) echo "Proxmox: Missing CTID variable" ;; 204) echo "Proxmox: Missing PCT_OSTYPE variable" ;; 205) echo "Proxmox: Invalid CTID (<100)" ;; 206) echo "Proxmox: CTID already in use" ;; 207) echo "Proxmox: Password contains unescaped special characters" ;; 208) echo "Proxmox: Invalid configuration (DNS/MAC/Network format)" ;; 209) echo "Proxmox: Container creation failed" ;; 210) echo "Proxmox: Cluster not quorate" ;; 211) echo "Proxmox: Timeout waiting for template lock" ;; 212) echo "Proxmox: Storage type 'iscsidirect' does not support containers (VMs only)" ;; 213) echo "Proxmox: Storage type does not support 'rootdir' content" ;; 214) echo "Proxmox: Not enough storage space" ;; 215) echo "Proxmox: Container created but not listed (ghost state)" ;; 216) echo "Proxmox: RootFS entry missing in config" ;; 217) echo "Proxmox: Storage not accessible" ;; 218) echo "Proxmox: Template file corrupted or incomplete" ;; 219) echo "Proxmox: CephFS does not support containers - use RBD" ;; 220) echo "Proxmox: Unable to resolve template path" ;; 221) echo "Proxmox: Template file not readable" ;; 222) echo "Proxmox: Template download failed" ;; 223) echo "Proxmox: Template not available after download" ;; 224) echo "Proxmox: PBS storage is for backups only" ;; 225) echo "Proxmox: No template available for OS/Version" ;; 231) echo "Proxmox: LXC stack upgrade failed" ;; # --- Node.js / npm / pnpm / yarn (243-249) --- 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 "npm/pnpm/yarn: Unknown fatal error" ;; # --- DPKG --- 255) echo "DPKG: Fatal internal error" ;; # --- 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/dev/upload" local pve_version="not found" pve_version=$(pveversion | awk -F'[/ ]' '{print $2}') JSON_PAYLOAD=$( cat </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/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 error=$(explain_exit_code "$exit_code") if [ -z "$error" ]; then error="Unknown error" fi JSON_PAYLOAD=$( cat <