Files
hoerdle/scripts/backup-restic.sh
Hördle Bot e48d823c92 feat: enhance Gotify notification handling in backup script
- Added loading of environment variables from a .env file.
- Extracted Gotify configuration from docker-compose.yml if not set.
- Improved notification sending with success and error messages based on curl exit codes.
- Ensured Gotify notifications are only sent if properly configured.
2025-12-07 10:29:09 +01:00

175 lines
5.8 KiB
Bash
Executable File

#!/bin/bash
# Restic backup script for Hördle deployment
# Creates a backup snapshot with tags and handles errors gracefully
set -e
if [ -f "$HOME/.restic-env" ]; then
# shellcheck source=/dev/null
. "$HOME/.restic-env"
fi
# Load .env file if present (for Gotify variables)
if [ -f ".env" ]; then
# shellcheck source=/dev/null
set -a
. ".env"
set +a
fi
# Extract Gotify variables from docker-compose.yml if not set
if [ -z "$GOTIFY_URL" ] && [ -f "docker-compose.yml" ]; then
GOTIFY_URL=$(grep -oP 'GOTIFY_URL=\K[^\s]+' docker-compose.yml | head -1 | tr -d '"' | tr -d "'" || echo "")
fi
if [ -z "$GOTIFY_APP_TOKEN" ] && [ -f "docker-compose.yml" ]; then
GOTIFY_APP_TOKEN=$(grep -oP 'GOTIFY_APP_TOKEN=\K[^\s]+' docker-compose.yml | head -1 | tr -d '"' | tr -d "'" || echo "")
fi
# Function to send Gotify notification
send_gotify_notification() {
local title="$1"
local message="$2"
local priority="${3:-5}"
# Check if Gotify is configured
if [ -z "$GOTIFY_URL" ] || [ -z "$GOTIFY_APP_TOKEN" ]; then
echo "⚠️ Gotify not configured (GOTIFY_URL or GOTIFY_APP_TOKEN not set), skipping notification"
return 0
fi
echo "📢 Sending Gotify notification..."
# Send notification (fire and forget, don't fail on error)
# Use jq if available for proper JSON encoding, otherwise use simple approach
if command -v jq >/dev/null 2>&1; then
local json_payload
json_payload=$(jq -n \
--arg title "$title" \
--arg message "$message" \
--argjson priority "$priority" \
'{title: $title, message: $message, priority: $priority}')
local curl_exit_code=0
curl -sSf -X POST "${GOTIFY_URL}/message?token=${GOTIFY_APP_TOKEN}" \
-H "Content-Type: application/json" \
-d "$json_payload" \
>/dev/null 2>&1 || curl_exit_code=$?
if [ $curl_exit_code -eq 0 ]; then
echo "✅ Gotify notification sent successfully"
else
echo "⚠️ Failed to send Gotify notification (curl exit code: $curl_exit_code)"
fi
else
# Fallback: simple JSON encoding (replace " with \" and newlines with \n)
local escaped_title escaped_message
escaped_title=$(echo "$title" | sed 's/"/\\"/g')
escaped_message=$(echo "$message" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
local curl_exit_code=0
curl -sSf -X POST "${GOTIFY_URL}/message?token=${GOTIFY_APP_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"title\":\"${escaped_title}\",\"message\":\"${escaped_message}\",\"priority\":${priority}}" \
>/dev/null 2>&1 || curl_exit_code=$?
if [ $curl_exit_code -eq 0 ]; then
echo "✅ Gotify notification sent successfully"
else
echo "⚠️ Failed to send Gotify notification (curl exit code: $curl_exit_code)"
fi
fi
}
echo "💾 Creating Restic backup..."
if ! command -v restic >/dev/null 2>&1; then
echo "⚠️ restic not found in PATH, skipping Restic backup"
exit 0
fi
# Check required environment variables
if [ -z "$RESTIC_PASSWORD" ]; then
echo "⚠️ RESTIC_PASSWORD not set, skipping Restic backup"
exit 0
fi
if [ -z "$RESTIC_AUTH_USER" ] || [ -z "$RESTIC_AUTH_PASSWORD" ]; then
echo "⚠️ RESTIC_AUTH_USER or RESTIC_AUTH_PASSWORD not set, skipping Restic backup"
exit 0
fi
# Build repository URL
RESTIC_REPO="rest:https://${RESTIC_AUTH_USER}:${RESTIC_AUTH_PASSWORD}@restic.elpatron.me/"
# Get current commit hash for tagging
CURRENT_COMMIT_SHORT="$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')"
CURRENT_DATE="$(date +%Y-%m-%d)"
# Export password for restic
export RESTIC_PASSWORD
# Check if repository exists, initialize if not
if ! restic -r "$RESTIC_REPO" snapshots >/dev/null 2>&1; then
echo " Initializing Restic repository..."
if ! restic -r "$RESTIC_REPO" init >/dev/null 2>&1; then
echo "⚠️ Failed to initialize Restic repository, skipping backup"
exit 0
fi
fi
# Create backup with tags
# Backup important directories: backups, config files, but exclude node_modules, .git, etc.
echo " Creating Restic snapshot..."
RESTIC_EXIT_CODE=0
restic -r "$RESTIC_REPO" backup \
--tag deployment \
--tag hoerdle \
--tag "date:${CURRENT_DATE}" \
--tag "commit:${CURRENT_COMMIT_SHORT}" \
--exclude='.git' \
--exclude='node_modules' \
--exclude='.next' \
--exclude='*.log' \
./backups \
./data \
./public/uploads \
docker-compose.yml \
.env \
package.json \
prisma/schema.prisma \
prisma/migrations \
scripts/ || RESTIC_EXIT_CODE=$?
if [ $RESTIC_EXIT_CODE -eq 0 ]; then
echo "✅ Restic backup completed successfully"
# Send success notification
send_gotify_notification \
"Hördle Backup: Erfolgreich" \
"Restic Backup wurde erfolgreich abgeschlossen.\nDatum: ${CURRENT_DATE}\nCommit: ${CURRENT_COMMIT_SHORT}" \
5
exit 0
elif [ $RESTIC_EXIT_CODE -eq 3 ]; then
echo "⚠️ Restic backup completed with warnings (some files could not be read), continuing..."
# Send warning notification
send_gotify_notification \
"Hördle Backup: Mit Warnungen" \
"Restic Backup wurde mit Warnungen abgeschlossen (einige Dateien konnten nicht gelesen werden).\nDatum: ${CURRENT_DATE}\nCommit: ${CURRENT_COMMIT_SHORT}" \
7
exit 0
else
echo "⚠️ Restic backup failed (exit code: $RESTIC_EXIT_CODE), continuing deployment..."
# Send error notification
send_gotify_notification \
"Hördle Backup: Fehlgeschlagen" \
"Restic Backup ist fehlgeschlagen (Exit Code: ${RESTIC_EXIT_CODE}).\nDatum: ${CURRENT_DATE}\nCommit: ${CURRENT_COMMIT_SHORT}" \
9
exit 0
fi