We wrote an improved postgresql dump bash script for Postgresql version 9.1. This one will save each dump file with the name: database_name_DAYNAME.sql.bz2
In this way, we would only have 7 backups at any time, because each file will be overwritten after seven days. Since our backup system (TSM) saves 7 versions of each file, we would then have 49 versions at any time. That means we can go 49 days back in time to restore a certain dumpfile. In addition the script saves monthly a dump file with the name: database_name_MONTHNAME.sql.bz2.
You can also set a variable TEST to ‘yes’ to, then the script will only dump one specific filename: database_name_daily.sql.bz2. This can be useful on Test servers, where you might not be interested in a historical backup back in time.
Here it is:
#!/bin/bash ## This scripts dumps all the databases in a Postgres 9.1 server, localhost ## 2 dump files are made for each database. One with Inserts another without. ## TODO # - implement a 'if system is Test' option to minimize number of dump files UNDER PROGRESS # - use functions instead? # - some kind of integration with Jenkins? # - fix the 2 strange '|' that appears in the DATABASE list FIXED? # - Add timer so we can optimize speed of the script execution time # - enable use of the logfile LOGFILE. Could be nice to log what this script is/has been doing and when. # - number of days to keep a dump file could be a parameter to this script # - enable print of name of the script, where the script is run (hostname and directory). Makes it easy to find the script on a server # - would be nice to add a incremental feature for this script. Then one can dump files several times a day, without worrying about space problems on the harddisk DIFFICULT? ## TODO END # Timer start_time=$(date +%s) # Variables LOGFILE="/var/lib/pgsql/9.1/data/pg_log/pgsql_dump.log" BACKUP_DIR="/var/backup/postgresql_dumps" BACKUP_DIR2="var/backup/postgresql_dumps" # Gosh.. HOSTNAME=`hostname` MAILLIST="someone att somewhere" # should be edited # Is this a test system? Set TESTSYSTEM to 'yes' in order to remove date and time information from dumpfile names (in order to minimize number of dumpfiles). TESTSYSTEM="no" TODAY=$(date|awk '{ print $1 }') MONTH=$(date|awk '{ print $1 }') MONTHNAME=`date +%b --date '0 month'` DAYINMONTH=$(date|awk '{ print $3 }') YEAR=$(date | awk '{ print $6 }') # Only postgres can run this script if [ `whoami` != "postgres" ]; then echo "pgsql_dump tried to run, but user is not postgres!" >> $LOGFILE echo "You are not postgres, can not run." echo "Try: su -c ./pgsql_dump.sh postgres" exit; fi # Check if there any backup files. If not, something is wrong! if [ `find $BACKUP_DIR -type f -name '*.sql.bz2' -mtime -2 | wc -l` -eq 0 ]; then echo "There are no pgsql dumps for the last 2 days at $HOSTNAME. Something is wrong!" | mail -s "[PGSQLDUMP ERROR] $HOSTNAME" $MAILLIST fi # logfile might be nice to have (or maybe Jenkins is the way to go?) if [ ! -e $LOGFILE ]; then touch $LOGFILE fi if [ $TESTSYSTEM == "yes" ];then #DATABASES=`psql -q -c "\l" | sed -n 4,/\eof/p | grep -v rows | grep -v template0 | awk {'print $1}' | sed 's/^://g' | sed -e '/^$/d' | grep -v '|'` # For testing purposes DATABASES="database-1 database-2" else DATABASES=`psql -q -c "\l" | sed -n 4,/\eof/p | grep -v rows | grep -v template0 | awk {'print $1}' | sed 's/^://g' | sed -e '/^$/d' | grep -v '|'` fi for i in $DATABASES; do ## Create folders for each database if they don't exist if [ ! -d "$BACKUP_DIR/$i/" ];then mkdir $BACKUP_DIR/$i fi if [ ! -d "$BACKUP_DIR/$i/daily" ];then mkdir $BACKUP_DIR/$i/daily fi if [ ! -d "$BACKUP_DIR/$i/monthly" ];then mkdir $BACKUP_DIR/$i/monthly fi # On Test servers we don't want dump files with date and time information if [ $TESTSYSTEM == "yes" ];then DAILYFILENAME="daily_$i" MONTHLYFILENAME="monthly_$i" ALLDATABASESFILENAME="all-databases" else DAILYFILENAME="daily_$i_$TODAY" MONTHLYFILENAME="monthly_$i_$MONTHNAME" ALLDATABASESFILENAME="all-databases_$TODAY" fi # backup for each weekday (Mon, Tue, ...) nice -n 10 /usr/pgsql-9.1/bin/pg_dump --column-inserts $i > $BACKUP_DIR/$i/daily/"$DAILYFILENAME".sql nice -n 10 tar cjf $BACKUP_DIR/$i/daily/"$DAILYFILENAME".sql.bz2 -C / $BACKUP_DIR2/$i/daily/"$DAILYFILENAME".sql rm -f $BACKUP_DIR/$i/daily/"$DAILYFILENAME".sql # dump with copy statements nice -n 10 /usr/pgsql-9.1/bin/pg_dump $i > $BACKUP_DIR/$i/daily/"$DAILYFILENAME"_copy.sql nice -n 10 tar cjf $BACKUP_DIR/$i/daily/"$DAILYFILENAME"_copy.sql.bz2 -C / $BACKUP_DIR2/$i/daily/"$DAILYFILENAME"_copy.sql rm -f $BACKUP_DIR/$i/daily/"$DAILYFILENAME"_copy.sql # monthly backup (Jan, Feb...) if [ $DAYINMONTH==10 ]; then cp -f $BACKUP_DIR/$i/daily/"$DAILYFILENAME".sql.bz2 $BACKUP_DIR/$i/monthly/"$MONTHLYFILENAME".sql.bz2 cp -f $BACKUP_DIR/$i/daily/"$DAILYFILENAME"_copy.sql.bz2 $BACKUP_DIR/$i/monthly/"$MONTHLYFILENAME"_copy.sql.bz2 fi # Year backup # coming after a while done ## Full backup nice -n 10 /usr/pgsql-9.1/bin/pg_dumpall --column-inserts > $BACKUP_DIR/"$ALLDATABASESFILENAME".sql nice -n 10 /usr/pgsql-9.1/bin/pg_dumpall > $BACKUP_DIR/"$ALLDATABASESFILENAME"_copy.sql nice -n 10 tar cjf $BACKUP_DIR/"$ALLDATABASESFILENAME".sql.bz2 -C / var/backup/postgresql_dumps/"$ALLDATABASESFILENAME".sql nice -n 10 tar cjf $BACKUP_DIR/"$ALLDATABASESFILENAME"_copy.sql.bz2 -C / var/backup/postgresql_dumps/"$ALLDATABASESFILENAME"_copy.sql rm -f $BACKUP_DIR/"$ALLDATABASESFILENAME".sql rm -f $BACKUP_DIR/"$ALLDATABASESFILENAME"_copy.sql ## Vacuuming (is it really necessary for PG 9.1? Don't think so...) #nice -n 10 vacuumdb -a -f -z -q finish_time=$(date +%s) echo "Time duration for pg_dump script at $HOSTNAME: $((finish_time - start_time)) secs." | mail $MAILLIST