From e9d36aa2611fb3e812bb8ae4a6252bbd65f9cfcf Mon Sep 17 00:00:00 2001 From: Mattia Tadini Date: Tue, 12 Nov 2024 12:08:10 +0000 Subject: [PATCH] Add postgres-backup.sh --- postgres-backup.sh | 348 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 348 insertions(+) create mode 100644 postgres-backup.sh diff --git a/postgres-backup.sh b/postgres-backup.sh new file mode 100644 index 0000000..b0f3102 --- /dev/null +++ b/postgres-backup.sh @@ -0,0 +1,348 @@ +#!/bin/bash +# Script per il backup di database PostgreSQL +# Autore: Mattia Tadini +# Nome File: postgres-backup.sh +# Revisione: 1.0 + + +# Prerequisiti + +apt install ftp msmtp -y +mkdir -p /$BACKUPDIR +cat > /etc/msmtprc <<'EOF' +# Configurazione msmtp - account predefinito +defaults +auth on +tls on +tls_trust_file /etc/ssl/certs/ca-certificates.crt +host relay.poloinformatico.it +port 587 +user brass@relay.poloinformatico.it +from brass@relay.poloinformatico.it +password DMKqP9vUYn8s +logfile ~/.msmtp.log + +# Impostiamo l'account predefinito +account default + +EOF + +# Load configuration from external file +CONFIG_FILE="/zucchetti/backupdb/psqlconfig.env" +if [ -f "$CONFIG_FILE" ]; then + source "$CONFIG_FILE" +else + echo "Configuration file not found: $CONFIG_FILE" + exit 1 +fi + +# Default values for configuration (will be overridden by config.env if present) +: ${BACKUP_DIR:="/zucchetti/backupdb/bkfiles"} +: ${PGDUMP:="pg_dump"} +: ${PSQL:="psql"} +: ${HOST:="localhost"} +: ${PORT:="5432"} +: ${RETENTION:=1} # Retention per i backup locali +: ${REMOTE_RETENTION:=2} # Retention per i backup remoti +: ${SERVER_NAME:="PGDB01"} # Identificativo del server fisico +: ${LOG_FILE:="/zucchetti/backupdb/backup_log.txt"} +: ${ERROR_LOG_FILE:="/zucchetti/backupdb/backup_err.txt"} +: ${REMOTE_DIR:="/BackupDB"} +: ${DO_LOCAL_BACKUP:=1} # 1 per eseguire il backup locale, 0 per disabilitarlo +: ${DO_FTP_BACKUP:=1} # 1 per eseguire il backup FTP, 0 per disabilitarlo +: ${COMPRESSION_LEVEL:="9"} # Livello di compressione (1-9) + +# Required variables check +required_vars=( + "USER" "PASSWORD" "FTP_SERVER" "FTP_USER" "FTP_PASSWORD" + "SMTP_SERVER" "SMTP_USER" "SMTP_PASS" "DO_LOCAL_BACKUP" "DO_FTP_BACKUP" +) + +for var in "${required_vars[@]}"; do + if [ -z "${!var}" ]; then + echo "Error: Required variable $var is not set in config file" + exit 1 + fi +done + +# Set date format +DATE=$(LC_TIME=C date +%Y%m%d%H%M%S) + +# Export PostgreSQL password +export PGPASSWORD="$PASSWORD" + +# Function to get all user databases +get_all_databases() { + $PSQL -h "$HOST" -p "$PORT" -U "$USER" -t -c "SELECT datname FROM pg_database WHERE datistemplate = false AND datname != 'postgres'" | grep -v "^$" | tr -d ' ' +} + +# Function to check FTP connection +check_ftp_connection() { + # Skip if FTP backup is disabled + if [ "$DO_FTP_BACKUP" -eq 0 ]; then + return 0 + fi + + local temp_file=$(mktemp) + ftp -inv $FTP_SERVER > $temp_file 2>&1 < $temp_file 2>&1 <> $LOG_FILE + sleep 5 + done + + cat $temp_file >> $LOG_FILE 2>> $ERROR_LOG_FILE + rm -f $temp_file + return $upload_status +} + +# Function to send email with msmtp +send_email() { + local db_name="$1" + local status_message="" + + # Costruisci il messaggio di stato dettagliato + if [ "$DO_LOCAL_BACKUP" -eq 1 ]; then + if [ $LOCAL_STATUS -eq 0 ]; then + status_message="Local backup: SUCCESS\n" + else + status_message="Local backup: FAILED\n" + fi + else + status_message="Local backup: DISABLED\n" + fi + + if [ "$DO_FTP_BACKUP" -eq 1 ]; then + if [ $FTP_STATUS -eq 0 ]; then + status_message+="FTP upload: SUCCESS\n" + else + status_message+="FTP upload: FAILED\n" + fi + else + status_message+="FTP upload: DISABLED\n" + fi + + SUBJECT="Backup [${EMAIL_STATUS}] for $db_name on $SERVER_NAME - $(LC_TIME=C date)" + MESSAGE="Backup process completed with following status:\n\n${status_message}\nDetailed log:\n\n$(cat $LOG_FILE)" + + if [ -f "$ERROR_LOG_FILE" ] && [ -s "$ERROR_LOG_FILE" ]; then + MESSAGE+="\n\nErrors encountered:\n\n$(cat $ERROR_LOG_FILE)" + fi + + echo -e "Subject: $SUBJECT\nFrom: $SMTP_USER\nTo: $SMTP_USER\n\n$MESSAGE" | \ + msmtp --debug --from="$SMTP_USER" -t +} + +# Function to perform backup for a single database +perform_backup() { + local db_name="$1" + local LOCAL_STATUS=1 + local FTP_STATUS=1 + local EMAIL_STATUS="" + + echo "Starting backup process for database: $db_name" + + LOCAL_DB_DIR="$BACKUP_DIR/$db_name" + REMOTE_DB_DIR="$REMOTE_DIR/$db_name" + BACKUP_FILE="$LOCAL_DB_DIR/${db_name}_backup_$DATE.sql.gz" + REMOTE_BACKUP_FILE="${db_name}_backup_$DATE.sql.gz" + + # Create local backup directory if local backup is enabled + if [ "$DO_LOCAL_BACKUP" -eq 1 ]; then + mkdir -p "$LOCAL_DB_DIR" + fi + + # Create remote directory on FTP server if FTP backup is enabled + if [ "$DO_FTP_BACKUP" -eq 1 ] && check_ftp_connection; then + ftp -inv $FTP_SERVER <> $LOG_FILE 2>> $ERROR_LOG_FILE +user $FTP_USER $FTP_PASSWORD +mkdir "$REMOTE_DB_DIR" +bye +EOF + fi + + # Start time for the backup + START_TIME=$(date +%s) + echo "$(LC_TIME=C date): Starting backup for database: $db_name on server $SERVER_NAME" > $LOG_FILE + + # Perform local backup if enabled + if [ "$DO_LOCAL_BACKUP" -eq 1 ]; then + # Esegui il backup con pg_dump e comprimi direttamente + $PGDUMP -h "$HOST" -p "$PORT" -U "$USER" -F c -Z $COMPRESSION_LEVEL "$db_name" > "$BACKUP_FILE" 2>> $ERROR_LOG_FILE + + # Check if the local backup was successful + if [ $? -eq 0 ] && [ -f "$BACKUP_FILE" ]; then + LOCAL_STATUS=0 + echo "$(LC_TIME=C date): Local backup completed successfully for $db_name." >> $LOG_FILE + else + LOCAL_STATUS=1 + echo "$(LC_TIME=C date): Error during local backup of $db_name. Check error log." >> $LOG_FILE + fi + else + LOCAL_STATUS=0 + echo "$(LC_TIME=C date): Local backup disabled for $db_name." >> $LOG_FILE + fi + + # End time and duration + END_TIME=$(date +%s) + DURATION=$((END_TIME - START_TIME)) + echo "$(LC_TIME=C date): Backup ended for $db_name." >> $LOG_FILE + echo "Start time: $(LC_TIME=C date -d @$START_TIME)" >> $LOG_FILE + echo "End time: $(LC_TIME=C date -d @$END_TIME)" >> $LOG_FILE + echo "Duration: $((DURATION / 60)) minutes and $((DURATION % 60)) seconds" >> $LOG_FILE + + # Upload backup to remote FTP server if enabled and local backup was successful + if [ "$DO_FTP_BACKUP" -eq 1 ]; then + if [ "$DO_LOCAL_BACKUP" -eq 0 ] || [ $LOCAL_STATUS -eq 0 ]; then + echo "$(LC_TIME=C date): Starting FTP upload for $db_name." >> $LOG_FILE + + if ! check_ftp_connection; then + FTP_STATUS=1 + echo "$(LC_TIME=C date): Cannot establish FTP connection. Upload failed." >> $LOG_FILE + echo "FTP connection failed - Cannot connect to server" >> $ERROR_LOG_FILE + else + if perform_ftp_upload "$BACKUP_FILE" "$REMOTE_BACKUP_FILE"; then + FTP_STATUS=0 + echo "$(LC_TIME=C date): FTP upload completed successfully for $db_name." >> $LOG_FILE + else + FTP_STATUS=1 + echo "$(LC_TIME=C date): Error during FTP upload for $db_name. Check error log." >> $LOG_FILE + fi + fi + else + echo "$(LC_TIME=C date): Skipping FTP upload due to local backup failure." >> $LOG_FILE + FTP_STATUS=1 + fi + else + FTP_STATUS=0 + echo "$(LC_TIME=C date): FTP upload disabled for $db_name." >> $LOG_FILE + fi + + # Local retention policy if local backup is enabled + if [ "$DO_LOCAL_BACKUP" -eq 1 ] && [ $LOCAL_STATUS -eq 0 ]; then + find "$LOCAL_DB_DIR" -name "${db_name}_backup_*.sql.gz" -type f -mtime +$RETENTION -delete >> $LOG_FILE 2>> $ERROR_LOG_FILE + fi + + # Remote retention policy if FTP backup is enabled + if [ "$DO_FTP_BACKUP" -eq 1 ] && [ $FTP_STATUS -eq 0 ]; then + echo "$(LC_TIME=C date): Performing remote retention check." >> $LOG_FILE + + temp_list_file=$(mktemp) + ftp -inv $FTP_SERVER > $temp_list_file 2>> $ERROR_LOG_FILE <> $LOG_FILE + retention_date=$(LC_TIME=C date -d "-$REMOTE_RETENTION days" +%Y%m%d%H%M%S) + + if [ "$file_date" -lt "$retention_date" ]; then + ftp -inv $FTP_SERVER <> $LOG_FILE 2>> $ERROR_LOG_FILE +user $FTP_USER $FTP_PASSWORD +cd $REMOTE_DB_DIR +delete "$file" +bye +EOF + echo "$(LC_TIME=C date): File remoto $file eliminato perché più vecchio di $REMOTE_RETENTION giorni." >> $LOG_FILE + fi + fi + fi + done + rm -f $temp_list_file + fi + + # Determine email status based on enabled backups + if [ "$DO_LOCAL_BACKUP" -eq 1 ] && [ "$DO_FTP_BACKUP" -eq 1 ]; then + if [ $LOCAL_STATUS -eq 0 ] && [ $FTP_STATUS -eq 0 ]; then + EMAIL_STATUS="SUCCESS" + elif [ $LOCAL_STATUS -eq 1 ] && [ $FTP_STATUS -eq 1 ]; then + EMAIL_STATUS="FAILED" + else + EMAIL_STATUS="WARNING" + fi + elif [ "$DO_LOCAL_BACKUP" -eq 1 ]; then + if [ $LOCAL_STATUS -eq 0 ]; then + EMAIL_STATUS="SUCCESS" + else + EMAIL_STATUS="FAILED" + fi + elif [ "$DO_FTP_BACKUP" -eq 1 ]; then + if [ $FTP_STATUS -eq 0 ]; then + EMAIL_STATUS="SUCCESS" + else + EMAIL_STATUS="FAILED" + fi + else + EMAIL_STATUS="DISABLED" + fi + + # Send email with log + send_email "$db_name" + + # Cleanup + rm -f $LOG_FILE + [ -f "$ERROR_LOG_FILE" ] && [ ! -s "$ERROR_LOG_FILE" ] && rm -f "$ERROR_LOG_FILE" + + echo "Backup process complete for $db_name with status: $EMAIL_STATUS (Local: $LOCAL_STATUS, FTP: $FTP_STATUS)" + return $(( LOCAL_STATUS | FTP_STATUS )) +} + +# Main script logic +if [ -z "$1" ]; then + echo "No database specified, backing up all databases..." + OVERALL_STATUS=0 + + for db in $(get_all_databases); do + perform_backup "$db" + BACKUP_STATUS=$? + [ $BACKUP_STATUS -ne 0 ] && OVERALL_STATUS=1 + done + + exit $OVERALL_STATUS +else + perform_backup "$1" + exit $? +fi \ No newline at end of file