From 7f1b0ead93e011757dd52b07846060db9ff56e95 Mon Sep 17 00:00:00 2001 From: Sir106 Date: Sat, 18 Jul 2026 22:19:31 +0200 Subject: [PATCH] [tools.update-lxcs] feat: optional reporting success/failures to heathchecks.io (or others) (#15701) * feat: add task monitoring option via e.g. healthchecks.io. To be configured via PING variable in config file. * attach logfile on failure to healthcheck.io message * fixed error status when updating lxc even if finished successful --------- Co-authored-by: Sir106 --- tools/pve/cron-update-lxcs.sh | 11 ++++++-- tools/pve/update-lxcs-cron.sh | 48 ++++++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/tools/pve/cron-update-lxcs.sh b/tools/pve/cron-update-lxcs.sh index c97975c44..437c7e472 100644 --- a/tools/pve/cron-update-lxcs.sh +++ b/tools/pve/cron-update-lxcs.sh @@ -116,6 +116,9 @@ add() { # Add container IDs to exclude from updates (comma-separated): # EXCLUDE=100,101,102 EXCLUDE= + +# Healthchecks.io Ping URL (optional) +# PING_URL= CONF ok "Created config ${CONF_FILE}" fi @@ -235,9 +238,11 @@ view_cron_config() { fi if [[ -f "$CONF_FILE" ]]; then echo -e " \e[36mConfig file:\e[0m ${CONF_FILE}" - local excludes + local excludes ping_url excludes=$(grep -oP '^\s*EXCLUDE\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null || true) + ping_url=$(grep -oP '^\s*PING_URL\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null | tr -d '"' | tr -d "'" || true) echo -e " \e[36mExcluded:\e[0m ${excludes:-(none)}" + echo -e " \e[36mPing URL:\e[0m ${ping_url:-(none)}" echo "" echo -e " \e[90m--- ${CONF_FILE} ---\e[0m" cat "$CONF_FILE" @@ -284,9 +289,11 @@ show_status() { fi if [[ -f "$CONF_FILE" ]]; then - local excludes + local excludes ping_url excludes=$(grep -oP '^\s*EXCLUDE\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null || echo "(none)") + ping_url=$(grep -oP '^\s*PING_URL\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null | tr -d '"' | tr -d "'" || echo "(none)") echo -e " \e[36mExcluded:\e[0m ${excludes:-"(none)"}" + echo -e " \e[36mPing URL:\e[0m ${ping_url:-"(none)"}" fi if [[ -f "$LOG_FILE" ]]; then diff --git a/tools/pve/update-lxcs-cron.sh b/tools/pve/update-lxcs-cron.sh index d7abc4cae..0e021944a 100644 --- a/tools/pve/update-lxcs-cron.sh +++ b/tools/pve/update-lxcs-cron.sh @@ -11,14 +11,15 @@ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin CONF_FILE="/etc/update-lxcs.conf" - -echo -e "\n $(date)" +LOG_FILE="/var/log/update-lxcs-cron.log" +PING_URL="" # Collect excluded containers from arguments excluded_containers=("$@") -# Merge exclusions from config file if it exists +# Merge exclusions and healthchecks URL from config file if it exists if [[ -f "$CONF_FILE" ]]; then + PING_URL=$(grep -oP '^\s*PING_URL\s*=\s*\K.+' "$CONF_FILE" 2>/dev/null | tr -d '"' | tr -d "'" || true) conf_exclude=$(grep -oP '^\s*EXCLUDE\s*=\s*\K[0-9,]+' "$CONF_FILE" 2>/dev/null || true) IFS=',' read -ra conf_ids <<<"$conf_exclude" for id in "${conf_ids[@]}"; do @@ -27,6 +28,17 @@ if [[ -f "$CONF_FILE" ]]; then done fi +# Overwrite logfile on each run when healthchecks is used +if [[ -n "$PING_URL" ]]; then + true > "$LOG_FILE" +fi + +if [[ -n "$PING_URL" ]]; then + curl -fsS -m 10 --retry 5 "${PING_URL}/start" -o /dev/null 2>/dev/null || true +fi + +echo -e "\n $(date)" + function update_container() { local container=$1 local name @@ -38,12 +50,36 @@ function update_container() { alpine) pct exec "$container" -- ash -c "apk -U upgrade" ;; archlinux) pct exec "$container" -- bash -c "pacman -Syyu --noconfirm" ;; fedora | rocky | centos | alma) pct exec "$container" -- bash -c "dnf -y update && dnf -y upgrade" ;; - ubuntu | debian | devuan) pct exec "$container" -- bash -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::='--force-confold' dist-upgrade -y; rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED" ;; + ubuntu | debian | devuan) pct exec "$container" -- bash -c "apt-get update; DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::='--force-confold' dist-upgrade -y; status=\$?; rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED || true; exit \$status" ;; opensuse) pct exec "$container" -- bash -c "zypper ref && zypper --non-interactive dup" ;; *) echo " [Warn] Unknown OS type '$os' for container $container, skipping" ;; esac } +update_status=0 + +# Define exit handler to send healthchecks.io status (with logfile on failure/success) +function exit_handler() { + local exit_code=$? + if [[ -n "$PING_URL" ]]; then + sync + if [[ $exit_code -ne 0 || $update_status -ne 0 ]]; then + if [[ -f "$LOG_FILE" ]]; then + curl -fsS -m 10 --retry 5 --data-binary @"$LOG_FILE" "${PING_URL}/fail" -o /dev/null 2>/dev/null || true + else + curl -fsS -m 10 --retry 5 "${PING_URL}/fail" -o /dev/null 2>/dev/null || true + fi + else + if [[ -f "$LOG_FILE" ]]; then + curl -fsS -m 10 --retry 5 --data-binary @"$LOG_FILE" "$PING_URL" -o /dev/null 2>/dev/null || true + else + curl -fsS -m 10 --retry 5 "$PING_URL" -o /dev/null 2>/dev/null || true + fi + fi + fi +} +trap exit_handler EXIT + for container in $(pct list | awk '{if(NR>1) print $1}'); do excluded=false for excluded_container in "${excluded_containers[@]}"; do @@ -65,7 +101,7 @@ for container in $(pct list | awk '{if(NR>1) print $1}'); do echo -e "[Info] Starting $container" pct start "$container" sleep 5 - update_container "$container" || echo " [Error] Update failed for $container" + update_container "$container" || { echo " [Error] Update failed for $container"; update_status=1; } # check if patchmon agent is present in container and run a report if found if pct exec "$container" -- [ -e "/usr/local/bin/patchmon-agent" ]; then echo -e "${BL}[Info]${GN} patchmon-agent found in ${BL} $container ${CL}, triggering report. \n" @@ -74,7 +110,7 @@ for container in $(pct list | awk '{if(NR>1) print $1}'); do echo -e "[Info] Shutting down $container" pct shutdown "$container" --timeout 60 & elif [ "$status" == "status: running" ]; then - update_container "$container" || echo " [Error] Update failed for $container" + update_container "$container" || { echo " [Error] Update failed for $container"; update_status=1; } # check if patchmon agent is present in container and run a report if found if pct exec "$container" -- [ -e "/usr/local/bin/patchmon-agent" ]; then echo -e "${BL}[Info]${GN} patchmon-agent found in ${BL} $container ${CL}, triggering report. \n"