Files
lxs/apps/proxmox.sh
T
hykocx 15c42e1f24 feat(lib): add require_disk_space helper and enforce pre-flight disk checks
- add `require_disk_space` function to lib/common.sh with dedup logic for shared filesystems
- gate cloudpanel, coolify, pterodactyl installs behind a 2–3 GB disk check
- gate uptime-kuma, proxmox update, harden, update-server, and server-benchmark behind 300–1024 MB disk checks
- fail early with a clear error before apt installs or config writes can leave the system in a partial state
2026-05-12 22:39:19 -04:00

387 lines
14 KiB
Bash
Executable File

#!/bin/bash
# LXS - Proxmox VE Management Script
# Description: Tools for managing and troubleshooting Proxmox VE
# Author: LXS
# Date: 2025
# Load LXS common library (colors, separator, run_spinner, loggers, helpers)
LXS_RAW_BASE="${LXS_RAW_BASE:-https://git.hyko.cx/hykocx/lxs/raw/branch/main}"
_lib=$(curl -fsSL "${LXS_RAW_BASE}/lib/common.sh") || { echo "Failed to fetch lib/common.sh" >&2; exit 1; }
eval "$_lib"
unset _lib
export LXS_LOG_FILE="/tmp/lxs_proxmox.log"
require_root "$0" "$@"
# ═══════════════════════════════════════════════════════════════════════════
# Configuration
# ═══════════════════════════════════════════════════════════════════════════
LOCKFILE="/var/lib/pve-cluster/.pmxcfs.lockfile"
SERVICE_NAME="pve-cluster"
PANEL_PORT=8006
# ═══════════════════════════════════════════════════════════════════════════
# Helper Functions
# ═══════════════════════════════════════════════════════════════════════════
is_proxmox() {
[ -f /etc/pve/.version ] || command -v pveversion &> /dev/null
}
get_service_status() {
if systemctl is-active --quiet $SERVICE_NAME; then
echo -e "${GREEN}running${NC}"
else
echo -e "${RED}stopped${NC}"
fi
}
check_proxmox() {
if ! is_proxmox; then
echo -e "${RED}[!] This is not a Proxmox VE system!${NC}"
echo -e "${YELLOW} This script is designed for Proxmox VE only.${NC}"
return 1
fi
return 0
}
# ═══════════════════════════════════════════════════════════════════════════
# Login Fix Functions
# ═══════════════════════════════════════════════════════════════════════════
fix_login_issue() {
local start_time=$(date +%s)
echo -e "${WHITE}${BOLD}PROXMOX LOGIN FIX${NC}\n"
check_proxmox || return 1
echo -e "${CYAN}This will reset the pve-cluster lockfile to fix login issues.${NC}"
echo ""
echo "[1/3] Stopping pve-cluster service..."
run_spinner "Stopping $SERVICE_NAME..." "systemctl stop $SERVICE_NAME"
if [ $? -ne 0 ]; then
echo -e "${RED}[!] Failed to stop pve-cluster service${NC}"
return 1
fi
echo ""
echo "[2/3] Removing lockfile..."
if [ -f "$LOCKFILE" ]; then
run_spinner "Removing lockfile..." "rm -f '$LOCKFILE'"
echo -e "${GRAY} Lockfile was present and has been removed${NC}"
else
echo -e "${YELLOW}[!] Lockfile not found (may already be removed)${NC}"
fi
echo ""
echo "[3/3] Starting pve-cluster service..."
run_spinner "Starting $SERVICE_NAME..." "systemctl start $SERVICE_NAME"
if [ $? -ne 0 ]; then
echo -e "${RED}[!] Failed to start pve-cluster service${NC}"
echo -e "${YELLOW} Check logs with: journalctl -xe${NC}"
return 1
fi
sleep 2
local duration=$(( $(date +%s) - start_time ))
local server_ip=$(hostname -I | awk '{print $1}')
echo ""
show_separator
echo -e "${GREEN}${BOLD}Fix Completed!${NC}"
echo -e "${GRAY}Time: ${duration}s${NC}"
echo ""
echo -e "${WHITE}Service Status:${NC} $(get_service_status)"
echo ""
echo -e "${CYAN}You should now be able to login to the Proxmox web interface.${NC}"
echo -e "${WHITE}Panel URL: ${GREEN}${BOLD}https://$server_ip:$PANEL_PORT${NC}"
show_separator
}
# ═══════════════════════════════════════════════════════════════════════════
# Service Management Functions
# ═══════════════════════════════════════════════════════════════════════════
restart_pve_cluster() {
echo -e "${WHITE}${BOLD}RESTART PVE-CLUSTER${NC}\n"
check_proxmox || return 1
run_spinner "Restarting $SERVICE_NAME..." "systemctl restart $SERVICE_NAME"
sleep 2
echo ""
echo -e "${WHITE}Service Status:${NC} $(get_service_status)"
}
restart_all_services() {
echo -e "${WHITE}${BOLD}RESTART ALL PROXMOX SERVICES${NC}\n"
check_proxmox || return 1
local services=("pve-cluster" "pvedaemon" "pveproxy" "pvestatd")
for service in "${services[@]}"; do
if systemctl list-unit-files | grep -q "^$service.service"; then
run_spinner "Restarting $service..." "systemctl restart $service"
fi
done
sleep 2
echo ""
echo -e "${GREEN}[✓] All services restarted${NC}"
echo ""
echo -e "${WHITE}Panel URL: ${GREEN}${BOLD}https://$(hostname -I | awk '{print $1}'):$PANEL_PORT${NC}"
}
# ═══════════════════════════════════════════════════════════════════════════
# Status Functions
# ═══════════════════════════════════════════════════════════════════════════
show_status() {
echo -e "${WHITE}${BOLD}PROXMOX VE STATUS${NC}\n"
check_proxmox || return 1
# Proxmox version
echo -e "${WHITE}Proxmox Version:${NC}"
pveversion 2>/dev/null || echo -e "${GRAY}Unable to determine version${NC}"
echo ""
# Service statuses
echo -e "${WHITE}Service Status:${NC}"
local services=("pve-cluster" "pvedaemon" "pveproxy" "pvestatd")
for service in "${services[@]}"; do
if systemctl list-unit-files | grep -q "^$service.service"; then
if systemctl is-active --quiet $service; then
echo -e " ${GREEN}[✓]${NC} $service"
else
echo -e " ${RED}[✗]${NC} $service"
fi
fi
done
echo ""
# Lockfile status
if [ -f "$LOCKFILE" ]; then
echo -e "${WHITE}Lockfile:${NC} ${YELLOW}Present${NC} ($LOCKFILE)"
else
echo -e "${WHITE}Lockfile:${NC} ${GREEN}Not present${NC}"
fi
echo ""
# Access URL
local server_ip=$(hostname -I | awk '{print $1}')
echo -e "${WHITE}Panel URL: ${GREEN}${BOLD}https://$server_ip:$PANEL_PORT${NC}"
echo ""
# Cluster info
if command -v pvecm &> /dev/null; then
echo -e "${WHITE}Cluster Status:${NC}"
pvecm status 2>/dev/null | head -5 || echo -e "${GRAY}Not in a cluster or unable to get status${NC}"
fi
return 0
}
show_storage_status() {
echo -e "${WHITE}${BOLD}PROXMOX STORAGE STATUS${NC}\n"
check_proxmox || return 1
# Storage list
echo -e "${WHITE}Storage Configuration:${NC}"
if command -v pvesm &> /dev/null; then
pvesm status 2>/dev/null || echo -e "${GRAY}Unable to get storage status${NC}"
else
echo -e "${GRAY}pvesm command not available${NC}"
fi
echo ""
# Disk usage
echo -e "${WHITE}Disk Usage:${NC}"
df -h / /var /tmp 2>/dev/null | head -5
return 0
}
# ═══════════════════════════════════════════════════════════════════════════
# Maintenance Functions
# ═══════════════════════════════════════════════════════════════════════════
clear_cache() {
echo -e "${WHITE}${BOLD}CLEAR PROXMOX CACHE${NC}\n"
check_proxmox || return 1
echo -e "${CYAN}This will clear various Proxmox caches and temporary files.${NC}"
echo ""
run_spinner "Clearing apt cache..." "apt clean"
run_spinner "Clearing journal logs (older than 7 days)..." "journalctl --vacuum-time=7d"
# Clear task logs older than 30 days
if [ -d "/var/log/pve/tasks" ]; then
run_spinner "Clearing old task logs..." "find /var/log/pve/tasks -type f -mtime +30 -delete"
fi
echo ""
echo -e "${GREEN}[✓] Cache cleared${NC}"
}
update_proxmox() {
echo -e "${WHITE}${BOLD}UPDATE PROXMOX VE${NC}\n"
check_proxmox || return 1
require_disk_space 1024 || return 1
# Configure non-interactive mode
export DEBIAN_FRONTEND=noninteractive
export NEEDRESTART_MODE=a
export NEEDRESTART_SUSPEND=1
local start_time=$(date +%s)
run_spinner "Updating package lists..." "apt update"
echo ""
echo -e "${PURPLE}[*] Upgrading packages...${NC}"
show_separator
apt dist-upgrade -y
local exit_code=$?
show_separator
if [ $exit_code -eq 0 ]; then
local duration=$(( $(date +%s) - start_time ))
echo ""
echo -e "${GREEN}${BOLD}Update Completed!${NC}"
echo -e "${GRAY}Time: $((duration / 60))m $((duration % 60))s${NC}"
echo ""
echo -e "${YELLOW}[!] A reboot may be required if the kernel was updated.${NC}"
else
echo ""
echo -e "${RED}[✗] Update failed${NC}"
return 1
fi
}
# ═══════════════════════════════════════════════════════════════════════════
# Network Functions
# ═══════════════════════════════════════════════════════════════════════════
show_network_info() {
echo -e "${WHITE}${BOLD}PROXMOX NETWORK INFO${NC}\n"
check_proxmox || return 1
local server_ip=$(hostname -I | awk '{print $1}')
local public_ip=$(get_public_ip)
echo -e "${WHITE}Hostname:${NC} $(hostname)"
echo -e "${WHITE}Local IP:${NC} $server_ip"
echo -e "${WHITE}Public IP:${NC} $public_ip"
echo ""
echo -e "${WHITE}Network Interfaces:${NC}"
ip -br addr show 2>/dev/null || ifconfig 2>/dev/null | grep -E "^[a-z]|inet "
echo ""
echo -e "${WHITE}Bridges:${NC}"
if command -v brctl &> /dev/null; then
brctl show 2>/dev/null || echo -e "${GRAY}No bridges found${NC}"
else
ip link show type bridge 2>/dev/null || echo -e "${GRAY}No bridges found${NC}"
fi
return 0
}
# ═══════════════════════════════════════════════════════════════════════════
# Firewall
# ═══════════════════════════════════════════════════════════════════════════
open_firewall_ports() {
echo -e "${WHITE}${BOLD}OPEN PROXMOX FIREWALL PORTS${NC}\n"
check_proxmox || return 1
if ! command -v ufw >/dev/null 2>&1; then
echo -e "${YELLOW}[!] UFW is not installed on this host. Nothing to do.${NC}"
echo -e "${GRAY} Proxmox uses its own pve-firewall; UFW is optional.${NC}"
return 0
fi
if ! ufw status 2>/dev/null | grep -q "Status: active"; then
echo -e "${YELLOW}[!] UFW is installed but inactive. Enable it first.${NC}"
return 0
fi
ufw_allow "${PANEL_PORT}/tcp" "Proxmox web UI"
ufw_allow 5900:5999/tcp "Proxmox VNC console"
ufw_allow 3128/tcp "Proxmox SPICE proxy"
echo ""
echo -e "${GRAY}[i] For clustered nodes, also open: 5404-5405/udp (corosync), 60000-60050/tcp (live migration).${NC}"
echo -e "${GRAY}[i] If using NFS storage: 111/tcp+udp and 2049/tcp.${NC}"
}
# ═══════════════════════════════════════════════════════════════════════════
# Main Menu
# ═══════════════════════════════════════════════════════════════════════════
show_menu() {
clear
echo -e "${WHITE}${BOLD}PROXMOX VE MANAGEMENT${NC}\n"
echo -e " ${GREEN}[1]${NC} Fix Login Issue (reset lockfile)"
echo -e " ${YELLOW}[2]${NC} Restart pve-cluster service"
echo -e " ${YELLOW}[3]${NC} Restart all Proxmox services"
echo -e " ${CYAN}[4]${NC} View System Status"
echo -e " ${CYAN}[5]${NC} View Storage Status"
echo -e " ${CYAN}[6]${NC} View Network Info"
echo -e " ${PURPLE}[7]${NC} Update Proxmox VE"
echo -e " ${PURPLE}[8]${NC} Clear Cache"
echo -e " ${PURPLE}[9]${NC} Open Firewall Ports (UFW)"
echo -e " ${RED}[0]${NC} Back to main menu"
echo ""
echo -n "Choice [0-9]: "
}
main() {
while true; do
show_menu
read -r choice
echo ""
case $choice in
1) fix_login_issue ;;
2) restart_pve_cluster ;;
3) restart_all_services ;;
4) show_status ;;
5) show_storage_status ;;
6) show_network_info ;;
7) update_proxmox ;;
8) clear_cache ;;
9) open_firewall_ports ;;
0) return 75 ;;
*) echo -e "${RED}Invalid option${NC}" ;;
esac
echo ""
read -p "Press Enter to continue..."
done
}
main