feat: initial project scaffold for lxs multi-tool
- add main entrypoint with interactive menu and CLI dispatcher (lxs.sh) - add shared helpers library with colors, loggers, and spinner (lib/common.sh) - add app installers for coolify, pterodactyl, uptime-kuma, cloudpanel, and proxmox (apps/) - add system tools for monitoring, benchmarking, and hardening (tools/) - add VERSION file (0.1.0) as single source of truth for releases - add MIT LICENSE - expand README with usage, project structure, and release workflow
This commit is contained in:
Executable
+354
@@ -0,0 +1,354 @@
|
||||
#!/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
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
# 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 " ${RED}[0]${NC} Back to main menu"
|
||||
echo ""
|
||||
echo -n "Choice [0-8]: "
|
||||
}
|
||||
|
||||
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 ;;
|
||||
0) return 0 ;;
|
||||
*) echo -e "${RED}Invalid option${NC}" ;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
read -p "Press Enter to continue..."
|
||||
done
|
||||
}
|
||||
|
||||
main
|
||||
|
||||
Reference in New Issue
Block a user