feat: support PBS hosts and remote PBS monitoring

This commit is contained in:
Jonatan
2026-10-16 21:46:26 +02:00
parent 3000c1cd66
commit 511bfe52ea
26 changed files with 1355 additions and 15 deletions
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
# Canonical detection is shared with the Monitor; never infer PBS from a client package.
pmx_platform_field() {
python3 "$(dirname "${BASH_SOURCE[0]}")/proxmox_platform.py" --field "$1"
}
pmx_is_pbs() {
[[ "$(pmx_platform_field product)" == pbs ]]
}
pmx_require_pve() {
if [[ "$(pmx_platform_field product)" != pve ]]; then
msg_error "$(translate 'This operation requires a Proxmox VE host. Use the PBS menu on Proxmox Backup Server.')"
return 1
fi
}
+56
View File
@@ -0,0 +1,56 @@
"""Shared PVE/PBS platform detection for the menus and the Monitor (stdlib only)."""
import argparse
import json
from pathlib import Path
import re
import subprocess
OS_RELEASE = Path("/etc/os-release")
SUPPORTED = {("pve", 8): "bookworm", ("pve", 9): "trixie",
("pbs", 3): "bookworm", ("pbs", 4): "trixie"}
def detect_platform():
codename = ""
try:
match = re.search(r'^VERSION_CODENAME=["\']?([a-z0-9-]+)', OS_RELEASE.read_text(), re.M)
codename = match.group(1) if match else ""
except OSError:
pass
installed = {}
try:
result = subprocess.run(
["dpkg-query", "-W", "-f=${Package}\t${Status}\t${Version}\n",
"pve-manager", "proxmox-backup-server"], capture_output=True, text=True, timeout=5,
)
# dpkg returns nonzero if ONE requested package is missing; its other
# installed rows remain authoritative. A PBS client alone is not PBS.
for line in result.stdout.splitlines():
columns = line.split("\t")
if len(columns) == 3 and columns[1] == "install ok installed":
installed[columns[0]] = columns[2]
except (OSError, subprocess.TimeoutExpired):
pass
for package, product in (("pve-manager", "pve"), ("proxmox-backup-server", "pbs")):
version = installed.get(package, "")
match = re.fullmatch(r"(?:[0-9]+:)?([0-9]+)\.[0-9]+(?:\.[0-9]+)?(?:[-+~.a-zA-Z0-9]*)", version)
if match:
major = int(match.group(1))
return {"product": product, "version": version, "major": major,
"codename": codename, "supported": SUPPORTED.get((product, major)) == codename}
return {"product": "unknown", "version": None, "major": None,
"codename": codename, "supported": False}
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--field", choices=("product", "version", "major", "codename", "supported"))
arguments = parser.parse_args()
data = detect_platform()
value = data.get(arguments.field) if arguments.field else data
print(value if isinstance(value, str) else json.dumps(value))
if __name__ == "__main__":
main()
+9
View File
@@ -2,12 +2,21 @@
# Shared repository policy for package-install and safe-update flows.
# Proxmox's own repository API parses .list/.sources and edits individual
# entries. No shell rewriting of operator-maintained APT files.
source "$(dirname "${BASH_SOURCE[0]}")/platform-functions.sh"
repository_policy() {
python3 "$(dirname "${BASH_SOURCE[0]}")/repository_policy.py" "$@"
}
ensure_repositories() {
local version suite decision refresh_status
if pmx_is_pbs; then
if [[ "$(pmx_platform_field supported)" != true ]]; then
msg_error "$(translate 'This operation supports PBS 3 on Debian 12 and PBS 4 on Debian 13.')"
return 1
fi
msg_info "$(translate 'PBS: using the configured APT repositories without changing sources.')"
return 0
fi
version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
case "$version" in
8) suite=bookworm ;;
+4
View File
@@ -128,4 +128,8 @@ show_menu() {
done
}
source "$LOCAL_SCRIPTS/global/platform-functions.sh"
if pmx_is_pbs; then
exec bash "$LOCAL_SCRIPTS/menus/pbs_menu.sh"
fi
show_menu
+46
View File
@@ -0,0 +1,46 @@
#!/bin/bash
# PBS exposes compatible host tools; PVE guest/repository optimizations stay in the PVE menu.
BASE_DIR="/usr/local/share/proxmenux"
LOCAL_SCRIPTS="$BASE_DIR/scripts"
source "$BASE_DIR/utils.sh"
source "$LOCAL_SCRIPTS/global/platform-functions.sh"
load_language
initialize_cache
if ! pmx_is_pbs; then
msg_error "$(translate 'This menu requires Proxmox Backup Server.')"
exit 1
fi
pbs_show() {
local output
output=$(mktemp)
if "$@" > "$output" 2>&1; then
dialog --backtitle "ProxMenux · PBS" --title "Proxmox Backup Server" --textbox "$output" 24 100
else
dialog --backtitle "ProxMenux · PBS" --title "$(translate 'Command failed')" --textbox "$output" 24 100
fi
rm -f "$output"
}
while true; do
choice=$(dialog --clear --backtitle "ProxMenux · PBS" --title "Proxmox Backup Server" \
--menu "$(translate 'Select an option:')" 20 80 10 \
status "$(translate 'PBS version and packages')" \
stores "$(translate 'PBS datastores')" \
tasks "$(translate 'Recent PBS tasks')" \
utilities "$(translate 'System Utilities Installer')" \
update "$(translate 'Update PBS using configured repositories')" \
settings "$(translate 'Settings')" \
exit "$(translate 'Exit')" 2>&1 >/dev/tty) || break
case "$choice" in
status) pbs_show proxmox-backup-manager versions --verbose --output-format json-pretty ;;
stores) pbs_show proxmox-backup-manager datastore list --output-format json-pretty ;;
tasks) pbs_show proxmox-backup-manager task list --all true --limit 20 --output-format json-pretty ;;
utilities) bash "$LOCAL_SCRIPTS/utilities/system_utils.sh" ;;
update) bash "$LOCAL_SCRIPTS/utilities/pbs_update.sh" ;;
settings) bash "$LOCAL_SCRIPTS/menus/config_menu.sh" ;;
exit) break ;;
esac
done
clear
@@ -57,6 +57,11 @@ fi
load_language
initialize_cache
if [[ -f "$LOCAL_SCRIPTS/global/platform-functions.sh" ]]; then
source "$LOCAL_SCRIPTS/global/platform-functions.sh"
pmx_require_pve || exit 1
fi
# Global variables
OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs)"
RAM_SIZE_GB=$(awk '/^MemTotal:/{print int($2/1024/1024)}' /proc/meminfo)
@@ -51,6 +51,11 @@ fi
load_language
initialize_cache
if [[ -f "$LOCAL_SCRIPTS/global/platform-functions.sh" ]]; then
source "$LOCAL_SCRIPTS/global/platform-functions.sh"
pmx_require_pve || exit 1
fi
# Load shared global functions
if [[ -f "$LOCAL_SCRIPTS/global/common-functions.sh" ]]; then
source "$LOCAL_SCRIPTS/global/common-functions.sh"
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
# Use PBS's existing repositories; never run PVE repo, Ceph or major-upgrade scripts.
BASE_DIR="/usr/local/share/proxmenux"
LOCAL_SCRIPTS="$BASE_DIR/scripts"
source "$BASE_DIR/utils.sh"
source "$LOCAL_SCRIPTS/global/platform-functions.sh"
load_language
initialize_cache
if ! pmx_is_pbs || [[ "$(pmx_platform_field supported)" != true ]]; then
msg_error "$(translate 'This operation supports PBS 3 on Debian 12 and PBS 4 on Debian 13.')"
exit 1
fi
[[ $EUID -eq 0 ]] || { msg_error "$(translate 'Run this operation as root.')"; exit 1; }
dialog --backtitle "ProxMenux · PBS" --title "$(translate 'PBS package update')" \
--yesno "$(translate 'Refresh the configured APT repositories and review the PBS package upgrade? Repository files will be preserved.')" 10 80 || exit 0
if ! apt-get -o APT::Update::Error-Mode=any update; then
msg_error "$(translate 'APT refresh failed. Check the PBS subscription and repositories in the native PBS interface; no source was changed.')"
read -r _
exit 1
fi
plan=$(mktemp)
trap 'rm -f "$plan"' EXIT
if ! apt-get -s full-upgrade > "$plan" 2>&1; then
dialog --textbox "$plan" 24 100
exit 1
fi
dialog --backtitle "ProxMenux · PBS" --title "$(translate 'Review package upgrade')" --textbox "$plan" 24 100
dialog --defaultno --title "$(translate 'Apply PBS package upgrade')" \
--yesno "$(translate 'Apply the reviewed package upgrade now? Services may restart and packages listed for removal will be removed.')" 11 80 || exit 0
if apt-get -y full-upgrade; then
msg_ok "$(translate 'PBS package upgrade completed. Check whether a reboot is required before your next backup window.')"
else
msg_error "$(translate 'PBS package upgrade failed. Review the APT output before retrying.')"
read -r _
exit 1
fi
read -r _