From faf5102cd776b82e9badcc42694918dd4e5ca897 Mon Sep 17 00:00:00 2001 From: Peter Wood Date: Thu, 29 May 2025 07:19:12 -0400 Subject: [PATCH] refactor: Improve backup-env-files.sh for temp file handling and enhance crontab entries for .env backups --- backup-env-files.sh | 101 +++++++++++------- .../europa/current-crontab.backup | 2 + crontab/crontab-io.txt | 8 ++ crontab/crontab-racknerd.txt | 8 ++ docs/env-backup-integration-guide.md | 15 +++ docs/env-backup-system.md | 5 + 6 files changed, 99 insertions(+), 40 deletions(-) diff --git a/backup-env-files.sh b/backup-env-files.sh index 8fb386f..2fd0d6f 100755 --- a/backup-env-files.sh +++ b/backup-env-files.sh @@ -83,6 +83,10 @@ list_env_files() { echo -e "${BLUE}=== Environment Files Found ===${NC}" local count=0 + # Use a temp file to avoid subshell issues + local temp_file=$(mktemp) + find_env_files "$DOCKER_DIR" > "$temp_file" + while IFS= read -r env_file; do if [ -n "$env_file" ]; then local rel_path="${env_file#$DOCKER_DIR/}" @@ -93,9 +97,12 @@ list_env_files() { echo " Size: $size | Modified: $modified" echo " Full path: $env_file" echo "" - ((count++)) + count=$((count + 1)) fi - done < <(find_env_files "$DOCKER_DIR") + done < "$temp_file" + + # Clean up temp file + rm -f "$temp_file" echo -e "${BLUE}Total .env files found: $count${NC}" @@ -247,7 +254,10 @@ backup_env_files() { local backup_count=0 local unchanged_count=0 - # Process each .env file + # Process each .env file using a temp file to avoid subshell issues + local temp_file=$(mktemp) + find_env_files "$DOCKER_DIR" > "$temp_file" + while IFS= read -r env_file; do if [ -n "$env_file" ]; then # Determine relative path and backup location @@ -268,7 +278,7 @@ backup_env_files() { if [ -f "$backup_path" ] && [ "$force" != "true" ]; then if cmp -s "$env_file" "$backup_path"; then needs_backup=false - ((unchanged_count++)) + unchanged_count=$((unchanged_count + 1)) fi fi @@ -276,7 +286,7 @@ backup_env_files() { # Copy the file cp "$env_file" "$backup_path" echo -e "${GREEN}✓ Backed up: $rel_path${NC}" - ((backup_count++)) + backup_count=$((backup_count + 1)) # Also create a reference docker-compose.yml if it exists local compose_file=$(dirname "$env_file")/docker-compose.yml @@ -290,7 +300,10 @@ backup_env_files() { echo -e "${YELLOW}- Unchanged: $rel_path${NC}" fi fi - done < <(find_env_files "$DOCKER_DIR") + done < "$temp_file" + + # Clean up temp file + rm -f "$temp_file" if [ "$dry_run" = "true" ]; then echo -e "${BLUE}Dry run completed. No files were actually backed up.${NC}" @@ -374,44 +387,52 @@ restore_env_files() { local restore_count=0 local error_count=0 - # Find all backed up .env files - find docker-containers -name "*.env" -type f 2>/dev/null | while IFS= read -r backup_file; do - # Determine target path - local rel_path="${backup_file#docker-containers/}" - local target_file="$DOCKER_DIR/$rel_path" - local target_dir=$(dirname "$target_file") - - # Create target directory if it doesn't exist - if [ ! -d "$target_dir" ]; then - echo -e "${YELLOW}Creating directory: $target_dir${NC}" - mkdir -p "$target_dir" - fi - - # Ask for confirmation if file exists and is different - if [ -f "$target_file" ]; then - if ! cmp -s "$backup_file" "$target_file"; then - echo -e "${YELLOW}File exists and differs: $rel_path${NC}" - read -p "Overwrite? (y/N): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - echo -e "${YELLOW}Skipped: $rel_path${NC}" + # Use a temp file to avoid subshell issues + local temp_file=$(mktemp) + find docker-containers -name "*.env" -type f 2>/dev/null > "$temp_file" + + while IFS= read -r backup_file; do + if [ -n "$backup_file" ]; then + # Determine target path + local rel_path="${backup_file#docker-containers/}" + local target_file="$DOCKER_DIR/$rel_path" + local target_dir=$(dirname "$target_file") + + # Create target directory if it doesn't exist + if [ ! -d "$target_dir" ]; then + echo -e "${YELLOW}Creating directory: $target_dir${NC}" + mkdir -p "$target_dir" + fi + + # Ask for confirmation if file exists and is different + if [ -f "$target_file" ]; then + if ! cmp -s "$backup_file" "$target_file"; then + echo -e "${YELLOW}File exists and differs: $rel_path${NC}" + read -p "Overwrite? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo -e "${YELLOW}Skipped: $rel_path${NC}" + continue + fi + else + echo -e "${GREEN}Identical: $rel_path${NC}" continue fi + fi + + # Copy the file + if cp "$backup_file" "$target_file"; then + echo -e "${GREEN}✓ Restored: $rel_path${NC}" + restore_count=$((restore_count + 1)) else - echo -e "${GREEN}Identical: $rel_path${NC}" - continue + echo -e "${RED}✗ Failed to restore: $rel_path${NC}" + error_count=$((error_count + 1)) fi fi - - # Copy the file - if cp "$backup_file" "$target_file"; then - echo -e "${GREEN}✓ Restored: $rel_path${NC}" - ((restore_count++)) - else - echo -e "${RED}✗ Failed to restore: $rel_path${NC}" - ((error_count++)) - fi - done + done < "$temp_file" + + # Clean up temp file + rm -f "$temp_file" echo -e "${GREEN}Restore completed!${NC}" echo -e "${BLUE}Summary:${NC}" @@ -479,7 +500,7 @@ main() { if [ "$list_files" = true ]; then list_env_files elif [ "$init_repo" = true ]; then - init_repo + init_backup_repo elif [ "$restore" = true ]; then restore_env_files else diff --git a/crontab/crontab-backups/europa/current-crontab.backup b/crontab/crontab-backups/europa/current-crontab.backup index eccea34..f191bba 100644 --- a/crontab/crontab-backups/europa/current-crontab.backup +++ b/crontab/crontab-backups/europa/current-crontab.backup @@ -1,6 +1,8 @@ 0 1 * * * /home/acedanger/shell/move-backups.sh 2>&1 | logger -t backup-move -p user.info +0 2 * * * { echo "Starting .env files backup"; /home/acedanger/shell/backup-env-files.sh; echo ".env backup completed with exit code: $?"; } 2>&1 | logger -t env-backup -p user.info 15 4 * * * { echo "Starting Plex backup"; /home/acedanger/shell/plex/backup-plex.sh --non-interactive --auto-repair; echo "Plex backup completed with exit code: $?"; } 2>&1 | logger -t plex-backup -p user.info 0 7 * * * { echo "Starting Plex backup validation"; /home/acedanger/shell/plex/validate-plex-backups.sh --fix; echo "Validation completed with exit code: $?"; } 2>&1 | logger -t plex-validation -p user.info 0 5 * * 1 { echo "Starting Immich database backup move"; if mv /mnt/share/media/immich/uploads/backups/immich-db-backup* /mnt/share/media/backups/immich 2>/dev/null; then echo "Immich backup move completed successfully"; else echo "No Immich backup files found or move failed"; fi; } 2>&1 | logger -t immich-backup -p user.info 0 4 * * * /home/acedanger/shell/crontab/crontab-backup-system.sh backup auto --auto-cleanup 2>&1 | logger -t crontab-backup -p user.info 0 8 * * 0 { echo "Starting weekly Plex backup report generation"; /home/acedanger/shell/plex/validate-plex-backups.sh --report; echo "Weekly report generation completed with exit code: $?"; } 2>&1 | logger -t plex-report -p user.info +30 8 * * 0 { echo "Starting .env backup validation"; /home/acedanger/shell/validate-env-backups.sh; echo ".env validation completed with exit code: $?"; } 2>&1 | logger -t env-validation -p user.info diff --git a/crontab/crontab-io.txt b/crontab/crontab-io.txt index 8854581..d18645f 100644 --- a/crontab/crontab-io.txt +++ b/crontab/crontab-io.txt @@ -10,6 +10,14 @@ # Daily system backup at 0400 with auto-cleanup 0 4 * * * /home/acedanger/shell/crontab/crontab-backup-system.sh backup auto --auto-cleanup 2>&1 | logger -t crontab-backup -p user.info +# Daily .env files backup at 0300 with enhanced logging +# Backs up Docker container .env files to Git repository +0 3 * * * { echo "Starting .env files backup"; /home/acedanger/shell/backup-env-files.sh; echo ".env backup completed with exit code: $?"; } 2>&1 | logger -t env-backup -p user.info + +# Weekly .env backup validation at 0830 on Sundays +# Validates the integrity of .env backup repository +30 8 * * 0 { echo "Starting .env backup validation"; /home/acedanger/shell/validate-env-backups.sh; echo ".env validation completed with exit code: $?"; } 2>&1 | logger -t env-validation -p user.info + # Optional: Monitor Docker container health (every 6 hours) # This can help detect if any download services are failing # 0 */6 * * * { echo "Docker health check"; docker ps --format "table {{.Names}}\t{{.Status}}" | grep -v "Up"; } 2>&1 | logger -t docker-health -p user.info diff --git a/crontab/crontab-racknerd.txt b/crontab/crontab-racknerd.txt index 06ebdde..7a6f443 100644 --- a/crontab/crontab-racknerd.txt +++ b/crontab/crontab-racknerd.txt @@ -9,6 +9,14 @@ # Daily system backup at 0400 with auto-cleanup 0 4 * * * /home/acedanger/shell/crontab/crontab-backup-system.sh backup auto --auto-cleanup 2>&1 | logger -t crontab-backup -p user.info +# Daily .env files backup at 0300 with enhanced logging +# Backs up Docker container .env files to Git repository +0 3 * * * { echo "Starting .env files backup"; /home/acedanger/shell/backup-env-files.sh; echo ".env backup completed with exit code: $?"; } 2>&1 | logger -t env-backup -p user.info + +# Weekly .env backup validation at 0830 on Sundays +# Validates the integrity of .env backup repository +30 8 * * 0 { echo "Starting .env backup validation"; /home/acedanger/shell/validate-env-backups.sh; echo ".env validation completed with exit code: $?"; } 2>&1 | logger -t env-validation -p user.info + # Optional: Add a health check entry to monitor backup jobs (every 6 hours) # This can help detect if the backup process is failing # 0 */6 * * * { echo "Cron health check - Docker backup job scheduled"; ps aux | grep "backup-docker" | grep -v grep | wc -l; } 2>&1 | logger -t cron-health -p user.info diff --git a/docs/env-backup-integration-guide.md b/docs/env-backup-integration-guide.md index e1ea00a..cc2d5da 100644 --- a/docs/env-backup-integration-guide.md +++ b/docs/env-backup-integration-guide.md @@ -5,6 +5,7 @@ Your .env backup system is now fully operational! Here's what was set up: ### ✅ What's Working + - **31 .env files** discovered across your Docker containers - **30 files backed up** successfully to `/home/acedanger/.env-backup` - **Private Gitea repository** configured and pushed successfully @@ -14,6 +15,7 @@ Your .env backup system is now fully operational! Here's what was set up: ### 🔧 Integration Options #### 1. Manual Backup (Current) + ```bash cd /home/acedanger/shell ./backup-env-files.sh # Regular backup @@ -22,14 +24,18 @@ cd /home/acedanger/shell ``` #### 2. Automated Daily Backup (Recommended) + Add to your crontab for daily backups at 2 AM: + ```bash # Daily .env backup at 2 AM 0 2 * * * /home/acedanger/shell/backup-env-files.sh >/dev/null 2>&1 ``` #### 3. Integration with Existing Backup Scripts + The backup integrates with your existing backup system through: + - **Logs**: Written to `/home/acedanger/shell/logs/env-backup.log` - **Completion**: Tab completion available via `env-backup-completion.bash` - **Validation**: Use `validate-env-backups.sh` for integrity checks @@ -64,16 +70,19 @@ The backup integrates with your existing backup system through: ### 🔄 Common Operations #### Restore Files (if needed) + ```bash ./backup-env-files.sh --restore ``` #### Force Backup (ignore unchanged files) + ```bash ./backup-env-files.sh --force ``` #### Check What Would Change + ```bash ./backup-env-files.sh --dry-run ``` @@ -95,27 +104,32 @@ If you lose your filesystem: ### 🔧 Maintenance #### Weekly Validation (Recommended) + ```bash # Add to crontab for weekly validation 0 3 * * 0 /home/acedanger/shell/validate-env-backups.sh >/dev/null 2>&1 ``` #### Cleanup Old Logs (Monthly) + The system automatically manages logs, but you can clean them manually if needed. ### 🆘 Troubleshooting #### Push Fails + - Check SSH key: `ssh -T git@git.ptrwd.com` - Verify repository exists and is private - Check network connectivity #### Files Not Found + - Verify Docker directory structure: `ls -la ~/docker/*/` - Check file permissions - Run with `--list` to see what's detected #### Restore Issues + - Ensure target directories exist - Check file permissions - Use `--dry-run` first to preview @@ -123,6 +137,7 @@ The system automatically manages logs, but you can clean them manually if needed ## Integration Complete! 🎉 Your .env files are now safely backed up and version controlled. The system will: + 1. Track all changes to your .env files 2. Maintain a secure backup in your private Gitea 3. Provide easy restore capabilities diff --git a/docs/env-backup-system.md b/docs/env-backup-system.md index 24098a3..3f51076 100644 --- a/docs/env-backup-system.md +++ b/docs/env-backup-system.md @@ -207,6 +207,7 @@ The system automatically finds: ### Common Issues 1. **Git Push Fails** + ```bash # Check remote URL cd ~/.env-backup && git remote -v @@ -216,6 +217,7 @@ The system automatically finds: ``` 2. **Missing Files** + ```bash # List what would be found ./backup-env-files.sh --list @@ -279,12 +281,14 @@ git status --porcelain ### Additional Security Measures 1. **GPG Encryption** (Optional) + ```bash # Encrypt sensitive files before committing gpg --symmetric --cipher-algo AES256 file.env ``` 2. **Restricted Permissions** + ```bash # Secure backup directory chmod 700 ~/.env-backup @@ -292,6 +296,7 @@ git status --porcelain ``` 3. **Audit Trail** + ```bash # Monitor repository access git log --oneline --graph --all