mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-02 10:52:22 +00:00
fix(post-install): prioritize ZRAM ahead of disk swap
This commit is contained in:
@@ -0,0 +1,286 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_ROOT/../.." && pwd)"
|
||||
TEST_ROOT="$(mktemp -d)"
|
||||
trap 'rm -rf "$TEST_ROOT"' EXIT
|
||||
|
||||
CONFIG="$TEST_ROOT/etc/systemd/zram-generator.conf.d/90-proxmenux.conf"
|
||||
MARKER="$TEST_ROOT/state/zram-swap.state"
|
||||
SWAPS="$TEST_ROOT/proc/swaps"
|
||||
FSTAB="$TEST_ROOT/etc/fstab"
|
||||
EXPECTED_FSTAB="$TEST_ROOT/fstab.expected"
|
||||
VERIFY_MODE=0
|
||||
START_COUNT=0
|
||||
PURGE_COUNT=0
|
||||
|
||||
fail() {
|
||||
printf 'FAIL: %s\n' "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
load_language() { :; }
|
||||
initialize_cache() { :; }
|
||||
translate() { printf '%s' "$1"; }
|
||||
msg_info() { :; }
|
||||
msg_info2() { :; }
|
||||
msg_ok() { :; }
|
||||
msg_warn() { :; }
|
||||
msg_error() { printf '%s\n' "$*" >&2; }
|
||||
msg_success() { :; }
|
||||
show_proxmenux_logo() { :; }
|
||||
clear() { :; }
|
||||
pmx_install_pkg() { return 1; }
|
||||
pmx_record_uninstall() { :; }
|
||||
apt-get() {
|
||||
if [[ "$*" == "purge -y systemd-zram-generator" ]]; then
|
||||
PURGE_COUNT=$((PURGE_COUNT + 1))
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
pmx_journal_context() { :; }
|
||||
|
||||
dpkg-query() {
|
||||
case "$*" in
|
||||
*'${Status}'*) printf 'install ok installed\n' ;;
|
||||
*'${Version}'*) printf '1.2.0-1\n' ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
dpkg() {
|
||||
[[ "$1" == "--compare-versions" && "$3" == "ge" && "$2" == "1.2.0-1" && "$4" == "1.2.0" ]]
|
||||
}
|
||||
|
||||
systemctl() {
|
||||
case "$1" in
|
||||
daemon-reload|stop) return 0 ;;
|
||||
start)
|
||||
START_COUNT=$((START_COUNT + 1))
|
||||
if [[ "${2:-}" == "dev-zram0.swap" ]] &&
|
||||
! awk 'NR > 1 && $1 == "/dev/zram0" { found=1 } END { exit !found }' "$SWAPS"; then
|
||||
printf '/dev/zram0\tpartition\t3355443\t0\t32767\n' >> "$SWAPS"
|
||||
fi
|
||||
return 0
|
||||
;;
|
||||
is-active) return 1 ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
swapoff() {
|
||||
local target="${1:-}" next="$TEST_ROOT/swaps.next"
|
||||
[[ -n "$target" ]] || fail "swapoff was called without a target"
|
||||
awk -v target="$target" 'NR == 1 || $1 != target' "$SWAPS" > "$next"
|
||||
mv "$next" "$SWAPS"
|
||||
}
|
||||
|
||||
PMX_JOURNAL_ROOT="$TEST_ROOT/journal"
|
||||
export PMX_JOURNAL_ROOT
|
||||
source "$REPO_ROOT/scripts/global/pmx_journal.sh"
|
||||
|
||||
mkdir -p "$TEST_ROOT/host/scripts/post_install"
|
||||
cp "$SCRIPT_ROOT/zram_profile_helpers.sh" "$TEST_ROOT/host/scripts/post_install/"
|
||||
|
||||
# Isolate only host paths; source the real installer function and helper library.
|
||||
python3 - "$SCRIPT_ROOT/customizable_post_install.sh" "$TEST_ROOT/customizable.sh" "$TEST_ROOT" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
source_path, output_path, root = map(Path, sys.argv[1:])
|
||||
text = source_path.read_text(encoding="utf-8")
|
||||
|
||||
def replace_exact(old, new, expected=1):
|
||||
global text
|
||||
count = text.count(old)
|
||||
if count != expected:
|
||||
raise SystemExit(f"expected {expected} path substitutions, found {count}: {old}")
|
||||
text = text.replace(old, new)
|
||||
|
||||
replace_exact(
|
||||
'LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"',
|
||||
f'LOCAL_SCRIPTS="{root}/host/scripts"',
|
||||
)
|
||||
replace_exact(
|
||||
'BASE_DIR="/usr/local/share/proxmenux"',
|
||||
f'BASE_DIR="{root}/state"',
|
||||
)
|
||||
replace_exact(
|
||||
'UTILS_FILE="$BASE_DIR/utils.sh"',
|
||||
f'UTILS_FILE="{root}/missing-utils.sh"',
|
||||
)
|
||||
replace_exact(
|
||||
'TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"',
|
||||
f'TOOLS_JSON="{root}/state/installed_tools.json"',
|
||||
)
|
||||
replace_exact(
|
||||
'local config=/etc/systemd/zram-generator.conf.d/90-proxmenux.conf',
|
||||
f'local config={root}/etc/systemd/zram-generator.conf.d/90-proxmenux.conf',
|
||||
)
|
||||
replace_exact(
|
||||
'if [[ ! -r /proc/swaps || ! -r /etc/fstab ]]; then',
|
||||
f'if [[ ! -r "{root}/proc/swaps" || ! -r "{root}/etc/fstab" ]]; then',
|
||||
)
|
||||
replace_exact(
|
||||
'zram_list_foreign_active_zram_swap /proc/swaps "$allowed_zram"',
|
||||
f'zram_list_foreign_active_zram_swap "{root}/proc/swaps" "$allowed_zram"',
|
||||
)
|
||||
replace_exact(
|
||||
'zram_list_foreign_fstab_zram_swap /etc/fstab',
|
||||
f'zram_list_foreign_fstab_zram_swap "{root}/etc/fstab"',
|
||||
)
|
||||
replace_exact(
|
||||
'zram_list_foreign_systemd_zram_units)',
|
||||
'zram_list_foreign_systemd_zram_units "$TEST_ROOT")',
|
||||
)
|
||||
replace_exact(
|
||||
'zram_foreign_generator_config "$config"',
|
||||
'zram_foreign_generator_config "$config" "$TEST_ROOT"',
|
||||
expected=3,
|
||||
)
|
||||
replace_exact(
|
||||
"awk 'NR > 1 && $1 == \"/dev/zram0\" { found=1 } END { exit !found }' /proc/swaps",
|
||||
f"awk 'NR > 1 && $1 == \"/dev/zram0\" {{ found=1 }} END {{ exit !found }}' \"{root}/proc/swaps\"",
|
||||
expected=2,
|
||||
)
|
||||
output_path.write_text(text, encoding="utf-8")
|
||||
PY
|
||||
|
||||
# Isolate the real uninstall function and redirect only the paths it inspects.
|
||||
python3 - "$SCRIPT_ROOT/uninstall-tools.sh" "$TEST_ROOT/uninstall-zram.sh" "$TEST_ROOT" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
source_path, output_path, root = map(Path, sys.argv[1:])
|
||||
text = source_path.read_text(encoding="utf-8")
|
||||
start = text.index("uninstall_zram_swap() {")
|
||||
end = text.index("\n}\n", start) + 3
|
||||
function = text[start:end]
|
||||
replacements = {
|
||||
"local config=/etc/systemd/zram-generator.conf.d/90-proxmenux.conf":
|
||||
f"local config={root}/etc/systemd/zram-generator.conf.d/90-proxmenux.conf",
|
||||
'awk \'NR > 1 && $1 == "/dev/zram0" { found=1 } END { exit !found }\' /proc/swaps':
|
||||
f'awk \'NR > 1 && $1 == "/dev/zram0" {{ found=1 }} END {{ exit !found }}\' "{root}/proc/swaps"',
|
||||
'zram_foreign_generator_config "$config"':
|
||||
'zram_foreign_generator_config "$config" "$TEST_ROOT"',
|
||||
'zram_list_foreign_active_zram_swap /proc/swaps /dev/zram0':
|
||||
f'zram_list_foreign_active_zram_swap "{root}/proc/swaps" /dev/zram0',
|
||||
'zram_list_foreign_fstab_zram_swap /etc/fstab':
|
||||
f'zram_list_foreign_fstab_zram_swap "{root}/etc/fstab"',
|
||||
'zram_list_foreign_systemd_zram_units)':
|
||||
'zram_list_foreign_systemd_zram_units "$TEST_ROOT")',
|
||||
}
|
||||
for old, new in replacements.items():
|
||||
if function.count(old) != 1:
|
||||
raise SystemExit(f"expected one uninstall path to rewrite: {old}")
|
||||
function = function.replace(old, new)
|
||||
output_path.write_text(function, encoding="utf-8")
|
||||
PY
|
||||
|
||||
source "$TEST_ROOT/customizable.sh"
|
||||
source "$TEST_ROOT/uninstall-zram.sh"
|
||||
BASE_DIR="$TEST_ROOT/state"
|
||||
TOOLS_JSON="$TEST_ROOT/state/installed_tools.json"
|
||||
mkdir -p "$BASE_DIR"
|
||||
register_tool() { printf '%s|%s|%s\n' "$1" "$2" "${3:-}" >> "$TEST_ROOT/registry.log"; }
|
||||
zram_profile_verify_active() { return "$VERIFY_MODE"; }
|
||||
|
||||
reset_fixture() {
|
||||
rm -rf "$TEST_ROOT/etc" "$TEST_ROOT/run" "$TEST_ROOT/proc" "$BASE_DIR" "$TEST_ROOT/journal"
|
||||
mkdir -p "$TEST_ROOT/etc/systemd/system" "$TEST_ROOT/proc" "$BASE_DIR" "$TEST_ROOT/run/systemd/system"
|
||||
printf 'Filename\tType\tSize\tUsed\tPriority\n/dev/nvme0n1p3\tpartition\t1048576\t8\t-2\n' > "$SWAPS"
|
||||
printf '/dev/nvme0n1p3 none swap defaults 0 0\n/swapfile none swap sw 0 0\n' > "$FSTAB"
|
||||
cp "$FSTAB" "$EXPECTED_FSTAB"
|
||||
printf '[Swap]\nWhat=/dev/mapper/pve-swap\n' > "$TEST_ROOT/etc/systemd/system/pve-swap.swap"
|
||||
PMX_JOURNAL_ROOT="$TEST_ROOT/journal"
|
||||
START_COUNT=0
|
||||
PURGE_COUNT=0
|
||||
VERIFY_MODE=0
|
||||
: > "$TEST_ROOT/registry.log"
|
||||
}
|
||||
|
||||
assert_disk_swap_unchanged() {
|
||||
cmp -s "$FSTAB" "$EXPECTED_FSTAB" || fail "installer changed fstab"
|
||||
grep -Fq '/dev/nvme0n1p3' "$SWAPS" || fail "active disk swap was removed"
|
||||
}
|
||||
|
||||
reset_fixture
|
||||
configure_zram_swap || fail "disk swap prevented ZRAM installation"
|
||||
grep -Fq 'swap-priority = 32767' "$CONFIG" || fail "ZRAM priority is not maximal"
|
||||
grep -Fq 'installed_by_proxmenux=false' "$MARKER" || fail "package ownership was not preserved"
|
||||
grep -Fq '/dev/zram0' "$SWAPS" || fail "ZRAM did not become active"
|
||||
assert_disk_swap_unchanged
|
||||
|
||||
configure_zram_swap || fail "owned ZRAM profile could not be re-applied with disk swap"
|
||||
[[ "$START_COUNT" -eq 1 ]] || fail "matching owned profile was not idempotent"
|
||||
assert_disk_swap_unchanged
|
||||
printf 'PASS: disk swap coexists and owned profile is idempotent\n'
|
||||
|
||||
reset_fixture
|
||||
printf '/dev/zram1 none swap defaults 0 0\n' >> "$FSTAB"
|
||||
cp "$FSTAB" "$EXPECTED_FSTAB"
|
||||
if configure_zram_swap; then
|
||||
fail "foreign fstab ZRAM entry was accepted"
|
||||
fi
|
||||
[[ ! -e "$CONFIG" && ! -e "$MARKER" ]] || fail "foreign fstab ZRAM entry left partial profile state"
|
||||
assert_disk_swap_unchanged
|
||||
printf 'PASS: foreign fstab ZRAM setup is refused without changing disk swap\n'
|
||||
|
||||
reset_fixture
|
||||
printf '%s\n' '[Swap]' 'What=/dev/zram1' > "$TEST_ROOT/etc/systemd/system/external-zram.swap"
|
||||
if configure_zram_swap; then
|
||||
fail "foreign systemd ZRAM unit was accepted"
|
||||
fi
|
||||
[[ ! -e "$CONFIG" && ! -e "$MARKER" ]] || fail "foreign systemd ZRAM unit left partial profile state"
|
||||
assert_disk_swap_unchanged
|
||||
printf 'PASS: foreign systemd ZRAM unit is refused without changing disk swap\n'
|
||||
|
||||
reset_fixture
|
||||
VERIFY_MODE=1
|
||||
if configure_zram_swap; then
|
||||
fail "activation verification failure was reported as success"
|
||||
fi
|
||||
[[ ! -e "$CONFIG" && ! -e "$MARKER" ]] || fail "failed activation left partial profile state"
|
||||
if awk 'NR > 1 && $1 == "/dev/zram0" { found=1 } END { exit !found }' "$SWAPS"; then
|
||||
fail "rollback left the failed ZRAM device active"
|
||||
fi
|
||||
assert_disk_swap_unchanged
|
||||
printf 'PASS: verification failure rolls back only the ProxMenux ZRAM state\n'
|
||||
|
||||
reset_fixture
|
||||
mkdir -p "$(dirname "$CONFIG")"
|
||||
printf '# ProxMenux ZRAM profile\n[zram0]\nzram-size = ram / 10\n' > "$CONFIG"
|
||||
printf 'installed_by_proxmenux=true\n' > "$MARKER"
|
||||
printf '/dev/zram1 none swap defaults 0 0\n' >> "$FSTAB"
|
||||
printf '[Swap]\nWhat=/dev/zram2\n' > "$TEST_ROOT/etc/systemd/system/external-zram.swap"
|
||||
cp "$FSTAB" "$EXPECTED_FSTAB"
|
||||
uninstall_zram_swap || fail "profile uninstall failed with foreign ZRAM configuration"
|
||||
[[ "$PURGE_COUNT" -eq 0 ]] || fail "uninstaller purged generator while foreign ZRAM config exists"
|
||||
[[ ! -e "$CONFIG" && ! -e "$MARKER" ]] || fail "uninstaller left ProxMenux profile files behind"
|
||||
assert_disk_swap_unchanged
|
||||
printf 'PASS: uninstall retains generator when foreign ZRAM config exists\n'
|
||||
|
||||
reset_fixture
|
||||
mkdir -p "$(dirname "$CONFIG")"
|
||||
printf '# ProxMenux ZRAM profile\n[zram0]\nzram-size = ram / 10\n' > "$CONFIG"
|
||||
printf 'installed_by_proxmenux=true\n' > "$MARKER"
|
||||
printf '%s\n' '[Swap]' 'What=/dev/zram2' > "$TEST_ROOT/etc/systemd/system/external-zram.swap"
|
||||
uninstall_zram_swap || fail "profile uninstall failed with foreign systemd ZRAM unit"
|
||||
[[ "$PURGE_COUNT" -eq 0 ]] || fail "uninstaller purged generator while foreign systemd ZRAM unit exists"
|
||||
assert_disk_swap_unchanged
|
||||
printf 'PASS: uninstall retains generator for foreign systemd ZRAM unit\n'
|
||||
|
||||
reset_fixture
|
||||
mkdir -p "$(dirname "$CONFIG")"
|
||||
printf '# ProxMenux ZRAM profile\n[zram0]\nzram-size = ram / 10\n' > "$CONFIG"
|
||||
printf 'installed_by_proxmenux=true\n' > "$MARKER"
|
||||
printf '/dev/zram0\tpartition\t3355443\t8\t32767\n' >> "$SWAPS"
|
||||
uninstall_zram_swap || fail "owned profile could not be uninstalled"
|
||||
[[ "$PURGE_COUNT" -eq 1 ]] || fail "owned generator package was not purged"
|
||||
if awk 'NR > 1 && $1 == "/dev/zram0" { found=1 } END { exit !found }' "$SWAPS"; then
|
||||
fail "uninstaller left ProxMenux ZRAM active"
|
||||
fi
|
||||
assert_disk_swap_unchanged
|
||||
printf 'PASS: uninstall removes owned ZRAM and preserves disk swap\n'
|
||||
Reference in New Issue
Block a user