diff --git a/README.md b/README.md index e5dd876..5c7b259 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,15 @@ rmm Install the ConnectWise RMM agent omsa Install Dell OpenManage Server Administrator glances Install Glances acronis Install the Acronis agent +post-install Run the ProxMenux post-install configuration proxmenux Install or open ProxMenux +virtio Download current VirtIO drivers +sentinelone Install the SentinelOne agent screenconnect Install the ScreenConnect agent restart Restart local Proxmox services cpu Detect and optionally apply a migration-safe CPU model -mm Toggle local HA maintenance mode -timeout Set VM shutdown timeouts +maintenance Toggle local HA maintenance mode +keepalived Deploy Keepalived across the cluster ``` ## Companion files diff --git a/defaults.inc b/defaults.inc index e08a5c3..037aaa2 100755 --- a/defaults.inc +++ b/defaults.inc @@ -3,7 +3,7 @@ action="${1:-}" FOLDER='/opt/idssys/ta-proxmenu' -VERS='2026.7.25-14' +VERS='2026.7.25-15' noupdate=' ' diff --git a/proxmenu-scripts.sh b/proxmenu-scripts.sh index 52121bb..7ca5c3a 100755 --- a/proxmenu-scripts.sh +++ b/proxmenu-scripts.sh @@ -25,7 +25,7 @@ INSTALL_PULSE() { INSTALL_ACRONIS() { read -n 1 -p "Are you sure you wish to install Acronis (Y/n)?" choice case "$choice" in - [Nn]) MAIN_MENU;; + [Nn]) echo;; * ) echo cd /tmp || return 1 @@ -255,23 +255,6 @@ RESTART_PVE_SERVICES(){ esac } -SET_VM_SHUTDOWNTIMEOUT(){ - if [ "${1}" == "" ]; then - echo -en "${idsCL[LightCyan]}Would you like to set all VM's shutdown timeout to 180secs (Y/n)?${idsCL[Default]} " - read -n 1 choice - else - choice=${1} - fi - case "${choice}" in - [Nn]) echo;; - *) - echo "Updating all VM's shutdown timeout to 180 seconds..." - sed -E -i 's/(down=)[0-9]+/\1180/g' /etc/pve/nodes/*/qemu-server/*.conf - FINISH_ACTION - ;; - esac -} - MAINTENANCE_MODE(){ local local_node local_node="$(hostname -s)" @@ -314,108 +297,264 @@ INSTALL_KEEPALIVE() { -MAIN_MENU() { - echo -en "${idsCL[LightCyan]}Pulling host info ... " - CRES=$(pvesh get /cluster/resources) - DPL=$(dpkg -l) - echo -e "${idsCL[Green]}Done${idsCL[Default]}" - - while : - do - clear +MENU_HEADER() { + clear + echo + echo -e " ${idsCL[Green]}TA-ProxMenu - Proxmox Setup Scripts${idsCL[Default]} ${VERS}" + 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]}" + echo -e "${idsCL[Green]}---------------------------------------------------------------------------${idsCL[Default]}" +} + +SELECT_MENU() { + local title="$1" + local labels_name="$2" + local values_name="$3" + local allow_back="${4:-1}" + local -n labels_ref="$labels_name" + local -n values_ref="$values_name" + local selected=0 + local key + local sequence + local index + + while true; do + MENU_HEADER echo - echo -e " ${idsCL[Green]}TA-Proxmenu - Proxmox Setup Scripts${idsCL[Default]} ${idsCL[Default]}${VERS}" - echo -e "${idsCL[Green]}---------------------------------------------------------------------------${idsCL[Default]}" - echo -e " Hostname: ${idsCL[Cyan]}$(hostname -s)${idsCL[Default]}" - echo -e " IP Address: ${idsCL[Cyan]}${RNIP}${idsCL[Default]}" - echo -e "${idsCL[Green]}---------------------------------------------------------------------------${idsCL[Default]}" + echo -e " ${idsCL[LightCyan]}${title}${idsCL[Default]}" echo - - echo -en "${idsCL[White]} [${idsCL[LightYellow]}0${idsCL[Default]}] ${idsCL[White]}Run Post-Install Script${idsCL[Default]}" - [ -f /opt/.PROXMENUX_POST_INSTALL ] && echo -e "${idsCL[Cyan]} - Has been run previously${idsCL[Default]}" || echo - echo -e "${idsCL[White]} [${idsCL[LightYellow]}1${idsCL[Default]}] ${idsCL[White]}Detect CPU-Arch for Live Migrations${idsCL[Default]}" - if ! grep -qi pulse <<< "$CRES"; then - echo -e "${idsCL[White]} [${idsCL[LightYellow]}2${idsCL[Default]}] ${idsCL[White]}Install Pulse Monitoring${idsCL[Default]}" - else - echo -e "${idsCL[DarkGray]} [2] Pulse Monitoring is already installed${idsCL[Default]}" - fi - if [ -f "${DLDIR}/${VIRTIO_FILE}" ]; then - echo -e "${idsCL[DarkGray]} [3] Current VirtIO drivers already downloaded to 'local' on this host${idsCL[Default]}" - elif compgen -G "${DLDIR}/virtio*.iso" > /dev/null; then - echo -e "${idsCL[White]} [${idsCL[LightYellow]}3${idsCL[Default]}] ${idsCL[LightGreen]}**${idsCL[White]}Download the available updated Win-VirtIO drivers to 'local' on this host${idsCL[Default]}" - else - echo -e "${idsCL[White]} [${idsCL[LightYellow]}3${idsCL[Default]}] ${idsCL[White]}Download the current Win-VirtIO drivers to 'local' on this host${idsCL[Default]}" - fi - if ! command -v glances &> /dev/null; then - echo -e "${idsCL[White]} [${idsCL[LightYellow]}4${idsCL[Default]}] ${idsCL[White]}Install Glances (CLI Monitor)${idsCL[Default]}" - else - echo -e "${idsCL[DarkGray]} [4] Glances is already installed${idsCL[Default]}" - fi - if ! grep -q 'srvadmin-all' <<< "$DPL"; then - echo -e "${idsCL[White]} [${idsCL[LightYellow]}5${idsCL[Default]}] ${idsCL[White]}Install Dell OpenManage Server Administrator${idsCL[Default]}" - else - echo -e "${idsCL[DarkGray]} [5] Dell OMSA is already installed - ${idsCL[Cyan]}https://${RNIP}:1311" - fi + + for index in "${!labels_ref[@]}"; do + if (( index == selected )); then + printf '\e[7m %d %-64s\e[0m\n' "$((index + 1))" "${labels_ref[$index]}" + else + printf ' %d %s\n' "$((index + 1))" "${labels_ref[$index]}" + fi + done + echo - if [ "$(systemctl is-active ITSPlatform)" != "active" ]; then - echo -e "${idsCL[White]} [${idsCL[LightYellow]}6${idsCL[Default]}] ${idsCL[White]}Install ConnectWise RMM Agent${idsCL[Default]}" + if (( allow_back == 1 )); then + echo " ↑/↓ Navigate Enter Select Number Quick Select ←/Esc/B Back Q Quit" else - echo -e "${idsCL[DarkGray]} [6] ConnectWise RMM Agent is already installed${idsCL[Default]}" - fi - if ! grep -q 'cyberprotect' <<< "$DPL"; then - echo -e "${idsCL[White]} [${idsCL[LightYellow]}7${idsCL[Default]}] ${idsCL[White]}Install Acronis Backup Agent${idsCL[Default]}" - else - echo -e "${idsCL[DarkGray]} [7] Acronis Backup is already installed${idsCL[Default]}" + echo " ↑/↓ Navigate Enter Select Number Quick Select Q Quit" fi - if ! grep -q 'sentinelagent' <<< "$DPL"; then - echo -e "${idsCL[White]} [${idsCL[LightYellow]}8${idsCL[Default]}] ${idsCL[White]}Install SentinelOne Agent (v${S1_VERSION//_/.})${idsCL[Default]}" + + IFS= read -rsn1 key + case "$key" in + "") + MENU_SELECTION="${values_ref[$selected]}" + return 0 + ;; + [1-9]) + index=$((10#$key - 1)) + if (( index < ${#values_ref[@]} )); then + MENU_SELECTION="${values_ref[$index]}" + return 0 + fi + ;; + [Qq]) + MENU_SELECTION="quit" + return 0 + ;; + [Bb]) + if (( allow_back == 1 )); then + MENU_SELECTION="back" + return 0 + fi + ;; + $'\e') + sequence="" + IFS= read -rsn2 -t 0.1 sequence || true + case "$sequence" in + "[A"|"OA") + (( selected = (selected - 1 + ${#labels_ref[@]}) % ${#labels_ref[@]} )) + ;; + "[B"|"OB") + (( selected = (selected + 1) % ${#labels_ref[@]} )) + ;; + "[C"|"OC") + MENU_SELECTION="${values_ref[$selected]}" + return 0 + ;; + "[D"|"OD"|"") + if (( allow_back == 1 )); then + MENU_SELECTION="back" + return 0 + fi + ;; + "[H") + selected=0 + ;; + "[F") + selected=$((${#labels_ref[@]} - 1)) + ;; + esac + ;; + esac + done +} + +SHOW_ABOUT() { + MENU_HEADER + echo + echo -e " ${idsCL[LightCyan]}About TA-ProxMenu${idsCL[Default]}" + echo + echo " Version: ${VERS}" + echo " Install: /opt/idssys/ta-proxmenu" + echo " Branch: $(git -C /opt/idssys/ta-proxmenu branch --show-current 2>/dev/null || echo unknown)" + echo + read -r -p " Press ENTER to return..." _ +} + +HOST_SETUP_MENU() { + local -a labels + local -a values=( + "post_install" + "cpu" + "virtio" + "glances" + "omsa" + ) + + while true; do + labels=("Run ProxMenux post-install configuration") + [ -f /opt/.PROXMENUX_POST_INSTALL ] && + labels[0]="Run ProxMenux post-install configuration (previously run)" + labels+=("Detect CPU model for live migrations") + + if [ -f "${DLDIR}/${VIRTIO_FILE}" ]; then + labels+=("VirtIO drivers (${VIRTIO_FILE} already downloaded)") + elif compgen -G "${DLDIR}/virtio*.iso" >/dev/null; then + labels+=("Download updated VirtIO drivers") else - echo -e "${idsCL[DarkGray]} [8] SentinelOne is already installed${idsCL[Default]}" + labels+=("Download current VirtIO drivers") fi - echo - if [ "$(systemctl is-active connectwise*)" != "active" ]; then - echo -e "${idsCL[White]} [${idsCL[LightYellow]}S${idsCL[Default]}] ${idsCL[White]}Install ScreenConnect Agent${idsCL[Default]}" - else - echo -e "${idsCL[DarkGray]} [S] ScreenConnect is already installed${idsCL[Default]}" - fi - echo + + command -v glances >/dev/null 2>&1 && + labels+=("Glances CLI monitor (installed)") || + labels+=("Install Glances CLI monitor") + + dpkg-query -W -f='${Status}' srvadmin-all 2>/dev/null | grep -q "install ok installed" && + labels+=("Dell OpenManage Server Administrator (installed)") || + labels+=("Install Dell OpenManage Server Administrator") + + SELECT_MENU "Host Setup" labels values + case "$MENU_SELECTION" in + post_install) PROXMENUX_POST_INSTALL;; + cpu) DETECT_CPU;; + virtio) DOWNLOAD_VIRTIO;; + glances) INSTALL_GLANCES;; + omsa) INSTALL_OMSA;; + back) return;; + quit) EXIT1; exit 0;; + esac + done +} + +MONITORING_MENU() { + local -a labels + local -a values=("pulse" "rmm" "acronis" "sentinelone" "screenconnect") + local cluster_resources + + while true; do + cluster_resources="$(pvesh get /cluster/resources 2>/dev/null)" + grep -qi pulse <<< "$cluster_resources" && + labels=("Pulse monitoring (installed)") || + labels=("Install Pulse monitoring") + + systemctl is-active --quiet ITSPlatform && + labels+=("ConnectWise RMM agent (installed)") || + labels+=("Install ConnectWise RMM agent") + + dpkg-query -W -f='${Status}' cyberprotect 2>/dev/null | grep -q "install ok installed" && + labels+=("Acronis backup agent (installed)") || + labels+=("Install Acronis backup agent") + + dpkg-query -W -f='${Status}' sentinelagent 2>/dev/null | grep -q "install ok installed" && + labels+=("SentinelOne agent (installed)") || + labels+=("Install SentinelOne agent v${S1_VERSION//_/.}") + + systemctl is-active --quiet 'connectwise*' && + labels+=("ScreenConnect agent (installed)") || + labels+=("Install ScreenConnect agent") + + SELECT_MENU "Monitoring & Agents" labels values + case "$MENU_SELECTION" in + pulse) INSTALL_PULSE;; + rmm) INSTALL_RMM;; + acronis) INSTALL_ACRONIS;; + sentinelone) INSTALL_S1;; + screenconnect) INSTALL_SCREENCONNECT;; + back) return;; + quit) EXIT1; exit 0;; + esac + done +} + +CLUSTER_MENU() { + local -a labels + local -a values=("maintenance" "restart" "keepalived") + + while true; do if ha-manager status | grep -F "$(hostname -s)" | grep -q "maintenance mode"; then - echo -e "${idsCL[White]} [${idsCL[LightYellow]}M${idsCL[Default]}] ${idsCL[White]}Take Host out of Maintenance Mode${idsCL[Default]}" + labels=("Take this host out of maintenance mode") else - echo -e "${idsCL[White]} [${idsCL[LightYellow]}M${idsCL[Default]}] ${idsCL[White]}Put Host into Maintenance Mode${idsCL[Default]}" + labels=("Put this host into maintenance mode and evacuate guests") fi - echo -e "${idsCL[White]} [${idsCL[LightYellow]}R${idsCL[Default]}] ${idsCL[White]}Restart Proxmox Services${idsCL[Default]}" - echo - if ! grep -q 'keepalived' <<< "$DPL"; then - echo -e "${idsCL[White]} [${idsCL[LightYellow]}K${idsCL[Default]}] ${idsCL[White]}Install Keepalive on all Hosts${idsCL[Default]}" - else - echo -e "${idsCL[DarkGray]} [K] Keepalive is already installed${idsCL[Default]}" - fi - - echo - echo -e "${idsCL[White]} [${idsCL[LightYellow]}Q${idsCL[Default]}] ${idsCL[White]}Quit${idsCL[Default]}" - echo - echo - echo -e -n "${idsCL[Yellow]}Enter ${idsCL[LightYellow]}option${idsCL[Yellow]} from above:${idsCL[Default]} " - read -n 1 opt - echo - case $opt in - [0]) PROXMENUX_POST_INSTALL;; - [1]) DETECT_CPU;; - [2]) INSTALL_PULSE;; - [3]) DOWNLOAD_VIRTIO;; - [4]) INSTALL_GLANCES;; - [5]) INSTALL_OMSA;; - [6]) INSTALL_RMM;; - [7]) INSTALL_ACRONIS;; - [8]) INSTALL_S1;; - - [Ss]) INSTALL_SCREENCONNECT;; - [Mm]) MAINTENANCE_MODE;; - [Rr]) RESTART_PVE_SERVICES;; - [Kk]) INSTALL_KEEPALIVE;; - [Qq]) EXIT1; exit 0;; - *) echo -e "That's an invalid option.\nPlease select a valid option."; sleep 1;; + + labels+=("Restart local Proxmox services") + 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") + + SELECT_MENU "Cluster & Maintenance" labels values + case "$MENU_SELECTION" in + maintenance) MAINTENANCE_MODE;; + restart) RESTART_PVE_SERVICES;; + keepalived) INSTALL_KEEPALIVE;; + back) return;; + quit) EXIT1; exit 0;; + esac + done +} + +UTILITIES_MENU() { + local -a labels=("Check for script updates" "Version and installation information") + local -a values=("update" "about") + + while true; do + SELECT_MENU "Utilities" labels values + case "$MENU_SELECTION" in + update) + /opt/idssys/ta-proxmenu/run.sh update + read -r -p " Press ENTER to return..." _ + ;; + about) SHOW_ABOUT;; + back) return;; + quit) EXIT1; exit 0;; + esac + done +} + +MAIN_MENU() { + local -a labels=( + "Host Setup" + "Monitoring & Agents" + "Cluster & Maintenance" + "Utilities" + "Quit" + ) + local -a values=("host" "monitoring" "cluster" "utilities" "quit") + + while true; do + SELECT_MENU "Main Menu" labels values 0 + case "$MENU_SELECTION" in + host) HOST_SETUP_MENU;; + monitoring) MONITORING_MENU;; + cluster) CLUSTER_MENU;; + utilities) UTILITIES_MENU;; + quit) EXIT1; exit 0;; esac done } @@ -428,12 +567,15 @@ if (( ACTION_REQUESTED == 1 )); then omsa) INSTALL_OMSA;; glances) INSTALL_GLANCES;; acronis) INSTALL_ACRONIS;; + post-install|post_install) PROXMENUX_POST_INSTALL;; proxmenux) [ ! -f /usr/local/bin/menu ] && INSTALL_PROXMENUX || /usr/local/bin/menu;; + virtio) DOWNLOAD_VIRTIO;; + sentinelone|s1) INSTALL_S1;; screenconnect) INSTALL_SCREENCONNECT;; restart) RESTART_PVE_SERVICES "${2:-}";; cpu) DETECT_CPU;; - mm) MAINTENANCE_MODE;; - timeout) SET_VM_SHUTDOWNTIMEOUT "${2:-}";; + maintenance|mm) MAINTENANCE_MODE;; + keepalived) INSTALL_KEEPALIVE;; *) MAIN_MENU;; esac else