141 lines
4.8 KiB
Bash
Executable File
141 lines
4.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# =====================================================
|
|
# ERP GENERIC - PostgreSQL Full Backup Script
|
|
# Performs full database backup with multi-schema support
|
|
# =====================================================
|
|
|
|
set -euo pipefail
|
|
|
|
# Configuration
|
|
BACKUP_DIR="/backups/postgres"
|
|
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
|
RETENTION_DAYS=7
|
|
DB_HOST="${POSTGRES_HOST:-postgres}"
|
|
DB_PORT="${POSTGRES_PORT:-5432}"
|
|
DB_NAME="${POSTGRES_DB:-erp_generic}"
|
|
DB_USER="${POSTGRES_USER:-erp_user}"
|
|
PGPASSWORD="${POSTGRES_PASSWORD}"
|
|
export PGPASSWORD
|
|
|
|
# Logging
|
|
LOG_FILE="/var/log/erp-generic/backup.log"
|
|
exec > >(tee -a "$LOG_FILE")
|
|
exec 2>&1
|
|
|
|
echo "===== PostgreSQL Backup Started at $(date) ====="
|
|
|
|
# Create backup directory if not exists
|
|
mkdir -p "$BACKUP_DIR"
|
|
|
|
# 1. Full Database Backup
|
|
echo "1. Creating full database backup..."
|
|
FULL_BACKUP_FILE="${BACKUP_DIR}/full_${TIMESTAMP}.dump"
|
|
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -Fc -v -d "$DB_NAME" -f "$FULL_BACKUP_FILE"
|
|
|
|
if [ $? -eq 0 ]; then
|
|
echo "✓ Full backup created: $FULL_BACKUP_FILE"
|
|
FILE_SIZE=$(du -h "$FULL_BACKUP_FILE" | cut -f1)
|
|
echo " Size: $FILE_SIZE"
|
|
else
|
|
echo "✗ Full backup failed!"
|
|
exit 1
|
|
fi
|
|
|
|
# 2. Generate MD5 checksum
|
|
echo "2. Generating checksum..."
|
|
md5sum "$FULL_BACKUP_FILE" > "${FULL_BACKUP_FILE}.md5"
|
|
echo "✓ Checksum saved: ${FULL_BACKUP_FILE}.md5"
|
|
|
|
# 3. Per-Schema Backups (Multi-Tenant Isolation)
|
|
echo "3. Creating per-schema backups..."
|
|
SCHEMAS=("auth" "core" "financial" "inventory" "purchase" "sales" "analytics" "projects" "system")
|
|
|
|
for schema in "${SCHEMAS[@]}"; do
|
|
SCHEMA_BACKUP_FILE="${BACKUP_DIR}/${schema}_${TIMESTAMP}.dump"
|
|
echo " Backing up schema: $schema"
|
|
|
|
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -Fc -n "$schema" -d "$DB_NAME" -f "$SCHEMA_BACKUP_FILE"
|
|
|
|
if [ $? -eq 0 ]; then
|
|
SCHEMA_SIZE=$(du -h "$SCHEMA_BACKUP_FILE" | cut -f1)
|
|
echo " ✓ $schema backup created ($SCHEMA_SIZE)"
|
|
else
|
|
echo " ✗ $schema backup failed!"
|
|
fi
|
|
done
|
|
|
|
# 4. Backup Database Roles and Permissions
|
|
echo "4. Backing up database roles..."
|
|
ROLES_BACKUP_FILE="${BACKUP_DIR}/roles_${TIMESTAMP}.sql"
|
|
pg_dumpall -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" --roles-only -f "$ROLES_BACKUP_FILE"
|
|
echo "✓ Roles backup created: $ROLES_BACKUP_FILE"
|
|
|
|
# 5. Backup PostgreSQL Configuration
|
|
echo "5. Backing up PostgreSQL configuration..."
|
|
CONFIG_BACKUP_DIR="${BACKUP_DIR}/config_${TIMESTAMP}"
|
|
mkdir -p "$CONFIG_BACKUP_DIR"
|
|
|
|
# Copy config files (if accessible)
|
|
if [ -f /etc/postgresql/16/main/postgresql.conf ]; then
|
|
cp /etc/postgresql/16/main/postgresql.conf "$CONFIG_BACKUP_DIR/"
|
|
cp /etc/postgresql/16/main/pg_hba.conf "$CONFIG_BACKUP_DIR/"
|
|
echo "✓ Config files backed up"
|
|
fi
|
|
|
|
# 6. Backup WAL Archive Status
|
|
echo "6. Recording WAL archive status..."
|
|
psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -tAc "SELECT * FROM pg_stat_archiver;" > "${BACKUP_DIR}/wal_status_${TIMESTAMP}.txt"
|
|
|
|
# 7. Upload to Cloud Storage (S3)
|
|
if [ -n "${AWS_S3_BUCKET:-}" ]; then
|
|
echo "7. Uploading to S3..."
|
|
aws s3 cp "$FULL_BACKUP_FILE" "s3://${AWS_S3_BUCKET}/postgres/${TIMESTAMP}/" --storage-class STANDARD_IA
|
|
aws s3 cp "${FULL_BACKUP_FILE}.md5" "s3://${AWS_S3_BUCKET}/postgres/${TIMESTAMP}/"
|
|
|
|
# Upload per-schema backups
|
|
for schema in "${SCHEMAS[@]}"; do
|
|
SCHEMA_BACKUP_FILE="${BACKUP_DIR}/${schema}_${TIMESTAMP}.dump"
|
|
if [ -f "$SCHEMA_BACKUP_FILE" ]; then
|
|
aws s3 cp "$SCHEMA_BACKUP_FILE" "s3://${AWS_S3_BUCKET}/postgres/${TIMESTAMP}/schemas/" --storage-class STANDARD_IA
|
|
fi
|
|
done
|
|
|
|
echo "✓ Backup uploaded to S3"
|
|
fi
|
|
|
|
# 8. Cleanup Old Backups (Local)
|
|
echo "8. Cleaning up old backups (older than $RETENTION_DAYS days)..."
|
|
find "$BACKUP_DIR" -type f -name "*.dump" -mtime +$RETENTION_DAYS -delete
|
|
find "$BACKUP_DIR" -type f -name "*.sql" -mtime +$RETENTION_DAYS -delete
|
|
find "$BACKUP_DIR" -type f -name "*.md5" -mtime +$RETENTION_DAYS -delete
|
|
find "$BACKUP_DIR" -type d -name "config_*" -mtime +$RETENTION_DAYS -exec rm -rf {} + 2>/dev/null || true
|
|
echo "✓ Old backups cleaned up"
|
|
|
|
# 9. Verify Backup Integrity
|
|
echo "9. Verifying backup integrity..."
|
|
md5sum -c "${FULL_BACKUP_FILE}.md5"
|
|
if [ $? -eq 0 ]; then
|
|
echo "✓ Backup integrity verified"
|
|
else
|
|
echo "✗ Backup integrity check failed!"
|
|
exit 1
|
|
fi
|
|
|
|
# 10. Send Notification
|
|
echo "10. Sending backup notification..."
|
|
BACKUP_SIZE=$(du -sh "$BACKUP_DIR" | cut -f1)
|
|
|
|
# Slack notification (optional)
|
|
if [ -n "${SLACK_WEBHOOK_URL:-}" ]; then
|
|
curl -X POST "$SLACK_WEBHOOK_URL" \
|
|
-H 'Content-Type: application/json' \
|
|
-d "{\"text\": \"✅ PostgreSQL backup completed successfully\n• Database: $DB_NAME\n• Size: $FILE_SIZE\n• Timestamp: $TIMESTAMP\n• Total backup dir size: $BACKUP_SIZE\"}"
|
|
fi
|
|
|
|
echo "===== PostgreSQL Backup Completed at $(date) ====="
|
|
echo "Total backup size: $BACKUP_SIZE"
|
|
echo "Backup location: $BACKUP_DIR"
|
|
|
|
# Exit successfully
|
|
exit 0
|