mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-01 10:22:08 +00:00
feat(post-install): add optional zram profile and metrics
This commit is contained in:
@@ -63,6 +63,9 @@ fi
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
if [[ -f "$LOCAL_SCRIPTS/post_install/zram_profile_helpers.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/post_install/zram_profile_helpers.sh"
|
||||
fi
|
||||
# ==========================================================
|
||||
|
||||
|
||||
@@ -2448,6 +2451,187 @@ EOF
|
||||
}
|
||||
|
||||
|
||||
configure_zram_swap() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Enable an opt-in ZRAM-only swap profile sized to one tenth of RAM.
|
||||
pmx_journal_context "configure_zram_swap" "$FUNC_VERSION"
|
||||
|
||||
local config=/etc/systemd/zram-generator.conf.d/90-proxmenux.conf
|
||||
local marker="$BASE_DIR/zram-swap.state"
|
||||
local package_added=false package_owned=false owned=false previous_active=false state_mutated=false
|
||||
local previous_config="" previous_marker="" desired="" conflicts="" systemd_conflicts="" version="" algorithm=""
|
||||
local supports_params=false failure="" old_umask swap_detection_status
|
||||
|
||||
if ! declare -f zram_render_generator_config >/dev/null ||
|
||||
! declare -f zram_has_non_zram_swap >/dev/null ||
|
||||
! declare -f zram_list_non_zram_swap >/dev/null ||
|
||||
! declare -f zram_list_defined_systemd_swap_units >/dev/null ||
|
||||
! declare -f zram_foreign_generator_config >/dev/null ||
|
||||
! declare -f zram_profile_verify_active >/dev/null; then
|
||||
msg_error "$(translate "ZRAM profile helpers are missing")"
|
||||
return 1
|
||||
fi
|
||||
if [[ ! -r /proc/swaps || ! -r /etc/fstab ]]; then
|
||||
msg_error "$(translate "Cannot inspect current swap configuration")"
|
||||
return 1
|
||||
fi
|
||||
if zram_has_non_zram_swap /proc/swaps /etc/fstab; then
|
||||
conflicts="$(zram_list_non_zram_swap /proc/swaps /etc/fstab)" || return 1
|
||||
else
|
||||
swap_detection_status=$?
|
||||
if [[ "$swap_detection_status" -ne 1 ]]; then
|
||||
msg_error "$(translate "Cannot inspect current swap configuration")"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
systemd_conflicts="$(zram_list_defined_systemd_swap_units)"
|
||||
if [[ -n "$systemd_conflicts" ]]; then
|
||||
[[ -n "$conflicts" ]] && conflicts+=$'\n'
|
||||
conflicts+="$systemd_conflicts"
|
||||
fi
|
||||
if [[ -n "$conflicts" ]]; then
|
||||
msg_error "$(translate "ZRAM-only profile requires removing these conflicting swap sources first:") $conflicts"
|
||||
return 1
|
||||
fi
|
||||
conflicts="$(zram_foreign_generator_config "$config")"
|
||||
if [[ -n "$conflicts" ]]; then
|
||||
msg_error "$(translate "Another ZRAM generator configuration exists; refusing to overwrite it:") $conflicts"
|
||||
return 1
|
||||
fi
|
||||
if [[ -e "$marker" ]]; then
|
||||
if [[ ! -f "$config" || -L "$config" || -L "$marker" ]] ||
|
||||
! grep -qx '# ProxMenux ZRAM profile' "$config" ||
|
||||
! grep -Eq '^installed_by_proxmenux=(true|false)$' "$marker"; then
|
||||
msg_error "$(translate "ZRAM ownership state is incomplete; inspect it before retrying")"
|
||||
return 1
|
||||
fi
|
||||
owned=true
|
||||
previous_config="$(cat "$config")"
|
||||
previous_marker="$(cat "$marker")"
|
||||
grep -qx 'installed_by_proxmenux=true' "$marker" && package_owned=true
|
||||
elif [[ -e "$config" || -L "$config" ]] || awk 'NR > 1 && $1 == "/dev/zram0" { found=1 } END { exit !found }' /proc/swaps; then
|
||||
msg_error "$(translate "Existing zram0 configuration or swap is not owned by ProxMenux")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if awk 'NR > 1 && $1 == "/dev/zram0" { found=1 } END { exit !found }' /proc/swaps; then
|
||||
previous_active=true
|
||||
fi
|
||||
if ! dpkg-query -W -f='${Status}' systemd-zram-generator 2>/dev/null | grep -q 'install ok installed'; then
|
||||
if ! pmx_install_pkg systemd-zram-generator; then
|
||||
if [[ "$owned" == false ]] &&
|
||||
dpkg-query -W -f='${Status}' systemd-zram-generator 2>/dev/null | grep -q 'install ok installed' &&
|
||||
[[ -z "$(zram_foreign_generator_config "$config")" ]]; then
|
||||
if DEBIAN_FRONTEND=noninteractive apt-get purge -y systemd-zram-generator >/dev/null 2>&1; then
|
||||
pmx_record_uninstall "systemd-zram-generator" "$FUNC_VERSION"
|
||||
fi
|
||||
fi
|
||||
msg_error "$(translate "Could not install systemd-zram-generator")"
|
||||
return 1
|
||||
fi
|
||||
package_added=true
|
||||
package_owned=true
|
||||
fi
|
||||
version="$(dpkg-query -W -f='${Version}' systemd-zram-generator 2>/dev/null)"
|
||||
if [[ -z "$version" ]]; then
|
||||
failure="Cannot determine installed systemd-zram-generator version"
|
||||
else
|
||||
if dpkg --compare-versions "$version" ge '1.2.0'; then
|
||||
supports_params=true
|
||||
fi
|
||||
desired="$(zram_render_generator_config "$supports_params")"
|
||||
algorithm=zstd
|
||||
fi
|
||||
if [[ -z "$failure" && "$owned" == true && "$previous_config" == "$desired" && "$previous_active" == true ]]; then
|
||||
if zram_profile_verify_active "$algorithm"; then
|
||||
register_tool "zram_swap" true "$FUNC_VERSION"
|
||||
msg_success "$(translate "ZRAM profile is already active")"
|
||||
return 0
|
||||
fi
|
||||
failure="Existing ZRAM profile is active but does not match its configuration"
|
||||
fi
|
||||
if [[ -z "$failure" && "$previous_active" == true ]]; then
|
||||
if ! swapoff /dev/zram0; then
|
||||
msg_error "$(translate "Could not release ZRAM pages; existing profile remains active")"
|
||||
return 1
|
||||
fi
|
||||
state_mutated=true
|
||||
if ! systemctl stop dev-zram0.swap >/dev/null 2>&1; then
|
||||
failure="Could not stop existing dev-zram0.swap"
|
||||
fi
|
||||
fi
|
||||
if [[ -z "$failure" ]]; then
|
||||
state_mutated=true
|
||||
if ! install -d -m 755 "$(dirname "$config")"; then
|
||||
failure="Could not create ZRAM generator directory"
|
||||
elif ! printf '%s\n' "$desired" | pmx_write_file "$config"; then
|
||||
failure="Could not write ZRAM generator configuration"
|
||||
fi
|
||||
fi
|
||||
if [[ -z "$failure" ]]; then
|
||||
old_umask="$(umask)"
|
||||
umask 077
|
||||
if ! printf 'installed_by_proxmenux=%s\n' "$package_owned" | pmx_write_file "$marker"; then
|
||||
failure="Could not write ZRAM package ownership state"
|
||||
fi
|
||||
umask "$old_umask"
|
||||
[[ -f "$marker" ]] && chmod 600 "$marker"
|
||||
fi
|
||||
if [[ -z "$failure" ]]; then
|
||||
if ! systemctl daemon-reload || ! systemctl start dev-zram0.swap; then
|
||||
failure="Could not activate dev-zram0.swap"
|
||||
elif ! zram_profile_verify_active "$algorithm"; then
|
||||
failure="Active ZRAM algorithm, capacity or swap sources did not match the profile"
|
||||
fi
|
||||
fi
|
||||
if [[ -z "$failure" ]]; then
|
||||
register_tool "zram_swap" true "$FUNC_VERSION"
|
||||
msg_success "$(translate "ZRAM-only swap profile enabled")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
msg_error "$(translate "ZRAM profile activation failed; details:") $failure"
|
||||
if [[ "$state_mutated" == true ]] && awk 'NR > 1 && $1 == "/dev/zram0" { found=1 } END { exit !found }' /proc/swaps; then
|
||||
if ! swapoff /dev/zram0; then
|
||||
# Keep the drop-in and marker so a later uninstall can retry safely.
|
||||
register_tool "zram_swap" true "$FUNC_VERSION"
|
||||
msg_error "$(translate "ZRAM still holds pages; configuration was preserved")"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
if [[ "$state_mutated" == true ]]; then
|
||||
systemctl stop dev-zram0.swap >/dev/null 2>&1 || true
|
||||
if [[ "$owned" == true ]]; then
|
||||
printf '%s\n' "$previous_config" | pmx_write_file "$config"
|
||||
printf '%s\n' "$previous_marker" | pmx_write_file "$marker"
|
||||
chmod 600 "$marker"
|
||||
else
|
||||
pmx_remove_file "$config"
|
||||
pmx_remove_file "$marker"
|
||||
fi
|
||||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||
[[ "$previous_active" == true ]] && systemctl start dev-zram0.swap >/dev/null 2>&1
|
||||
fi
|
||||
if [[ "$package_added" == true && "$owned" == false && ! -e "$config" && ! -e "$marker" && -z "$(zram_foreign_generator_config "$config")" ]]; then
|
||||
if DEBIAN_FRONTEND=noninteractive apt-get purge -y systemd-zram-generator >/dev/null 2>&1; then
|
||||
pmx_record_uninstall "systemd-zram-generator" "$FUNC_VERSION"
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
zram_profile_verify_active() {
|
||||
local expected_algorithm="$1" expected_bytes actual_bytes active_algorithm
|
||||
[[ -r /sys/block/zram0/disksize && -r /sys/block/zram0/comp_algorithm ]] || return 1
|
||||
expected_bytes="$(awk '/^MemTotal:/ { print int($2 * 1024 / 10) }' /proc/meminfo)"
|
||||
actual_bytes="$(cat /sys/block/zram0/disksize)"
|
||||
[[ "$expected_bytes" =~ ^[0-9]+$ && "$actual_bytes" =~ ^[0-9]+$ ]] || return 1
|
||||
(( actual_bytes >= expected_bytes - 1048576 && actual_bytes <= expected_bytes + 1048576 )) || return 1
|
||||
active_algorithm="$(grep -oE '\[[^]]+\]' /sys/block/zram0/comp_algorithm | tr -d '[]')"
|
||||
[[ "$active_algorithm" == "$expected_algorithm" ]] || return 1
|
||||
awk 'NR > 1 { if ($1 !~ /^\/dev\/zram[0-9]+$/) bad=1; if ($1 == "/dev/zram0") found=1 } END { exit !(found && !bad) }' /proc/swaps
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3674,6 +3858,7 @@ custom_post_description_label() {
|
||||
"Enable High Availability services") translate "Enable High Availability services" ;;
|
||||
"Install Figurine") translate "Install Figurine" ;;
|
||||
"Install and configure Log2RAM") translate "Install and configure Log2RAM" ;;
|
||||
"Enable ZRAM-only swap profile") translate "Enable ZRAM-only swap profile" ;;
|
||||
*) echo "$1" ;;
|
||||
esac
|
||||
}
|
||||
@@ -3769,6 +3954,7 @@ main_menu() {
|
||||
"System|Increase various system limits|LIMITS"
|
||||
# Entropy (haveged) removed — modern kernels 5.6+ have built-in entropy generation
|
||||
"System|Optimize Memory|MEMORYFIXES"
|
||||
"Optional|Enable ZRAM-only swap profile|ZRAM_SWAP"
|
||||
"System|Enable fast reboots|KEXEC"
|
||||
"System|Enable restart on kernel panic|KERNELPANIC"
|
||||
"Optional|Apply AMD CPU fixes|AMDFIXES"
|
||||
@@ -3912,6 +4098,7 @@ done
|
||||
LIMITS) increase_system_limits ;;
|
||||
# ENTROPY removed — modern kernels 5.6+ have built-in entropy
|
||||
MEMORYFIXES) optimize_memory_settings ;;
|
||||
ZRAM_SWAP) configure_zram_swap ;;
|
||||
KEXEC) enable_kexec ;;
|
||||
KERNELPANIC) configure_kernel_panic ;;
|
||||
AMDFIXES) apply_amd_fixes ;;
|
||||
|
||||
@@ -37,6 +37,9 @@ fi
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
if [[ -f "$LOCAL_SCRIPTS/post_install/zram_profile_helpers.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/post_install/zram_profile_helpers.sh"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
@@ -55,6 +58,76 @@ register_tool() {
|
||||
|
||||
################################################################
|
||||
|
||||
uninstall_zram_swap() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "uninstall_zram_swap" "$FUNC_VERSION"
|
||||
local config=/etc/systemd/zram-generator.conf.d/90-proxmenux.conf
|
||||
local marker="$BASE_DIR/zram-swap.state"
|
||||
local package_owned=false foreign="" other_active="" old_active=false
|
||||
local old_config="" old_marker=""
|
||||
|
||||
if ! declare -f zram_foreign_generator_config >/dev/null; then
|
||||
msg_error "$(translate "ZRAM profile helpers are missing")"
|
||||
return 1
|
||||
fi
|
||||
if [[ ! -f "$config" || ! -f "$marker" || -L "$config" || -L "$marker" ]] ||
|
||||
! grep -qx '# ProxMenux ZRAM profile' "$config" ||
|
||||
! grep -Eq '^installed_by_proxmenux=(true|false)$' "$marker"; then
|
||||
msg_error "$(translate "ZRAM ownership state is incomplete; no files were removed")"
|
||||
return 1
|
||||
fi
|
||||
old_config="$(cat "$config")"
|
||||
old_marker="$(cat "$marker")"
|
||||
[[ "$old_marker" == installed_by_proxmenux=true ]] && package_owned=true
|
||||
|
||||
if awk 'NR > 1 && $1 == "/dev/zram0" { found=1 } END { exit !found }' /proc/swaps; then
|
||||
old_active=true
|
||||
if ! swapoff /dev/zram0; then
|
||||
msg_error "$(translate "ZRAM still holds pages; profile remains active")"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
if systemctl is-active --quiet dev-zram0.swap && ! systemctl stop dev-zram0.swap; then
|
||||
if [[ "$old_active" == true ]]; then
|
||||
systemctl start dev-zram0.swap >/dev/null 2>&1 || true
|
||||
fi
|
||||
msg_error "$(translate "Could not stop ZRAM swap; profile configuration remains")"
|
||||
return 1
|
||||
fi
|
||||
if ! pmx_remove_file "$config" || ! pmx_remove_file "$marker" || ! systemctl daemon-reload; then
|
||||
printf '%s\n' "$old_config" | pmx_write_file "$config"
|
||||
printf '%s\n' "$old_marker" | pmx_write_file "$marker"
|
||||
chmod 600 "$marker"
|
||||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||
if [[ "$old_active" == true ]] && ! systemctl start dev-zram0.swap >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Could not remove ZRAM profile; configuration was restored but swap could not be restarted")"
|
||||
else
|
||||
msg_error "$(translate "Could not remove ZRAM profile; configuration was restored")"
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
rmdir "$(dirname "$config")" 2>/dev/null || true
|
||||
|
||||
if [[ "$package_owned" == true ]]; then
|
||||
foreign="$(zram_foreign_generator_config "$config")"
|
||||
other_active="$(awk 'NR > 1 && $1 ~ /^\/dev\/zram[0-9]+$/ { print $1 }' /proc/swaps)"
|
||||
if [[ -z "$foreign" && -z "$other_active" ]]; then
|
||||
if DEBIAN_FRONTEND=noninteractive apt-get purge -y systemd-zram-generator >/dev/null 2>&1; then
|
||||
pmx_record_uninstall "systemd-zram-generator" "$FUNC_VERSION"
|
||||
else
|
||||
msg_warn "$(translate "ZRAM profile removed, but package purge failed")"
|
||||
fi
|
||||
else
|
||||
msg_warn "$(translate "systemd-zram-generator is still used by another configuration; package retained")"
|
||||
fi
|
||||
fi
|
||||
register_tool "zram_swap" false
|
||||
msg_success "$(translate "ZRAM swap profile removed")"
|
||||
return 0
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
uninstall_fastfetch() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "uninstall_fastfetch" "$FUNC_VERSION"
|
||||
@@ -1270,6 +1343,7 @@ show_uninstall_menu() {
|
||||
system_limits) desc="System Limits Increase";;
|
||||
entropy) desc="Entropy Generation (haveged)";;
|
||||
memory_settings) desc="Memory Settings Optimization";;
|
||||
zram_swap) desc="ZRAM-only swap profile";;
|
||||
kernel_panic) desc="Kernel Panic Configuration";;
|
||||
apt_ipv4) desc="APT IPv4 Force";;
|
||||
kexec) desc="kexec for quick reboots";;
|
||||
@@ -1315,18 +1389,30 @@ show_uninstall_menu() {
|
||||
fi
|
||||
|
||||
# Execute uninstallations
|
||||
local failed=0
|
||||
for tool in $selected_tools; do
|
||||
tool=$(echo "$tool" | tr -d '"')
|
||||
if declare -f "uninstall_$tool" > /dev/null 2>&1; then
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
"uninstall_$tool"
|
||||
# Preserve legacy return handling for existing uninstallers.
|
||||
# Only ZRAM uses a failure status to signal that its active swap
|
||||
# profile could not be safely removed.
|
||||
if [[ "$tool" == "zram_swap" ]]; then
|
||||
uninstall_zram_swap || failed=1
|
||||
else
|
||||
"uninstall_$tool" || true
|
||||
fi
|
||||
else
|
||||
msg_warn "$(translate "No uninstaller found for:") $tool"
|
||||
fi
|
||||
done
|
||||
|
||||
msg_success "$(translate "Selected optimizations have been uninstalled.")"
|
||||
if [[ "$failed" -eq 0 ]]; then
|
||||
msg_success "$(translate "Selected optimizations have been uninstalled.")"
|
||||
else
|
||||
msg_error "$(translate "Some optimizations could not be uninstalled; their configuration was preserved.")"
|
||||
fi
|
||||
msg_warn "$(translate "A system reboot is recommended to ensure all changes take effect.")"
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to continue...")"
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env bash
|
||||
# Pure helpers shared by the ZRAM installer and its fixture tests.
|
||||
|
||||
zram_render_generator_config() {
|
||||
local algorithm=zstd
|
||||
[[ "${1:-false}" == true ]] && algorithm='zstd(level=9)'
|
||||
cat <<EOF
|
||||
# ProxMenux ZRAM profile
|
||||
[zram0]
|
||||
zram-size = ram / 10
|
||||
compression-algorithm = $algorithm
|
||||
swap-priority = 100
|
||||
EOF
|
||||
}
|
||||
|
||||
zram_list_non_zram_swap() {
|
||||
local swaps_file="$1" fstab_file="$2"
|
||||
awk 'NR > 1 && $1 !~ /^\/dev\/zram[0-9]+$/ { print "active: " $1 }' "$swaps_file"
|
||||
awk '$0 !~ /^[[:space:]]*#/ && NF >= 3 && $3 == "swap" && $1 !~ /^\/dev\/zram[0-9]+$/ { print "fstab: " $1 }' "$fstab_file"
|
||||
}
|
||||
|
||||
zram_has_non_zram_swap() {
|
||||
[[ -r "$1" && -r "$2" ]] || return 2
|
||||
[[ -n "$(zram_list_non_zram_swap "$1" "$2")" ]]
|
||||
}
|
||||
|
||||
# Print generator configuration outside this feature's dedicated drop-in.
|
||||
zram_foreign_generator_config() {
|
||||
local owned_file="$1" fixture_root="${2:-}" root file
|
||||
local roots=(/etc/systemd /run/systemd /usr/local/lib/systemd /usr/lib/systemd /lib/systemd)
|
||||
if [[ -n "$fixture_root" ]]; then
|
||||
roots=("$fixture_root/etc/systemd" "$fixture_root/run/systemd" "$fixture_root/usr/local/lib/systemd" "$fixture_root/usr/lib/systemd" "$fixture_root/lib/systemd")
|
||||
fi
|
||||
for root in "${roots[@]}"; do
|
||||
for file in "$root/zram-generator.conf" "$root"/zram-generator.conf.d/*.conf; do
|
||||
[[ -e "$file" || -L "$file" ]] || continue
|
||||
[[ "$file" == "$owned_file" ]] && continue
|
||||
# Ignore package defaults containing only comments, whitespace and
|
||||
# section headers. Any directive or malformed active line is foreign.
|
||||
if awk '
|
||||
{
|
||||
line=$0
|
||||
sub(/^[[:space:]]+/, "", line)
|
||||
sub(/[[:space:]]+$/, "", line)
|
||||
if (line == "" || line ~ /^[#;]/ || line ~ /^\[[^]]+\]$/) next
|
||||
found=1
|
||||
}
|
||||
END { exit !found }
|
||||
' "$file"; then
|
||||
printf '%s\n' "$file"
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
zram_list_defined_systemd_swap_units() {
|
||||
local fixture_root="${1:-}" root file
|
||||
local roots=(/etc/systemd/system /run/systemd/system)
|
||||
if [[ -n "$fixture_root" ]]; then
|
||||
roots=("$fixture_root/etc/systemd/system" "$fixture_root/run/systemd/system")
|
||||
fi
|
||||
for root in "${roots[@]}"; do
|
||||
[[ -d "$root" ]] || continue
|
||||
while IFS= read -r file; do
|
||||
# Files in these roots are administrator-defined units. The
|
||||
# generator's own output lives under /run/systemd/generator and
|
||||
# is intentionally outside this scan.
|
||||
printf 'systemd: %s\n' "$file"
|
||||
done < <(find "$root" -name '*.swap' \( -type f -o -type l \) -print 2>/dev/null)
|
||||
done
|
||||
}
|
||||
Reference in New Issue
Block a user