diff --git a/plex32_backup2.sh b/plex32_backup2.sh deleted file mode 100644 index af06a64..0000000 --- a/plex32_backup2.sh +++ /dev/null @@ -1,365 +0,0 @@ -#!/bin/bash -# ============================================================= -# PLEX32 — Config Backup Script -# Creates tar archives of Plex and Tautulli configs -# Copies to NAS08 via NFS as single files -# Keeps last 3 backups, deletes older ones -# Sends HTML email report in KingDezigns style -# Location: /usr/scripts/plex32/plex32_backup.sh -# Schedule: Every 3 days at 2:00 AM (cron) -# ============================================================= - -# --- Config --- -HOSTNAME="plex32" -PLEX_SRC="/opt/plex/config" -TAUTULLI_SRC="/opt/tautulli/config" -NFS_DEST="/mnt/plex/config" -TAUTULLI_LOC="backups/tautulli" -PLEX_LOC="backups/plex" - -TMP_DIR="/tmp/plex32-backup" -LOG_DIR="/var/log/plex32-backup" -LOG_FILE="$LOG_DIR/backup-$(date +%Y%m%d).log" -RETENTION_COUNT=3 -COMPOSE_DIR="/home/rufusking/docker/plex" - -DATESTAMP=$(date '+%Y-%m-%d') -TIMESTAMP=$(date '+%B %d, %Y at %I:%M %p') - -PLEX_ARCHIVE="plex-config-${DATESTAMP}.tar.gz" -TAUTULLI_ARCHIVE="tautulli-config-${DATESTAMP}.tar.gz" - -SMTP_SERVER="smtppro.zoho.com" -SMTP_PORT=465 -SMTP_USER="rufus.king@kingdezigns.com" -SMTP_PASS="$(cat /etc/plex32-smtp-pass 2>/dev/null)" -EMAIL_TO="rufus.king@kingdezigns.com" -EMAIL_FROM="rufus.king@kingdezigns.com" - -# --- Setup --- -mkdir -p "$LOG_DIR" "$TMP_DIR" -START_TIME=$(date +%s) - -exec > >(tee -a "$LOG_FILE") 2>&1 -echo "[$(date '+%Y-%m-%d %H:%M:%S')] PLEX32 backup started" - -# --- Check NFS mount --- -if ! mountpoint -q "$NFS_DEST"; then - echo "[ERROR] NFS mount not available: $NFS_DEST" - exit 1 -fi - -# --- Stop containers --- -echo "[$(date '+%Y-%m-%d %H:%M:%S')] Stopping Plex and Tautulli containers..." -cd "$COMPOSE_DIR" && docker compose down -STOP_STATUS=$? -if [ $STOP_STATUS -ne 0 ]; then - echo "[ERROR] Failed to stop containers cleanly" -fi - -# --- Tar Plex config --- -echo "[$(date '+%Y-%m-%d %H:%M:%S')] Creating Plex config archive..." -PLEX_START=$(date +%s) -tar -czf "$TMP_DIR/$PLEX_ARCHIVE" \ - --exclude="config/Library/Application Support/Plex Media Server/Cache" \ - --exclude="config/Library/Application Support/Plex Media Server/Logs" \ - --exclude="config/Library/Application Support/Plex Media Server/Crash Reports" \ - -C /opt/plex config 2>&1 -PLEX_TAR_STATUS=$? -PLEX_END=$(date +%s) -PLEX_DURATION=$((PLEX_END - PLEX_START)) - -if [ $PLEX_TAR_STATUS -eq 0 ]; then - echo "[$(date '+%Y-%m-%d %H:%M:%S')] Plex archive created in ${PLEX_DURATION}s" -else - echo "[ERROR] Plex tar failed with status $PLEX_TAR_STATUS" -fi - -# --- Tar Tautulli config --- -echo "[$(date '+%Y-%m-%d %H:%M:%S')] Creating Tautulli config archive..." -TAUTULLI_START=$(date +%s) -tar -czf "$TMP_DIR/$TAUTULLI_ARCHIVE" \ - -C /opt/tautulli config 2>&1 -TAUTULLI_TAR_STATUS=$? -TAUTULLI_END=$(date +%s) -TAUTULLI_DURATION=$((TAUTULLI_END - TAUTULLI_START)) - -if [ $TAUTULLI_TAR_STATUS -eq 0 ]; then - echo "[$(date '+%Y-%m-%d %H:%M:%S')] Tautulli archive created in ${TAUTULLI_DURATION}s" -else - echo "[ERROR] Tautulli tar failed with status $TAUTULLI_TAR_STATUS" -fi - -# --- Restart containers --- -echo "[$(date '+%Y-%m-%d %H:%M:%S')] Restarting containers..." -cd "$COMPOSE_DIR" && docker compose up -d -START_STATUS=$? -if [ $START_STATUS -eq 0 ]; then - echo "[$(date '+%Y-%m-%d %H:%M:%S')] Containers restarted successfully" -else - echo "[ERROR] Failed to restart containers — manual intervention required" -fi - -# --- Copy Plex archive to NAS08 --- -echo "[$(date '+%Y-%m-%d %H:%M:%S')] Copying Plex archive to NAS08..." -COPY_PLEX_START=$(date +%s) -cp "$TMP_DIR/$PLEX_ARCHIVE" "$NFS_DEST/$PLEX_LOC/" -PLEX_COPY_STATUS=$? -COPY_PLEX_END=$(date +%s) -PLEX_COPY_DURATION=$((COPY_PLEX_END - COPY_PLEX_START)) - -if [ $PLEX_COPY_STATUS -eq 0 ]; then - echo "[$(date '+%Y-%m-%d %H:%M:%S')] Plex archive copied in ${PLEX_COPY_DURATION}s" -else - echo "[ERROR] Plex archive copy failed" -fi - -# --- Copy Tautulli archive to NAS08 --- -echo "[$(date '+%Y-%m-%d %H:%M:%S')] Copying Tautulli archive to NAS08..." -COPY_TAUTULLI_START=$(date +%s) -cp "$TMP_DIR/$TAUTULLI_ARCHIVE" "$NFS_DEST/$TAUTULLI_LOC/" -TAUTULLI_COPY_STATUS=$? -COPY_TAUTULLI_END=$(date +%s) -TAUTULLI_COPY_DURATION=$((COPY_TAUTULLI_END - COPY_TAUTULLI_START)) - -if [ $TAUTULLI_COPY_STATUS -eq 0 ]; then - echo "[$(date '+%Y-%m-%d %H:%M:%S')] Tautulli archive copied in ${TAUTULLI_COPY_DURATION}s" -else - echo "[ERROR] Tautulli archive copy failed" -fi - -# --- Rotate old backups — keep last 3 --- -echo "[$(date '+%Y-%m-%d %H:%M:%S')] Rotating old backups..." -ls -t "$NFS_DEST/$PLEX_LOC"/plex-config-*.tar.gz 2>/dev/null | tail -n +$((RETENTION_COUNT + 1)) | xargs rm -f -ls -t "$NFS_DEST/$TAUTULLI_LOC"/tautulli-config-*.tar.gz 2>/dev/null | tail -n +$((RETENTION_COUNT + 1)) | xargs rm -f - -# --- Cleanup temp files --- -rm -f "$TMP_DIR/$PLEX_ARCHIVE" "$TMP_DIR/$TAUTULLI_ARCHIVE" - -# --- Sizes --- -PLEX_ARCHIVE_SIZE=$(ls -lh "$NFS_DEST/$PLEX_LOC/$PLEX_ARCHIVE" 2>/dev/null | awk '{print $5}') -TAUTULLI_ARCHIVE_SIZE=$(ls -lh "$NFS_DEST/$TAUTULLI_LOC/$TAUTULLI_ARCHIVE" 2>/dev/null | awk '{print $5}') -NFS_FREE=$(df -h "$NFS_DEST" 2>/dev/null | awk 'NR==2{print $4}') -PLEX_BACKUP_COUNT=$(ls "$NFS_DEST/$PLEX_LOC"/plex-config-*.tar.gz 2>/dev/null | wc -l) -TAUTULLI_BACKUP_COUNT=$(ls "$NFS_DEST/$TAUTULLI_LOC"/tautulli-config-*.tar.gz 2>/dev/null | wc -l) - -# --- Total duration --- -END_TIME=$(date +%s) -TOTAL_DURATION=$((END_TIME - START_TIME)) -TOTAL_MIN=$((TOTAL_DURATION / 60)) -TOTAL_SEC=$((TOTAL_DURATION % 60)) - -# --- Overall status --- -PLEX_STATUS=$((PLEX_TAR_STATUS + PLEX_COPY_STATUS)) -TAUTULLI_STATUS=$((TAUTULLI_TAR_STATUS + TAUTULLI_COPY_STATUS)) - -if [ $PLEX_STATUS -eq 0 ] && [ $TAUTULLI_STATUS -eq 0 ] && [ $START_STATUS -eq 0 ]; then - OVERALL_STATUS="SUCCESS" - STATUS_COLOR="#1a7f4b" - BANNER_ICON="✅" - BANNER_MSG="Backup completed successfully — Plex and Tautulli configs archived to NAS08" - BADGE_COLOR="#1a7f4b" -elif [ $PLEX_STATUS -ne 0 ] && [ $TAUTULLI_STATUS -ne 0 ]; then - OVERALL_STATUS="FAILED" - STATUS_COLOR="#b91c1c" - BANNER_ICON="🔴" - BANNER_MSG="Backup failed — both archive operations encountered errors" - BADGE_COLOR="#b91c1c" -else - OVERALL_STATUS="PARTIAL" - STATUS_COLOR="#b45309" - BANNER_ICON="⚠️" - BANNER_MSG="Backup partially completed — review individual results below" - BADGE_COLOR="#b45309" -fi - -# --- Status labels --- -if [ $PLEX_STATUS -eq 0 ]; then - PLEX_LABEL="✅ SUCCESS" - PLEX_ROW_BG="#f0fdf4" - PLEX_TEXT_COLOR="#166534" -else - PLEX_LABEL="❌ FAILED" - PLEX_ROW_BG="#fff1f2" - PLEX_TEXT_COLOR="#b91c1c" -fi - -if [ $TAUTULLI_STATUS -eq 0 ]; then - TAUTULLI_LABEL="✅ SUCCESS" - TAUTULLI_ROW_BG="#f0fdf4" - TAUTULLI_TEXT_COLOR="#166534" -else - TAUTULLI_LABEL="❌ FAILED" - TAUTULLI_ROW_BG="#fff1f2" - TAUTULLI_TEXT_COLOR="#b91c1c" -fi - -if [ $START_STATUS -eq 0 ]; then - RESTART_LABEL="✅ RUNNING" - RESTART_COLOR="#166534" -else - RESTART_LABEL="❌ CHECK REQUIRED" - RESTART_COLOR="#b91c1c" -fi - -# --- Send email --- -echo "[$(date '+%Y-%m-%d %H:%M:%S')] Sending email report..." - -python3 << PYEOF -import smtplib, ssl -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText - -smtp_server = "$SMTP_SERVER" -smtp_port = $SMTP_PORT -smtp_user = "$SMTP_USER" -smtp_pass = "$SMTP_PASS" -email_to = "$EMAIL_TO" -email_from = "$EMAIL_FROM" - -subject = "PLEX32 Backup — $OVERALL_STATUS — $DATESTAMP" - -html = """ - - - - - -
- - - - - - - - - - - - - - -
- - - -
-
Config Backup
-
🎬 plex32
-
$TIMESTAMP  |  VLAN 50 — Lab/Servers
-
-
$OVERALL_STATUS
-
-
- $BANNER_ICON  $BANNER_MSG -
- - - - - - - - - -
-
-
Duration
-
${TOTAL_MIN}m ${TOTAL_SEC}s
-
-
-
-
Plex Archive
-
$PLEX_ARCHIVE_SIZE
-
-
-
-
Tautulli Archive
-
$TAUTULLI_ARCHIVE_SIZE
-
-
-
-
NAS08 Free
-
$NFS_FREE
-
-
- - -
-
📋 Backup Results
- - - - - - - - - - - - - - - - - - - - - - -
ComponentArchiveCopies KeptDurationStatus
🎬 Plex Config$PLEX_ARCHIVE$PLEX_BACKUP_COUNT / $RETENTION_COUNT${PLEX_DURATION}s tar + ${PLEX_COPY_DURATION}s copy$PLEX_LABEL
📊 Tautulli Config$TAUTULLI_ARCHIVE$TAUTULLI_BACKUP_COUNT / $RETENTION_COUNT${TAUTULLI_DURATION}s tar + ${TAUTULLI_COPY_DURATION}s copy$TAUTULLI_LABEL
-
- - -
- Container Status After Backup - $RESTART_LABEL -
- - -
- Backup Destination - NAS08 (192.168.150.35) via NFS — $NFS_FREE free -
- - -
- 💡 To Restore - tar -xzf $PLEX_ARCHIVE -C /opt/plex -
- -
- Config Backup  |  plex32  |  KingDezigns Infrastructure -
-
- - -""" - -msg = MIMEMultipart("alternative") -msg["Subject"] = subject -msg["From"] = email_from -msg["To"] = email_to -msg.attach(MIMEText(html, "html")) - -ctx = ssl.create_default_context() -with smtplib.SMTP_SSL(smtp_server, smtp_port, context=ctx, timeout=15) as s: - s.login(smtp_user, smtp_pass) - s.sendmail(email_from, [email_to], msg.as_string()) -print("Email sent successfully") -PYEOF - -EMAIL_STATUS=$? -if [ $EMAIL_STATUS -eq 0 ]; then - echo "[$(date '+%Y-%m-%d %H:%M:%S')] Email sent successfully" -else - echo "[ERROR] Email send failed" -fi - -# --- Cleanup old logs --- -find "$LOG_DIR" -name "backup-*.log" -mtime +$RETENTION_DAYS -delete 2>/dev/null - -echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup complete — Status: $OVERALL_STATUS | Duration: ${TOTAL_MIN}m ${TOTAL_SEC}s" diff --git a/plex32_update_check.sh b/plex32_update_check.sh index f947572..8fd7a5f 100644 --- a/plex32_update_check.sh +++ b/plex32_update_check.sh @@ -71,6 +71,25 @@ fi echo "[INFO] Plex status: $PLEX_STATUS_TEXT" +# ============================================================= +# STEP 2B — VERIFY RUNNING CONTAINER (independent of pull result) +# ============================================================= +echo "[INFO] Checking actual running Plex container..." + +CONTAINER_STATUS=$(docker inspect -f '{{.State.Status}}' plex 2>/dev/null) +CONTAINER_STARTED=$(docker inspect -f '{{.State.StartedAt}}' plex 2>/dev/null | cut -d'.' -f1 | tr 'T' ' ') +CONTAINER_HEALTH=$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}n/a{{end}}' plex 2>/dev/null) + +if [ "$CONTAINER_STATUS" = "running" ]; then + CONTAINER_OK=true + CONTAINER_STATUS_TEXT="Running since $CONTAINER_STARTED UTC" +else + CONTAINER_OK=false + CONTAINER_STATUS_TEXT="NOT running (status: ${CONTAINER_STATUS:-unknown})" +fi + +echo "[INFO] Plex container status: $CONTAINER_STATUS_TEXT" + # ============================================================= # STEP 3 — CHECK FAIL2BAN VERSION # ============================================================= @@ -115,15 +134,25 @@ ANY_UPDATES=false [ "$APT_FAILED" = true ] && ANY_FAILED=true [ "$PLEX_FAILED" = true ] && ANY_FAILED=true +[ "$CONTAINER_OK" = false ] && ANY_FAILED=true [ "$APT_UPDATES" -gt 0 ] && ANY_UPDATES=true [ "$PLEX_UPDATE_AVAILABLE" = true ] && ANY_UPDATES=true [ "$F2B_UPDATE_AVAILABLE" = true ] && ANY_UPDATES=true [ "$DOCKER_UPDATE_AVAILABLE" = true ] && ANY_UPDATES=true -if [ "$ANY_FAILED" = true ]; then +# A failed registry pull (rate-limit, transient network blip, etc.) is not the +# same severity as the actual Plex container being down. If the pull check +# failed but the running container is confirmed healthy, badge it as a lower +# severity "registry check failed" rather than a full CHECK FAILED/critical state. +if [ "$CONTAINER_OK" = false ]; then + STATUS_COLOR="#b91c1c" + STATUS_BADGE="🔴 CONTAINER DOWN" + STATUS_BANNER_MSG="🔴  Plex container is NOT running — investigate immediately" + SUBJECT="🔴 PLEX32 — Plex Container Down — $DATE_SHORT" +elif [ "$ANY_FAILED" = true ]; then STATUS_COLOR="#b45309" STATUS_BADGE="⚠ CHECK FAILED" - STATUS_BANNER_MSG="⚠  One or more update checks failed — manual verification required" + STATUS_BANNER_MSG="⚠  Registry/update check failed, but Plex container itself is confirmed running — no action required unless this repeats daily" SUBJECT="⚠ PLEX32 — Update Check Failed — $DATE_SHORT" elif [ "$ANY_UPDATES" = true ]; then STATUS_COLOR="#1d6fa8" @@ -229,6 +258,12 @@ PLEX_BADGE=$(make_badge "$PLEX_UPDATE_AVAILABLE" "$PLEX_FAILED") F2B_BADGE=$(make_badge "$F2B_UPDATE_AVAILABLE" "false") DOCKER_BADGE=$(make_badge "$DOCKER_UPDATE_AVAILABLE" "false") +if [ "$CONTAINER_OK" = true ]; then + CONTAINER_BADGE="RUNNING" +else + CONTAINER_BADGE="DOWN" +fi + # ============================================================= # STEP 9 — BUILD & SEND EMAIL # ============================================================= @@ -249,9 +284,12 @@ subject = "$SUBJECT" plex_status = "$PLEX_STATUS_TEXT" f2b_status = "$F2B_STATUS_TEXT" docker_status = "$DOCKER_STATUS_TEXT" +container_ok = "$CONTAINER_OK" == "true" +container_status = "$CONTAINER_STATUS_TEXT" plex_badge = """$PLEX_BADGE""" f2b_badge = """$F2B_BADGE""" docker_badge = """$DOCKER_BADGE""" +container_badge = """$CONTAINER_BADGE""" update_commands = """$UPDATE_COMMANDS_HTML""" apt_packages_html = """$APT_PACKAGES_HTML""" plex_error_html = """$PLEX_ERROR_HTML""" @@ -338,6 +376,10 @@ html = f""" 🎬 Plex Media Server {plex_badge} {plex_status}
Image: {plex_image_ver} | Built: {current_image_date}{plex_error_html} + + ✅ Plex Container (actual) {container_badge} + {container_status}
This is the real, running-right-now status — independent of the registry check above. + 🛡 Fail2Ban {f2b_badge} {f2b_status}