From d12e034ef1fb4227eb0dc2059703e5ea5b30febf Mon Sep 17 00:00:00 2001 From: FailedProxy Date: Wed, 8 Apr 2026 21:42:56 -0400 Subject: [PATCH] added notification support, and added to a few scripts . need to update the rest --- Docker_essentials/docker_daily_restart.sh | 184 ++++++++++++++++++++++ Docker_essentials/docker_watchdog.sh | 7 +- Master.conf | 19 +++ common.sh | 53 ++++++- 4 files changed, 260 insertions(+), 3 deletions(-) create mode 100644 Docker_essentials/docker_daily_restart.sh diff --git a/Docker_essentials/docker_daily_restart.sh b/Docker_essentials/docker_daily_restart.sh new file mode 100644 index 0000000..e516b7d --- /dev/null +++ b/Docker_essentials/docker_daily_restart.sh @@ -0,0 +1,184 @@ +#!/bin/bash +# ----------------------------------------------------------------------------------------------- +# --------------------------------- Docker Daily Restart --------------------------------------- +# ----------------------------------------------------------------------------------------------- +# Restarts or starts specified Docker containers with retry logic. +# Containers are configured in Master.conf under DAILY_RESTART_CONTAINERS. +# Uses global RETRY_COUNT and SLEEP from Master.conf for retry behaviour. +# Sends notifications on completion or failure via common.sh notify(). +# Supports --dry-run to preview what would be restarted without taking action. +# ----------------------------------------------------------------------------------------------- + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +source "$SCRIPT_DIR/../Master.conf" +source "$SCRIPT_DIR/../common.sh" + +parse_args "$@" + +# ----------------------------------------------------------------------------------------------- +# ━━━ $ICON_GEAR Setup ━━━ +# ----------------------------------------------------------------------------------------------- +echo "" +echo "━━━ $ICON_GEAR Setup ━━━" + +# ROOT CHECK +if [[ "$EUID" -ne 0 ]]; then + error "Must be run as root" + exit 1 +fi + +success "Running as root" + +# Verify Docker is available +if ! command -v docker &>/dev/null; then + error "Docker command not found — check PATH or Docker installation" + notify "Docker daily restart failed — Docker not found on $(hostname)" "Docker Daily Restart" "alert" + exit 1 +fi + +success "Docker found" + +# ----------------------------------------------------------------------------------------------- +# ━━━ $ICON_SUMMARY Status ━━━ +# ----------------------------------------------------------------------------------------------- +if [[ "$SHOW_STATUS" == true ]]; then + echo "" + echo "━━━━━ $ICON_SUMMARY STATUS ━━━━━" + echo "$ICON_CONTAINERS Containers: ${DAILY_RESTART_CONTAINERS[*]}" + echo "$ICON_RETRY Retries: $RETRY_COUNT" + echo "$ICON_TIME Sleep: ${SLEEP}s between retries" + echo "$ICON_NOTIFY Notifications: unRAID=${NOTIFY_UNRAID:-false} Discord=$([[ -n "${DISCORD_WEBHOOK:-}" ]] && echo enabled || echo disabled)" + echo "$ICON_GEAR Dry Run: $DRY_RUN" + echo "━━━━━━━━━━━━━━━━━━━━━━━" + exit 0 +fi + +[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no containers will be restarted" + +# ----------------------------------------------------------------------------------------------- +# FUNCTIONS +# ----------------------------------------------------------------------------------------------- + +# Attempts a docker command up to RETRY_COUNT times with SLEEP seconds between attempts. +# Returns 0 on success, 1 if all attempts fail. +# Usage: retry_docker docker restart Emby +retry_docker() { + local attempt=1 + + while [[ "$attempt" -le "$RETRY_COUNT" ]]; do + info "$ICON_RETRY Attempt $attempt of $RETRY_COUNT: $*" + + if "$@"; then + success "Succeeded on attempt $attempt" + return 0 + else + warn "Attempt $attempt failed" + (( attempt++ )) + [[ "$attempt" -le "$RETRY_COUNT" ]] && sleep "$SLEEP" + fi + done + + error "Command failed after $RETRY_COUNT attempts: $*" + return 1 +} + +# ----------------------------------------------------------------------------------------------- +# ━━━ $ICON_CONTAINERS $ICON_STOP $ICON_START Daily Restart ━━━ +# ----------------------------------------------------------------------------------------------- +echo "" +echo "━━━ $ICON_CONTAINERS Daily Restart — $(date '+%Y-%m-%d %H:%M:%S') ━━━" +echo "$ICON_CONTAINERS Containers: ${DAILY_RESTART_CONTAINERS[*]}" +echo "$ICON_RETRY Retries: $RETRY_COUNT" +echo "" + +START=$(date +%s) +FAILED=() +RESTARTED=() +STARTED=() + +for container in "${DAILY_RESTART_CONTAINERS[@]}"; do + echo "━━━ $ICON_CONTAINERS $container ━━━" + + # Verify container exists + if ! docker inspect "$container" &>/dev/null; then + error "$container does not exist — skipping" + FAILED+=("$container") + echo "" + continue + fi + + STATUS=$(docker inspect -f '{{.State.Running}}' "$container" 2>/dev/null) + + case "$STATUS" in + true) + echo "$ICON_RUNNING $container is running — restarting..." + + if [[ "$DRY_RUN" == true ]]; then + warn "DRY RUN — would restart $container" + else + if retry_docker docker restart "$container"; then + echo "$ICON_STARTED $container restarted" + RESTARTED+=("$container") + else + error "Failed to restart $container" + FAILED+=("$container") + fi + fi + ;; + false) + echo "$ICON_NOT_RUNNING $container is stopped — starting..." + + if [[ "$DRY_RUN" == true ]]; then + warn "DRY RUN — would start $container" + else + if retry_docker docker start "$container"; then + echo "$ICON_STARTED $container started" + STARTED+=("$container") + else + error "Failed to start $container" + FAILED+=("$container") + fi + fi + ;; + *) + error "Unknown status for $container: $STATUS" + FAILED+=("$container") + ;; + esac + + echo "" +done + +END=$(date +%s) + +# ----------------------------------------------------------------------------------------------- +# ━━━ $ICON_SUMMARY Summary ━━━ +# ----------------------------------------------------------------------------------------------- +echo "━━━━━ $ICON_SUMMARY DAILY RESTART SUMMARY ━━━━━" +echo "$ICON_TIME Duration: $(format_duration $((END - START)))" + +if [[ ${#RESTARTED[@]} -gt 0 ]]; then + echo "$ICON_STARTED Restarted: ${RESTARTED[*]}" +fi +if [[ ${#STARTED[@]} -gt 0 ]]; then + echo "$ICON_STARTED Started: ${STARTED[*]}" +fi +if [[ ${#FAILED[@]} -gt 0 ]]; then + echo "$ICON_ERROR Failed: ${FAILED[*]}" +fi + +if [[ "$DRY_RUN" == true ]]; then + echo "$ICON_WARN Status: DRY RUN — no changes made" +elif [[ ${#FAILED[@]} -eq 0 ]]; then + echo "$ICON_DONE Status: $ICON_SUCCESS ALL DONE" + notify "Daily restart complete — ${#RESTARTED[@]} restarted, ${#STARTED[@]} started" "Docker Daily Restart" "normal" +else + echo "$ICON_ERROR Status: $ICON_ERROR ${#FAILED[@]} container(s) failed" + notify "Daily restart completed with errors — failed: ${FAILED[*]}" "Docker Daily Restart" "alert" +fi + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + +[[ ${#FAILED[@]} -gt 0 ]] && exit 1 +exit 0 \ No newline at end of file diff --git a/Docker_essentials/docker_watchdog.sh b/Docker_essentials/docker_watchdog.sh index a0a4849..1c877de 100644 --- a/Docker_essentials/docker_watchdog.sh +++ b/Docker_essentials/docker_watchdog.sh @@ -66,6 +66,7 @@ if [[ "$SHOW_STATUS" == true ]]; then echo "$ICON_RETRY CPU fail limit: ${CPU_FAIL_LIMIT} strikes" echo "$ICON_PING Resp fail limit: ${RESP_FAIL_LIMIT} strikes" echo "$ICON_TIME Curl timeout: ${CURL_TIMEOUT}s" + echo "$ICON_NOTIFY Notifications: unRAID=${NOTIFY_UNRAID:-false} Discord=$([[ -n "${DISCORD_WEBHOOK:-}" ]] && echo enabled || echo disabled)" echo "$ICON_GEAR Dry Run: $DRY_RUN" echo "━━━━━━━━━━━━━━━━━━━━━━━" exit 0 @@ -118,7 +119,7 @@ convert_to_mb() { esac } -# Restarts a container locally. +# Restarts a container locally and sends a notification. # In dry run mode reports what would happen without acting. restart_container() { local container="$1" reason="$2" @@ -131,9 +132,11 @@ restart_container() { info "Restarting $container ($reason)..." if docker restart "$container" >/dev/null 2>&1; then echo "$ICON_STARTED $container restarted" + notify "$container restarted — $reason" "Docker Watchdog" "warning" log "Restarted $container — reason: $reason" else error "Failed to restart $container" + notify "Failed to restart $container — $reason" "Docker Watchdog" "alert" fi } @@ -258,8 +261,8 @@ echo "" echo "━━━ $ICON_WATCHDOG Watchdog Check — $(date '+%Y-%m-%d %H:%M:%S') ━━━" echo "" -RESTARTED=() SKIPPED=() +RESTARTED=0 START=$(date +%s) diff --git a/Master.conf b/Master.conf index 9a2f80d..921973d 100644 --- a/Master.conf +++ b/Master.conf @@ -15,6 +15,13 @@ # ━━━ Logging ━━━ ENABLE_LOGGING=true # false = only echo user-facing messages +# ━━━ Notifications ━━━ +# unRAID native notification system — set to true to enable +# Configure unRAID to send errors only: Settings → Notification Settings + NOTIFY_UNRAID=true +# Discord webhook URL — leave blank to disable + DISCORD_WEBHOOK="" + # ━━━ Git, Pull & Execute Script ━━━ REPO_SSH="git@192.168.50.2:FailedProxy/Unraid_Scripts.git" TARGET_DIR="/mnt/user/appdata/unraid_scripts" @@ -80,6 +87,18 @@ DAILY_SYNC_SHARES=( # clear_logs.sh system log file paths LOG_FILES=(/var/log/syslog /var/log/messages /var/log/dmesg) +# ━━━ Docker Daily Restart ━━━ +# Containers to restart daily — space-separated, case-sensitive +# These are the same containers as critical-data and other rsync profiles +DAILY_RESTART_CONTAINERS=( + "NginxProxyManager" + "Authelia" + "Dispatcharr-Iptv-Users" + "Dispatcharr" + "Dispatcharr-Basic" + "Code-Server" +) + # ━━━ Docker Watchdog ━━━ # Containers to monitor with their memory hard limits in MB # 20GB=20480 16GB=16384 14GB=14336 12GB=12288 10GB=10240 8GB=8192 6GB=6144 4GB=4096 1GB=1024 diff --git a/common.sh b/common.sh index 3dc6ddf..0cd2a20 100644 --- a/common.sh +++ b/common.sh @@ -2,7 +2,7 @@ # ----------------------------------------------------------------------------------------------- # ----------------- UNRAID OPS COMMON LIBRARY (STABLE FRAMEWORK v1) ---------------------------- # ----------------------------------------------------------------------------------------------- -# Version: 2.2 +# Version: 2.3 # ----------------------------------------------------------------------------------------------- # Changelog: # v1.0 — Initial stable framework @@ -34,6 +34,9 @@ # v2.1 — ICON_ZFS and ICON_MEM added for ZFS and memory diagnostics # Diagnostics icon group added to icon block # v2.2 — ICON_WATCHDOG added for Docker watchdog monitoring operations +# v2.3 — ICON_NOTIFY added for notification operations +# notify() added — shared notification function supporting unRAID native and Discord +# NOTIFY_UNRAID and DISCORD_WEBHOOK configured in Master.conf # ----------------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------- @@ -82,6 +85,9 @@ ICON_ZFS="📊" # ZFS ARC statistics ICON_MEM="🧠" # memory status ICON_WATCHDOG="🐾" # docker watchdog monitoring operations +# Notifications +ICON_NOTIFY="🔔" # notification operations + # Output ICON_INFO="ℹ️" ICON_WARN="⚠️" @@ -102,6 +108,51 @@ log() { [[ "${ENABLE_LOGGING:-false}" == true ]] && echo "[LOG] $*" } +# ----------------------------------------------------------------------------------------------- +# NOTIFICATION +# Sends a notification via unRAID native system and/or Discord webhook. +# Both channels are optional and independently controlled via Master.conf. +# unRAID native: requires NOTIFY_UNRAID=true and the dynamix notify script to be present. +# Discord: requires DISCORD_WEBHOOK to be set to a valid webhook URL. +# Severity levels: normal, warning, alert — maps to unRAID notification severity. +# Usage: notify "message" "subject" "severity" +# notify "Rsync failed: Movies" "Rsync Alert" "alert" +# notify "Daily sync complete" "Daily Sync" "normal" +# ----------------------------------------------------------------------------------------------- +notify() { + local message="$1" + local subject="${2:-unRAID Notification}" + local severity="${3:-normal}" + + log "$ICON_NOTIFY Sending notification: $subject — $message" + + # unRAID native notification + if [[ "${NOTIFY_UNRAID:-false}" == true ]]; then + local notify_script="/usr/local/emhttp/plugins/dynamix/scripts/notify" + if [[ -x "$notify_script" ]]; then + "$notify_script" -s "$subject" -d "$message" -i "$severity" 2>/dev/null + log "$ICON_NOTIFY unRAID notification sent" + else + log "$ICON_NOTIFY unRAID notify script not found — skipping" + fi + fi + + # Discord webhook notification + if [[ -n "${DISCORD_WEBHOOK:-}" ]]; then + local hostname + hostname=$(hostname) + local payload + payload=$(printf '{"content": "%s — **%s**\\n%s"}' \ + "$ICON_NOTIFY" "$subject" "$message") + if curl -s -H "Content-Type: application/json" \ + -d "$payload" "$DISCORD_WEBHOOK" >/dev/null 2>&1; then + log "$ICON_NOTIFY Discord notification sent" + else + warn "Discord notification failed — check DISCORD_WEBHOOK in Master.conf" + fi + fi +} + # ----------------------------------------------------------------------------------------------- # DURATION FORMATTER # Converts raw seconds into a human readable string — e.g. 10m53s or 47s