mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-07-30 04:18:22 +00:00
update 1.2.2.2 beta
This commit is contained in:
@@ -99,6 +99,17 @@ _bk_pbs() {
|
||||
staged_size=$(hb_file_size "$staging_root/rootfs")
|
||||
msg_ok "$(translate "Staging ready.") $(translate "Data size:") $staged_size"
|
||||
|
||||
# Notify host_backup_start. Per-channel/per-event toggles in
|
||||
# Settings decide whether the user actually receives it; same
|
||||
# template the scheduled runner uses.
|
||||
export HB_NOTIFY_JOB_ID="manual-pbs-${backup_id}"
|
||||
export HB_NOTIFY_BACKEND="pbs"
|
||||
export HB_NOTIFY_DESTINATION="$HB_PBS_REPOSITORY"
|
||||
export HB_NOTIFY_PROFILE_MODE="$profile_mode"
|
||||
export HB_NOTIFY_LOG_FILE="$log_file"
|
||||
export HB_NOTIFY_DATA_SIZE="$staged_size"
|
||||
hb_notify_lifecycle "start"
|
||||
|
||||
echo -e ""
|
||||
msg_info "$(translate "Connecting to PBS and starting backup...")"
|
||||
stop_spinner
|
||||
@@ -164,9 +175,19 @@ _bk_pbs() {
|
||||
[[ -s "$log_file" ]] && echo -e "${TAB}${BGN}$(translate "Log:")${CL} ${BL}${log_file}${CL}"
|
||||
echo -e ""
|
||||
msg_ok "$(translate "Backup completed successfully.")"
|
||||
export HB_NOTIFY_ARCHIVE_SIZE="-"
|
||||
export HB_NOTIFY_DURATION="$(hb_human_elapsed "$elapsed" 2>/dev/null || echo "${elapsed}s")"
|
||||
hb_notify_lifecycle "complete"
|
||||
else
|
||||
echo -e ""
|
||||
msg_error "$(translate "PBS backup failed.")"
|
||||
local _hb_reason
|
||||
_hb_reason=$(grep -iE 'error|fail|fatal|abort' "$log_file" 2>/dev/null | tail -1 | sed 's/^[[:space:]]*//')
|
||||
[[ -z "$_hb_reason" ]] && _hb_reason="proxmox-backup-client returned non-zero"
|
||||
export HB_NOTIFY_ARCHIVE_SIZE="-"
|
||||
export HB_NOTIFY_DURATION="$(hb_human_elapsed "$((SECONDS - t_start))" 2>/dev/null || echo "")"
|
||||
export HB_NOTIFY_REASON="$_hb_reason"
|
||||
hb_notify_lifecycle "fail"
|
||||
hb_show_log "$log_file" "$(translate "PBS backup error log")"
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
@@ -215,6 +236,14 @@ _bk_borg() {
|
||||
staged_size=$(hb_file_size "$staging_root/rootfs")
|
||||
msg_ok "$(translate "Staging ready.") $(translate "Data size:") $staged_size"
|
||||
|
||||
export HB_NOTIFY_JOB_ID="manual-borg-${archive_name}"
|
||||
export HB_NOTIFY_BACKEND="borg"
|
||||
export HB_NOTIFY_DESTINATION="$repo"
|
||||
export HB_NOTIFY_PROFILE_MODE="$profile_mode"
|
||||
export HB_NOTIFY_LOG_FILE="$log_file"
|
||||
export HB_NOTIFY_DATA_SIZE="$staged_size"
|
||||
hb_notify_lifecycle "start"
|
||||
|
||||
msg_info "$(translate "Initializing Borg repository if needed...")"
|
||||
if ! hb_borg_init_if_needed "$borg_bin" "$repo" "${BORG_ENCRYPT_MODE:-none}" >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Failed to initialize Borg repository at:") $repo"
|
||||
@@ -252,9 +281,19 @@ _bk_borg() {
|
||||
[[ -s "$log_file" ]] && echo -e "${TAB}${BGN}$(translate "Log:")${CL} ${BL}${log_file}${CL}"
|
||||
echo -e ""
|
||||
msg_ok "$(translate "Backup completed successfully.")"
|
||||
export HB_NOTIFY_ARCHIVE_SIZE="$borg_compressed"
|
||||
export HB_NOTIFY_DURATION="$(hb_human_elapsed "$elapsed" 2>/dev/null || echo "${elapsed}s")"
|
||||
hb_notify_lifecycle "complete"
|
||||
else
|
||||
echo -e ""
|
||||
msg_error "$(translate "Borg backup failed.")"
|
||||
local _hb_reason
|
||||
_hb_reason=$(grep -iE 'error|fail|fatal|abort' "$log_file" 2>/dev/null | tail -1 | sed 's/^[[:space:]]*//')
|
||||
[[ -z "$_hb_reason" ]] && _hb_reason="borg create returned non-zero"
|
||||
export HB_NOTIFY_ARCHIVE_SIZE="-"
|
||||
export HB_NOTIFY_DURATION="$(hb_human_elapsed "$((SECONDS - t_start))" 2>/dev/null || echo "")"
|
||||
export HB_NOTIFY_REASON="$_hb_reason"
|
||||
hb_notify_lifecycle "fail"
|
||||
hb_show_log "$log_file" "$(translate "Borg backup error log")"
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
@@ -331,6 +370,14 @@ _bk_local() {
|
||||
staged_size=$(hb_file_size "$staging_root/rootfs")
|
||||
msg_ok "$(translate "Staging ready.") $(translate "Data size:") $staged_size"
|
||||
|
||||
export HB_NOTIFY_JOB_ID="manual-local-$(basename "$archive" .tar.zst)"
|
||||
export HB_NOTIFY_BACKEND="local"
|
||||
export HB_NOTIFY_DESTINATION="$archive"
|
||||
export HB_NOTIFY_PROFILE_MODE="$profile_mode"
|
||||
export HB_NOTIFY_LOG_FILE="$log_file"
|
||||
export HB_NOTIFY_DATA_SIZE="$staged_size"
|
||||
hb_notify_lifecycle "start"
|
||||
|
||||
echo -e ""
|
||||
msg_info "$(translate "Creating compressed archive...")"
|
||||
stop_spinner
|
||||
@@ -384,9 +431,19 @@ _bk_local() {
|
||||
[[ -s "$log_file" ]] && echo -e "${TAB}${BGN}$(translate "Log:")${CL} ${BL}${log_file}${CL}"
|
||||
echo -e ""
|
||||
msg_ok "$(translate "Backup completed successfully.")"
|
||||
export HB_NOTIFY_ARCHIVE_SIZE="$archive_size"
|
||||
export HB_NOTIFY_DURATION="$(hb_human_elapsed "$elapsed" 2>/dev/null || echo "${elapsed}s")"
|
||||
hb_notify_lifecycle "complete"
|
||||
else
|
||||
echo -e ""
|
||||
msg_error "$(translate "Local backup failed.")"
|
||||
local _hb_reason
|
||||
_hb_reason=$(grep -iE 'error|fail|fatal|abort' "$log_file" 2>/dev/null | tail -1 | sed 's/^[[:space:]]*//')
|
||||
[[ -z "$_hb_reason" ]] && _hb_reason="tar/zstd returned non-zero"
|
||||
export HB_NOTIFY_ARCHIVE_SIZE="-"
|
||||
export HB_NOTIFY_DURATION="$(hb_human_elapsed "$elapsed" 2>/dev/null || echo "${elapsed}s")"
|
||||
export HB_NOTIFY_REASON="$_hb_reason"
|
||||
hb_notify_lifecycle "fail"
|
||||
hb_show_log "$log_file" "$(translate "Local backup error log")"
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
|
||||
@@ -2424,6 +2424,86 @@ hb_file_size() {
|
||||
fi
|
||||
}
|
||||
|
||||
# POST a Host Backup lifecycle event to the local webhook so the
|
||||
# Monitor notification pipeline can route it through the host_backup_*
|
||||
# event types (toggle-able per channel in Settings). Used by both the
|
||||
# scheduled runner (`run_scheduled_backup.sh`) and the manual flow
|
||||
# (`backup_host.sh`).
|
||||
#
|
||||
# Arg: action (start|complete|fail)
|
||||
# Required env: HB_NOTIFY_JOB_ID (or `job_id` shell var)
|
||||
# Optional env (per the host_backup_* template fields):
|
||||
# HB_NOTIFY_BACKEND = pbs|local|borg
|
||||
# HB_NOTIFY_DESTINATION = path / URI
|
||||
# HB_NOTIFY_PROFILE_MODE = default|custom
|
||||
# HB_NOTIFY_DATA_SIZE = staged data (e.g. "12.4 GiB")
|
||||
# HB_NOTIFY_ARCHIVE_SIZE = output archive size (local) or '-'
|
||||
# HB_NOTIFY_DURATION = pretty elapsed (e.g. "2m 13s")
|
||||
# HB_NOTIFY_LOG_FILE = path to job log (rendered in fail body)
|
||||
# HB_NOTIFY_REASON = short failure reason (last error line)
|
||||
#
|
||||
# Best-effort: the curl is bounded (--connect-timeout 3 / --max-time 5)
|
||||
# and silenced so a Monitor outage never aborts the backup itself.
|
||||
hb_notify_lifecycle() {
|
||||
command -v jq >/dev/null 2>&1 || return 0
|
||||
command -v curl >/dev/null 2>&1 || return 0
|
||||
|
||||
local action="$1"
|
||||
local jid="${HB_NOTIFY_JOB_ID:-${job_id:-}}"
|
||||
local severity="info" title="Host backup ${action}: ${jid:-?}"
|
||||
case "$action" in
|
||||
fail) severity="error"; title="Host backup FAILED: ${jid:-?}" ;;
|
||||
complete) title="Host backup complete: ${jid:-?}" ;;
|
||||
start) title="Host backup started: ${jid:-?}" ;;
|
||||
esac
|
||||
|
||||
local pve_type="proxmenux-host-backup-${action}"
|
||||
local host
|
||||
host="$(hostname 2>/dev/null || echo unknown)"
|
||||
|
||||
local message="Backend: ${HB_NOTIFY_BACKEND:-}
|
||||
Destination: ${HB_NOTIFY_DESTINATION:-}
|
||||
Profile: ${HB_NOTIFY_PROFILE_MODE:-default}
|
||||
Data size: ${HB_NOTIFY_DATA_SIZE:-}
|
||||
Archive size: ${HB_NOTIFY_ARCHIVE_SIZE:-}
|
||||
Duration: ${HB_NOTIFY_DURATION:-}"
|
||||
[[ "$action" == "fail" ]] && message+="
|
||||
Reason: ${HB_NOTIFY_REASON:-unknown}
|
||||
Log: ${HB_NOTIFY_LOG_FILE:-}"
|
||||
|
||||
local payload
|
||||
payload=$(jq -nc \
|
||||
--arg t "$title" \
|
||||
--arg m "$message" \
|
||||
--arg s "$severity" \
|
||||
--arg ts "$(date -Iseconds)" \
|
||||
--arg pty "$pve_type" \
|
||||
--arg host "$host" \
|
||||
--arg jid "${jid:-}" \
|
||||
--arg backend "${HB_NOTIFY_BACKEND:-}" \
|
||||
--arg dest "${HB_NOTIFY_DESTINATION:-}" \
|
||||
--arg profile "${HB_NOTIFY_PROFILE_MODE:-default}" \
|
||||
--arg dsize "${HB_NOTIFY_DATA_SIZE:-}" \
|
||||
--arg asize "${HB_NOTIFY_ARCHIVE_SIZE:-}" \
|
||||
--arg dur "${HB_NOTIFY_DURATION:-}" \
|
||||
--arg log "${HB_NOTIFY_LOG_FILE:-}" \
|
||||
--arg reason "${HB_NOTIFY_REASON:-}" \
|
||||
'{title:$t, message:$m, severity:$s, timestamp:$ts,
|
||||
fields:{type:$pty, hostname:$host, "job-id":$jid,
|
||||
backend:$backend, destination:$dest,
|
||||
profile_mode:$profile, data_size:$dsize,
|
||||
archive_size:$asize, duration:$dur,
|
||||
log_file:$log, reason:$reason}}' \
|
||||
2>/dev/null)
|
||||
[[ -z "$payload" ]] && return 0
|
||||
curl -sk --connect-timeout 3 --max-time 5 \
|
||||
-X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload" \
|
||||
http://127.0.0.1:8008/api/notifications/webhook \
|
||||
>/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
hb_show_log() {
|
||||
local logfile="$1" title="${2:-$(hb_translate "Operation log")}"
|
||||
[[ -f "$logfile" && -s "$logfile" ]] || return 0
|
||||
|
||||
@@ -384,6 +384,21 @@ main() {
|
||||
echo "Profile: ${PROFILE_MODE:-default}"
|
||||
} >"$log_file"
|
||||
|
||||
# Fire the lifecycle "start" event. Per-channel/per-event toggles in
|
||||
# Settings decide whether the user actually receives it
|
||||
# (host_backup_start ships with default_enabled=False).
|
||||
local _hb_dest=""
|
||||
case "${BACKEND:-}" in
|
||||
local) _hb_dest="${LOCAL_DEST_DIR:-/var/lib/vz/dump}" ;;
|
||||
borg) _hb_dest="${BORG_REPO:-}" ;;
|
||||
pbs) _hb_dest="${PBS_REPOSITORY:-}" ;;
|
||||
esac
|
||||
export HB_NOTIFY_BACKEND="${BACKEND:-}"
|
||||
export HB_NOTIFY_DESTINATION="$_hb_dest"
|
||||
export HB_NOTIFY_PROFILE_MODE="${PROFILE_MODE:-default}"
|
||||
export HB_NOTIFY_LOG_FILE="$log_file"
|
||||
hb_notify_lifecycle "start"
|
||||
|
||||
local -a paths=()
|
||||
if [[ "${PROFILE_MODE:-default}" == "custom" && -f "${JOBS_DIR}/${job_id}.paths" ]]; then
|
||||
mapfile -t paths < "${JOBS_DIR}/${job_id}.paths"
|
||||
@@ -466,15 +481,27 @@ main() {
|
||||
echo "Cleaning up staging area ..." >>"$log_file"
|
||||
rm -rf "$stage_root"
|
||||
|
||||
# Single source of truth for archive_size (was previously computed
|
||||
# only inside the TTY block, which left the notification body with
|
||||
# '-' for headless scheduled runs). Local backends know the actual
|
||||
# output file; PBS / Borg backends manage their own dedupe storage
|
||||
# so we leave '-' meaning "see repository for usage".
|
||||
local archive_size="-"
|
||||
if [[ "${BACKEND:-}" == "local" && -n "$archive_path" && -f "$archive_path" ]]; then
|
||||
archive_size=$(hb_file_size "$archive_path" 2>/dev/null || echo '-')
|
||||
fi
|
||||
local pretty_duration
|
||||
pretty_duration=$(hb_human_elapsed "$elapsed" 2>/dev/null || echo "${elapsed}s")
|
||||
|
||||
if [[ $rc -eq 0 ]]; then
|
||||
echo "RESULT=ok" >>"$summary_file"
|
||||
echo "LOG_FILE=${log_file}" >>"$summary_file"
|
||||
echo "=== Job finished OK at $(date -Iseconds) ===" >>"$log_file"
|
||||
export HB_NOTIFY_DATA_SIZE="$staged_size"
|
||||
export HB_NOTIFY_ARCHIVE_SIZE="$archive_size"
|
||||
export HB_NOTIFY_DURATION="$pretty_duration"
|
||||
hb_notify_lifecycle "complete"
|
||||
if (( TTY )); then
|
||||
local archive_size="-"
|
||||
case "${BACKEND:-}" in
|
||||
local) [[ -f "$archive_path" ]] && archive_size=$(hb_file_size "$archive_path") ;;
|
||||
esac
|
||||
local method_label
|
||||
case "${BACKEND:-}" in
|
||||
local) method_label="Local archive (tar)" ;;
|
||||
@@ -499,6 +526,17 @@ main() {
|
||||
echo "RESULT=failed" >>"$summary_file"
|
||||
echo "LOG_FILE=${log_file}" >>"$summary_file"
|
||||
echo "=== Job finished with errors at $(date -Iseconds) ===" >>"$log_file"
|
||||
# Build a one-line reason from the last error-ish line in the log
|
||||
# so the notification body has something actionable rather than a
|
||||
# generic "Reason: unknown". Falls back to the literal exit code.
|
||||
local _hb_reason=""
|
||||
_hb_reason=$(grep -iE 'error|fail|fatal|abort' "$log_file" 2>/dev/null | tail -1 | sed 's/^[[:space:]]*//')
|
||||
[[ -z "$_hb_reason" ]] && _hb_reason="Runner exited with status ${rc}"
|
||||
export HB_NOTIFY_DATA_SIZE="${staged_size:-}"
|
||||
export HB_NOTIFY_ARCHIVE_SIZE="$archive_size"
|
||||
export HB_NOTIFY_DURATION="$pretty_duration"
|
||||
export HB_NOTIFY_REASON="$_hb_reason"
|
||||
hb_notify_lifecycle "fail"
|
||||
(( TTY )) && msg_error "$(translate "Backup failed. See log:") $log_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -40,6 +40,14 @@ if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
# Pull in ensure_repositories + PROXMENUX_UTILS — customizable already
|
||||
# sources this helper; auto did not, so a function that calls
|
||||
# `ensure_repositories` (setup_proxmox_repositories below) needs the
|
||||
# import here too.
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/utils-install-functions.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/utils-install-functions.sh"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
@@ -191,6 +199,35 @@ remove_subscription_banner() {
|
||||
|
||||
|
||||
|
||||
setup_proxmox_repositories() {
|
||||
local FUNC_VERSION="1.1"
|
||||
# Description: Configure Proxmox + Debian APT repositories (no-subscription)
|
||||
# and set the correct file permissions.
|
||||
|
||||
msg_info2 "$(translate "Configuring Proxmox APT repositories...")"
|
||||
|
||||
if ! ensure_repositories; then
|
||||
msg_error "$(translate "Failed to configure Proxmox repositories")"
|
||||
register_tool "proxmox_repos" false "$FUNC_VERSION"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Defensive re-chmod: if the files already existed with the old 0640
|
||||
# permissions there is nothing for `ensure_repositories` to recreate,
|
||||
# so we still flip the bits explicitly here.
|
||||
local f
|
||||
for f in /etc/apt/sources.list.d/proxmox.sources \
|
||||
/etc/apt/sources.list.d/debian.sources \
|
||||
/etc/apt/sources.list.d/pve-no-subscription.list \
|
||||
/etc/apt/sources.list.d/pve-enterprise.list; do
|
||||
[[ -f "$f" ]] && chmod 0644 "$f" 2>/dev/null
|
||||
done
|
||||
|
||||
register_tool "proxmox_repos" true "$FUNC_VERSION"
|
||||
msg_success "$(translate "Proxmox APT repositories configured")"
|
||||
}
|
||||
|
||||
|
||||
configure_time_sync() {
|
||||
local FUNC_VERSION="1.0"
|
||||
# description: Detect timezone from public IP and enable systemd time sync (NTP).
|
||||
|
||||
@@ -101,6 +101,32 @@ register_tool() {
|
||||
|
||||
|
||||
|
||||
setup_proxmox_repositories() {
|
||||
local FUNC_VERSION="1.1"
|
||||
# Description: Configure Proxmox + Debian APT repositories (no-subscription)
|
||||
# and set the correct file permissions.
|
||||
|
||||
msg_info2 "$(translate "Configuring Proxmox APT repositories...")"
|
||||
|
||||
if ! ensure_repositories; then
|
||||
msg_error "$(translate "Failed to configure Proxmox repositories")"
|
||||
register_tool "proxmox_repos" false "$FUNC_VERSION"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local f
|
||||
for f in /etc/apt/sources.list.d/proxmox.sources \
|
||||
/etc/apt/sources.list.d/debian.sources \
|
||||
/etc/apt/sources.list.d/pve-no-subscription.list \
|
||||
/etc/apt/sources.list.d/pve-enterprise.list; do
|
||||
[[ -f "$f" ]] && chmod 0644 "$f" 2>/dev/null
|
||||
done
|
||||
|
||||
register_tool "proxmox_repos" true "$FUNC_VERSION"
|
||||
msg_success "$(translate "Proxmox APT repositories configured")"
|
||||
}
|
||||
|
||||
|
||||
check_extremeshok_warning() {
|
||||
local marker_file="/etc/extremeshok"
|
||||
|
||||
@@ -2930,6 +2956,7 @@ custom_post_category_label() {
|
||||
|
||||
custom_post_description_label() {
|
||||
case "$1" in
|
||||
"Configure Proxmox APT repositories") translate "Configure Proxmox APT repositories" ;;
|
||||
"Update and upgrade system") translate "Update and upgrade system" ;;
|
||||
"Synchronize time automatically") translate "Synchronize time automatically" ;;
|
||||
"Skip downloading additional languages") translate "Skip downloading additional languages" ;;
|
||||
@@ -3049,6 +3076,7 @@ main_menu() {
|
||||
)
|
||||
|
||||
local options=(
|
||||
"Basic Settings|Configure Proxmox APT repositories|REPOS"
|
||||
"Basic Settings|Update and upgrade system|APTUPGRADE"
|
||||
"Basic Settings|Synchronize time automatically|TIMESYNC"
|
||||
"Basic Settings|Skip downloading additional languages|NOAPTLANG"
|
||||
@@ -3184,6 +3212,7 @@ done
|
||||
IFS='|' read -r _ description function_name <<< "$option"
|
||||
if [[ ${selected_functions[$function_name]} -eq 1 ]]; then
|
||||
case $function_name in
|
||||
REPOS) setup_proxmox_repositories ;;
|
||||
APTUPGRADE) apt_upgrade ;;
|
||||
TIMESYNC) configure_time_sync ;;
|
||||
NOAPTLANG) skip_apt_languages ;;
|
||||
|
||||
@@ -75,7 +75,16 @@ SOURCED_CUSTOM=0
|
||||
ensure_flow_loaded() {
|
||||
local source_type="$1"
|
||||
case "$source_type" in
|
||||
auto)
|
||||
# `detected` is the synthetic source the registry assigns to a
|
||||
# tool when a legacy detector finds it on the host but the
|
||||
# entry was never written to installed_tools.json (e.g.
|
||||
# proxmox_repos on a pre-1.2.2 install). Treat it as `auto`
|
||||
# for the source-loading step — the legacy-tool's wrapper
|
||||
# function lives in auto_post_install.sh, and once the update
|
||||
# runs successfully `register_tool` overwrites the synthetic
|
||||
# entry with source="auto" so subsequent runs don't hit this
|
||||
# branch again.
|
||||
auto|detected)
|
||||
if [[ $SOURCED_AUTO -eq 0 ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source "$LOCAL_SCRIPTS/post_install/auto_post_install.sh"
|
||||
@@ -90,7 +99,7 @@ ensure_flow_loaded() {
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: invalid source '$source_type' (must be 'auto' or 'custom')"
|
||||
echo "ERROR: invalid source '$source_type' (must be 'auto', 'custom', or 'detected')"
|
||||
return 2
|
||||
;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user