#!/bin/bash # # This is the backup script for Zarafa, to be used by Bacula. # # It uses /usr/bin/zarafa-backup (or specify a different path below), # and expires files from /var/lib/zarafa/bricklevel/ (configure below), # to ensure the files for the new bricklevel backup run represent the # Type of Job Bacula runs on this Client. # # Copyright (c) 2010 - Jeroen van Meeuwen # # = Before a Full Backup = # # 1) Expire all backups # 2) Create a new Full # 3) Preserve the .index.zbk files for upcoming Differentials # # = After a Full Backup = # # 1) Expire the .data.zbk files (they have been backed up) # # = Before a Differential Backup = # # 1) Expire the last Differential's .index.zbk files # 2) Make sure the last Full .index.zbk files are in the right location # 3) Preserve the .index.zbk # # Create the backup # # In case of a Differential backup: # - we need everything that has changed since the last Full backup. This includes # that we use the .index.zbk files from the last Full in # /var/lib/zarafa/bricklevel/. Luckily, we have saved those in # ZARAFA_BACKUP=/usr/bin/zarafa-backup ZARAFA_BACKUP_PATH=/var/lib/zarafa/bricklevel/ ZARAFA_BACKUP_LOG=/var/log/zarafa/backup.log # Runtime variables FULL=0 DIFF=0 INC=0 BEFORE=0 AFTER=0 # This is the implementation schedule: # # - Every first saturday of the month, do a Full backup at 11:59 (am). # - Every other saturday of the month, do a Differential backup at 22:59. # - Every weekday, do an Incremental backup at 22:59. # # However, crontab does not allow you create such a schedule easily. Ergo, # we do some of our own logic here. See the parsing of command-line # parameters for the application of this logic. # # Example crontab entries: # # # Puppet Name: zarafa-backup-bacula-monthly-full # 59 10 1-7 * 6 /usr/local/sbin/zarafa-backup-bacula Full --before; \ # /usr/local/sbin/zarafa-backup-bacula Full --after # | | | | | # | | | | `-- Run on the sixth day of the week (as well) # | | | `----- Run in all months # | | `----------- Run on all of the first 7 days of the month (as well) # `---+--------------- Run at 10:59 am # # # Puppet Name: zarafa-backup-bacula-weekly-diff # 59 22 8-31 * 6 /usr/local/sbin/zarafa-backup-bacula Differential --before; \ # /usr/local/sbin/zarafa-backup-bacula Differential --after # | | | | | # | | | | `-- Run on the sixth day of the week (as well) # | | | `----- Run in all months # | | `----------- Run on all but the first 7 days of the month (as well) # `---+--------------- Run at 22:59 # # # Puppet Name: zarafa-backup-bacula-daily-inc # 59 22 * * 1-5 /usr/local/sbin/zarafa-backup-bacula Incremental --before; \ # /usr/local/sbin/zarafa-backup-bacula Incremental --after # | | | | | # | | | | `-- Run on every weekday (as well) # | | | `----- Run in all months # | | `----------- Run on all days of the month (as well) # `---+--------------- Run at 10:59 am # function first_saturday_of_month() { # Returns 1 if this is the first saturday in this month. # Today is a? if [ `date +'%w'` -eq 6 -a `date +'%d'` -le 6 ]; then # It's a saturday, so if the day of the month -le 6, we have a winner return 1 else return 0 fi } function weekday() { # Returns 1 if this is a weekday. # Today is a? if [ `date +'%w'` -gt 0 -a `date +'%w'` -lt 6 ]; then # It's a weekday (not a saturday or sunday) return 1 else return 0 fi } function not_first_saturday_of_month() { # Returns 1 if this is the second, third, fourth or fifth saturday in this month. # Today is a? if [ `date +'%w'` -eq 6 -a `date +'%d'` -gt 6 ]; then # It's a saturday, so if the day of the month -gt 6, we have a winner return 1 else return 0 fi } function usage() { echo "Usage: $0 <--before|--after> [options]" echo "" echo "Options:" echo "" echo "Full Create a Full bricklevel backup set." echo "Differential Create a Differential bricklevel backup set." echo "Incremental Create an Incremental bricklevel backup set." echo "" echo "--after Expire files that have been backed up and" echo " may be expired." echo "--before Make sure the correct files are in the correct" echo " place and create the bricklevel backup." echo "" echo "--log [file] Log to file, not stdout. Default path is" echo " ${ZARAFA_BACKUP_LOG}" exit 1 } while [ $# -gt 0 ]; do case $1 in Full) [ `first_saturday_of_month; echo $?` -eq 1 ] && \ FULL=1 shift ;; Differential) [ `not_first_saturday_of_month; echo $?` -eq 1 ] && \ DIFF=1 shift ;; Incremental) [ `weekday; echo $?` -eq 1 ] && \ INC=1 shift ;; --before) BEFORE=1 shift ;; --after) AFTER=1 shift ;; --log) if [ -d `dirname $2` ]; then ZARAFA_BACKUP_LOG=$2 shift; shift else echo "Directory `dirname $2` does not exist." echo "" usage exit 1 fi ;; esac done if [ `pgrep -l zarafa-backup-bacula | wc -l` -gt 1 ]; then echo "Zarafa backup already running" exit 2 fi if [ $BEFORE -eq 1 ]; then if [ $FULL -eq 1 ]; then # real 1630m2.673s # user 118m23.616s # sys 32m57.687s # real 3m12.293s # user 0m0.020s # sys 0m0.254s # Remove everything; this Full is going to generate all # existing .index.zbk files useless. rm -rf ${ZARAFA_BACKUP_PATH}/working rm -rf ${ZARAFA_BACKUP_PATH}/Full rm -rf ${ZARAFA_BACKUP_PATH}/Differential rm -rf ${ZARAFA_BACKUP_PATH}/Incremental # Create the backup directory mkdir -p ${ZARAFA_BACKUP_PATH}/working # Create the backup echo "ALERT: Starting a Full backup" >> ${ZARAFA_BACKUP_LOG} ${ZARAFA_BACKUP} -v -a -J -o ${ZARAFA_BACKUP_PATH}/working >> ${ZARAFA_BACKUP_LOG} 2>&1 # Preserve the .index.zbk files for later Differentials or Incrementals mkdir -p ${ZARAFA_BACKUP_PATH}/Full find ${ZARAFA_BACKUP_PATH}/working/ -type f -name "*.index.zbk" -exec cp -af {} ${ZARAFA_BACKUP_PATH}/Full/. \; elif [ $DIFF -eq 1 ]; then # Remove all files in ZARAFA_BACKUP_PATH, and use the .index.zbk files # from the last Full backup. rm -rf ${ZARAFA_BACKUP_PATH}/working rm -rf ${ZARAFA_BACKUP_PATH}/Differential rm -rf ${ZARAFA_BACKUP_PATH}/Incremental mkdir -p ${ZARAFA_BACKUP_PATH}/working find ${ZARAFA_BACKUP_PATH}/Full/ -type f -name "*.index.zbk" -exec cp -af {} ${ZARAFA_BACKUP_PATH}/working/. \; # Create the backup echo "ALERT: Starting a Differential backup" >> ${ZARAFA_BACKUP_LOG} ${ZARAFA_BACKUP} -v -a -J -o ${ZARAFA_BACKUP_PATH}/working >> ${ZARAFA_BACKUP_LOG} 2>&1 # Preserve the .index.zbk files for later Incrementals mkdir -p ${ZARAFA_BACKUP_PATH}/Differential find ${ZARAFA_BACKUP_PATH}/working/ -type f -name "*.index.zbk" -exec cp -af {} ${ZARAFA_BACKUP_PATH}/Differential/. \; elif [ $INC -eq 1 ]; then # Remove all files in ZARAFA_BACKUP_PATH, and use the .index.zbk files # from either the last Full, Differential or Incremental (in that order). # real 81m57.098s # user 6m50.410s # sys 1m33.215s # # real 0m0.986s # user 0m0.010s # sys 0m0.090s rm -rf ${ZARAFA_BACKUP_PATH}/working mkdir -p ${ZARAFA_BACKUP_PATH}/working find ${ZARAFA_BACKUP_PATH}/Full/ -type f -name "*.index.zbk" -exec cp -af {} ${ZARAFA_BACKUP_PATH}/working/. \; find ${ZARAFA_BACKUP_PATH}/Differential/ -type f -name "*.index.zbk" -exec cp -af {} ${ZARAFA_BACKUP_PATH}/working/. \; find ${ZARAFA_BACKUP_PATH}/Incremental/ -type f -name "*.index.zbk" -exec cp -af {} ${ZARAFA_BACKUP_PATH}/working/. \; # Create the backup echo "ALERT: Starting an Incremental backup" >> ${ZARAFA_BACKUP_LOG} ${ZARAFA_BACKUP} -v -a -J -o ${ZARAFA_BACKUP_PATH}/working >> ${ZARAFA_BACKUP_LOG} 2>&1 mkdir -p ${ZARAFA_BACKUP_PATH}/Incremental find ${ZARAFA_BACKUP_PATH}/working/ -type f -name "*.index.zbk" -exec cp -af {} ${ZARAFA_BACKUP_PATH}/Incremental/. \; fi elif [ $AFTER -eq 1 ]; then # After the files have been backed up, we delete it all but preserve the # .index.zbk files. These can be used for upcoming incrementals. The .data.zbk # files however just consume space -and they have been backed up already. find ${ZARAFA_BACKUP_PATH}/working/ -type f ! -name '*.index.zbk' -delete fi