feat: Add base HTML template and implement dashboard, logs, and service views

- Created a base HTML template for consistent layout across pages.
- Developed a dashboard page to display backup service metrics and statuses.
- Implemented a log viewer for detailed log file inspection.
- Added error handling page for better user experience during failures.
- Introduced service detail page to show specific service metrics and actions.
- Enhanced log filtering and viewing capabilities.
- Integrated auto-refresh functionality for real-time updates on metrics.
- Created integration and unit test scripts for backup metrics functionality.
This commit is contained in:
Peter Wood
2025-06-18 08:06:08 -04:00
parent d066f32b10
commit 6d726cb015
34 changed files with 6006 additions and 26 deletions

View File

@@ -1,25 +1,337 @@
#! /bin/bash
#!/bin/bash
# vaultwarden
docker stop vaultwarden
tar zcf "/home/acedanger/backup/docker-data/vaultwarden-data-bk-$(date +%Y%m%d).tar.gz" /var/lib/docker/volumes/vaultwarden_data/_data
docker start vaultwarden
# backup-docker.sh - Comprehensive Docker volumes backup script
# Author: Shell Repository
# Description: Backup Docker container volumes with proper error handling, logging, and metrics
# paperless
#docker stop paperless-ng_broker_1 paperless-ng_db_1 paperless-ng_webserver_1
#tar zcf /home/acedanger/backup/docker-data/paperless-data-bk-`date +%Y%m%d`.tar.gz /var/lib/docker/volumes/paperless-ng_data/_data
#tar zcf /home/acedanger/backup/docker-data/paperless-media-bk-`date +%Y%m%d`.tar.gz /var/lib/docker/volumes/paperless-ng_media/_data
#tar zcf /home/acedanger/backup/docker-data/paperless-pgdata-bk-`date +%Y%m%d`.tar.gz /var/lib/docker/volumes/paperless-ng_pgdata/_data
#docker start paperless-ng_broker_1 paperless-ng_db_1 paperless-ng_webserver_1
set -e
# uptime-kuma
docker stop uptime-kuma
tar zcf "/home/acedanger/backup/docker-data/uptime-kuma-data-bk-$(date +%Y%m%d).tar.gz" /var/lib/docker/volumes/uptime-kuma/_data
docker start uptime-kuma
# Load the unified backup metrics library
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="$SCRIPT_DIR/lib"
if [[ -f "$LIB_DIR/unified-backup-metrics.sh" ]]; then
# shellcheck source=lib/unified-backup-metrics.sh
source "$LIB_DIR/unified-backup-metrics.sh"
METRICS_ENABLED=true
else
echo "Warning: Unified backup metrics library not found at $LIB_DIR/unified-backup-metrics.sh"
METRICS_ENABLED=false
fi
# send a notification to https://notify.peterwood.rocks\lab
curl \
-H priority:default \
-H tags:backup,docker,vaultwarden,uptime-kuma,"${HOSTNAME}" \
-d "Completed backup of vaultwarden, uptime-kuma" \
https://notify.peterwood.rocks/lab
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
BACKUP_ROOT="/home/acedanger/backup/docker-data"
LOG_FILE="$SCRIPT_DIR/logs/docker-backup.log"
NOTIFICATION_URL="https://notify.peterwood.rocks/lab"
# Container definitions: container_name:volume_path:description
declare -A CONTAINERS=(
["vaultwarden"]="/var/lib/docker/volumes/vaultwarden_data/_data:Password manager data"
["uptime-kuma"]="/var/lib/docker/volumes/uptime-kuma/_data:Uptime monitoring data"
# ["paperless-ng"]="/var/lib/docker/volumes/paperless-ng_data/_data:Document management data"
# ["paperless-media"]="/var/lib/docker/volumes/paperless-ng_media/_data:Document media files"
# ["paperless-pgdata"]="/var/lib/docker/volumes/paperless-ng_pgdata/_data:PostgreSQL database"
)
# Ensure directories exist
mkdir -p "$(dirname "$LOG_FILE")"
mkdir -p "$BACKUP_ROOT"
# Logging function
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
# Cleanup function for metrics finalization
cleanup() {
if [[ "$METRICS_ENABLED" == "true" ]]; then
if [[ -n "$1" && "$1" == "error" ]]; then
metrics_backup_complete "failed" "Docker backup failed during execution"
else
metrics_backup_complete "success" "Docker volumes backup completed successfully"
fi
fi
}
# Set up cleanup trap
trap 'cleanup error' ERR
# Check if container is running
check_container_running() {
local container="$1"
if docker ps --format "table {{.Names}}" | grep -q "^${container}$"; then
return 0
else
return 1
fi
}
# Stop container safely
stop_container() {
local container="$1"
log "Stopping container: $container"
if [[ "$METRICS_ENABLED" == "true" ]]; then
metrics_status_update "stopping_service" "Stopping container: $container"
fi
if ! docker stop "$container" >/dev/null 2>&1; then
log "Warning: Failed to stop container $container or container not running"
return 1
fi
# Wait for container to fully stop
local max_wait=30
local wait_count=0
while [ $wait_count -lt $max_wait ]; do
if ! docker ps -q --filter "name=$container" | grep -q .; then
log "Container $container stopped successfully"
return 0
fi
wait_count=$((wait_count + 1))
sleep 1
done
log "Warning: Container $container may not have stopped completely"
return 1
}
# Start container safely
start_container() {
local container="$1"
log "Starting container: $container"
if [[ "$METRICS_ENABLED" == "true" ]]; then
metrics_status_update "starting_service" "Starting container: $container"
fi
if ! docker start "$container" >/dev/null 2>&1; then
log "Error: Failed to start container $container"
return 1
fi
# Wait for container to be running
local max_wait=30
local wait_count=0
while [ $wait_count -lt $max_wait ]; do
if docker ps -q --filter "name=$container" | grep -q .; then
log "Container $container started successfully"
return 0
fi
wait_count=$((wait_count + 1))
sleep 1
done
log "Warning: Container $container may not have started properly"
return 1
}
# Backup container volume
backup_container_volume() {
local container="$1"
local volume_path="$2"
local description="$3"
local backup_file="$BACKUP_ROOT/${container}-data-bk-$(date +%Y%m%d).tar.gz"
log "Starting backup for $container ($description)"
# Check if volume path exists
if [ ! -d "$volume_path" ]; then
log "Error: Volume path does not exist: $volume_path"
return 1
fi
# Check if container was running
local was_running=false
if check_container_running "$container"; then
was_running=true
if ! stop_container "$container"; then
log "Error: Failed to stop container $container"
return 1
fi
else
log "Container $container is not running, proceeding with backup"
fi
# Create backup
log "Creating backup archive: $(basename "$backup_file")"
if [[ "$METRICS_ENABLED" == "true" ]]; then
metrics_status_update "backing_up" "Creating archive for $container"
fi
if tar -czf "$backup_file" -C "$(dirname "$volume_path")" "$(basename "$volume_path")" 2>/dev/null; then
local backup_size
backup_size=$(du -h "$backup_file" | cut -f1)
log "Backup completed successfully: $(basename "$backup_file") ($backup_size)"
# Track file completion in metrics
if [[ "$METRICS_ENABLED" == "true" ]]; then
local file_size_bytes
file_size_bytes=$(stat -c%s "$backup_file" 2>/dev/null || echo "0")
metrics_file_backup_complete "$(basename "$backup_file")" "$file_size_bytes" "created"
fi
else
log "Error: Failed to create backup for $container"
# Try to restart container even if backup failed
if [ "$was_running" = true ]; then
start_container "$container" || true
fi
return 1
fi
# Restart container if it was running
if [ "$was_running" = true ]; then
if ! start_container "$container"; then
log "Error: Failed to restart container $container after backup"
return 1
fi
fi
return 0
}
# Send notification
send_notification() {
local status="$1"
local message="$2"
local failed_containers="$3"
local tags="backup,docker,${HOSTNAME}"
local priority="default"
if [ "$status" = "failed" ]; then
priority="high"
tags="${tags},error"
fi
# Add successful container names to tags
for container in "${!CONTAINERS[@]}"; do
if [[ ! " $failed_containers " =~ " $container " ]]; then
tags="${tags},$container"
fi
done
curl -s \
-H "priority:$priority" \
-H "tags:$tags" \
-d "$message" \
"$NOTIFICATION_URL" || log "Warning: Failed to send notification"
}
# Check dependencies
check_dependencies() {
local missing_deps=()
if ! command -v docker >/dev/null 2>&1; then
missing_deps+=("docker")
fi
if ! command -v tar >/dev/null 2>&1; then
missing_deps+=("tar")
fi
if ! command -v curl >/dev/null 2>&1; then
missing_deps+=("curl")
fi
if [ ${#missing_deps[@]} -ne 0 ]; then
log "Error: Missing required dependencies: ${missing_deps[*]}"
exit 1
fi
# Check if Docker daemon is running
if ! docker info >/dev/null 2>&1; then
log "Error: Docker daemon is not running or not accessible"
exit 1
fi
}
# Main backup function
main() {
log "=== Docker Volumes Backup Started ==="
# Initialize metrics if enabled
if [[ "$METRICS_ENABLED" == "true" ]]; then
metrics_backup_start "docker-volumes" "Docker container volumes backup" "$BACKUP_ROOT"
metrics_status_update "initializing" "Preparing Docker volumes backup"
fi
# Check dependencies
check_dependencies
# Check backup directory space
local available_space_gb
available_space_gb=$(df -BG "$BACKUP_ROOT" | awk 'NR==2 {print $4}' | sed 's/G//')
if [ "$available_space_gb" -lt 5 ]; then
log "Warning: Low disk space in backup directory: ${available_space_gb}GB available"
fi
local successful_backups=0
local failed_backups=0
local failed_containers=()
# Update metrics for backup phase
if [[ "$METRICS_ENABLED" == "true" ]]; then
metrics_status_update "backing_up" "Backing up Docker container volumes"
fi
# Backup each container
for container in "${!CONTAINERS[@]}"; do
local volume_info="${CONTAINERS[$container]}"
local volume_path="${volume_info%%:*}"
local description="${volume_info##*:}"
if backup_container_volume "$container" "$volume_path" "$description"; then
((successful_backups++))
else
((failed_backups++))
failed_containers+=("$container")
fi
done
# Update metrics for completion
if [[ "$METRICS_ENABLED" == "true" ]]; then
if [ $failed_backups -eq 0 ]; then
metrics_status_update "completed" "All Docker backups completed successfully"
else
metrics_status_update "completed_with_errors" "Docker backup completed with $failed_backups failures"
fi
fi
# Summary
log "=== Docker Volumes Backup Summary ==="
log "Successful backups: $successful_backups"
log "Failed backups: $failed_backups"
if [ ${#failed_containers[@]} -gt 0 ]; then
log "Failed containers: ${failed_containers[*]}"
fi
# Send notification
if [ $failed_backups -eq 0 ]; then
log "All backups completed successfully!"
send_notification "success" "Completed backup of all Docker containers ($successful_backups services)" ""
else
log "Some backups failed!"
send_notification "failed" "Docker backup completed with errors: $failed_backups failed, $successful_backups succeeded" "${failed_containers[*]}"
fi
# Finalize metrics
if [[ "$METRICS_ENABLED" == "true" ]]; then
cleanup
fi
log "=== Docker Volumes Backup Finished ==="
# Exit with error code if any backups failed
exit $failed_backups
}
# Run main function
main "$@"