This commit is contained in:
2026-07-25 11:46:04 -05:00
parent cc83cce667
commit 376d029fc8
4 changed files with 380 additions and 98 deletions
+301 -29
View File
@@ -235,24 +235,88 @@ DETECT_CPU(){
}
RESTART_PVE_SERVICES(){
if [ "${1}" == "" ]; then
echo -en "${idsCL[LightCyan]}Would you like to restart all Proxmox services on the local host (Y/n)?${idsCL[Default]} "
read -n 1 choice
else
choice=${1}
fi
case "${choice}" in
[Nn]) echo;;
*) echo
echo -en "\n${idsCL[Yellow]}Restarting services ... "
#systemctl restart pve-cluster pvedaemon pvestatd pveproxy pve-ha-lrm pve-ha-crm
systemctl restart pve-cluster pvedaemon pvestatd pveproxy
echo -e "${idsCL[Green]}Done${idsCL[Default]}"
echo -e "\n${idsCL[Green]}This hosts Proxmox services have been restarted${idsCL[Default]}\n"
FINISH_ACTION
;;
esac
RESTART_SERVICE_GROUP() {
local description="$1"
shift
local -a services=("$@")
local service
local failed=0
local choice
if (( ${RESTART_ASSUME_YES:-0} == 1 )); then
choice="y"
else
echo -en "${idsCL[LightCyan]}Restart ${description} on this host (Y/n)?${idsCL[Default]} "
read -n 1 choice
echo
fi
[[ "$choice" =~ ^[Nn]$ ]] && return
echo -e "\n${idsCL[Yellow]}Restarting ${description}...${idsCL[Default]}"
if ! systemctl restart "${services[@]}"; then
failed=1
fi
echo
for service in "${services[@]}"; do
if systemctl is-active --quiet "$service"; then
echo -e " ${idsCL[Green]}[active]${idsCL[Default]} ${service}"
else
echo -e " ${idsCL[Red]}[failed]${idsCL[Default]} ${service}"
failed=1
fi
done
if (( failed == 0 )); then
echo -e "\n${idsCL[Green]}Service restart completed successfully.${idsCL[Default]}"
else
echo -e "\n${idsCL[Red]}One or more services failed to restart.${idsCL[Default]}"
echo "Review: journalctl -u <service> --since '-10 minutes'"
fi
FINISH_ACTION
}
RESTART_CLUSTER_FILESYSTEM() {
local choice
echo -e "${idsCL[LightYellow]}This temporarily interrupts /etc/pve (pmxcfs) and cluster configuration access.${idsCL[Default]}"
echo -e "${idsCL[LightYellow]}It does not restart Corosync or the HA daemons.${idsCL[Default]}"
if systemctl is-active --quiet corosync &&
! timeout 5 pvecm status 2>/dev/null |
grep -Eq '^Quorate:[[:space:]]+Yes[[:space:]]*$'; then
echo -e "\n${idsCL[Red]}The cluster is not quorate. pve-cluster will not be restarted.${idsCL[Default]}"
ENTER2CONTINUE
return
fi
echo -en "\n${idsCL[LightCyan]}Restart pve-cluster on this host (y/N)?${idsCL[Default]} "
read -n 1 choice
echo
[[ "$choice" =~ ^[Yy]$ ]] || return
if systemctl restart pve-cluster &&
systemctl is-active --quiet pve-cluster &&
timeout 15 bash -c 'until test -d /etc/pve/nodes; do sleep 1; done'; then
echo -e "\n${idsCL[Green]}pve-cluster restarted and /etc/pve is available.${idsCL[Default]}"
else
echo -e "\n${idsCL[Red]}pve-cluster did not recover normally.${idsCL[Default]}"
echo "Review: journalctl -u pve-cluster --since '-10 minutes'"
fi
ENTER2CONTINUE
}
RESTART_PVE_SERVICES() {
local requested_choice="${1:-}"
local RESTART_ASSUME_YES=0
[[ "$requested_choice" =~ ^[Nn]$ ]] && return
[[ "$requested_choice" =~ ^[Yy]$ ]] && RESTART_ASSUME_YES=1
RESTART_SERVICE_GROUP "core Proxmox management services" \
pvedaemon pveproxy pvestatd pvescheduler
}
MAINTENANCE_MODE(){
@@ -295,12 +359,151 @@ INSTALL_KEEPALIVE() {
esac
}
UPDATE_CACHE_DIR='/var/cache/ta-proxmenu'
UPDATE_CACHE_FILE="${UPDATE_CACHE_DIR}/update-status"
UPDATE_CACHE_SECONDS=14400
UPDATE_CHECK_PID=''
UPDATE_STATUS='unknown'
UPDATE_REMOTE_COMMIT=''
WRITE_UPDATE_CACHE() {
local status="$1"
local branch="$2"
local local_commit="$3"
local remote_commit="$4"
local cache_temp
mkdir -p "$UPDATE_CACHE_DIR" || return 1
cache_temp="$(mktemp "${UPDATE_CACHE_DIR}/.update-status.XXXXXX")" || return 1
printf '%s|%s|%s|%s|%s\n' \
"$(date +%s)" "$branch" "$local_commit" "$remote_commit" "$status" \
>"$cache_temp"
chmod 0644 "$cache_temp"
mv -f "$cache_temp" "$UPDATE_CACHE_FILE"
}
UPDATE_CHECK_WORKER() {
local branch
local local_commit
local remote_commit
local status
branch="$(git -C "$FOLDER" branch --show-current 2>/dev/null)"
local_commit="$(git -C "$FOLDER" rev-parse HEAD 2>/dev/null)"
if [[ -z "$branch" || -z "$local_commit" ]]; then
WRITE_UPDATE_CACHE "unavailable" "$branch" "$local_commit" ""
return
fi
remote_commit="$(git -C "$FOLDER" ls-remote origin "refs/heads/${branch}" 2>/dev/null | cut -f1)"
if [[ -z "$remote_commit" ]]; then
status="unavailable"
elif [[ "$local_commit" == "$remote_commit" ]]; then
status="current"
else
status="available"
fi
WRITE_UPDATE_CACHE "$status" "$branch" "$local_commit" "$remote_commit"
}
START_UPDATE_CHECK() {
if [[ -n "$UPDATE_CHECK_PID" ]] &&
kill -0 "$UPDATE_CHECK_PID" 2>/dev/null; then
return
fi
UPDATE_CHECK_WORKER >/dev/null 2>&1 &
UPDATE_CHECK_PID="$!"
}
LOAD_UPDATE_STATUS() {
local checked_at
local cached_branch
local cached_local
local cached_remote
local cached_status
local current_branch
local current_commit
local now
UPDATE_STATUS='unknown'
UPDATE_REMOTE_COMMIT=''
current_branch="$(git -C "$FOLDER" branch --show-current 2>/dev/null)"
current_commit="$(git -C "$FOLDER" rev-parse HEAD 2>/dev/null)"
now="$(date +%s)"
if [[ -r "$UPDATE_CACHE_FILE" ]]; then
IFS='|' read -r checked_at cached_branch cached_local cached_remote cached_status \
<"$UPDATE_CACHE_FILE"
if [[ "$checked_at" =~ ^[0-9]+$ ]] &&
(( now - checked_at < UPDATE_CACHE_SECONDS )) &&
[[ "$cached_branch" == "$current_branch" ]] &&
[[ "$cached_local" == "$current_commit" ]] &&
[[ "$cached_status" =~ ^(current|available|unavailable)$ ]]; then
UPDATE_STATUS="$cached_status"
UPDATE_REMOTE_COMMIT="$cached_remote"
return
fi
fi
UPDATE_STATUS='checking'
START_UPDATE_CHECK
}
FORCE_UPDATE_CHECK() {
local attempts=0
rm -f "$UPDATE_CACHE_FILE"
UPDATE_CHECK_PID=''
START_UPDATE_CHECK
echo -en "${idsCL[LightCyan]}Checking current branch for updates"
while (( attempts < 20 )); do
sleep 0.5
LOAD_UPDATE_STATUS
[[ "$UPDATE_STATUS" != "checking" ]] && break
echo -n "."
((attempts++))
done
echo -e "${idsCL[Default]}"
case "$UPDATE_STATUS" in
available)
echo -e "${idsCL[LightYellow]}An update is available for the current branch.${idsCL[Default]}"
;;
current)
echo -e "${idsCL[Green]}TA-ProxMenu is current.${idsCL[Default]}"
;;
*)
echo -e "${idsCL[Red]}The update status could not be determined.${idsCL[Default]}"
;;
esac
ENTER2CONTINUE
}
MENU_HEADER() {
local version_display
LOAD_UPDATE_STATUS
case "$UPDATE_STATUS" in
available)
version_display="${idsCL[LightYellow]}${VERS} ** UPDATE AVAILABLE **${idsCL[Default]}"
;;
checking)
version_display="${idsCL[LightCyan]}${VERS} (checking for updates)${idsCL[Default]}"
;;
*)
version_display="${idsCL[White]}${VERS}${idsCL[Default]}"
;;
esac
clear
echo
echo -e " ${idsCL[Green]}TA-ProxMenu - Proxmox Setup Scripts${idsCL[Default]} ${VERS}"
echo -e " ${idsCL[Green]}TA-ProxMenu - Proxmox Setup Scripts${idsCL[Default]} ${version_display}"
echo -e "${idsCL[Green]}---------------------------------------------------------------------------${idsCL[Default]}"
echo -e " Hostname: ${idsCL[Cyan]}$(hostname -s)${idsCL[Default]}"
echo -e " IP Address: ${idsCL[Cyan]}${RNIP:-Unavailable}${idsCL[Default]}"
@@ -340,7 +543,12 @@ SELECT_MENU() {
echo " ↑/↓ Navigate Enter Select Number Quick Select Q Quit"
fi
IFS= read -rsn1 key
key=""
if [[ "$UPDATE_STATUS" == "checking" ]]; then
IFS= read -rsn1 -t 1 key || continue
else
IFS= read -rsn1 key
fi
case "$key" in
"")
MENU_SELECTION="${values_ref[$selected]}"
@@ -494,7 +702,7 @@ MONITORING_MENU() {
CLUSTER_MENU() {
local -a labels
local -a values=("maintenance" "restart" "keepalived")
local -a values=("maintenance" "services" "keepalived")
while true; do
if ha-manager status | grep -F "$(hostname -s)" | grep -q "maintenance mode"; then
@@ -503,7 +711,7 @@ CLUSTER_MENU() {
labels=("Put this host into maintenance mode and evacuate guests")
fi
labels+=("Restart local Proxmox services")
labels+=("Proxmox service recovery")
dpkg-query -W -f='${Status}' keepalived 2>/dev/null | grep -q "install ok installed" &&
labels+=("Deploy/reconfigure Keepalived (installed locally)") ||
labels+=("Deploy Keepalived on all cluster hosts")
@@ -511,7 +719,7 @@ CLUSTER_MENU() {
SELECT_MENU "Cluster & Maintenance" labels values
case "$MENU_SELECTION" in
maintenance) MAINTENANCE_MODE;;
restart) RESTART_PVE_SERVICES;;
services) SERVICE_RECOVERY_MENU;;
keepalived) INSTALL_KEEPALIVE;;
back) return;;
quit) EXIT1; exit 0;;
@@ -519,17 +727,81 @@ CLUSTER_MENU() {
done
}
UTILITIES_MENU() {
local -a labels=("Check for script updates" "Version and installation information")
local -a values=("update" "about")
SERVICE_RECOVERY_MENU() {
local -a labels=(
"Restart Web UI and API (pveproxy, pvedaemon)"
"Restart statistics collection (pvestatd)"
"Restart task scheduler (pvescheduler)"
"Restart core management services"
"Restart cluster filesystem (pve-cluster)"
)
local -a values=("web" "statistics" "scheduler" "core" "clusterfs")
while true; do
SELECT_MENU "Proxmox Service Recovery" labels values
case "$MENU_SELECTION" in
web)
RESTART_SERVICE_GROUP "Web UI and API services" pveproxy pvedaemon
;;
statistics)
RESTART_SERVICE_GROUP "statistics collection" pvestatd
;;
scheduler)
RESTART_SERVICE_GROUP "task scheduler" pvescheduler
;;
core)
RESTART_PVE_SERVICES
;;
clusterfs)
RESTART_CLUSTER_FILESYSTEM
;;
back) return;;
quit) EXIT1; exit 0;;
esac
done
}
UTILITIES_MENU() {
local -a labels
local -a values=("install_update" "check_update" "about")
local choice
while true; do
LOAD_UPDATE_STATUS
case "$UPDATE_STATUS" in
available)
labels=("Install available update")
;;
current)
labels=("TA-ProxMenu is current")
;;
checking)
labels=("Update check in progress")
;;
*)
labels=("Update status unavailable")
;;
esac
labels+=("Check again now" "Version and installation information")
SELECT_MENU "Utilities" labels values
case "$MENU_SELECTION" in
update)
/opt/idssys/ta-proxmenu/run.sh update
read -r -p " Press ENTER to return..." _
install_update)
if [[ "$UPDATE_STATUS" != "available" ]]; then
echo -e "\n${idsCL[LightCyan]}No available update is currently detected.${idsCL[Default]}"
ENTER2CONTINUE
continue
fi
echo -en "\n${idsCL[LightCyan]}Install the update for the current branch (y/N)?${idsCL[Default]} "
read -n 1 choice
echo
if [[ "$choice" =~ ^[Yy]$ ]] &&
/opt/idssys/ta-proxmenu/run.sh update; then
exec /opt/idssys/ta-proxmenu/run.sh
fi
ENTER2CONTINUE
;;
check_update) FORCE_UPDATE_CHECK;;
about) SHOW_ABOUT;;
back) return;;
quit) EXIT1; exit 0;;