#!/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