2025-02-24 23:44:47 +01:00
#!/bin/bash
# ==========================================================
2026-05-09 18:59:59 +02:00
# ProxMenux - Post-Install Menu Dispatcher
2025-02-24 23:44:47 +01:00
# ==========================================================
# Author : MacRimi
# Copyright : (c) 2024 MacRimi
2026-05-09 18:59:59 +02:00
# License : GPL-3.0
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
2025-07-06 13:49:52 +02:00
# Version : 1.2
2026-05-09 18:59:59 +02:00
# ==========================================================
# Description:
# Dispatcher for the post-installation options: Automated
# (zero-prompt baseline), Customizable (checklist per category)
# and Uninstall Optimizations (reverse any previously applied
# change). Also exposes two community post-install scripts
# (Proxmox VE Post Install and Microcode) via wget | bash.
2025-02-24 23:44:47 +01:00
# ==========================================================
2025-11-03 01:09:12 +00:00
LOCAL_SCRIPTS = "/usr/local/share/proxmenux/scripts"
2025-02-24 23:44:47 +01:00
BASE_DIR = "/usr/local/share/proxmenux"
UTILS_FILE = " $BASE_DIR /utils.sh "
VENV_PATH = "/opt/googletrans-env"
if [ [ -f " $UTILS_FILE " ] ] ; then
source " $UTILS_FILE "
fi
2025-05-28 23:26:58 +02:00
2025-02-24 23:44:47 +01:00
load_language
initialize_cache
2025-05-28 23:26:58 +02:00
# ==========================================================
2025-05-07 18:51:17 +02:00
confirm_and_run( ) {
local name = " $1 "
local command = " $2 "
2025-07-06 13:49:52 +02:00
2025-05-28 23:26:58 +02:00
dialog --clear --title " $( translate "Confirmation" ) " \
--yesno " \n\n $( translate "Do you want to run the post-installation script from" ) $name ? " 10 70
2025-07-06 13:49:52 +02:00
2025-05-28 23:26:58 +02:00
response = $?
clear
2025-07-06 13:49:52 +02:00
2025-05-28 23:26:58 +02:00
if [ $response -eq 0 ] ; then
2025-05-07 18:51:17 +02:00
eval " $command "
2025-05-28 23:26:58 +02:00
echo
2025-05-07 18:51:17 +02:00
msg_success " $( translate 'Press ENTER to continue...' ) "
read -r _
else
msg_warn " $( translate "Cancelled by user." ) "
sleep 1
fi
}
2025-07-06 13:49:52 +02:00
# ==========================================================
confirm_automated_script( ) {
local script_info = ""
2025-07-09 14:55:05 +02:00
script_info += " $( translate "This script will apply the following optimizations and advanced adjustments to your Proxmox VE server" ) :\n\n "
script_info += " • $( translate "Configure" ) \Z4free repositories\Z0 $( translate "and upgrade the system (disables the enterprise repo)" ) \n "
script_info += " • $( translate "Optionally remove" ) \Z4subscription banner\Z0 $( translate "from Proxmox web interface (you will be asked)" ) \n "
script_info += " • $( translate "Optimize" ) \Z4memory\Z0, \Z4kernel\Z0, $( translate "and" ) \Z4network\Z0 $( translate "for better performance and stability" ) \n "
script_info += " • $( translate "Install and configure" ) \Z4Log2RAM\Z0 $( translate "(only on SSD/NVMe) to protect your disk" ) \n "
2026-05-14 06:45:59 +02:00
script_info += " • $( translate "Enable" ) \Z4ZFS autotrim\Z0 $( translate "on SSD/NVMe pools that support discard" ) \n "
2025-07-09 14:55:05 +02:00
script_info += " • $( translate "Improve log rotation and limit log size to save space and extend disk life" ) \n "
script_info += " • $( translate "Increase file and process limits for advanced workloads" ) \n "
script_info += " • $( translate "Set up time synchronization and entropy generation" ) \n "
script_info += " • $( translate "Add color prompts and useful aliases to the terminal environment" ) \n\n "
script_info += " \Zb $( translate "All changes are reversible using the ProxMenux uninstaller." ) \Z0\n\n "
script_info += " $( translate "Do you want to apply these optimizations now?" ) "
2025-07-06 13:49:52 +02:00
dialog --clear --colors \
--backtitle "ProxMenux" \
2025-07-09 14:55:05 +02:00
--title " $( translate "Automated Post-Install Script" ) " \
--yesno " $script_info " 22 80
local response = $?
2025-07-06 13:49:52 +02:00
clear
2025-07-09 14:55:05 +02:00
2025-07-06 13:49:52 +02:00
if [ $response -eq 0 ] ; then
2025-11-03 01:09:12 +00:00
bash " $LOCAL_SCRIPTS /post_install/auto_post_install.sh "
2025-07-06 13:49:52 +02:00
else
msg_warn " $( translate "Cancelled by user." ) "
sleep 1
fi
}
# ==========================================================
declare -a PROXMENUX_SCRIPTS = (
2025-07-09 14:55:05 +02:00
"Automated post-installation script|ProxMenux|confirm_automated_script"
2026-04-03 10:44:10 +02:00
" Customizable post-installation script|ProxMenux|bash \" $LOCAL_SCRIPTS /post_install/customizable_post_install.sh\" "
2025-11-03 01:09:12 +00:00
" Uninstall optimizations|ProxMenux|bash \" $LOCAL_SCRIPTS /post_install/uninstall-tools.sh\" "
2025-05-28 23:26:58 +02:00
)
2025-05-07 18:51:17 +02:00
2026-05-09 18:59:59 +02:00
# ==========================================================
# Sprint 12C: post-install function update detection.
#
# The Monitor's startup hook writes updates_available.json. We read it
# here so the bash menu can show a conditional "Apply available updates"
# entry above Uninstall when bumped versions are detected on disk vs the
# user's installed_tools.json.
# ==========================================================
UPDATES_FILE = "/usr/local/share/proxmenux/updates_available.json"
UPDATE_WRAPPER = " $LOCAL_SCRIPTS /post_install/update_post_install_function.sh "
count_post_install_updates( ) {
[ [ ! -f " $UPDATES_FILE " ] ] && { echo 0; return ; }
command -v jq >/dev/null 2>& 1 || { echo 0; return ; }
jq '.updates | length' " $UPDATES_FILE " 2>/dev/null || echo 0
}
# Build a dialog checklist with the available updates and run the
# wrapper script for whichever the user picks. Entries flagged
# `source_certain=false` (legacy bool entries) are listed but not
# pre-checked; they need a source pick first via the Monitor or a
# fresh re-run of the customizable post-install.
run_updates_dialog( ) {
if ! command -v jq >/dev/null 2>& 1; then
msg_error " $( translate "jq is required to apply updates from this menu." ) "
sleep 2
return
fi
if [ [ ! -f " $UPDATES_FILE " ] ] ; then
msg_warn " $( translate "No updates available — run a scan first or wait for the Monitor to refresh." ) "
sleep 2
return
fi
local count
count = $( count_post_install_updates)
if [ [ " $count " -eq 0 ] ] ; then
msg_ok " $( translate "All ProxMenux optimizations are up to date." ) "
sleep 2
return
fi
# Build the dialog --checklist arguments. Format per row:
# <tag> <description> <on|off>
# We use the tool key as the tag so the selection callback can map
# back to source/function via jq.
local checklist = ( )
while IFS = $'\t' read -r key current available; do
# Sprint 12C v2: every row is checked by default. Legacy bool
# entries default to the auto flow on the wrapper side so the
# user no longer needs to do a "source pick" first.
local label = " ${ key } (v ${ current } → v ${ available } ) "
checklist += ( " $key " " $label " "on" )
done < <( jq -r '.updates[] | [.key, .current_version, .available_version] | @tsv' " $UPDATES_FILE " 2>/dev/null)
if [ [ ${# checklist [@] } -eq 0 ] ] ; then
msg_warn " $( translate "Updates file is empty or unreadable." ) "
sleep 2
return
fi
local selected
selected = $( dialog --clear --colors --separate-output \
--backtitle "ProxMenux" \
--title " $( translate "Apply Available Updates" ) " \
--checklist " \n $( translate "Select the optimizations to update. Each one re-runs its post-install function and registers the new version." ) :\n " \
22 78 12 \
" ${ checklist [@] } " 3>& 1 1>& 2 2>& 3)
local rc = $?
clear
[ [ $rc -ne 0 ] ] && return # cancelled
[ [ -z " $selected " ] ] && return
# Build FUNCTIONS_BATCH (newline-separated source:function:key) by
# looking up each picked key in the JSON. The detector already
# populates `.source` (defaulting to "auto" for legacy bool entries
# that didn't record one) and `.function`, so this is a straight
# passthrough. Sprint 12C v2 dropped the source-pick gate.
local batch = ""
while IFS = read -r key; do
[ [ -z " $key " ] ] && continue
local entry
entry = $( jq -r --arg k " $key " '
.updates[ ] | select ( .key = = $k ) |
select ( .function != "" ) |
"\((.source // " auto")):\(.function):\(.key)"
' " $UPDATES_FILE " )
[ [ -n " $entry " ] ] && batch += " ${ entry } " $'\n'
done <<< " $selected "
if [ [ -z " $batch " ] ] ; then
msg_warn " $( translate "Nothing to apply — none of the selected updates have a runnable function on disk." ) "
sleep 3
return
fi
# Hand off to the same wrapper the Monitor uses. Running it directly
# (not through a dialog menu) so the user sees the post-install
# function output verbatim.
EXECUTION_MODE = "cli" FUNCTIONS_BATCH = " $batch " bash " $UPDATE_WRAPPER "
# Sprint 12C v2: force the Monitor to rewrite updates_available.json
# so the next loop iteration of show_menu sees the post-update state
# and the "Apply available updates (N)" entry hides/decrements
# correctly. The endpoint is exposed on localhost without auth (POST
# is idempotent — just re-runs the parser), so a plain curl works
# whether HTTPS is on or off. Falls back to direct file write via
# the Python module if the service isn't reachable (host where the
# Monitor isn't running yet).
local scheme = "http"
[ [ -f /etc/proxmenux/ssl_config.json ] ] && \
jq -e '.enabled' /etc/proxmenux/ssl_config.json >/dev/null 2>& 1 && \
scheme = "https"
if ! curl -k -s --max-time 5 -X POST " ${ scheme } ://127.0.0.1:8008/api/updates/post-install/scan " >/dev/null 2>& 1; then
# Fallback: regenerate the JSON via the module directly. We
# can't import it from system Python because dependencies live
# inside the AppImage, so just rewrite the file by re-running
# the detector logic in-process via jq + the on-disk scripts.
# Simpler: leave the file stale — the next AppImage restart will
# rewrite it. The Monitor's _ensure_fresh_cache also auto-
# refreshes when installed_tools.json changes, so the API view
# is correct even if the bash menu sees a one-cycle-stale list.
:
fi
msg_success " $( translate 'Press ENTER to continue...' ) "
read -r _
}
2025-07-06 13:49:52 +02:00
declare -a COMMUNITY_SCRIPTS = (
2025-05-07 18:51:17 +02:00
"Proxmox VE Post Install|Helper-Scripts|bash -c \"\$(wget -qLO - https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/post-pve-install.sh); msg_success \\\"\$(translate 'Press ENTER to continue...')\\\"; read -r _\""
2026-04-03 10:44:10 +02:00
"Proxmox VE Microcode|Helper-Scripts|bash -c \"\$(wget -qLO - https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/microcode.sh); msg_success \\\"\$(translate 'Press ENTER to continue...')\\\"; read -r _\""
2025-02-24 23:44:47 +01:00
)
2025-07-06 13:49:52 +02:00
# ==========================================================
format_menu_item( ) {
local description = " $1 "
local source = " $2 "
local total_width = 62
local desc_length = ${# description }
local source_length = ${# source }
local spaces_needed = $(( total_width - desc_length - source_length))
[ $spaces_needed -lt 3 ] && spaces_needed = 3
local spacing = ""
for ( ( i = 0; i<spaces_needed; i++) ) ; do
spacing += " "
done
echo " ${ description } ${ spacing } ${ source } "
}
# ==========================================================
2025-02-24 23:44:47 +01:00
show_menu( ) {
while true; do
2025-07-06 13:49:52 +02:00
local menu_items = ( )
2026-05-09 18:59:59 +02:00
2025-05-28 23:26:58 +02:00
2025-07-06 13:49:52 +02:00
declare -A script_commands
local counter = 1
2026-05-09 18:59:59 +02:00
# Sprint 12C: re-evaluate available updates on every loop so the
# entry vanishes after the user has applied everything (and the
# Monitor has rewritten updates_available.json on its next scan).
local update_count
update_count = $( count_post_install_updates)
2025-07-06 13:49:52 +02:00
for script in " ${ PROXMENUX_SCRIPTS [@] } " ; do
IFS = '|' read -r name source command <<< " $script "
2026-05-09 18:59:59 +02:00
# Insert the conditional "Apply available updates" item right
# above "Uninstall optimizations" so it sits next to the
# related rollback action and not buried in the middle.
if [ [ " $name " = = "Uninstall optimizations" && " $update_count " -gt 0 ] ] ; then
local update_label
update_label = " Apply available updates ( $update_count ) "
local translated_update
translated_update = " $( translate " $update_label " ) "
local formatted_update
formatted_update = $( format_menu_item " $translated_update " "ProxMenux" )
menu_items += ( " $counter " " $formatted_update " )
script_commands[ " $counter " ] = "run_updates_dialog"
( ( counter++) )
fi
2025-07-06 13:49:52 +02:00
local translated_name = " $( translate " $name " ) "
local formatted_item
formatted_item = $( format_menu_item " $translated_name " " $source " )
menu_items += ( " $counter " " $formatted_item " )
script_commands[ " $counter " ] = " $command "
( ( counter++) )
done
2025-02-24 23:44:47 +01:00
2025-07-06 13:49:52 +02:00
menu_items += ( "" "" )
2026-04-04 00:54:57 +02:00
menu_items += ( "-" "───────────────────── Community Scripts ──────────────────────" )
2025-07-06 13:49:52 +02:00
menu_items += ( "" "" )
2025-05-28 23:26:58 +02:00
2025-07-06 13:49:52 +02:00
for script in " ${ COMMUNITY_SCRIPTS [@] } " ; do
IFS = '|' read -r name source command <<< " $script "
local translated_name = " $( translate " $name " ) "
local formatted_item
formatted_item = $( format_menu_item " $translated_name " " $source " )
menu_items += ( " $counter " " $formatted_item " )
script_commands[ " $counter " ] = " $command "
( ( counter++) )
2025-02-24 23:44:47 +01:00
done
2025-07-06 13:49:52 +02:00
2025-02-24 23:44:47 +01:00
2025-07-06 13:49:52 +02:00
menu_items += ( "" "" )
menu_items += ( "0" " $( translate "Return to Main Menu" ) " )
2025-02-25 17:44:17 +01:00
2025-05-28 23:26:58 +02:00
exec 3>& 1
2025-07-06 13:49:52 +02:00
script_selection = $( dialog --clear \
--backtitle "ProxMenux" \
--title " $( translate "Post-Installation Scripts" ) " \
--menu " \n $( translate "Select a post-installation script:" ) :\n " \
22 78 15 \
" ${ menu_items [@] } " 2>& 1 1>& 3)
2025-05-28 23:26:58 +02:00
exit_status = $?
exec 3>& -
2025-05-28 23:33:59 +02:00
2025-05-28 23:26:58 +02:00
2025-07-06 13:49:52 +02:00
if [ $exit_status -ne 0 ] || [ " $script_selection " = "0" ] ; then
2025-11-03 01:09:12 +00:00
exec bash " $LOCAL_SCRIPTS /menus/main_menu.sh "
2025-05-28 23:26:58 +02:00
fi
2025-07-06 13:49:52 +02:00
2025-05-28 23:26:58 +02:00
2025-07-06 13:49:52 +02:00
if [ [ " $script_selection " = = "-" || " $script_selection " = = "" ] ] ; then
continue
2025-02-24 23:44:47 +01:00
fi
2025-07-06 13:49:52 +02:00
2025-05-28 23:26:58 +02:00
2025-07-06 13:49:52 +02:00
if [ [ -n " ${ script_commands [ $script_selection ] } " ] ] ; then
eval " ${ script_commands [ $script_selection ] } "
else
msg_error " $( translate "Invalid selection" ) "
sleep 1
2025-05-28 23:26:58 +02:00
fi
2025-02-24 23:44:47 +01:00
done
}
2025-07-06 13:49:52 +02:00
# ==========================================================
2025-02-25 18:17:24 +01:00
2025-07-09 14:55:05 +02:00
show_menu