mirror of
https://github.com/narrrl/holy-flavor-rater.git
synced 2026-11-03 16:41:27 +01:00
implemented automated SQLite and media backup system with rotation
This commit is contained in:
1 parent
e3947e933c
commit
dc4b5e4512
3 files changed
+123
No files matched your search
@@ -104,6 +104,34 @@ bash scripts/install-hooks.sh
|
|||||||
- `python manage.py sync_flavors`: Syncs the latest products from the official Holy Energy API.
|
- `python manage.py sync_flavors`: Syncs the latest products from the official Holy Energy API.
|
||||||
- `python manage.py cleanup_duplicates`: Merges duplicate entries and maintains rating integrity.
|
- `python manage.py cleanup_duplicates`: Merges duplicate entries and maintains rating integrity.
|
||||||
- `python manage.py seed_banners`: Updates procedurally generated banner configurations from JSON.
|
- `python manage.py seed_banners`: Updates procedurally generated banner configurations from JSON.
|
||||||
|
- `python manage.py backup_db`: Creates a consistent SQLite snapshot.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💾 Backups & Restoration
|
||||||
|
|
||||||
|
### Create a Backup
|
||||||
|
To create a full snapshot of your database and user-uploaded media:
|
||||||
|
```bash
|
||||||
|
bash scripts/backup.sh
|
||||||
|
```
|
||||||
|
This will create a `.tar.gz` file in `backend/backups/`.
|
||||||
|
|
||||||
|
**Automating with Cron:**
|
||||||
|
Add this to your `crontab -e` to backup every night at 2:00 AM:
|
||||||
|
```bash
|
||||||
|
0 2 * * * /path/to/Holy-Flavor-Rater/scripts/backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restore from Backup
|
||||||
|
1. Extract the archive: `tar -xzf backup_filename.tar.gz`
|
||||||
|
2. Stop the containers: `docker-compose down`
|
||||||
|
3. Replace the current files:
|
||||||
|
```bash
|
||||||
|
cp extracted_folder/db.sqlite3 backend/db.sqlite3
|
||||||
|
cp -r extracted_folder/media/* backend/media/
|
||||||
|
```
|
||||||
|
4. Restart: `docker-compose up -d`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import sqlite3
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Creates a safe, consistent backup of the SQLite database and manages rotation.'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('--output', type=str, help='Specific output path for the backup file')
|
||||||
|
parser.add_argument('--retention', type=int, default=7, help='Number of days to keep old backups')
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
db_conf = settings.DATABASES['default']
|
||||||
|
if db_conf['ENGINE'] != 'django.db.backends.sqlite3':
|
||||||
|
self.stdout.write(self.style.ERROR("This command only supports SQLite."))
|
||||||
|
return
|
||||||
|
|
||||||
|
db_path = str(db_conf['NAME'])
|
||||||
|
backup_dir = os.path.join(settings.BASE_DIR, 'backups')
|
||||||
|
os.makedirs(backup_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# 1. Database Backup
|
||||||
|
if options['output']:
|
||||||
|
backup_path = options['output']
|
||||||
|
else:
|
||||||
|
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||||
|
backup_path = os.path.join(backup_dir, f'db_backup_{timestamp}.sqlite3')
|
||||||
|
|
||||||
|
self.stdout.write(f"Starting backup of {db_path}...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Use SQLite's online backup API for a consistent copy
|
||||||
|
src = sqlite3.connect(db_path)
|
||||||
|
dst = sqlite3.connect(backup_path)
|
||||||
|
with dst:
|
||||||
|
src.backup(dst)
|
||||||
|
dst.close()
|
||||||
|
src.close()
|
||||||
|
self.stdout.write(self.style.SUCCESS(f"Successfully backed up database to {backup_path}"))
|
||||||
|
except Exception as e:
|
||||||
|
self.stdout.write(self.style.ERROR(f"Database backup failed: {e}"))
|
||||||
|
return
|
||||||
|
|
||||||
|
# 2. Cleanup Old Backups
|
||||||
|
retention_days = options['retention']
|
||||||
|
cutoff = datetime.now() - timedelta(days=retention_days)
|
||||||
|
|
||||||
|
self.stdout.write(f"Cleaning up backups older than {retention_days} days...")
|
||||||
|
for filename in os.listdir(backup_dir):
|
||||||
|
file_path = os.path.join(backup_dir, filename)
|
||||||
|
if os.path.isfile(file_path):
|
||||||
|
file_time = datetime.fromtimestamp(os.path.getmtime(file_path))
|
||||||
|
if file_time < cutoff:
|
||||||
|
os.remove(file_path)
|
||||||
|
self.stdout.write(f" -> Deleted: {filename}")
|
||||||
Executable
+37
@@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This script creates a full snapshot of the database and user media.
|
||||||
|
# Best run as a daily cron job.
|
||||||
|
|
||||||
|
ROOT_DIR=$(git rev-parse --show-toplevel)
|
||||||
|
cd "$ROOT_DIR"
|
||||||
|
|
||||||
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||||
|
BACKUP_NAME="full_snapshot_$TIMESTAMP"
|
||||||
|
TEMP_DIR="backend/backups/$BACKUP_NAME"
|
||||||
|
FINAL_DEST="backend/backups"
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
echo " Starting Full Project Backup... "
|
||||||
|
echo "========================================"
|
||||||
|
|
||||||
|
mkdir -p "$TEMP_DIR"
|
||||||
|
|
||||||
|
# 1. Run the database backup command
|
||||||
|
echo "Backing up database..."
|
||||||
|
docker exec holy-backend python manage.py backup_db --output "/app/backups/$BACKUP_NAME/db.sqlite3"
|
||||||
|
|
||||||
|
# 2. Copy the media folder
|
||||||
|
echo "Backing up media..."
|
||||||
|
cp -r backend/media "$TEMP_DIR/media"
|
||||||
|
|
||||||
|
# 3. Create compressed archive
|
||||||
|
echo "Compressing..."
|
||||||
|
tar -czf "$FINAL_DEST/$BACKUP_NAME.tar.gz" -C "backend/backups" "$BACKUP_NAME"
|
||||||
|
|
||||||
|
# 4. Cleanup temp folder
|
||||||
|
rm -rf "$TEMP_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Backup complete: $FINAL_DEST/$BACKUP_NAME.tar.gz"
|
||||||
|
echo "========================================"
|
||||||
Reference in new issue
Block a user