My Notes for Installing Zimbra OSE on Ubuntu Server 10.04 LTS
-
- Advanced member
- Posts: 148
- Joined: Sat Sep 13, 2014 2:14 am
My Notes for Installing Zimbra OSE on Ubuntu Server 10.04 LTS
ZIMBRA BACKUP
THERE ARE VARIOUS METHODS OF BACKUP THAT CAN BE UTILIZED BUT THESE ARE THE ONES I WILL BE USING:
BACKUP TO LOCAL FOLDER USING RSYNC
BACKUP INDIVIDUAL MAILBOXES
BACKUP USING LVM SNAPSHOTS
IF I HAVE TIME, I WILL ALSO EXPLORE THE SETUP OF AN ADDITIONAL SERVER TO SERVE AS A HOT-SPARE SO-TO-SPEAK. I'D LIKE TO SEE A BACKUP SERVER CONFIGURED TO RECEIVE BACKUPS FROM THE PRODUCTION SERVER AND IN THE EVENT THE PRODUCTION SERVER GOES DARK, SPIN UP THE BACKUP SERVER TO BE ITS REPLACEMENT.
FOR THE 1ST METHOD OF USING RSYNC, THERE IS ONE MAJOR CATCH USING RSYNC ALONE IN THAT YOU CANNOT BACKUP FILES CURRENTLY IN USE. THAT MEANS YOU HAVE TO SHUTDOWN THE SERVICES IN ORDER TO GET A COMPLETE BACKUP. WITH THIS IN MIND, MY SOLUTION IS TO UTILIIZE TWO SCRIPTS. THE 1ST SCRIPT WILL BACKUP WHAT IT CAN WHILE THE SERVER IS "ONLINE" AND THE 2ND SCRIPT WILL RUN DURING OFF-HOURS TO SHUTDOWN THE SERVICES (MAKE IT OFFLINE) AND PERFORM A COMPLETE BACKUP.
THE ONLINE SCRIPT WILL BE SCHEDULED TO RUN MULTIPLE TIMES THROUGHOUT THE DAY AND WILL NOT CAUSE ANY DOWNTIME.
THE OFFLINE SCRIPT WILL BE SCHEDULED ONCE PER DAY AT A TIME THAT WILL CAUSE THE LEAST AMOUNT OF IMPACT BECAUSE THE SERVER WILL GO OFFLINE FOR ABOUT 3 TO 5 MINUTES. IT WILL THEN COMPRESS THE BACKUP INTO A SINGLE ARCHIVE AND MOVE IT TO AN OFFSITE SERVER.
MY OFFSITE STORAGE WILL BE ON A WINDOWS 2008 SERVER. THE 1ST THING TO DO WILL BE THE CONFIGURATION OF THE WINDOWS SERVER TO ALLOW THE UBUNTU SERVER TO CONNECT AND MANAGE FILES.
BACKUP - RSYNC WHILE ONLINE
RSYNC-ONLINE.SH
#!/BIN/BASH
#############################################
## NAME : RSYNC-ONLINE.SH
## VERSION : 1.1
## DATE : 2011-11-04
## AUTHOR : LHAMMONDS
## COMPATIBILITY : UBUNTU SERVER 10.04.3 - 10.04.4 LTS, ZIMBRA 7.1.2 - 7.2.0 OSE
## PURPOSE : PARTIAL BACKUP WHILE ZIMBRA IS ONLINE.
## RUN FREQUENCY : SEVERAL TIMES THROUGHOUT THE DAY.
## EXIT CODES : (IF MULTIPLE ERRORS, VALUE IS THE ADDITION OF CODES)
## 0 = SUCCESS
## 1 = RSYNC FAILURE
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-10-21 LTH CREATED SCRIPT.
## 2011-11-04 LTH MOVED COMMON VARIABLES AND FUNCTIONS TO EXTERNAL FILE.
#############################################
## IMPORT COMMON VARIABLES AND FUNCTIONS. ##
SOURCE /VAR/SCRIPTS/COMMON/STANDARD.CONF
LOGFILE="${TEMPDIR}/RSYNC.LOG"
TARGET="${BACKUPDIR}/ZIMBRA"
LOCKFILE="${TEMPDIR}/RSYNC.LOCK"
ERRORFLAG=0
RETURNVALUE=0
#######################################
## FUNCTIONS ##
#######################################
FUNCTION F_CLEANUP()
{
IF [ -F ${LOCKFILE} ];THEN
## REMOVE LOCK FILE SO OTHER RSYNC JOBS CAN RUN.
RM ${LOCKFILE} 1>/DEV/NULL 2>&1
FI
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - ONLINE RSYNC BACKUP EXIT CODE: ${ERRORFLAG}" >> ${LOGFILE}
}
#######################################
## MAIN PROGRAM ##
#######################################
IF [ -F ${LOCKFILE} ]; THEN
## RSYNC LOCK FILE DETECTED. ABORT SCRIPT.
F_SENDMAIL "ONLINE RSYNC BACKUP ABORTED - LOCK FILE" "THIS SCRIPT TRIED TO RUN BUT DETECTED THE LOCK FILE: ${LOCKFILE}NNPLEASE CHECK TO MAKE SURE THE FILE DOES NOT REMAIN WHEN RSYNC IS NOT ACTUALLY RUNNING."
EXIT 1
ELSE
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` ${SCRIPTNAME}" > ${LOCKFILE}
FI
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - ONLINE RSYNC BACKUP MODE STARTED." >> ${LOGFILE}
## OUTPUT THE CURRENT VERSION TO A TEXT FILE WHICH WILL BE INCLUDED IN THE BACKUP.
## NOTE: YOU CAN ALSO VIEW /OPT/ZIMBRA/.INSTALL_HISTORY
SU - ZIMBRA -C "ZMCONTROL -V > ${ZIMBRADIR}/CONF/ZIMBRA_VERSION.TXT"
## RSYNC WILL COPY WHAT IT CAN TO THE TARGET LOCATION.
RSYNC -APOGHK --DELETE --EXCLUDE=*.PID ${ZIMBRADIR} ${TARGET} 1>/DEV/NULL 2>&1
RETURNVALUE=$?
IF [ ${RETURNVALUE} -NE 0 ]; THEN
## ERROR: SEND EMAIL NOTIFICATION.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- ERROR: ONLINE RSYNC FAILED. ${ZIMBRADIR} -> ${TARGET}" >> ${LOGFILE}
F_SENDMAIL "ONLINE RSYNC BACKUP FAILURE - RSYNC" "ERROR: ONLINE RSYNC FAILED. ${ZIMBRADIR} -> ${TARGET}, RETURN VALUE = ${RETURNVALUE}"
ERRORFLAG=${ERRORFLAG} + 1
FI
## DOCUMENT STATISTICS.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - DISK USAGE FOR BOTH SOURCE AND TARGET:" >> ${LOGFILE}
ECHO "`DU -SH ${ZIMBRADIR}`" >> ${LOGFILE}
ECHO "`DU -SH ${TARGET}`" >> ${LOGFILE}
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - ONLINE RSYNC BACKUP MODE COMPLETED." >> ${LOGFILE}
## PERFORM CLEANUP ROUTINE.
F_CLEANUP
## EXIT WITH THE COMBINED RETURN CODE VALUE.
EXIT ${ERRORFLAG}
THERE ARE VARIOUS METHODS OF BACKUP THAT CAN BE UTILIZED BUT THESE ARE THE ONES I WILL BE USING:
BACKUP TO LOCAL FOLDER USING RSYNC
BACKUP INDIVIDUAL MAILBOXES
BACKUP USING LVM SNAPSHOTS
IF I HAVE TIME, I WILL ALSO EXPLORE THE SETUP OF AN ADDITIONAL SERVER TO SERVE AS A HOT-SPARE SO-TO-SPEAK. I'D LIKE TO SEE A BACKUP SERVER CONFIGURED TO RECEIVE BACKUPS FROM THE PRODUCTION SERVER AND IN THE EVENT THE PRODUCTION SERVER GOES DARK, SPIN UP THE BACKUP SERVER TO BE ITS REPLACEMENT.
FOR THE 1ST METHOD OF USING RSYNC, THERE IS ONE MAJOR CATCH USING RSYNC ALONE IN THAT YOU CANNOT BACKUP FILES CURRENTLY IN USE. THAT MEANS YOU HAVE TO SHUTDOWN THE SERVICES IN ORDER TO GET A COMPLETE BACKUP. WITH THIS IN MIND, MY SOLUTION IS TO UTILIIZE TWO SCRIPTS. THE 1ST SCRIPT WILL BACKUP WHAT IT CAN WHILE THE SERVER IS "ONLINE" AND THE 2ND SCRIPT WILL RUN DURING OFF-HOURS TO SHUTDOWN THE SERVICES (MAKE IT OFFLINE) AND PERFORM A COMPLETE BACKUP.
THE ONLINE SCRIPT WILL BE SCHEDULED TO RUN MULTIPLE TIMES THROUGHOUT THE DAY AND WILL NOT CAUSE ANY DOWNTIME.
THE OFFLINE SCRIPT WILL BE SCHEDULED ONCE PER DAY AT A TIME THAT WILL CAUSE THE LEAST AMOUNT OF IMPACT BECAUSE THE SERVER WILL GO OFFLINE FOR ABOUT 3 TO 5 MINUTES. IT WILL THEN COMPRESS THE BACKUP INTO A SINGLE ARCHIVE AND MOVE IT TO AN OFFSITE SERVER.
MY OFFSITE STORAGE WILL BE ON A WINDOWS 2008 SERVER. THE 1ST THING TO DO WILL BE THE CONFIGURATION OF THE WINDOWS SERVER TO ALLOW THE UBUNTU SERVER TO CONNECT AND MANAGE FILES.
BACKUP - RSYNC WHILE ONLINE
RSYNC-ONLINE.SH
#!/BIN/BASH
#############################################
## NAME : RSYNC-ONLINE.SH
## VERSION : 1.1
## DATE : 2011-11-04
## AUTHOR : LHAMMONDS
## COMPATIBILITY : UBUNTU SERVER 10.04.3 - 10.04.4 LTS, ZIMBRA 7.1.2 - 7.2.0 OSE
## PURPOSE : PARTIAL BACKUP WHILE ZIMBRA IS ONLINE.
## RUN FREQUENCY : SEVERAL TIMES THROUGHOUT THE DAY.
## EXIT CODES : (IF MULTIPLE ERRORS, VALUE IS THE ADDITION OF CODES)
## 0 = SUCCESS
## 1 = RSYNC FAILURE
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-10-21 LTH CREATED SCRIPT.
## 2011-11-04 LTH MOVED COMMON VARIABLES AND FUNCTIONS TO EXTERNAL FILE.
#############################################
## IMPORT COMMON VARIABLES AND FUNCTIONS. ##
SOURCE /VAR/SCRIPTS/COMMON/STANDARD.CONF
LOGFILE="${TEMPDIR}/RSYNC.LOG"
TARGET="${BACKUPDIR}/ZIMBRA"
LOCKFILE="${TEMPDIR}/RSYNC.LOCK"
ERRORFLAG=0
RETURNVALUE=0
#######################################
## FUNCTIONS ##
#######################################
FUNCTION F_CLEANUP()
{
IF [ -F ${LOCKFILE} ];THEN
## REMOVE LOCK FILE SO OTHER RSYNC JOBS CAN RUN.
RM ${LOCKFILE} 1>/DEV/NULL 2>&1
FI
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - ONLINE RSYNC BACKUP EXIT CODE: ${ERRORFLAG}" >> ${LOGFILE}
}
#######################################
## MAIN PROGRAM ##
#######################################
IF [ -F ${LOCKFILE} ]; THEN
## RSYNC LOCK FILE DETECTED. ABORT SCRIPT.
F_SENDMAIL "ONLINE RSYNC BACKUP ABORTED - LOCK FILE" "THIS SCRIPT TRIED TO RUN BUT DETECTED THE LOCK FILE: ${LOCKFILE}NNPLEASE CHECK TO MAKE SURE THE FILE DOES NOT REMAIN WHEN RSYNC IS NOT ACTUALLY RUNNING."
EXIT 1
ELSE
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` ${SCRIPTNAME}" > ${LOCKFILE}
FI
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - ONLINE RSYNC BACKUP MODE STARTED." >> ${LOGFILE}
## OUTPUT THE CURRENT VERSION TO A TEXT FILE WHICH WILL BE INCLUDED IN THE BACKUP.
## NOTE: YOU CAN ALSO VIEW /OPT/ZIMBRA/.INSTALL_HISTORY
SU - ZIMBRA -C "ZMCONTROL -V > ${ZIMBRADIR}/CONF/ZIMBRA_VERSION.TXT"
## RSYNC WILL COPY WHAT IT CAN TO THE TARGET LOCATION.
RSYNC -APOGHK --DELETE --EXCLUDE=*.PID ${ZIMBRADIR} ${TARGET} 1>/DEV/NULL 2>&1
RETURNVALUE=$?
IF [ ${RETURNVALUE} -NE 0 ]; THEN
## ERROR: SEND EMAIL NOTIFICATION.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- ERROR: ONLINE RSYNC FAILED. ${ZIMBRADIR} -> ${TARGET}" >> ${LOGFILE}
F_SENDMAIL "ONLINE RSYNC BACKUP FAILURE - RSYNC" "ERROR: ONLINE RSYNC FAILED. ${ZIMBRADIR} -> ${TARGET}, RETURN VALUE = ${RETURNVALUE}"
ERRORFLAG=${ERRORFLAG} + 1
FI
## DOCUMENT STATISTICS.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - DISK USAGE FOR BOTH SOURCE AND TARGET:" >> ${LOGFILE}
ECHO "`DU -SH ${ZIMBRADIR}`" >> ${LOGFILE}
ECHO "`DU -SH ${TARGET}`" >> ${LOGFILE}
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - ONLINE RSYNC BACKUP MODE COMPLETED." >> ${LOGFILE}
## PERFORM CLEANUP ROUTINE.
F_CLEANUP
## EXIT WITH THE COMBINED RETURN CODE VALUE.
EXIT ${ERRORFLAG}
-
- Advanced member
- Posts: 148
- Joined: Sat Sep 13, 2014 2:14 am
My Notes for Installing Zimbra OSE on Ubuntu Server 10.04 LTS
Backup - RSync while offline
Although this backup takes the services down, the RSync job just prior to taking the services down ensures the vast majority of the data is already backed up. The only thing that has to be done after the services are down is to copy the changes in the last minute and the files that could not be copied while the services were running.
The actual downtime is typically between 3 to 5 minutes of my server and I doubt it will require longer downtime time even as the data store increases.
rsync-offline.sh
#!/bin/bash
#############################################
## Name : rsync-offline.sh
## Version : 1.4
## Date : 2012-01-09
## Author : LHammonds
## Purpose : Complete backup while Zimbra is offline.
## Compatibility : Verified on Ubuntu Server 10.04.3 - 10.04.4 LTS, Zimbra 7.1.2 - 7.2.0 OSE
## Requirements : p7zip-full (if ARCHIVEMETHOD=tar.7z)
## Run Frequency : Once per day after hours.
## Exit Codes : (if multiple errors, value is the addition of codes)
## 0 = success
## 1 = rsync failure
## 2 = archive failure
## 4 = archive purge failure
## 8 = configuration error
## 16 = crontab backup error
## 32 = crontab restore warning
## 64 = mount warning
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-10-21 LTH Created script.
## 2011-10-28 LTH Added 7-Zip compression (gunzip optional)
## 2011-11-04 LTH Move common variables and funtions to external file.
## 2011-11-08 LTH Added zimbra subfolder to remote site for organization.
## 2012-01-09 LTH Bugfix for f_PurgeOldestArchive
#############################################
## Import common variables and functions. ##
source /var/scripts/common/standard.conf
LOGFILE="${TEMPDIR}/rsync.log"
TEMPLOG="${TEMPDIR}/rsync-offline-temp.$$"
LOCKFILE="${TEMPDIR}/rsync.lock"
TARGETDIR="${BACKUPDIR}/zimbra"
OFFSITEBACKDIR="${OFFSITEDIR}/zimbra"
ARCHIVEFILE="`date +%Y-%m-%d-%H-%M`_zimbra-backup.${ARCHIVEMETHOD}"
ZMCRONFILE="${TEMPDIR}/zimbra-crontab.$$"
ERRORFLAG=0
#######################################
## FUNCTIONS ##
#######################################
function f_PurgeOldestArchive()
{
## Purpose: Delete the oldest archive on the remote site.
## Return values:
## 0 = Success
## 1 = Cannot delete file
## 9 = Configuration error, path empty
## Variable Error Check. *
if [ ${OFFSITEBACKDIR} = "" ]; then
## Make darn sure the path is not empty since we do NOT
## want to start purging files from a random location.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purge error: OFFSITEBACKDIR site variable is empty!" >> ${TEMPLOG}
return 9
fi
## Get the name of the oldest file.
OLDESTFILE=`ls -1t ${OFFSITEBACKDIR} | tail -1`
FILESIZE=`ls -la ${OFFSITEDIR}/${OLDFILE} | awk '{print $5}' | sed -e :a -e 's/(.*[0-9])([0-9]{3})/1,2/;ta'`
if [ "${OLDESTFILE}" = "" ]; then
## Error. Filename variable empty.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purge error: OLDESTFILE variable is empty." >> ${TEMPLOG}
return 9
else
FILESIZE=`ls -lak "${OFFSITEBACKDIR}/${OLDESTFILE}" | awk '{ print $5 }' | sed -e :a -e 's/(.*[0-9])([0-9]{3})/1,2/;ta'`
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purging old file: ${OFFSITEBACKDIR}/${OLDESTFILE}, Size = ${FILESIZE} kb" >> ${TEMPLOG}
rm "${OFFSITEBACKDIR}/${OLDESTFILE}"
if [ -f "${OFFSITEBACKDIR}/${OLDESTFILE}" ]; then
## File still exists. Return error.
return 1
else
return 0
fi
fi
}
function f_cleanup()
{
echo "`date +%Y-%m-%d_%H:%M:%S` - Offline RSync backup exit code: ${ERRORFLAG}" >> ${TEMPLOG}
## Copy temporary log file into main log file.
cat ${TEMPLOG} >> ${LOGFILE}
if [ -f ${LOCKFILE} ];then
## Remove lock file so other rsync jobs can run.
rm ${LOCKFILE} 1>/dev/null 2>&1
fi
## Email the log to the administrator.
EMAILBODY=""
while read FILELINE; do
EMAILBODY=${EMAILBODY}${FILELINE}"
"
done
f_sendmail "Offline RSync Backup Log" "${EMAILBODY}"
if [ -f ${TEMPLOG} ]; then
rm ${TEMPLOG}
fi
}
function f_emergencyexit()
{
## Purpose: Exit script as cleanly as possible.
## Parameter #1 = Error Code
f_cleanup
exit $1
}
#######################################
## MAIN PROGRAM ##
#######################################
if [ -f ${LOCKFILE} ]; then
# rsync lock file detected. Abort script.
f_sendmail "Offline RSync Backup Aborted - Lock File" "This script tried to run but detected the lock file: ${LOCKFILE}
Please check to make sure the file does not remain when rsync is not actually running."
exit 1
else
echo "`date +%Y-%m-%d_%H:%M:%S` ${SCRIPTNAME}" > ${LOCKFILE}
fi
echo "`date +%Y-%m-%d_%H:%M:%S` - Offline RSync backup started." >> ${TEMPLOG}
## If the 7-Zip archive method is specified, make sure the package is installed.
if [ "${ARCHIVEMETHOD}" = "tar.7z" ]; then
if [ ! -f "/usr/bin/7za" ]; then
## Required package (7-Zip) not installed.
echo "`date +%Y-%m-%d_%H:%M:%S` - CRITICAL ERROR: 7-Zip package not installed. Please install by typing 'aptitude -y install p7zip-full'" >> ${TEMPLOG}
ERRORFLAG=2
f_emergencyexit ${ERRORFLAG}
fi
fi
echo "`date +%Y-%m-%d_%H:%M:%S` --- Partition status:" >> ${TEMPLOG}
df -h >> ${TEMPLOG}
## Output the current version to a text file to be included in the backup.
## NOTE: You can also view /opt/zimbra/.install_history
su - zimbra -c "zmcontrol -v > ${ZIMBRADIR}/conf/zimbra_version.txt"
echo "`date +%Y-%m-%d_%H:%M:%S` --- Begin pre-shutdown rsync command." >> ${TEMPLOG}
rsync -apogHK --delete --exclude=*.pid ${ZIMBRADIR} ${TARGETDIR} 1>/dev/null 2>&1
## Backup the zimbra crontab schedule.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Backup and disable Zimbra crontab schedule." >> ${TEMPLOG}
crontab -u zimbra -l > ${ZMCRONFILE}
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Something went wrong with the backup of the crontab file.
## This error will be considered fatal and terminate the script.
f_sendmail "RSync Offline Backup Error - Crontab" "Could not backup crontab for the zimbra user account. RETURN VALUE = ${RETURNVALUE}"
ERRORFLAG=$((${ERRORFLAG} + 16))
f_emergencyexit ${ERRORFLAG}
else
## Backup successful, now disable the zimbra crontab schedule.
echo "" > ${TEMPDIR}emptyfile.$$
crontab -u zimbra ${TEMPDIR}emptyfile.$$
rm ${TEMPDIR}emptyfile.$$ 1>/dev/null 2>&1
## Add a copy of the crontab file to the Zimbra folder to be backed up.
cp ${ZMCRONFILE} ${ZIMBRADIR} 1>/dev/null 2>&1
fi
StartTime="$(date +%s)"
## Stop Zimbra Services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Stopping Zimbra services." >> ${TEMPLOG}
/etc/init.d/zimbra stop 1>/dev/null 2>&1
## Kill any orphaned Zimbra processes.
pkill -9 -u zimbra 1>/dev/null 2>&1
echo "`date +%Y-%m-%d_%H:%M:%S` --- Space consumed in ${ZIMBRADIR} = `du -sh ${ZIMBRADIR} | awk '{ print $1 }'`" >> ${TEMPLOG}
## Now that Zimbra is offline, rsync can quickly copy all remaining files to the backup target.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Begin post-shutdown rsync command." >> ${TEMPLOG}
rsync -apogHK --delete --exclude=*.pid ${ZIMBRADIR} ${TARGETDIR} 1>/dev/null 2>&1
RETURNVALUE=$?
## Quickly start the Zimbra services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Starting Zimbra services." >> ${TEMPLOG}
/etc/init.d/zimbra start 1>/dev/null 2>&1
if [ ${RETURNVALUE} -ne 0 ]; then
## rsync command failed. Send warning email.
f_sendmail "RSync Offline Backup Failure - rsync" "rsync failed with return value of ${RETURNVALUE}"
ERRORFLAG=$((${ERRORFLAG} + 1))
fi
## Calculates downtime of Zimbra services.
FinishTime="$(date +%s)"
ElapsedTime="$(expr ${FinishTime} - ${StartTime})"
Hours=$((${ElapsedTime} / 3600))
ElapsedTime=$((${ElapsedTime} - ${Hours} * 3600))
Minutes=$((${ElapsedTime} / 60))
Seconds=$((${ElapsedTime} - ${Minutes} * 60))
echo "`date +%Y-%m-%d_%H:%M:%S` --- Zimbra downtime: ${Hours} hour(s) ${Minutes} minute(s) ${Seconds} second(s)" >> ${TEMPLOG}
## Restore the zimbra crontab schedule.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Restore Zimbra crontab schedule." >> ${TEMPLOG}
crontab -u zimbra ${ZMCRONFILE}
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Could not restore the zimbra crontab schedule.
## This is considered a non-fatal error and the script will continue.
f_sendmail "Offline RSync Backup Warning - Crontab" "Could not restore the zimbra crontab schedule using ${ZMCRONFILE} RETURN VALUE = ${RETURNVALUE}"
ERRORFLAG=$((${ERRORFLAG} + 32))
else
## Zimbra crontab schedule restored. Remove temp file.
rm ${ZMCRONFILE}
fi
echo "`date +%Y-%m-%d_%H:%M:%S` --- Space consumed in ${TARGETDIR} = `du -sh ${TARGETDIR} | awk '{ print $1 }'`" >> ${TEMPLOG}
## Show status of Zimbra services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Status of Zimbra services:" >> ${TEMPLOG}
su - zimbra -c "zmcontrol status" >> ${TEMPLOG}
## Compress the backup into a single file based on archive method specified.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Compressing archive: ${TEMPDIR}/${ARCHIVEFILE}" >> ${TEMPLOG}
case "${ARCHIVEMETHOD}" in
tar.7z)
tar -cpf - ${TARGETDIR} | 7za a -si -mx=9 -w${TEMPDIR} ${TEMPDIR}/${ARCHIVEFILE} 1>/dev/null 2>&1
## Restore using one of the following commands (do not uncomment, only for notation):
## 7za x -so -w/tmp ${TEMPDIR}/${ARCHIVEFILE} | tar -C / -xf -
## 7za x -so -w/tmp ${TEMPDIR}/${ARCHIVEFILE} | tar -C ${TEMPDIR}/restore --strip-components=1 -xf -
;;
tgz)
tar -cpzf ${TEMPDIR}/${ARCHIVEFILE} ${TARGETDIR} 1>/dev/null 2>&1
## Restore using one of the following commands (do not uncomment, only for notation):
## tar -C / -xzf ${TEMPDIR}/${ARCHIVEFILE}
## tar -C ${TEMPDIR}/restore --strip-components=1 -xzf ${TEMPDIR}/${ARCHIVEFILE}
;;
*)
tar -cpzf ${TEMPDIR}/${ARCHIVEFILE} ${TARGETDIR} 1>/dev/null 2>&1
;;
esac
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## tar command failed. Send warning email.
f_sendmail "Offline RSync Backup Failure - tar" "tar failed with return value of ${RETURNVALUE}"
ERRORFLAG=$((${ERRORFLAG} + 2))
fi
## Mount the Windows share folder. ##
f_mount
sleep 2
if [ ! -f ${OFFSITETESTFILE} ]; then
## Could not find expected file on remote site. Assuming failed mount.
ERRORFLAG=$((${ERRORFLAG} + 64))
f_sendmail "Offline RSync Backup - Win Mount Error" "${HOSTNAME} could not detect ${OFFSITETESTFILE}"
else
## Remote site is available.
FREESPACE=`df -k ${OFFSITEDIR} | grep ${OFFSITEDIR} | awk '{ print $3 }'`
BACKUPSIZE=`ls -lak "${TEMPDIR}/${ARCHIVEFILE}" | awk '{ print $5 }'`
## Make sure space is available on the remote server to copy the file.
if [ ${FREESPACE} -lt ${BACKUPSIZE} ]; then
## Not enough free space available. Purge existing backups until there is room.
ENOUGHSPACE=0
while [ ${ENOUGHSPACE} -eq 0 ]
do
f_PurgeOldestArchive
RETURNVALUE=$?
case ${RETURNVALUE} in
1)
## Cannot purge archives to free up space. End program gracefully.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Not enough free space on ${OFFSITEDIR} and cannot purge old archives. Script aborted." >> ${TEMPLOG}
## Stop and exit the script with an error code.
ERRORFLAG=$((${ERRORFLAG} + 4))
f_emergencyexit ${ERRORFLAG}
;;
9)
## Configuration error, end program gracefully.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Configuration problem. Script aborted." >> ${TEMPLOG}
## Stop and exit the script with an error code.
ERRORFLAG=$((${ERRORFLAG} + 8))
f_emergencyexit ${ERRORFLAG}
;;
esac
FREESPACE=`df -k ${OFFSITEDIR} | grep ${OFFSITEDIR} | awk '{ print $3 }'`
if [ ${FREESPACE} -gt ${BACKUPSIZE} ]; then
## Enough space is now available.
ENOUGHSPACE=1
else
## Not enough space is available yet.
ENOUGHSPACE=0
fi
done
fi
## Copy the backup to an offsite storage location.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Copying archive file to offsite location." >> ${TEMPLOG}
cp ${TEMPDIR}/${ARCHIVEFILE} ${OFFSITEBACKDIR}/${ARCHIVEFILE} 1>/dev/null 2>&1
if [ ! -f ${OFFSITEBACKDIR}/${ARCHIVEFILE} ]; then
## NON-FATAL ERROR: Copy command did not work. Send email notification.
echo "`date +%Y-%m-%d_%H:%M:%S` --- WARNING: Remote copy failed. ${OFFSITEBACKDIR}/${ARCHIVEFILE} does not exist!" >> ${TEMPLOG}
f_sendmail "Offline RSync Backup Failure - Remote Copy" "Remote copy failed. ${OFFSITEBACKDIR}/${ARCHIVEFILE} does not exist
Backup file still remains in this location: ${HOSTNAME}:${TEMPDIR}/${ARCHIVEFILE}"
else
## Remove local copy of the compressed backup file
rm ${TEMPDIR}/${ARCHIVEFILE}
fi
fi
## Unmount the Windows shared folder.
f_umount
## Calculate total time for backup.
FinishTime="$(date +%s)"
ElapsedTime="$(expr ${FinishTime} - ${StartTime})"
Hours=$((${ElapsedTime} / 3600))
ElapsedTime=$((${ElapsedTime} - ${Hours} * 3600))
Minutes=$((${ElapsedTime} / 60))
Seconds=$((${ElapsedTime} - ${Minutes} * 60))
echo "`date +%Y-%m-%d_%H:%M:%S` --- Total backup time: ${Hours} hour(s) ${Minutes} minute(s) ${Seconds} second(s)" >> ${TEMPLOG}
echo "`date +%Y-%m-%d_%H:%M:%S` - Offline RSync backup completed." >> ${TEMPLOG}
## Perform cleanup routine.
f_cleanup
## Exit with the combined return code value.
exit ${ERRORFLAG}
Example output in the log file:
2011-10-28_17:43:21 - Offline RSync backup started.
2011-10-28_17:43:21 --- Partition status:
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/LVG-root 3842104 1467924 2179008 41% /
none 2025164 188 2024976 1% /dev
none 2030020 0 2030020 0% /dev/shm
none 2030020 296 2029724 1% /var/run
none 2030020 0 2030020 0% /var/lock
none 2030020 0 2030020 0% /lib/init/rw
none 3842104 1467924 2179008 41% /var/lib/ureadahead/debugfs
/dev/sda1 182331 33053 139550 20% /boot
/dev/mapper/LVG-bak 240306696 3333320 224766480 2% /var/backup
/dev/mapper/LVG-opt 120152260 3287176 110761636 3% /opt
/dev/mapper/LVG-temp 240306696 799184 227300616 1% /var/temp
2011-10-28_17:43:22 --- Begin pre-shutdown rsync command.
2011-10-28_17:45:10 --- Backup and disable Zimbra crontab schedule.
2011-10-28_17:45:10 --- Stopping Zimbra services.
2011-10-28_17:45:54 --- Space consumed in /opt/zimbra = 3.3G
2011-10-28_17:45:58 --- Begin post-shutdown rsync command.
2011-10-28_17:47:05 --- Starting Zimbra services.
2011-10-28_17:48:32 --- Zimbra downtime: 0 hour(s) 3 minute(s) 22 second(s)
2011-10-28_17:48:32 --- Restore Zimbra crontab schedule.
2011-10-28_17:48:33 --- Space consumed in /temp/zimbra = 3.4G
2011-10-28_17:48:35 --- Status of Zimbra services:
Host mail.mydomain.com
antispam Running
antivirus Running
ldap Running
logger Running
mailbox Running
mta Running
snmp Running
spell Running
stats Running
zmconfigd Running
2011-10-28_17:48:50 --- Compressing archive: /var/temp/2011-10-28_zmbackup.tar.7z
2011-10-28_18:10:09 --- Copying archive file to offsite location.
2011-10-28_18:23:38 --- Total backup time: 0 hour(s) 38 minute(s) 28 second(s)
2011-10-28_18:23:39 - Offline RSync backup completed.
2011-10-28_18:23:39 - Offline RSync backup exit code: 0
To test the online script, make sure you are root and type the following commands:
nohup ./rsync-online.sh &
tail -f /var/temp/rsync-online*.log
The command above will start the script in the background and will allow it to run even if you log off the system.
The tail command will display the last 10 lines of the log. The -f option will keep the command active and continuously show the end of the log...thus you can sit there and just watch the entries show up in the log as they are written (works with any log file). Also note that this is the temporary log file which everything is placed until the very end...which is then copied to the main log file shared between both online and offline scripts.
Press CTRL+C to stop watching the log file.
Reference: OSE Backup Procedures (multiple)
NOTE: Synchronize files with rsync
Although this backup takes the services down, the RSync job just prior to taking the services down ensures the vast majority of the data is already backed up. The only thing that has to be done after the services are down is to copy the changes in the last minute and the files that could not be copied while the services were running.
The actual downtime is typically between 3 to 5 minutes of my server and I doubt it will require longer downtime time even as the data store increases.
rsync-offline.sh
#!/bin/bash
#############################################
## Name : rsync-offline.sh
## Version : 1.4
## Date : 2012-01-09
## Author : LHammonds
## Purpose : Complete backup while Zimbra is offline.
## Compatibility : Verified on Ubuntu Server 10.04.3 - 10.04.4 LTS, Zimbra 7.1.2 - 7.2.0 OSE
## Requirements : p7zip-full (if ARCHIVEMETHOD=tar.7z)
## Run Frequency : Once per day after hours.
## Exit Codes : (if multiple errors, value is the addition of codes)
## 0 = success
## 1 = rsync failure
## 2 = archive failure
## 4 = archive purge failure
## 8 = configuration error
## 16 = crontab backup error
## 32 = crontab restore warning
## 64 = mount warning
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-10-21 LTH Created script.
## 2011-10-28 LTH Added 7-Zip compression (gunzip optional)
## 2011-11-04 LTH Move common variables and funtions to external file.
## 2011-11-08 LTH Added zimbra subfolder to remote site for organization.
## 2012-01-09 LTH Bugfix for f_PurgeOldestArchive
#############################################
## Import common variables and functions. ##
source /var/scripts/common/standard.conf
LOGFILE="${TEMPDIR}/rsync.log"
TEMPLOG="${TEMPDIR}/rsync-offline-temp.$$"
LOCKFILE="${TEMPDIR}/rsync.lock"
TARGETDIR="${BACKUPDIR}/zimbra"
OFFSITEBACKDIR="${OFFSITEDIR}/zimbra"
ARCHIVEFILE="`date +%Y-%m-%d-%H-%M`_zimbra-backup.${ARCHIVEMETHOD}"
ZMCRONFILE="${TEMPDIR}/zimbra-crontab.$$"
ERRORFLAG=0
#######################################
## FUNCTIONS ##
#######################################
function f_PurgeOldestArchive()
{
## Purpose: Delete the oldest archive on the remote site.
## Return values:
## 0 = Success
## 1 = Cannot delete file
## 9 = Configuration error, path empty
## Variable Error Check. *
if [ ${OFFSITEBACKDIR} = "" ]; then
## Make darn sure the path is not empty since we do NOT
## want to start purging files from a random location.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purge error: OFFSITEBACKDIR site variable is empty!" >> ${TEMPLOG}
return 9
fi
## Get the name of the oldest file.
OLDESTFILE=`ls -1t ${OFFSITEBACKDIR} | tail -1`
FILESIZE=`ls -la ${OFFSITEDIR}/${OLDFILE} | awk '{print $5}' | sed -e :a -e 's/(.*[0-9])([0-9]{3})/1,2/;ta'`
if [ "${OLDESTFILE}" = "" ]; then
## Error. Filename variable empty.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purge error: OLDESTFILE variable is empty." >> ${TEMPLOG}
return 9
else
FILESIZE=`ls -lak "${OFFSITEBACKDIR}/${OLDESTFILE}" | awk '{ print $5 }' | sed -e :a -e 's/(.*[0-9])([0-9]{3})/1,2/;ta'`
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purging old file: ${OFFSITEBACKDIR}/${OLDESTFILE}, Size = ${FILESIZE} kb" >> ${TEMPLOG}
rm "${OFFSITEBACKDIR}/${OLDESTFILE}"
if [ -f "${OFFSITEBACKDIR}/${OLDESTFILE}" ]; then
## File still exists. Return error.
return 1
else
return 0
fi
fi
}
function f_cleanup()
{
echo "`date +%Y-%m-%d_%H:%M:%S` - Offline RSync backup exit code: ${ERRORFLAG}" >> ${TEMPLOG}
## Copy temporary log file into main log file.
cat ${TEMPLOG} >> ${LOGFILE}
if [ -f ${LOCKFILE} ];then
## Remove lock file so other rsync jobs can run.
rm ${LOCKFILE} 1>/dev/null 2>&1
fi
## Email the log to the administrator.
EMAILBODY=""
while read FILELINE; do
EMAILBODY=${EMAILBODY}${FILELINE}"
"
done
f_sendmail "Offline RSync Backup Log" "${EMAILBODY}"
if [ -f ${TEMPLOG} ]; then
rm ${TEMPLOG}
fi
}
function f_emergencyexit()
{
## Purpose: Exit script as cleanly as possible.
## Parameter #1 = Error Code
f_cleanup
exit $1
}
#######################################
## MAIN PROGRAM ##
#######################################
if [ -f ${LOCKFILE} ]; then
# rsync lock file detected. Abort script.
f_sendmail "Offline RSync Backup Aborted - Lock File" "This script tried to run but detected the lock file: ${LOCKFILE}
Please check to make sure the file does not remain when rsync is not actually running."
exit 1
else
echo "`date +%Y-%m-%d_%H:%M:%S` ${SCRIPTNAME}" > ${LOCKFILE}
fi
echo "`date +%Y-%m-%d_%H:%M:%S` - Offline RSync backup started." >> ${TEMPLOG}
## If the 7-Zip archive method is specified, make sure the package is installed.
if [ "${ARCHIVEMETHOD}" = "tar.7z" ]; then
if [ ! -f "/usr/bin/7za" ]; then
## Required package (7-Zip) not installed.
echo "`date +%Y-%m-%d_%H:%M:%S` - CRITICAL ERROR: 7-Zip package not installed. Please install by typing 'aptitude -y install p7zip-full'" >> ${TEMPLOG}
ERRORFLAG=2
f_emergencyexit ${ERRORFLAG}
fi
fi
echo "`date +%Y-%m-%d_%H:%M:%S` --- Partition status:" >> ${TEMPLOG}
df -h >> ${TEMPLOG}
## Output the current version to a text file to be included in the backup.
## NOTE: You can also view /opt/zimbra/.install_history
su - zimbra -c "zmcontrol -v > ${ZIMBRADIR}/conf/zimbra_version.txt"
echo "`date +%Y-%m-%d_%H:%M:%S` --- Begin pre-shutdown rsync command." >> ${TEMPLOG}
rsync -apogHK --delete --exclude=*.pid ${ZIMBRADIR} ${TARGETDIR} 1>/dev/null 2>&1
## Backup the zimbra crontab schedule.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Backup and disable Zimbra crontab schedule." >> ${TEMPLOG}
crontab -u zimbra -l > ${ZMCRONFILE}
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Something went wrong with the backup of the crontab file.
## This error will be considered fatal and terminate the script.
f_sendmail "RSync Offline Backup Error - Crontab" "Could not backup crontab for the zimbra user account. RETURN VALUE = ${RETURNVALUE}"
ERRORFLAG=$((${ERRORFLAG} + 16))
f_emergencyexit ${ERRORFLAG}
else
## Backup successful, now disable the zimbra crontab schedule.
echo "" > ${TEMPDIR}emptyfile.$$
crontab -u zimbra ${TEMPDIR}emptyfile.$$
rm ${TEMPDIR}emptyfile.$$ 1>/dev/null 2>&1
## Add a copy of the crontab file to the Zimbra folder to be backed up.
cp ${ZMCRONFILE} ${ZIMBRADIR} 1>/dev/null 2>&1
fi
StartTime="$(date +%s)"
## Stop Zimbra Services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Stopping Zimbra services." >> ${TEMPLOG}
/etc/init.d/zimbra stop 1>/dev/null 2>&1
## Kill any orphaned Zimbra processes.
pkill -9 -u zimbra 1>/dev/null 2>&1
echo "`date +%Y-%m-%d_%H:%M:%S` --- Space consumed in ${ZIMBRADIR} = `du -sh ${ZIMBRADIR} | awk '{ print $1 }'`" >> ${TEMPLOG}
## Now that Zimbra is offline, rsync can quickly copy all remaining files to the backup target.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Begin post-shutdown rsync command." >> ${TEMPLOG}
rsync -apogHK --delete --exclude=*.pid ${ZIMBRADIR} ${TARGETDIR} 1>/dev/null 2>&1
RETURNVALUE=$?
## Quickly start the Zimbra services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Starting Zimbra services." >> ${TEMPLOG}
/etc/init.d/zimbra start 1>/dev/null 2>&1
if [ ${RETURNVALUE} -ne 0 ]; then
## rsync command failed. Send warning email.
f_sendmail "RSync Offline Backup Failure - rsync" "rsync failed with return value of ${RETURNVALUE}"
ERRORFLAG=$((${ERRORFLAG} + 1))
fi
## Calculates downtime of Zimbra services.
FinishTime="$(date +%s)"
ElapsedTime="$(expr ${FinishTime} - ${StartTime})"
Hours=$((${ElapsedTime} / 3600))
ElapsedTime=$((${ElapsedTime} - ${Hours} * 3600))
Minutes=$((${ElapsedTime} / 60))
Seconds=$((${ElapsedTime} - ${Minutes} * 60))
echo "`date +%Y-%m-%d_%H:%M:%S` --- Zimbra downtime: ${Hours} hour(s) ${Minutes} minute(s) ${Seconds} second(s)" >> ${TEMPLOG}
## Restore the zimbra crontab schedule.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Restore Zimbra crontab schedule." >> ${TEMPLOG}
crontab -u zimbra ${ZMCRONFILE}
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Could not restore the zimbra crontab schedule.
## This is considered a non-fatal error and the script will continue.
f_sendmail "Offline RSync Backup Warning - Crontab" "Could not restore the zimbra crontab schedule using ${ZMCRONFILE} RETURN VALUE = ${RETURNVALUE}"
ERRORFLAG=$((${ERRORFLAG} + 32))
else
## Zimbra crontab schedule restored. Remove temp file.
rm ${ZMCRONFILE}
fi
echo "`date +%Y-%m-%d_%H:%M:%S` --- Space consumed in ${TARGETDIR} = `du -sh ${TARGETDIR} | awk '{ print $1 }'`" >> ${TEMPLOG}
## Show status of Zimbra services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Status of Zimbra services:" >> ${TEMPLOG}
su - zimbra -c "zmcontrol status" >> ${TEMPLOG}
## Compress the backup into a single file based on archive method specified.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Compressing archive: ${TEMPDIR}/${ARCHIVEFILE}" >> ${TEMPLOG}
case "${ARCHIVEMETHOD}" in
tar.7z)
tar -cpf - ${TARGETDIR} | 7za a -si -mx=9 -w${TEMPDIR} ${TEMPDIR}/${ARCHIVEFILE} 1>/dev/null 2>&1
## Restore using one of the following commands (do not uncomment, only for notation):
## 7za x -so -w/tmp ${TEMPDIR}/${ARCHIVEFILE} | tar -C / -xf -
## 7za x -so -w/tmp ${TEMPDIR}/${ARCHIVEFILE} | tar -C ${TEMPDIR}/restore --strip-components=1 -xf -
;;
tgz)
tar -cpzf ${TEMPDIR}/${ARCHIVEFILE} ${TARGETDIR} 1>/dev/null 2>&1
## Restore using one of the following commands (do not uncomment, only for notation):
## tar -C / -xzf ${TEMPDIR}/${ARCHIVEFILE}
## tar -C ${TEMPDIR}/restore --strip-components=1 -xzf ${TEMPDIR}/${ARCHIVEFILE}
;;
*)
tar -cpzf ${TEMPDIR}/${ARCHIVEFILE} ${TARGETDIR} 1>/dev/null 2>&1
;;
esac
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## tar command failed. Send warning email.
f_sendmail "Offline RSync Backup Failure - tar" "tar failed with return value of ${RETURNVALUE}"
ERRORFLAG=$((${ERRORFLAG} + 2))
fi
## Mount the Windows share folder. ##
f_mount
sleep 2
if [ ! -f ${OFFSITETESTFILE} ]; then
## Could not find expected file on remote site. Assuming failed mount.
ERRORFLAG=$((${ERRORFLAG} + 64))
f_sendmail "Offline RSync Backup - Win Mount Error" "${HOSTNAME} could not detect ${OFFSITETESTFILE}"
else
## Remote site is available.
FREESPACE=`df -k ${OFFSITEDIR} | grep ${OFFSITEDIR} | awk '{ print $3 }'`
BACKUPSIZE=`ls -lak "${TEMPDIR}/${ARCHIVEFILE}" | awk '{ print $5 }'`
## Make sure space is available on the remote server to copy the file.
if [ ${FREESPACE} -lt ${BACKUPSIZE} ]; then
## Not enough free space available. Purge existing backups until there is room.
ENOUGHSPACE=0
while [ ${ENOUGHSPACE} -eq 0 ]
do
f_PurgeOldestArchive
RETURNVALUE=$?
case ${RETURNVALUE} in
1)
## Cannot purge archives to free up space. End program gracefully.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Not enough free space on ${OFFSITEDIR} and cannot purge old archives. Script aborted." >> ${TEMPLOG}
## Stop and exit the script with an error code.
ERRORFLAG=$((${ERRORFLAG} + 4))
f_emergencyexit ${ERRORFLAG}
;;
9)
## Configuration error, end program gracefully.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Configuration problem. Script aborted." >> ${TEMPLOG}
## Stop and exit the script with an error code.
ERRORFLAG=$((${ERRORFLAG} + 8))
f_emergencyexit ${ERRORFLAG}
;;
esac
FREESPACE=`df -k ${OFFSITEDIR} | grep ${OFFSITEDIR} | awk '{ print $3 }'`
if [ ${FREESPACE} -gt ${BACKUPSIZE} ]; then
## Enough space is now available.
ENOUGHSPACE=1
else
## Not enough space is available yet.
ENOUGHSPACE=0
fi
done
fi
## Copy the backup to an offsite storage location.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Copying archive file to offsite location." >> ${TEMPLOG}
cp ${TEMPDIR}/${ARCHIVEFILE} ${OFFSITEBACKDIR}/${ARCHIVEFILE} 1>/dev/null 2>&1
if [ ! -f ${OFFSITEBACKDIR}/${ARCHIVEFILE} ]; then
## NON-FATAL ERROR: Copy command did not work. Send email notification.
echo "`date +%Y-%m-%d_%H:%M:%S` --- WARNING: Remote copy failed. ${OFFSITEBACKDIR}/${ARCHIVEFILE} does not exist!" >> ${TEMPLOG}
f_sendmail "Offline RSync Backup Failure - Remote Copy" "Remote copy failed. ${OFFSITEBACKDIR}/${ARCHIVEFILE} does not exist
Backup file still remains in this location: ${HOSTNAME}:${TEMPDIR}/${ARCHIVEFILE}"
else
## Remove local copy of the compressed backup file
rm ${TEMPDIR}/${ARCHIVEFILE}
fi
fi
## Unmount the Windows shared folder.
f_umount
## Calculate total time for backup.
FinishTime="$(date +%s)"
ElapsedTime="$(expr ${FinishTime} - ${StartTime})"
Hours=$((${ElapsedTime} / 3600))
ElapsedTime=$((${ElapsedTime} - ${Hours} * 3600))
Minutes=$((${ElapsedTime} / 60))
Seconds=$((${ElapsedTime} - ${Minutes} * 60))
echo "`date +%Y-%m-%d_%H:%M:%S` --- Total backup time: ${Hours} hour(s) ${Minutes} minute(s) ${Seconds} second(s)" >> ${TEMPLOG}
echo "`date +%Y-%m-%d_%H:%M:%S` - Offline RSync backup completed." >> ${TEMPLOG}
## Perform cleanup routine.
f_cleanup
## Exit with the combined return code value.
exit ${ERRORFLAG}
Example output in the log file:
2011-10-28_17:43:21 - Offline RSync backup started.
2011-10-28_17:43:21 --- Partition status:
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/LVG-root 3842104 1467924 2179008 41% /
none 2025164 188 2024976 1% /dev
none 2030020 0 2030020 0% /dev/shm
none 2030020 296 2029724 1% /var/run
none 2030020 0 2030020 0% /var/lock
none 2030020 0 2030020 0% /lib/init/rw
none 3842104 1467924 2179008 41% /var/lib/ureadahead/debugfs
/dev/sda1 182331 33053 139550 20% /boot
/dev/mapper/LVG-bak 240306696 3333320 224766480 2% /var/backup
/dev/mapper/LVG-opt 120152260 3287176 110761636 3% /opt
/dev/mapper/LVG-temp 240306696 799184 227300616 1% /var/temp
2011-10-28_17:43:22 --- Begin pre-shutdown rsync command.
2011-10-28_17:45:10 --- Backup and disable Zimbra crontab schedule.
2011-10-28_17:45:10 --- Stopping Zimbra services.
2011-10-28_17:45:54 --- Space consumed in /opt/zimbra = 3.3G
2011-10-28_17:45:58 --- Begin post-shutdown rsync command.
2011-10-28_17:47:05 --- Starting Zimbra services.
2011-10-28_17:48:32 --- Zimbra downtime: 0 hour(s) 3 minute(s) 22 second(s)
2011-10-28_17:48:32 --- Restore Zimbra crontab schedule.
2011-10-28_17:48:33 --- Space consumed in /temp/zimbra = 3.4G
2011-10-28_17:48:35 --- Status of Zimbra services:
Host mail.mydomain.com
antispam Running
antivirus Running
ldap Running
logger Running
mailbox Running
mta Running
snmp Running
spell Running
stats Running
zmconfigd Running
2011-10-28_17:48:50 --- Compressing archive: /var/temp/2011-10-28_zmbackup.tar.7z
2011-10-28_18:10:09 --- Copying archive file to offsite location.
2011-10-28_18:23:38 --- Total backup time: 0 hour(s) 38 minute(s) 28 second(s)
2011-10-28_18:23:39 - Offline RSync backup completed.
2011-10-28_18:23:39 - Offline RSync backup exit code: 0
To test the online script, make sure you are root and type the following commands:
nohup ./rsync-online.sh &
tail -f /var/temp/rsync-online*.log
The command above will start the script in the background and will allow it to run even if you log off the system.
The tail command will display the last 10 lines of the log. The -f option will keep the command active and continuously show the end of the log...thus you can sit there and just watch the entries show up in the log as they are written (works with any log file). Also note that this is the temporary log file which everything is placed until the very end...which is then copied to the main log file shared between both online and offline scripts.
Press CTRL+C to stop watching the log file.
Reference: OSE Backup Procedures (multiple)
NOTE: Synchronize files with rsync
-
- Advanced member
- Posts: 148
- Joined: Sat Sep 13, 2014 2:14 am
My Notes for Installing Zimbra OSE on Ubuntu Server 10.04 LTS
Backup - Individual Mailbox
The 2nd method involves backing up individual mailboxes. This process can occur while the server is online and thus will not cause any downtime. It can be run as often as you want but you should consider the performance impact on the server as well as how long each run will take. I plan to schedule it once per day during non-peak hours.
mailbox-backup.sh
#!/bin/bash
#############################################
## Name : mailbox-backup.sh
## Version : 1.1
## Date : 2012-01-09
## Author : LHammonds
## Purpose : Backup individual mailbox accounts.
## Compatibility : Verified on Ubuntu Server 10.04.3 - 10.04.4 LTS, Zimbra 7.1.2 - 7.2.0 OSE
## Requirements : Zimbra must be online, must be run as root user.
## Run Frequency : Once or more per day.
## Exit Codes : (if multiple errors, value is the addition of codes)
## 0 = Success (or non-critical failure)
## 1 = Root access failure
## 2 = Archive creation failure
## 4 = Archive purge error
## 8 = configuration error
## 16 = Offsite mount failure
## 32 = Offsite copy failure
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-10-23 LTH Created script.
## 2011-11-05 LTH Move common variables and functions to external file.
## 2011-11-06 LTH Additional error checks and better log info.
## 2012-01-09 LTH Bugfix f_PurgeOldestArchive
#############################################
## Import common variables and functions.
source /var/scripts/common/standard.conf
## Define local variables.
LOGFILE="${TEMPDIR}/mailbox-backup.log"
HISTORYFILE="${TEMPDIR}/mailbox-backup-size-history.log"
TARGETDIR="${BACKUPDIR}/mailbox"
OFFSITEBACKDIR="${OFFSITEDIR}/mailbox"
ARCHIVEFILE="`date +%Y-%m-%d-%H-%M`_mailbox-all.tar"
LOCKFILE="${TEMPDIR}/mailbox-backup.lock"
EXCEPTIONS="spam.ppnvqogp0@${MYDOMAIN};ham.iki6sotcy@${MYDOMAIN};virus-quarantine.qvj6nc_jl@${MYDOMAIN}"
RETURNVALUE=0
UCOUNT=0
ERRORFLAG=0
#######################################
## FUNCTIONS ##
#######################################
function f_PurgeOldestArchive()
{
## Purpose: Delete the oldest archive on the remote site.
## Return values:
## 0 = Success
## 1 = Cannot delete file
## 9 = Configuration error, path empty
## Variable Error Check. *
if [ ${OFFSITEBACKDIR} = "" ]; then
## Make darn sure the path is not empty since we do NOT
## want to start purging files from a random location.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purge error: OFFSITEBACKDIR site variable is empty!" >> ${LOGFILE}
return 9
fi
## Get the name of the oldest file.
OLDESTFILE=`ls -1t ${OFFSITEBACKDIR} | tail -1`
FILESIZE=`ls -la ${OFFSITEDIR}/${OLDFILE} | awk '{print $5}' | sed -e :a -e 's/(.*[0-9])([0-9]{3})/1,2/;ta'`
if [ "${OLDESTFILE}" = "" ]; then
## Error. Filename variable empty.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purge error: OLDESTFILE variable is empty." >> ${LOGFILE}
return 9
else
FILESIZE=`ls -lak "${OFFSITEBACKDIR}/${OLDESTFILE}" | awk '{ print $5 }' | sed -e :a -e 's/(.*[0-9])([0-9]{3})/1,2/;ta'`
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purging old file: ${OFFSITEBACKDIR}/${OLDESTFILE}, Size = ${FILESIZE} kb" >> ${LOGFILE}
rm "${OFFSITEBACKDIR}/${OLDESTFILE}"
if [ -f "${OFFSITEBACKDIR}/${OLDESTFILE}" ]; then
## File still exists. Return error.
return 1
else
return 0
fi
fi
}
function f_cleanup()
{
if [ -f "${LOCKFILE}" ]; then
## Remove run file since this script is complete.
rm ${LOCKFILE}
fi
}
function f_emergencyexit()
{
## Purpose: Exit script as cleanly as possible.
## Parameter #1 = Error Code.
f_cleanup
f_sendmail "Zimbra Mailbox Backup Error" "EXIT CODE = ${1}"
echo "`date +%Y-%m-%d_%H:%M:%S` - Mailbox backup aborted. EXIT CODE: ${1}" >> ${LOGFILE}
## Write script name and error code to the system log.
logger "${SCRIPTNAME}: ERROR CODE = ${1}"
exit $1
}
#######################################
## MAIN PROGRAM ##
#######################################
## Requirement Check: Script must run as root user.
if [ "$(id -u)" != "0" ]; then
## FATAL ERROR DETECTED: Document problem and terminate script.
ERRORFLAG=$((${ERRORFLAG} + 1))
echo "`date +%Y-%m-%d_%H:%M:%S` - Mailbox backup aborted. ERROR CODE ${ERRORFLAG}: Script must be run as root user instead of $(whoami)." | tee -a ${LOGFILE}
f_emergencyexit ${ERRORFLAG}
fi
if [ -f "${LOCKFILE}" ]; then
## Last call to this script is still running or failed to remove its lock file.
## As an additional check, see if the file is older than today...if so, we should
## probably send an email notification of a problem that may need manual interention.
FILEDATE=$(stat -c %y ${LOCKFILE})
FILEDATE=${FILEDATE%% *}
if [ "${FILEDATE}" != "$(date +%Y-%m-%d)" ]; then
## Lock file not created today, might need to be manually deleted. Send email notification.
f_sendmail "Zimbra Mailbox Backup Warning" "Warning: This script cannot run if it detects this lock file: ${LOCKFILE}
This file should only exist while this script is running which should not take more than a day.
System Date: $(date +%Y-%m-%d)
Lock File Date: ${FILEDATE}
If you determine that the file should be removed, do so by typing this command on the server's console: rm ${LOCKFILE}"
fi
exit 0
else
## Create the "script is running" lock file and process the script.
echo "`date +%Y-%m-%d_%H:%M:%S` - ${HOSTNAME}:${SCRIPTNAME} is currently running." > ${LOCKFILE}
fi
## Record the start time of the backup process.
STARTTIME="$(date +%s)"
echo "`date +%Y-%m-%d_%H:%M:%S` - Individual mailbox backup started." >> ${LOGFILE}
if [ -d "${TARGETDIR}" ]; then
## Purge existing archives.
rm ${TARGETDIR}/*.tgz 1>/dev/null 2>&1
else
## Make the folder since it does not exist.
mkdir -p ${TARGETDIR} 1>/dev/null 2>&1
fi
for ACCT in `su - zimbra -c "zmprov -l gaa"`
do
## Check to see if current account should be skipped.
if echo "${EXCEPTIONS}" | grep -q ${ACCT}
then
## Exception found, skip this account.
echo "" > /dev/null
else
## Backup user account.
UCOUNT=$((UCOUNT+1))
${ZIMBRADIR}/bin/zmmailbox -z -m ${ACCT} getRestURL "//?fmt=tgz" > ${TARGETDIR}/${ACCT}.tgz
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Something went wrong.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Error on ${ACCT}, RETURN VALUE = ${RETURNVALUE}" >> ${LOGFILE}
ERRORFLAG=$((ERRORFLAG+1))
else
## Calculate archive size.
MAILBOXSIZE=$(stat -c %s ${TARGETDIR}/${ACCT}.tgz)
## Comment out the below line if you do not want details in the log file.
echo "`date +%Y-%m-%d_%H:%M:%S` --- ${ACCT}, ${MAILBOXSIZE} bytes" >> ${LOGFILE}
fi
fi
done
echo "`date +%Y-%m-%d_%H:%M:%S` --- ${UCOUNT} accounts processed." >> ${LOGFILE}
## Calculate mailbox backup time.
FINISHTIME="$(date +%s)"
ELAPSEDTIME="$(expr ${FINISHTIME} - ${STARTTIME})"
HOURS=$((${ELAPSEDTIME} / 3600))
ELAPSEDTIME=$((${ELAPSEDTIME} - ${HOURS} * 3600))
MINUTES=$((${ELAPSEDTIME} / 60))
SECONDS=$((${ELAPSEDTIME} - ${MINUTES} * 60))
echo "`date +%Y-%m-%d_%H:%M:%S` --- Backup time for ${UCOUNT} mailboxes: ${HOURS} hour(s) ${MINUTES} minute(s) ${SECONDS} second(s)" >> ${LOGFILE}
echo "`date +%Y-%m-%d_%H:%M:%S` --- Setting file permissions on ${TARGETDIR}/*.tgz" >> ${LOGFILE}
chmod 0600 ${TARGETDIR}/*.tgz
echo "`date +%Y-%m-%d_%H:%M:%S` --- Creating a single file for archiving: ${TEMPDIR}/${ARCHIVEFILE}" >> ${LOGFILE}
tar -cf ${TEMPDIR}/${ARCHIVEFILE} ${TARGETDIR} 1>/dev/null 2>&1
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Something went wrong.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Error creating ${TEMPDIR}/${ARCHIVEFILE}, Return Value: ${RETURNVALUE}" >> ${LOGFILE}
ERRORFLAG=$((ERRORFLAG+2))
fi
ARCHIVESIZE=$(stat -c %s ${TEMPDIR}/${ARCHIVEFILE})
if [ ! -f "${HISTORYFILE}" ]; then
## Create history log and include header description as 1st line, field separator = space character.
echo "Date Archive SizeInBytes" > ${HISTORYFILE}
fi
## Append archive size to the history log.
echo "`date +%Y-%m-%d` ${ARCHIVEFILE} ${ARCHIVESIZE}" >> ${HISTORYFILE}
## Mount the offsite Windows share folder.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Mounting ${OFFSITEDIR}" >> ${LOGFILE}
f_mount
if [ -f ${OFFSITETESTFILE} ]; then
## Remote site is online / available.
if [ ! -d ${OFFSITEBACKDIR} ]; then
## Make the backup folder since it does not exist yet.
mkdir -p ${OFFSITEBACKDIR}
fi
if [ -f ${TEMPDIR}/${ARCHIVEFILE} ]; then
## Make sure space is available on the remote server to copy the file.
FREESPACE=`df -k ${OFFSITEDIR} | grep ${OFFSITEDIR} | awk '{ print $3 }'`
BACKUPSIZE=`ls -lak "${TEMPDIR}/${ARCHIVEFILE}" | awk '{ print $5 }'`
if [ ${FREESPACE} -lt ${BACKUPSIZE} ]; then
## Not enough free space available. Purge existing backups until there is room.
ENOUGHSPACE=0
while [ ${ENOUGHSPACE} -eq 0 ]
do
f_PurgeOldestArchive
RETURNVALUE=$?
case ${RETURNVALUE} in
1)
## Cannot purge archives to free up space. End program gracefully.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Not enough free space on ${OFFSITEBACKDIR} and cannot purge old archives. Script aborted." >> ${TEMPLOG}
## Stop and exit the script with an error code.
ERRORFLAG=$((${ERRORFLAG} + 4))
f_emergencyexit ${ERRORFLAG}
;;
9)
## Configuration error, end program gracefully.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Configuration problem. Script aborted." >> ${TEMPLOG}
## Stop and exit the script with an error code.
ERRORFLAG=$((${ERRORFLAG} + 8))
f_emergencyexit ${ERRORFLAG}
;;
esac
FREESPACE=`df -k ${OFFSITEDIR} | grep ${OFFSITEDIR} | awk '{ print $3 }'`
if [ ${FREESPACE} -gt ${BACKUPSIZE} ]; then
## Enough space is now available.
ENOUGHSPACE=1
else
## Not enough space is available yet.
ENOUGHSPACE=0
fi
done
fi
echo "`date +%Y-%m-%d_%H:%M:%S` --- Copying ${TEMPDIR}/${ARCHIVEFILE} to ${OFFSITEBACKDIR}/" >> ${LOGFILE}
cp ${TEMPDIR}/${ARCHIVEFILE} ${OFFSITEBACKDIR}/${ARCHIVEFILE} 1>/dev/null 2>&1
fi
else
## Remote site is offline / unavailable.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Error: Remote site is unavailable: ${OFFSITEBACKDIR}" >> ${LOGFILE}
ERRORFLAG=$((ERRORFLAG+16))
fi
if [ -f ${OFFSITEBACKDIR}/${ARCHIVEFILE} ]; then
## Remote copy worked. Remove local archive.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Copied ${ARCHIVESIZE} bytes." >> ${LOGFILE}
echo "`date +%Y-%m-%d_%H:%M:%S` --- Removing ${TEMPDIR}/${ARCHIVEFILE}" >> ${LOGFILE}
rm ${TEMPDIR}/${ARCHIVEFILE}
FREESPACE=`df -k ${OFFSITEDIR} | grep ${OFFSITEDIR} | awk '{ print $3 }'`
## Comment out the below line if you do not want to receive statistic emails.
f_sendmail "Zimbra Individual Mailbox Backup" "${UCOUNT} accounts backed up.
Total archive size: $((${ARCHIVESIZE}/1024)) kb
Available Backup Space: ${FREESPACE} kb"
## Uncomment the following 2 lines if you do not wish to have a local copy of individual mailboxes.
# rm ${TARGETDIR}/*.tgz
# rmdir ${TARGETDIR}
else
## Remote copy failed.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Error copying to ${OFFSITEBACKDIR}/${ARCHIVEFILE}" >> ${LOGFILE}
ERRORFLAG=$((ERRORFLAG+32))
fi
## Calculate total time for backup.
FINISHTIME="$(date +%s)"
ELAPSEDTIME="$(expr ${FINISHTIME} - ${STARTTIME})"
HOURS=$((${ELAPSEDTIME} / 3600))
ELAPSEDTIME=$((${ELAPSEDTIME} - ${HOURS} * 3600))
MINUTES=$((${ELAPSEDTIME} / 60))
SECONDS=$((${ELAPSEDTIME} - ${MINUTES} * 60))
echo "`date +%Y-%m-%d_%H:%M:%S` --- Total backup time: ${HOURS} hour(s) ${MINUTES} minute(s) ${SECONDS} second(s)" >> ${LOGFILE}
if [ ${ERRORFLAG} -ne 0 ]; then
f_sendmail "Zimbra Individual Mailbox Backup Error" "${ERRORFLAG} errors detected while trying to backup ${UCOUNT} individual mailboxes."
fi
## Unmount the offsite backup location.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Dismounting ${OFFSITEDIR}" >> ${LOGFILE}
f_umount
## Perform cleanup routine.
f_cleanup
## Exit with the combined return code value.
echo "`date +%Y-%m-%d_%H:%M:%S` - Individual mailbox backup complete. Exit code: ${ERRORFLAG}" >> ${LOGFILE}
exit ${ERRORFLAG}
Sample output of mailbox-backup.log
2011-11-06_15:48:02 - Individual mailbox backup started.
2011-11-06_15:48:11 --- admin@mydomain.com, 6781 bytes
2011-11-06_15:48:13 --- lhammonds@mydomain.com, 1066 bytes
2011-11-06_15:48:16 --- jsmith@mydomain.com, 1067 bytes
2011-11-06_15:48:18 --- jdoe@mydomain.com, 1066 bytes
2011-11-06_15:48:21 --- administrator@mydomain.com, 1069 bytes
2011-11-06_15:48:23 --- foobar@mydomain.com, 1067 bytes
2011-11-06_15:48:25 --- jvorhees@mydomain.com, 1068 bytes
2011-11-06_15:48:28 --- conferencerooms@mydomain.com, 1067 bytes
2011-11-06_15:48:30 --- test@mydomain.com, 1068 bytes
2011-11-06_15:48:48 --- 9 accounts processed.
2011-11-06_15:48:48 --- Backup time for 9 mailboxes: 0 hour(s) 0 minute(s) 46 second(s)
2011-11-06_15:48:48 --- Setting file permissions on /var/backup/mailbox/*.tgz
2011-11-06_15:48:48 --- Creating a single file for archiving: /var/temp/2011-11-06-15-48_mailbox-all.tar
2011-11-06_15:48:48 --- Mounting /mnt/backup
2011-11-06_15:48:49 --- Copying /var/temp/2011-11-06-15-48_mailbox-all.tar to /mnt/backup/mailbox/
2011-11-06_15:48:49 --- Copied 61440 bytes.
2011-11-06_15:48:49 --- Removing /var/temp/2011-11-06-15-48_mailbox-all.tar
2011-11-06_15:48:49 --- Total backup time: 0 hour(s) 0 minute(s) 47 second(s)
2011-11-06_15:48:49 --- Dismounting /mnt/backup
2011-11-06_15:48:49 - Individual mailbox backup complete. Exit code: 0
Sample output of mailbox-backup-size-history.log
Date Archive SizeInBytes
2011-11-06 2011-11-06-11-21_mailbox-all.tar 61440
2011-11-06 2011-11-06-15-17_mailbox-all.tar 61440
2011-11-06 2011-11-06-15-21_mailbox-all.tar 61440
2011-11-06 2011-11-06-15-22_mailbox-all.tar 61440
2011-11-06 2011-11-06-15-32_mailbox-all.tar 61440
2011-11-06 2011-11-06-15-48_mailbox-all.tar 61440
Sample email notification
Subject: Zimbra Individual Mailbox Backup
9 accounts backed up.
Total archive size: 60 kb
Available Backup Space: 28440616 kb
Server: mail
Program: /var/scripts/prod/mailbox-backup.sh
Log: /var/temp/mailbox-backup.log
Sample error email notification
Subject: Zimbra Individual Mailbox Backup Error
1 errors detected while trying to backup 9 individual mailboxes.
Server: mail
Program: /var/scripts/prod/mailbox-backup.sh
Log: /var/temp/mailbox-backup.log
Sample /var/log/messages
Nov 6 11:13:01 mail administrator: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 1
Nov 6 11:15:02 mail root: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 2
Nov 6 11:18:03 mail root: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 4
Nov 6 11:23:04 mail root: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 8
Nov 6 11:33:05 mail root: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 16
Nov 6 11:43:06 mail root: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 32
The 2nd method involves backing up individual mailboxes. This process can occur while the server is online and thus will not cause any downtime. It can be run as often as you want but you should consider the performance impact on the server as well as how long each run will take. I plan to schedule it once per day during non-peak hours.
mailbox-backup.sh
#!/bin/bash
#############################################
## Name : mailbox-backup.sh
## Version : 1.1
## Date : 2012-01-09
## Author : LHammonds
## Purpose : Backup individual mailbox accounts.
## Compatibility : Verified on Ubuntu Server 10.04.3 - 10.04.4 LTS, Zimbra 7.1.2 - 7.2.0 OSE
## Requirements : Zimbra must be online, must be run as root user.
## Run Frequency : Once or more per day.
## Exit Codes : (if multiple errors, value is the addition of codes)
## 0 = Success (or non-critical failure)
## 1 = Root access failure
## 2 = Archive creation failure
## 4 = Archive purge error
## 8 = configuration error
## 16 = Offsite mount failure
## 32 = Offsite copy failure
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-10-23 LTH Created script.
## 2011-11-05 LTH Move common variables and functions to external file.
## 2011-11-06 LTH Additional error checks and better log info.
## 2012-01-09 LTH Bugfix f_PurgeOldestArchive
#############################################
## Import common variables and functions.
source /var/scripts/common/standard.conf
## Define local variables.
LOGFILE="${TEMPDIR}/mailbox-backup.log"
HISTORYFILE="${TEMPDIR}/mailbox-backup-size-history.log"
TARGETDIR="${BACKUPDIR}/mailbox"
OFFSITEBACKDIR="${OFFSITEDIR}/mailbox"
ARCHIVEFILE="`date +%Y-%m-%d-%H-%M`_mailbox-all.tar"
LOCKFILE="${TEMPDIR}/mailbox-backup.lock"
EXCEPTIONS="spam.ppnvqogp0@${MYDOMAIN};ham.iki6sotcy@${MYDOMAIN};virus-quarantine.qvj6nc_jl@${MYDOMAIN}"
RETURNVALUE=0
UCOUNT=0
ERRORFLAG=0
#######################################
## FUNCTIONS ##
#######################################
function f_PurgeOldestArchive()
{
## Purpose: Delete the oldest archive on the remote site.
## Return values:
## 0 = Success
## 1 = Cannot delete file
## 9 = Configuration error, path empty
## Variable Error Check. *
if [ ${OFFSITEBACKDIR} = "" ]; then
## Make darn sure the path is not empty since we do NOT
## want to start purging files from a random location.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purge error: OFFSITEBACKDIR site variable is empty!" >> ${LOGFILE}
return 9
fi
## Get the name of the oldest file.
OLDESTFILE=`ls -1t ${OFFSITEBACKDIR} | tail -1`
FILESIZE=`ls -la ${OFFSITEDIR}/${OLDFILE} | awk '{print $5}' | sed -e :a -e 's/(.*[0-9])([0-9]{3})/1,2/;ta'`
if [ "${OLDESTFILE}" = "" ]; then
## Error. Filename variable empty.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purge error: OLDESTFILE variable is empty." >> ${LOGFILE}
return 9
else
FILESIZE=`ls -lak "${OFFSITEBACKDIR}/${OLDESTFILE}" | awk '{ print $5 }' | sed -e :a -e 's/(.*[0-9])([0-9]{3})/1,2/;ta'`
echo "`date +%Y-%m-%d_%H:%M:%S` --- Purging old file: ${OFFSITEBACKDIR}/${OLDESTFILE}, Size = ${FILESIZE} kb" >> ${LOGFILE}
rm "${OFFSITEBACKDIR}/${OLDESTFILE}"
if [ -f "${OFFSITEBACKDIR}/${OLDESTFILE}" ]; then
## File still exists. Return error.
return 1
else
return 0
fi
fi
}
function f_cleanup()
{
if [ -f "${LOCKFILE}" ]; then
## Remove run file since this script is complete.
rm ${LOCKFILE}
fi
}
function f_emergencyexit()
{
## Purpose: Exit script as cleanly as possible.
## Parameter #1 = Error Code.
f_cleanup
f_sendmail "Zimbra Mailbox Backup Error" "EXIT CODE = ${1}"
echo "`date +%Y-%m-%d_%H:%M:%S` - Mailbox backup aborted. EXIT CODE: ${1}" >> ${LOGFILE}
## Write script name and error code to the system log.
logger "${SCRIPTNAME}: ERROR CODE = ${1}"
exit $1
}
#######################################
## MAIN PROGRAM ##
#######################################
## Requirement Check: Script must run as root user.
if [ "$(id -u)" != "0" ]; then
## FATAL ERROR DETECTED: Document problem and terminate script.
ERRORFLAG=$((${ERRORFLAG} + 1))
echo "`date +%Y-%m-%d_%H:%M:%S` - Mailbox backup aborted. ERROR CODE ${ERRORFLAG}: Script must be run as root user instead of $(whoami)." | tee -a ${LOGFILE}
f_emergencyexit ${ERRORFLAG}
fi
if [ -f "${LOCKFILE}" ]; then
## Last call to this script is still running or failed to remove its lock file.
## As an additional check, see if the file is older than today...if so, we should
## probably send an email notification of a problem that may need manual interention.
FILEDATE=$(stat -c %y ${LOCKFILE})
FILEDATE=${FILEDATE%% *}
if [ "${FILEDATE}" != "$(date +%Y-%m-%d)" ]; then
## Lock file not created today, might need to be manually deleted. Send email notification.
f_sendmail "Zimbra Mailbox Backup Warning" "Warning: This script cannot run if it detects this lock file: ${LOCKFILE}
This file should only exist while this script is running which should not take more than a day.
System Date: $(date +%Y-%m-%d)
Lock File Date: ${FILEDATE}
If you determine that the file should be removed, do so by typing this command on the server's console: rm ${LOCKFILE}"
fi
exit 0
else
## Create the "script is running" lock file and process the script.
echo "`date +%Y-%m-%d_%H:%M:%S` - ${HOSTNAME}:${SCRIPTNAME} is currently running." > ${LOCKFILE}
fi
## Record the start time of the backup process.
STARTTIME="$(date +%s)"
echo "`date +%Y-%m-%d_%H:%M:%S` - Individual mailbox backup started." >> ${LOGFILE}
if [ -d "${TARGETDIR}" ]; then
## Purge existing archives.
rm ${TARGETDIR}/*.tgz 1>/dev/null 2>&1
else
## Make the folder since it does not exist.
mkdir -p ${TARGETDIR} 1>/dev/null 2>&1
fi
for ACCT in `su - zimbra -c "zmprov -l gaa"`
do
## Check to see if current account should be skipped.
if echo "${EXCEPTIONS}" | grep -q ${ACCT}
then
## Exception found, skip this account.
echo "" > /dev/null
else
## Backup user account.
UCOUNT=$((UCOUNT+1))
${ZIMBRADIR}/bin/zmmailbox -z -m ${ACCT} getRestURL "//?fmt=tgz" > ${TARGETDIR}/${ACCT}.tgz
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Something went wrong.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Error on ${ACCT}, RETURN VALUE = ${RETURNVALUE}" >> ${LOGFILE}
ERRORFLAG=$((ERRORFLAG+1))
else
## Calculate archive size.
MAILBOXSIZE=$(stat -c %s ${TARGETDIR}/${ACCT}.tgz)
## Comment out the below line if you do not want details in the log file.
echo "`date +%Y-%m-%d_%H:%M:%S` --- ${ACCT}, ${MAILBOXSIZE} bytes" >> ${LOGFILE}
fi
fi
done
echo "`date +%Y-%m-%d_%H:%M:%S` --- ${UCOUNT} accounts processed." >> ${LOGFILE}
## Calculate mailbox backup time.
FINISHTIME="$(date +%s)"
ELAPSEDTIME="$(expr ${FINISHTIME} - ${STARTTIME})"
HOURS=$((${ELAPSEDTIME} / 3600))
ELAPSEDTIME=$((${ELAPSEDTIME} - ${HOURS} * 3600))
MINUTES=$((${ELAPSEDTIME} / 60))
SECONDS=$((${ELAPSEDTIME} - ${MINUTES} * 60))
echo "`date +%Y-%m-%d_%H:%M:%S` --- Backup time for ${UCOUNT} mailboxes: ${HOURS} hour(s) ${MINUTES} minute(s) ${SECONDS} second(s)" >> ${LOGFILE}
echo "`date +%Y-%m-%d_%H:%M:%S` --- Setting file permissions on ${TARGETDIR}/*.tgz" >> ${LOGFILE}
chmod 0600 ${TARGETDIR}/*.tgz
echo "`date +%Y-%m-%d_%H:%M:%S` --- Creating a single file for archiving: ${TEMPDIR}/${ARCHIVEFILE}" >> ${LOGFILE}
tar -cf ${TEMPDIR}/${ARCHIVEFILE} ${TARGETDIR} 1>/dev/null 2>&1
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Something went wrong.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Error creating ${TEMPDIR}/${ARCHIVEFILE}, Return Value: ${RETURNVALUE}" >> ${LOGFILE}
ERRORFLAG=$((ERRORFLAG+2))
fi
ARCHIVESIZE=$(stat -c %s ${TEMPDIR}/${ARCHIVEFILE})
if [ ! -f "${HISTORYFILE}" ]; then
## Create history log and include header description as 1st line, field separator = space character.
echo "Date Archive SizeInBytes" > ${HISTORYFILE}
fi
## Append archive size to the history log.
echo "`date +%Y-%m-%d` ${ARCHIVEFILE} ${ARCHIVESIZE}" >> ${HISTORYFILE}
## Mount the offsite Windows share folder.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Mounting ${OFFSITEDIR}" >> ${LOGFILE}
f_mount
if [ -f ${OFFSITETESTFILE} ]; then
## Remote site is online / available.
if [ ! -d ${OFFSITEBACKDIR} ]; then
## Make the backup folder since it does not exist yet.
mkdir -p ${OFFSITEBACKDIR}
fi
if [ -f ${TEMPDIR}/${ARCHIVEFILE} ]; then
## Make sure space is available on the remote server to copy the file.
FREESPACE=`df -k ${OFFSITEDIR} | grep ${OFFSITEDIR} | awk '{ print $3 }'`
BACKUPSIZE=`ls -lak "${TEMPDIR}/${ARCHIVEFILE}" | awk '{ print $5 }'`
if [ ${FREESPACE} -lt ${BACKUPSIZE} ]; then
## Not enough free space available. Purge existing backups until there is room.
ENOUGHSPACE=0
while [ ${ENOUGHSPACE} -eq 0 ]
do
f_PurgeOldestArchive
RETURNVALUE=$?
case ${RETURNVALUE} in
1)
## Cannot purge archives to free up space. End program gracefully.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Not enough free space on ${OFFSITEBACKDIR} and cannot purge old archives. Script aborted." >> ${TEMPLOG}
## Stop and exit the script with an error code.
ERRORFLAG=$((${ERRORFLAG} + 4))
f_emergencyexit ${ERRORFLAG}
;;
9)
## Configuration error, end program gracefully.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Configuration problem. Script aborted." >> ${TEMPLOG}
## Stop and exit the script with an error code.
ERRORFLAG=$((${ERRORFLAG} + 8))
f_emergencyexit ${ERRORFLAG}
;;
esac
FREESPACE=`df -k ${OFFSITEDIR} | grep ${OFFSITEDIR} | awk '{ print $3 }'`
if [ ${FREESPACE} -gt ${BACKUPSIZE} ]; then
## Enough space is now available.
ENOUGHSPACE=1
else
## Not enough space is available yet.
ENOUGHSPACE=0
fi
done
fi
echo "`date +%Y-%m-%d_%H:%M:%S` --- Copying ${TEMPDIR}/${ARCHIVEFILE} to ${OFFSITEBACKDIR}/" >> ${LOGFILE}
cp ${TEMPDIR}/${ARCHIVEFILE} ${OFFSITEBACKDIR}/${ARCHIVEFILE} 1>/dev/null 2>&1
fi
else
## Remote site is offline / unavailable.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Error: Remote site is unavailable: ${OFFSITEBACKDIR}" >> ${LOGFILE}
ERRORFLAG=$((ERRORFLAG+16))
fi
if [ -f ${OFFSITEBACKDIR}/${ARCHIVEFILE} ]; then
## Remote copy worked. Remove local archive.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Copied ${ARCHIVESIZE} bytes." >> ${LOGFILE}
echo "`date +%Y-%m-%d_%H:%M:%S` --- Removing ${TEMPDIR}/${ARCHIVEFILE}" >> ${LOGFILE}
rm ${TEMPDIR}/${ARCHIVEFILE}
FREESPACE=`df -k ${OFFSITEDIR} | grep ${OFFSITEDIR} | awk '{ print $3 }'`
## Comment out the below line if you do not want to receive statistic emails.
f_sendmail "Zimbra Individual Mailbox Backup" "${UCOUNT} accounts backed up.
Total archive size: $((${ARCHIVESIZE}/1024)) kb
Available Backup Space: ${FREESPACE} kb"
## Uncomment the following 2 lines if you do not wish to have a local copy of individual mailboxes.
# rm ${TARGETDIR}/*.tgz
# rmdir ${TARGETDIR}
else
## Remote copy failed.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Error copying to ${OFFSITEBACKDIR}/${ARCHIVEFILE}" >> ${LOGFILE}
ERRORFLAG=$((ERRORFLAG+32))
fi
## Calculate total time for backup.
FINISHTIME="$(date +%s)"
ELAPSEDTIME="$(expr ${FINISHTIME} - ${STARTTIME})"
HOURS=$((${ELAPSEDTIME} / 3600))
ELAPSEDTIME=$((${ELAPSEDTIME} - ${HOURS} * 3600))
MINUTES=$((${ELAPSEDTIME} / 60))
SECONDS=$((${ELAPSEDTIME} - ${MINUTES} * 60))
echo "`date +%Y-%m-%d_%H:%M:%S` --- Total backup time: ${HOURS} hour(s) ${MINUTES} minute(s) ${SECONDS} second(s)" >> ${LOGFILE}
if [ ${ERRORFLAG} -ne 0 ]; then
f_sendmail "Zimbra Individual Mailbox Backup Error" "${ERRORFLAG} errors detected while trying to backup ${UCOUNT} individual mailboxes."
fi
## Unmount the offsite backup location.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Dismounting ${OFFSITEDIR}" >> ${LOGFILE}
f_umount
## Perform cleanup routine.
f_cleanup
## Exit with the combined return code value.
echo "`date +%Y-%m-%d_%H:%M:%S` - Individual mailbox backup complete. Exit code: ${ERRORFLAG}" >> ${LOGFILE}
exit ${ERRORFLAG}
Sample output of mailbox-backup.log
2011-11-06_15:48:02 - Individual mailbox backup started.
2011-11-06_15:48:11 --- admin@mydomain.com, 6781 bytes
2011-11-06_15:48:13 --- lhammonds@mydomain.com, 1066 bytes
2011-11-06_15:48:16 --- jsmith@mydomain.com, 1067 bytes
2011-11-06_15:48:18 --- jdoe@mydomain.com, 1066 bytes
2011-11-06_15:48:21 --- administrator@mydomain.com, 1069 bytes
2011-11-06_15:48:23 --- foobar@mydomain.com, 1067 bytes
2011-11-06_15:48:25 --- jvorhees@mydomain.com, 1068 bytes
2011-11-06_15:48:28 --- conferencerooms@mydomain.com, 1067 bytes
2011-11-06_15:48:30 --- test@mydomain.com, 1068 bytes
2011-11-06_15:48:48 --- 9 accounts processed.
2011-11-06_15:48:48 --- Backup time for 9 mailboxes: 0 hour(s) 0 minute(s) 46 second(s)
2011-11-06_15:48:48 --- Setting file permissions on /var/backup/mailbox/*.tgz
2011-11-06_15:48:48 --- Creating a single file for archiving: /var/temp/2011-11-06-15-48_mailbox-all.tar
2011-11-06_15:48:48 --- Mounting /mnt/backup
2011-11-06_15:48:49 --- Copying /var/temp/2011-11-06-15-48_mailbox-all.tar to /mnt/backup/mailbox/
2011-11-06_15:48:49 --- Copied 61440 bytes.
2011-11-06_15:48:49 --- Removing /var/temp/2011-11-06-15-48_mailbox-all.tar
2011-11-06_15:48:49 --- Total backup time: 0 hour(s) 0 minute(s) 47 second(s)
2011-11-06_15:48:49 --- Dismounting /mnt/backup
2011-11-06_15:48:49 - Individual mailbox backup complete. Exit code: 0
Sample output of mailbox-backup-size-history.log
Date Archive SizeInBytes
2011-11-06 2011-11-06-11-21_mailbox-all.tar 61440
2011-11-06 2011-11-06-15-17_mailbox-all.tar 61440
2011-11-06 2011-11-06-15-21_mailbox-all.tar 61440
2011-11-06 2011-11-06-15-22_mailbox-all.tar 61440
2011-11-06 2011-11-06-15-32_mailbox-all.tar 61440
2011-11-06 2011-11-06-15-48_mailbox-all.tar 61440
Sample email notification
Subject: Zimbra Individual Mailbox Backup
9 accounts backed up.
Total archive size: 60 kb
Available Backup Space: 28440616 kb
Server: mail
Program: /var/scripts/prod/mailbox-backup.sh
Log: /var/temp/mailbox-backup.log
Sample error email notification
Subject: Zimbra Individual Mailbox Backup Error
1 errors detected while trying to backup 9 individual mailboxes.
Server: mail
Program: /var/scripts/prod/mailbox-backup.sh
Log: /var/temp/mailbox-backup.log
Sample /var/log/messages
Nov 6 11:13:01 mail administrator: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 1
Nov 6 11:15:02 mail root: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 2
Nov 6 11:18:03 mail root: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 4
Nov 6 11:23:04 mail root: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 8
Nov 6 11:33:05 mail root: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 16
Nov 6 11:43:06 mail root: /var/scripts/prod/mailbox-backup.sh: ERROR CODE = 32
-
- Advanced member
- Posts: 148
- Joined: Sat Sep 13, 2014 2:14 am
My Notes for Installing Zimbra OSE on Ubuntu Server 10.04 LTS
ZIMBRA RESTORE
I SEE THE NEED TO RESTORE FROM AT LEAST SEVERAL DIFFERENT SCENARIOS. THAT MEANS COMING UP WITH A RESTORE PLAN AND SCRIPTS TO HELP SPEED UP RESTORE TIME AND REDUCE ERRORS DURING EMERGENCY SCENARIOS. THIS ALSO MEANS TESTING EACH OF THESE RESTORE PLANS; OTHERWISE YOU ARE PLAYING RUSSIAN ROULETTE WITH MORE THAN ONE BULLET IN THE REVOLVER! ALWAYS REMEMBER THAT THE VAST MAJORITY OF ADMINISTRATORS INVOLUNTARILY REMOVED FROM THEIR JOB ARE TYPICALLY RELATED TO DATA LOSS THAT CANNOT BE RECOVERED.
HERE ARE THE SCENARIOS I AM GOING TO COVER AND TEST:
RESTORE INDIVIDUAL MAILBOX FROM A LOCAL COPY - WE WILL RESTORE A MAILBOX ACCOUNT USING THE LATEST INDIVIDUAL MAILBOX BACKUP WHICH IS STORED ON THE LOCAL SERVER. THIS CAN BE DONE AT ANY TIME AND WILL NOT IMPACT SERVER UPTIME.
RESTORE INDIVIDUAL MAILBOX FROM AN OFFSITE LOCATION - WE WILL RESTORE A MAILBOX ACCOUNT USING ONE OF THE ARCHIVES LOCATED ON THE OFFSITE STORAGE. THIS CAN BE DONE AT ANY TIME AND WILL NOT IMPACT SERVER UPTIME.
RESTORE EXISTING SERVER FROM A LOCAL COPY (FASTEST, BUT POTENTIALLY PROBLEMATIC) - WE WILL USE THE LOCAL FOLDER USED FOR DOING DAILY RSYNC BACKUPS. THE CAVEAT HERE IS THAT YOU ONLY WANT TO DO THIS IF THE LAST RSYNC WAS FROM THE OFFLINE RSYNC SCRIPT...MEANING IT IS A COMPLETE SNAPSHOT AND NOT FROM ANY OF THE ONLINE RSYNCS WHICH DID NOT COPY OPEN AND IN-USE FILES. THIS WILL CAUSE THE SERVER TO BE OFFLINE, SO BE SURE TO COORDINATE AND PLAN ACCORDINGLY.
RESTORE EXISTING SERVER FROM AN OFFSITE LOCATION (SLOWER, BUT MORE RELIABLE) - WE WILL RESTORE THE SERVER USING ONE OF THE ARCHIVES LOCATED ON THE OFFSITE STORAGE. THIS WILL CAUSE THE SERVER TO BE OFFLINE, SO BE SURE TO COORDINATE AND PLAN ACCORDINGLY.
RESTORE TO NEW SERVER (PRODUCTION SERVER UNAVAILABLE) - WE WILL ASSUME THE PRODUCTION SERVER IS OFFLINE AND INACCESSIBLE. WE WILL CONFIGURE A NEW SERVER AND RESTORE USING ONE OF THE ARCHIVES LOCATED ON THE OFFSITE STORAGE.
I SEE THE NEED TO RESTORE FROM AT LEAST SEVERAL DIFFERENT SCENARIOS. THAT MEANS COMING UP WITH A RESTORE PLAN AND SCRIPTS TO HELP SPEED UP RESTORE TIME AND REDUCE ERRORS DURING EMERGENCY SCENARIOS. THIS ALSO MEANS TESTING EACH OF THESE RESTORE PLANS; OTHERWISE YOU ARE PLAYING RUSSIAN ROULETTE WITH MORE THAN ONE BULLET IN THE REVOLVER! ALWAYS REMEMBER THAT THE VAST MAJORITY OF ADMINISTRATORS INVOLUNTARILY REMOVED FROM THEIR JOB ARE TYPICALLY RELATED TO DATA LOSS THAT CANNOT BE RECOVERED.
HERE ARE THE SCENARIOS I AM GOING TO COVER AND TEST:
RESTORE INDIVIDUAL MAILBOX FROM A LOCAL COPY - WE WILL RESTORE A MAILBOX ACCOUNT USING THE LATEST INDIVIDUAL MAILBOX BACKUP WHICH IS STORED ON THE LOCAL SERVER. THIS CAN BE DONE AT ANY TIME AND WILL NOT IMPACT SERVER UPTIME.
RESTORE INDIVIDUAL MAILBOX FROM AN OFFSITE LOCATION - WE WILL RESTORE A MAILBOX ACCOUNT USING ONE OF THE ARCHIVES LOCATED ON THE OFFSITE STORAGE. THIS CAN BE DONE AT ANY TIME AND WILL NOT IMPACT SERVER UPTIME.
RESTORE EXISTING SERVER FROM A LOCAL COPY (FASTEST, BUT POTENTIALLY PROBLEMATIC) - WE WILL USE THE LOCAL FOLDER USED FOR DOING DAILY RSYNC BACKUPS. THE CAVEAT HERE IS THAT YOU ONLY WANT TO DO THIS IF THE LAST RSYNC WAS FROM THE OFFLINE RSYNC SCRIPT...MEANING IT IS A COMPLETE SNAPSHOT AND NOT FROM ANY OF THE ONLINE RSYNCS WHICH DID NOT COPY OPEN AND IN-USE FILES. THIS WILL CAUSE THE SERVER TO BE OFFLINE, SO BE SURE TO COORDINATE AND PLAN ACCORDINGLY.
RESTORE EXISTING SERVER FROM AN OFFSITE LOCATION (SLOWER, BUT MORE RELIABLE) - WE WILL RESTORE THE SERVER USING ONE OF THE ARCHIVES LOCATED ON THE OFFSITE STORAGE. THIS WILL CAUSE THE SERVER TO BE OFFLINE, SO BE SURE TO COORDINATE AND PLAN ACCORDINGLY.
RESTORE TO NEW SERVER (PRODUCTION SERVER UNAVAILABLE) - WE WILL ASSUME THE PRODUCTION SERVER IS OFFLINE AND INACCESSIBLE. WE WILL CONFIGURE A NEW SERVER AND RESTORE USING ONE OF THE ARCHIVES LOCATED ON THE OFFSITE STORAGE.
-
- Advanced member
- Posts: 148
- Joined: Sat Sep 13, 2014 2:14 am
My Notes for Installing Zimbra OSE on Ubuntu Server 10.04 LTS
SCENARIO #1 RESTORE INDIVIDUAL MAILBOX FROM A LOCAL COPY
THIS PROCESS WILL ASSUME YOU ARE WANTING TO RESTORE A MAILBOX BACK TO THE WAY IT WAS WHEN LAST BACKED UP. THIS MEANS ANYTHING NEW SINCE THE BACKUP WILL BE WIPED OUT. IF THIS IS NOT DESIRED, A SIMPLE SOLUTION (WHICH WILL BE MY STANDARD PROTOCOL) WILL BE TO CREATE A NEW MAILBOX AND RESTORE TO IT.
IF CREATING A NEW MAILBOX, BE SURE TO SET A PASSWORD ON IT AND TEST IT BY LOGGING INTO THE ACCOUNT...THIS ALSO CREATES THE MAILBOX STORE WHEN ACCESSED THE 1ST TIME. THEN COPY THE USER'S MAILBOX ARCHIVE TO LOOK LIKE THE ARCHIVE FOR THE RESTORE ACCOUNT.
EXAMPLE #1 - RESTORE THE ADMIN MAILBOX.
/VAR/SCRIPTS/PROD/MAILBOX-RESTORE-LOCAL.SH ADMIN@MYDOMAIN.COM
ONSCREEN RESULT:
2011-11-06_17:45:55 - RESTORED MAILBOX --> ADMIN@MYDOMAIN.COM
RECORDED EVENT IN THE LOG: /VAR/TEMP/MAILBOX-RESTORE.LOG
2011-11-06_17:45:55 - RESTORED MAILBOX --> ADMIN@MYDOMAIN.COM
EXAMPLE #2 - RESTORE THE ADMIN MAILBOX TO A TEMPORARY ACCOUNT CALLED "RESTORE".
LOGIN TO THE ADMIN CONSOLE: H T T P S ://MAIL.MYDOMAIN.COM:7071
CREATE A NEW ACCOUNT CALLED RESTORE AND SET THE PASSWORD
LOGIN TO THE WEBMAIL USING THE RESTORE ACCOUNT: H T T P S ://MAIL.MYDOMAIN.COM
ONCE LOGGED IN TO VERIFY THE EMPTY ACCOUNT WORKS, LOGOUT
ACCESS THE UBUNTU SERVER. AT THE LOGIN PROMPT, LOGIN WITH YOUR ADMINISTRATOR ACCOUNT (ADMINISTRATOR / MYADMINPASS) AND THEN TYPE SU AND THE ROOT PASSWORD (MYROOTPASS)
TYPE THE FOLLOWING:
CP /VAR/BACKUP/MAILBOX/ADMIN@MYDOMAIN.COM.TGZ /VAR/BACKUP/MAILBOX/RESTORE@MYDOMAIN.COM.TGZ
/VAR/SCRIPTS/PROD/MAILBOX-RESTORE-LOCAL.SH RESTORE@MYDOMAIN.COM
MAILBOX-RESTORE-LOCAL.SH
#!/BIN/BASH
#############################################
## NAME : MAILBOX-RESTORE-LOCAL.SH
## VERSION : 1.0
## DATE : 2011-11-06
## AUTHOR : LHAMMONDS
## COMPATIBILITY : VERIFIED ON UBUNTU 10.04.3 - 10.04.4 LTS, ZIMBRA 7.1.2 - 7.2.0
## PURPOSE : RESTORE INDIVIDUAL MAILBOX ACCOUNTS.
## RUN FREQUENCY : MANUAL AS NEEDED.
## EXIT CODES : (IF MULTIPLE ERRORS, VALUE IS THE ADDITION OF CODES)
## 0 = SUCCESS
## 1 = PARAMETER FAILURE
## 2 = UNKNOWN MAILBOX ACCOUNT
## 4 = MISSING ARCHIVE FOLDER
## 8 = MISSING ARCHIVE FILE
## 16 = MAILBOX RESTORE FAILURE
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-10-24 LTH CREATED SCRIPT.
## 2011-11-06 LTH MOVE COMMON VARIABLES AND FUNCTIONS TO EXTERNAL FILE.
#############################################
## IMPORT COMMON VARIABLES AND FUNCTIONS.
SOURCE /VAR/SCRIPTS/COMMON/STANDARD.CONF
## DEFINE LOCAL VARIABLES.
LOGFILE="${TEMPDIR}/MAILBOX-RESTORE.LOG"
ARCHIVEDIR="${BACKUPDIR}/MAILBOX"
ACCT=$1
RETURNVALUE=0
#######################################
## FUNCTIONS ##
#######################################
FUNCTION F_SHOWHELP()
{
ECHO ""
ECHO "USAGE : ${SCRIPTNAME} USER@${MYDOMAIN}"
ECHO ""
ECHO "NOTE: YOU COULD CREATE A TEMPORARY ACCOUNT AND COPY THE DESIRED ARCHIVE"
ECHO " TO BE NAMED THE SAME AS THE TEMPORARY ACCOUNT IN ORDER TO RESTORE"
ECHO " TO A NEW MAILBOX AND PRESERVE THE EXISTING MAILBOX."
ECHO " EXAMPLE:"
ECHO " CD ${ARCHIVEDIR}"
ECHO " CP ADMIN@${MYDOMAIN}.TGZ RESTORE@${MYDOMAIN}.TGZ"
ECHO " ${SCRIPTNAME} RESTORE@${MYDOMAIN}"
ECHO ""
}
FUNCTION F_EMERGENCYEXIT()
{
## PURPOSE: EXIT SCRIPT AS CLEANLY AS POSSIBLE.
## PARAMETER #1 = ERROR CODE.
ECHO -E "INDIVIDUAL MAILBOX RESTORE ABORTED. EXIT CODE: ${1}N"
EXIT $1
}
#######################################
## MAIN PROGRAM ##
#######################################
## CHECK COMMAND-LINE PARAMETERS.
CASE "$1" IN
"")
F_SHOWHELP
F_EMERGENCYEXIT 1
;;
--HELP|-H|-?)
F_SHOWHELP
F_EMERGENCYEXIT 1
;;
*)
ACCT=$1
;;
ESAC
## CHECK TO MAKE SURE THE ARCHIVE FOLDER EXISTS.
IF [ ! -D "${ARCHIVEDIR}" ]; THEN
## ERROR: ARCHIVE FOLDER DOES NOT EXIST.
ECHO "ERROR: THE ARCHIVE FOLDER DOES NOT EXIST! ${ARCHIVEDIR}"
F_EMERGENCYEXIT 4
FI
## CHECK TO MAKE SURE THE ARCHIVE EXISTS.
IF [ ! -F "${ARCHIVEDIR}/${ACCT}.TGZ" ]; THEN
## ERROR: ARCHIVE DOES NOT EXIST.
ECHO "ERROR: THE ARCHIVE DOES NOT EXIST! ${ARCHIVEDIR}/${ACCT}.TGZ"
F_EMERGENCYEXIT 8
FI
## CHECK TO MAKE SURE PARAMETER IS A VALID MAILBOX ACCOUNT NAME.
IF `SU - ZIMBRA -C "ZMPROV -L GAA" | GREP -Q ${ACCT}`
THEN
## THE PARAMETER CONTAINS A VALID MAILBOX ACCOUNT.
ECHO "" > /DEV/NULL
ELSE
## INVALID MAILBOX ACCOUNT.
ECHO "ERROR: INVALID MAILBOX: ${ACCT}"
F_SHOWHELP
F_EMERGENCYEXIT 2
FI
${ZIMBRADIR}/BIN/ZMMAILBOX -Z -M ${ACCT} POSTRESTURL "//?FMT=TGZ&RESOLVE=RESET" ${ARCHIVEDIR}/${ACCT}.TGZ
RETURNVALUE=$?
IF [ ${RETURNVALUE} -NE 0 ]; THEN
## SOMETHING WENT WRONG.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - ERROR RESTORING ${ACCT}, RETURN VALUE = ${RETURNVALUE}" | TEE -A ${LOGFILE}
F_EMERGENCYEXIT 16
FI
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - RESTORED MAILBOX --> ${ACCT}" | TEE -A ${LOGFILE}
F_SENDMAIL "ZIMBRA USER MAILBOX RESTORE" "${ACCT} WAS MANUALLY RESTORED."
EXIT 0
IF YOU DO NOT SUPPLY AN ACCOUNT TO THE SCRIPT AS A PARAMETER, IT WILL DISPLAY THE FOLLOWING HELP TEXT:
/VAR/SCRIPTS/PROD/MAILBOX-RESTORE.SH
USAGE : ./MAILBOX-RESTORE-LOCAL.SH USER@MYDOMAIN.COM
NOTE: YOU COULD CREATE A TEMPORARY ACCOUNT AND COPY THE DESIRED ARCHIVE
TO BE NAMED THE SAME AS THE TEMPORARY ACCOUNT IN ORDER TO RESTORE
TO A NEW MAILBOX AND PRESERVE THE EXISTING MAILBOX.
EXAMPLE:
CD /VAR/BACKUP/MAILBOX
CP ADMIN@MYDOMAIN.COM.TGZ RESTORE@MYDOMAIN.COM.TGZ
/VAR/SCRIPTS/PROD/MAILBOX-RESTORE.SH RESTORE@MYDOMAIN.COM
INDIVIDUAL MAILBOX RESTORE ABORTED. EXIT CODE: 1
NOTE: THE ABOVE WILL ACTUALLY USE YOUR DOMAIN IN ALL EXAMPLES BECAUSE IT PULLS THE DOMAIN FROM THE STANDARD.CONF FILE.
THIS PROCESS WILL ASSUME YOU ARE WANTING TO RESTORE A MAILBOX BACK TO THE WAY IT WAS WHEN LAST BACKED UP. THIS MEANS ANYTHING NEW SINCE THE BACKUP WILL BE WIPED OUT. IF THIS IS NOT DESIRED, A SIMPLE SOLUTION (WHICH WILL BE MY STANDARD PROTOCOL) WILL BE TO CREATE A NEW MAILBOX AND RESTORE TO IT.
IF CREATING A NEW MAILBOX, BE SURE TO SET A PASSWORD ON IT AND TEST IT BY LOGGING INTO THE ACCOUNT...THIS ALSO CREATES THE MAILBOX STORE WHEN ACCESSED THE 1ST TIME. THEN COPY THE USER'S MAILBOX ARCHIVE TO LOOK LIKE THE ARCHIVE FOR THE RESTORE ACCOUNT.
EXAMPLE #1 - RESTORE THE ADMIN MAILBOX.
/VAR/SCRIPTS/PROD/MAILBOX-RESTORE-LOCAL.SH ADMIN@MYDOMAIN.COM
ONSCREEN RESULT:
2011-11-06_17:45:55 - RESTORED MAILBOX --> ADMIN@MYDOMAIN.COM
RECORDED EVENT IN THE LOG: /VAR/TEMP/MAILBOX-RESTORE.LOG
2011-11-06_17:45:55 - RESTORED MAILBOX --> ADMIN@MYDOMAIN.COM
EXAMPLE #2 - RESTORE THE ADMIN MAILBOX TO A TEMPORARY ACCOUNT CALLED "RESTORE".
LOGIN TO THE ADMIN CONSOLE: H T T P S ://MAIL.MYDOMAIN.COM:7071
CREATE A NEW ACCOUNT CALLED RESTORE AND SET THE PASSWORD
LOGIN TO THE WEBMAIL USING THE RESTORE ACCOUNT: H T T P S ://MAIL.MYDOMAIN.COM
ONCE LOGGED IN TO VERIFY THE EMPTY ACCOUNT WORKS, LOGOUT
ACCESS THE UBUNTU SERVER. AT THE LOGIN PROMPT, LOGIN WITH YOUR ADMINISTRATOR ACCOUNT (ADMINISTRATOR / MYADMINPASS) AND THEN TYPE SU AND THE ROOT PASSWORD (MYROOTPASS)
TYPE THE FOLLOWING:
CP /VAR/BACKUP/MAILBOX/ADMIN@MYDOMAIN.COM.TGZ /VAR/BACKUP/MAILBOX/RESTORE@MYDOMAIN.COM.TGZ
/VAR/SCRIPTS/PROD/MAILBOX-RESTORE-LOCAL.SH RESTORE@MYDOMAIN.COM
MAILBOX-RESTORE-LOCAL.SH
#!/BIN/BASH
#############################################
## NAME : MAILBOX-RESTORE-LOCAL.SH
## VERSION : 1.0
## DATE : 2011-11-06
## AUTHOR : LHAMMONDS
## COMPATIBILITY : VERIFIED ON UBUNTU 10.04.3 - 10.04.4 LTS, ZIMBRA 7.1.2 - 7.2.0
## PURPOSE : RESTORE INDIVIDUAL MAILBOX ACCOUNTS.
## RUN FREQUENCY : MANUAL AS NEEDED.
## EXIT CODES : (IF MULTIPLE ERRORS, VALUE IS THE ADDITION OF CODES)
## 0 = SUCCESS
## 1 = PARAMETER FAILURE
## 2 = UNKNOWN MAILBOX ACCOUNT
## 4 = MISSING ARCHIVE FOLDER
## 8 = MISSING ARCHIVE FILE
## 16 = MAILBOX RESTORE FAILURE
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-10-24 LTH CREATED SCRIPT.
## 2011-11-06 LTH MOVE COMMON VARIABLES AND FUNCTIONS TO EXTERNAL FILE.
#############################################
## IMPORT COMMON VARIABLES AND FUNCTIONS.
SOURCE /VAR/SCRIPTS/COMMON/STANDARD.CONF
## DEFINE LOCAL VARIABLES.
LOGFILE="${TEMPDIR}/MAILBOX-RESTORE.LOG"
ARCHIVEDIR="${BACKUPDIR}/MAILBOX"
ACCT=$1
RETURNVALUE=0
#######################################
## FUNCTIONS ##
#######################################
FUNCTION F_SHOWHELP()
{
ECHO ""
ECHO "USAGE : ${SCRIPTNAME} USER@${MYDOMAIN}"
ECHO ""
ECHO "NOTE: YOU COULD CREATE A TEMPORARY ACCOUNT AND COPY THE DESIRED ARCHIVE"
ECHO " TO BE NAMED THE SAME AS THE TEMPORARY ACCOUNT IN ORDER TO RESTORE"
ECHO " TO A NEW MAILBOX AND PRESERVE THE EXISTING MAILBOX."
ECHO " EXAMPLE:"
ECHO " CD ${ARCHIVEDIR}"
ECHO " CP ADMIN@${MYDOMAIN}.TGZ RESTORE@${MYDOMAIN}.TGZ"
ECHO " ${SCRIPTNAME} RESTORE@${MYDOMAIN}"
ECHO ""
}
FUNCTION F_EMERGENCYEXIT()
{
## PURPOSE: EXIT SCRIPT AS CLEANLY AS POSSIBLE.
## PARAMETER #1 = ERROR CODE.
ECHO -E "INDIVIDUAL MAILBOX RESTORE ABORTED. EXIT CODE: ${1}N"
EXIT $1
}
#######################################
## MAIN PROGRAM ##
#######################################
## CHECK COMMAND-LINE PARAMETERS.
CASE "$1" IN
"")
F_SHOWHELP
F_EMERGENCYEXIT 1
;;
--HELP|-H|-?)
F_SHOWHELP
F_EMERGENCYEXIT 1
;;
*)
ACCT=$1
;;
ESAC
## CHECK TO MAKE SURE THE ARCHIVE FOLDER EXISTS.
IF [ ! -D "${ARCHIVEDIR}" ]; THEN
## ERROR: ARCHIVE FOLDER DOES NOT EXIST.
ECHO "ERROR: THE ARCHIVE FOLDER DOES NOT EXIST! ${ARCHIVEDIR}"
F_EMERGENCYEXIT 4
FI
## CHECK TO MAKE SURE THE ARCHIVE EXISTS.
IF [ ! -F "${ARCHIVEDIR}/${ACCT}.TGZ" ]; THEN
## ERROR: ARCHIVE DOES NOT EXIST.
ECHO "ERROR: THE ARCHIVE DOES NOT EXIST! ${ARCHIVEDIR}/${ACCT}.TGZ"
F_EMERGENCYEXIT 8
FI
## CHECK TO MAKE SURE PARAMETER IS A VALID MAILBOX ACCOUNT NAME.
IF `SU - ZIMBRA -C "ZMPROV -L GAA" | GREP -Q ${ACCT}`
THEN
## THE PARAMETER CONTAINS A VALID MAILBOX ACCOUNT.
ECHO "" > /DEV/NULL
ELSE
## INVALID MAILBOX ACCOUNT.
ECHO "ERROR: INVALID MAILBOX: ${ACCT}"
F_SHOWHELP
F_EMERGENCYEXIT 2
FI
${ZIMBRADIR}/BIN/ZMMAILBOX -Z -M ${ACCT} POSTRESTURL "//?FMT=TGZ&RESOLVE=RESET" ${ARCHIVEDIR}/${ACCT}.TGZ
RETURNVALUE=$?
IF [ ${RETURNVALUE} -NE 0 ]; THEN
## SOMETHING WENT WRONG.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - ERROR RESTORING ${ACCT}, RETURN VALUE = ${RETURNVALUE}" | TEE -A ${LOGFILE}
F_EMERGENCYEXIT 16
FI
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - RESTORED MAILBOX --> ${ACCT}" | TEE -A ${LOGFILE}
F_SENDMAIL "ZIMBRA USER MAILBOX RESTORE" "${ACCT} WAS MANUALLY RESTORED."
EXIT 0
IF YOU DO NOT SUPPLY AN ACCOUNT TO THE SCRIPT AS A PARAMETER, IT WILL DISPLAY THE FOLLOWING HELP TEXT:
/VAR/SCRIPTS/PROD/MAILBOX-RESTORE.SH
USAGE : ./MAILBOX-RESTORE-LOCAL.SH USER@MYDOMAIN.COM
NOTE: YOU COULD CREATE A TEMPORARY ACCOUNT AND COPY THE DESIRED ARCHIVE
TO BE NAMED THE SAME AS THE TEMPORARY ACCOUNT IN ORDER TO RESTORE
TO A NEW MAILBOX AND PRESERVE THE EXISTING MAILBOX.
EXAMPLE:
CD /VAR/BACKUP/MAILBOX
CP ADMIN@MYDOMAIN.COM.TGZ RESTORE@MYDOMAIN.COM.TGZ
/VAR/SCRIPTS/PROD/MAILBOX-RESTORE.SH RESTORE@MYDOMAIN.COM
INDIVIDUAL MAILBOX RESTORE ABORTED. EXIT CODE: 1
NOTE: THE ABOVE WILL ACTUALLY USE YOUR DOMAIN IN ALL EXAMPLES BECAUSE IT PULLS THE DOMAIN FROM THE STANDARD.CONF FILE.
-
- Advanced member
- Posts: 148
- Joined: Sat Sep 13, 2014 2:14 am
My Notes for Installing Zimbra OSE on Ubuntu Server 10.04 LTS
Scenario #2 Restore individual mailbox from an offsite location
Here is the general outline of the script:
Parameter #1 (required) = Account in which we will find the archive for.
Parameter #2 (optional) = Account in which we will restore the selected archive into (default = parameter 1)
Step 1 - Display all offsite archives (order oldest to newest) and present list to user for selection
Step 2 - Extract only the account's file from the archive to the temp folder
Step 3 - Restore archive to desired account
----------------------
/var/scripts/prod/mailbox-restore.sh
#!/bin/bash
#############################################
## Name : mailbox-restore.sh
## Version : 1.0
## Date : 2011-11-08
## Author : LHammonds
## Compatibility : Verified on Ubuntu 10.04.3 - 10.04.4 LTS, Zimbra 7.1.3 - 7.2.0 OSE
## Purpose : Restore individual mailbox accounts.
## Run Frequency : Manual as needed.
## Parameters :
## 1 = (Required) Account to search for archive (e.g. jdoe@mydomain.com)
## 2 = (Optional) Account to restore archive to (e.g. restore@mydomain.com)
## Exit Codes :
## 0 = Success or non-critical problem
## 1 = Archive folder does not exist
## 2 = Invalid mailbox account
## 3 = Mailbox restore failure
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-11-08 LTH Created script.
#############################################
## Import common variables and functions.
source /var/scripts/common/standard.conf
## Define local variables.
LOGFILE="${TEMPDIR}/mailbox-restore.log"
ARCHIVEDIR="${OFFSITEDIR}/mailbox"
ACCT1=$1
ACCT2=$2
RETURNVALUE=0
#######################################
## FUNCTIONS ##
#######################################
function f_showhelp()
{
echo ""
echo "Usage : ${SCRIPTNAME} user@${MYDOMAIN} restore@${MYDOMAIN} (optional)"
echo ""
echo "NOTE: If you specify a 2nd account, the 1st account data will be"
echo " restored to the 2nd account."
echo ""
}
function f_emergencyexit()
{
## Purpose: Exit script as cleanly as possible.
## Parameter #1 = Error Code.
if [ -f ${REMOTEDIR}/online.txt ]; then
## Dismount the remote site.
f_umount
fi
echo -e "Individual mailbox restore aborted. EXIT CODE: ${1}
"
exit $1
}
#######################################
## MAIN PROGRAM ##
#######################################
## Check command-line parameters.
case "$1" in
"")
f_showhelp
exit 0
;;
--help|-h|-?)
f_showhelp
exit 0
;;
*)
ACCT1=$1
ACCT2=$2
;;
esac
if [ "${ACCT1}" = "" ]; then
## Required parameter not specified.
f_showhelp
exit 0
fi
if [ "${ACCT2}" = "" ]; then
## Restore to the same account.
ACCT2=${ACCT1}
fi
## Mount the remote site.
f_mount
## Check to make sure the archive folder exists.
if [ ! -d "${ARCHIVEDIR}" ]; then
## ERROR: Archive folder does not exist.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: The archive folder does not exist! ${ARCHIVEDIR}, EC=1" | tee -a ${LOGFILE}
f_emergencyexit 1
fi
## Define user prompt using the special PS3 variable.
PS3="Type number for the desired archive or 'q' to quit: "
## Get sorted list of all archives (newest at the bottom).
FILELIST=$(find ${ARCHIVEDIR}/*.tar -maxdepth 1 -type f | sort -f)
## Prompt user to select a file to use.
## NOTE: If it is a long list, user can scroll up if
## using PuTTY to see older files.
select GETFILE in ${FILELIST}; do
if [ "${GETFILE}" != "" ]; then
FILENAME=${GETFILE}
fi
break
done
if [ "${FILENAME}" = "" ]; then
## User opted to quit.
echo -e "Exiting restore program.
"
exit 0
fi
## Extract just the mailbox file from the archive.
tar --extract -C ${TEMPDIR} --file=${FILENAME} --wildcards "*${ACCT1}*" --no-anchored --strip-components=3
if [ ! -f ${TEMPDIR}/${ACCT1}.tgz ]; then
## File did not exist in the archive.
echo -e "No file found matching ${ACCT1}
"
exit 0
fi
## Check to make sure parameter is a valid mailbox account name.
if `su - zimbra -c "zmprov -l gaa" | grep -q ${ACCT2}`
then
## The parameter contains a valid mailbox account.
echo "" > /dev/null
else
## Invalid mailbox account.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Invalid mailbox: ${ACCT2}, EC=2" | tee -a ${LOGFILE}
f_showhelp
f_emergencyexit 2
fi
${ZIMBRADIR}/bin/zmmailbox -z -m ${ACCT2} postRestURL "//?fmt=tgz&resolve=reset" ${TEMPDIR}/${ACCT1}.tgz
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Something went wrong.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Restore failure on ${ACCT2}, RETURN VALUE=${RETURNVALUE}, EC=3" | tee -a ${LOGFILE}
f_emergencyexit 3
fi
echo "`date +%Y-%m-%d_%H:%M:%S` - Restored mailbox --> ${ACCT2}" | tee -a ${LOGFILE}
f_sendmail "Zimbra User Mailbox Restore" "${ACCT2} was manually restored from ${ACCT1}"
## Clean up temporary files.
if [ -f ${TEMPDIR}/${ACCT1}.tgz ]; then
rm ${TEMPDIR}/${ACCT1}.tgz
fi
## Dismount the remote site.
f_umount
exit 0
/var/temp/mailbox-restore.log (sample)
2011-11-08_13:01:39 - ERROR: The archive folder does not exist! /mnt/backup/configtypo, EC=1
2011-11-08_15:54:34 - ERROR: Restore failure for admin@mydomain.com, RETURN VALUE=2, EC=3
2011-11-08_15:55:47 - Restored mailbox --> admin@mydomain.com
2011-11-08_15:57:50 - Restored mailbox --> lhammonds@mydomain.com
2011-11-08_16:00:14 - Restored mailbox --> ddiggler@mydomain.com
2011-11-08_16:01:16 - Restored mailbox --> restore@mydomain.com
2011-11-08_16:28:38 - ERROR: Invalid mailbox: bogus@mydomain.com, EC=2
Here is the general outline of the script:
Parameter #1 (required) = Account in which we will find the archive for.
Parameter #2 (optional) = Account in which we will restore the selected archive into (default = parameter 1)
Step 1 - Display all offsite archives (order oldest to newest) and present list to user for selection
Step 2 - Extract only the account's file from the archive to the temp folder
Step 3 - Restore archive to desired account
----------------------
/var/scripts/prod/mailbox-restore.sh
#!/bin/bash
#############################################
## Name : mailbox-restore.sh
## Version : 1.0
## Date : 2011-11-08
## Author : LHammonds
## Compatibility : Verified on Ubuntu 10.04.3 - 10.04.4 LTS, Zimbra 7.1.3 - 7.2.0 OSE
## Purpose : Restore individual mailbox accounts.
## Run Frequency : Manual as needed.
## Parameters :
## 1 = (Required) Account to search for archive (e.g. jdoe@mydomain.com)
## 2 = (Optional) Account to restore archive to (e.g. restore@mydomain.com)
## Exit Codes :
## 0 = Success or non-critical problem
## 1 = Archive folder does not exist
## 2 = Invalid mailbox account
## 3 = Mailbox restore failure
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-11-08 LTH Created script.
#############################################
## Import common variables and functions.
source /var/scripts/common/standard.conf
## Define local variables.
LOGFILE="${TEMPDIR}/mailbox-restore.log"
ARCHIVEDIR="${OFFSITEDIR}/mailbox"
ACCT1=$1
ACCT2=$2
RETURNVALUE=0
#######################################
## FUNCTIONS ##
#######################################
function f_showhelp()
{
echo ""
echo "Usage : ${SCRIPTNAME} user@${MYDOMAIN} restore@${MYDOMAIN} (optional)"
echo ""
echo "NOTE: If you specify a 2nd account, the 1st account data will be"
echo " restored to the 2nd account."
echo ""
}
function f_emergencyexit()
{
## Purpose: Exit script as cleanly as possible.
## Parameter #1 = Error Code.
if [ -f ${REMOTEDIR}/online.txt ]; then
## Dismount the remote site.
f_umount
fi
echo -e "Individual mailbox restore aborted. EXIT CODE: ${1}
"
exit $1
}
#######################################
## MAIN PROGRAM ##
#######################################
## Check command-line parameters.
case "$1" in
"")
f_showhelp
exit 0
;;
--help|-h|-?)
f_showhelp
exit 0
;;
*)
ACCT1=$1
ACCT2=$2
;;
esac
if [ "${ACCT1}" = "" ]; then
## Required parameter not specified.
f_showhelp
exit 0
fi
if [ "${ACCT2}" = "" ]; then
## Restore to the same account.
ACCT2=${ACCT1}
fi
## Mount the remote site.
f_mount
## Check to make sure the archive folder exists.
if [ ! -d "${ARCHIVEDIR}" ]; then
## ERROR: Archive folder does not exist.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: The archive folder does not exist! ${ARCHIVEDIR}, EC=1" | tee -a ${LOGFILE}
f_emergencyexit 1
fi
## Define user prompt using the special PS3 variable.
PS3="Type number for the desired archive or 'q' to quit: "
## Get sorted list of all archives (newest at the bottom).
FILELIST=$(find ${ARCHIVEDIR}/*.tar -maxdepth 1 -type f | sort -f)
## Prompt user to select a file to use.
## NOTE: If it is a long list, user can scroll up if
## using PuTTY to see older files.
select GETFILE in ${FILELIST}; do
if [ "${GETFILE}" != "" ]; then
FILENAME=${GETFILE}
fi
break
done
if [ "${FILENAME}" = "" ]; then
## User opted to quit.
echo -e "Exiting restore program.
"
exit 0
fi
## Extract just the mailbox file from the archive.
tar --extract -C ${TEMPDIR} --file=${FILENAME} --wildcards "*${ACCT1}*" --no-anchored --strip-components=3
if [ ! -f ${TEMPDIR}/${ACCT1}.tgz ]; then
## File did not exist in the archive.
echo -e "No file found matching ${ACCT1}
"
exit 0
fi
## Check to make sure parameter is a valid mailbox account name.
if `su - zimbra -c "zmprov -l gaa" | grep -q ${ACCT2}`
then
## The parameter contains a valid mailbox account.
echo "" > /dev/null
else
## Invalid mailbox account.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Invalid mailbox: ${ACCT2}, EC=2" | tee -a ${LOGFILE}
f_showhelp
f_emergencyexit 2
fi
${ZIMBRADIR}/bin/zmmailbox -z -m ${ACCT2} postRestURL "//?fmt=tgz&resolve=reset" ${TEMPDIR}/${ACCT1}.tgz
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Something went wrong.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: Restore failure on ${ACCT2}, RETURN VALUE=${RETURNVALUE}, EC=3" | tee -a ${LOGFILE}
f_emergencyexit 3
fi
echo "`date +%Y-%m-%d_%H:%M:%S` - Restored mailbox --> ${ACCT2}" | tee -a ${LOGFILE}
f_sendmail "Zimbra User Mailbox Restore" "${ACCT2} was manually restored from ${ACCT1}"
## Clean up temporary files.
if [ -f ${TEMPDIR}/${ACCT1}.tgz ]; then
rm ${TEMPDIR}/${ACCT1}.tgz
fi
## Dismount the remote site.
f_umount
exit 0
/var/temp/mailbox-restore.log (sample)
2011-11-08_13:01:39 - ERROR: The archive folder does not exist! /mnt/backup/configtypo, EC=1
2011-11-08_15:54:34 - ERROR: Restore failure for admin@mydomain.com, RETURN VALUE=2, EC=3
2011-11-08_15:55:47 - Restored mailbox --> admin@mydomain.com
2011-11-08_15:57:50 - Restored mailbox --> lhammonds@mydomain.com
2011-11-08_16:00:14 - Restored mailbox --> ddiggler@mydomain.com
2011-11-08_16:01:16 - Restored mailbox --> restore@mydomain.com
2011-11-08_16:28:38 - ERROR: Invalid mailbox: bogus@mydomain.com, EC=2
-
- Advanced member
- Posts: 148
- Joined: Sat Sep 13, 2014 2:14 am
My Notes for Installing Zimbra OSE on Ubuntu Server 10.04 LTS
SCENARIO #3 RESTORE EXISTING SERVER FROM A LOCAL COPY
WE WILL USE THE LOCAL FOLDER USED FOR DOING DAILY RSYNC BACKUPS.
THE CAVEOT HERE IS THAT YOU ONLY WANT TO DO THIS IF THE LAST RSYNC WAS FROM THE OFFLINE RSYNC SCRIPT...MEANING IT IS A COMPLETE SNAPSHOT AND NOT FROM ANY OF THE ONLINE RSYNCS WHICH DID NOT COPY OPEN AND IN-USE FILES. IF THE LAST RSYNC WAS THE ONLINE VERSION, WE WILL NEED TO USE A DIFFERENT SCRIPT TO ACCESS REMOTE STORAGE.
THIS SCRIPT IS INTENDED TO BE RUN MANUALLY AS THE ROOT USER.
HERE ARE THE INSTRUCTIONS TO RESTORE THE CURRENTLY RUNNING SERVER USING THE SCRIPT BELOW:
BEFORE RUNNING THIS, MAKE SURE EVERYONE IS AWARE THAT ZIMBRA WILL BE GOING DOWN TO BE RESTORED.
AT THE LOGIN PROMPT, LOGIN WITH YOUR ADMINISTRATOR ACCOUNT (ADMINISTRATOR / MYADMINPASS) AND THEN TYPE SU AND THE ROOT PASSWORD (MYROOTPASS)
RUN THE SCRIPT BY TYPING /VAR/SCRIPTS/PROD/RESTORE-RSYNC-LOCAL.SH
IF YOU MISSED ANY OF THE OUTPUT ON THE SCREEN, YOU CAN VIEW THE LOG BY TYPING VI /VAR/TEMP/RESTORE-RSYNC.LOG
RESTORE-RSYNC-LOCAL.SH
#!/BIN/BASH
#############################################
## NAME : RESTORE-RSYNC-LOCAL.SH
## VERSION : 1.1
## DATE : 2011-11-08
## AUTHOR : LHAMMONDS
## PURPOSE : RESTORE ZIMBRA USING RSYNC AND THE LOCAL BACKUP.
## COMPATIBILITY : VERIFED ON UBUNTU SERVER 10.04.3 - 10.04.4 LTS, ZIMBRA 7.1.3 - 7.2.0 OSE
## REQUIREMENTS : MUST BE RUN AS ROOT USER, LAST RSYNC SHOULD BE THE OFFLINE VERSION.
## RUN FREQUENCY : MANUAL AS NEEDED.
## EXIT CODES : ERRORS DISPLAYED TO SCREEN.
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-10-18 LTH CREATED SCRIPT.
## 2011-10-31 LTH ADDED BETTER LOGGING, ERROR CHECKS, USER INPUT.
## 2011-11-08 LTH MOVE COMMON VARIABLES AND FUNTIONS TO EXTERNAL FILE.
#############################################
## IMPORT COMMON VARIABLES AND FUNCTIONS. ##
SOURCE /VAR/SCRIPTS/COMMON/STANDARD.CONF
LOGFILE="${TEMPDIR}/RESTORE-RSYNC.LOG"
LOCKFILE="${TEMPDIR}/RSYNC.LOCK"
RSYNCLOGFILE="${TEMPDIR}/RSYNC.LOG"
PRODROOT="/OPT"
OLDDIR="${BACKUPDIR}/ZIMBRA.OLD"
LOCALBACKUP="${BACKUPDIR}/ZIMBRA/ZIMBRA"
LOCALBACKUPDEV="/DEV/MAPPER/LVG-BAK"
NOBACKUP=0
#######################################
## FUNCTIONS ##
#######################################
FUNCTION F_CLEANUP()
{
IF [ -F ${LOCKFILE} ];THEN
## REMOVE LOCK FILE SO OTHER RSYNC JOBS CAN RUN.
RM ${LOCKFILE} 1>/DEV/NULL 2>&1
FI
}
FUNCTION F_CHECKSPACE()
{
## NEED TO CHECK AND SEE IF THERE IS ENOUGH SPACE AVAILABLE TO MOVE ZIMBRA TO A BACKUP LOCATION.
FREESPACE=`DF -K ${LOCALBACKUPDEV} | GREP ${LOCALBACKUPDEV} | AWK '{ PRINT $4 }'`
BACKUPSIZE=`DU -SK ${ZIMBRADIR} | AWK '{ PRINT $1 }'`
IF [ ${BACKUPSIZE} -GT ${FREESPACE} ]; THEN
ECHO "THERE IS NOT ENOUGH FREESPACE AVAILABLE TO ARCHIVE PRODUCTION ZIMBRA."
ECHO "ZIMBRA SIZE IS ${BACKUPSIZE} KB, FREE SPACE IS ${FREESPACE} KB"
ECHO ""
ECHO "TO OVERRIDE AND NOT MAKE A BACKUP 1ST, USE THE --NOBACKUP OPTION."
ECHO ""
ECHO "EXAMPLE: ${SCRIPTNAME} --NOBACKUP"
ECHO ""
F_CLEANUP
EXIT 1
FI
}
#######################################
## MAIN PROGRAM ##
#######################################
IF [ -F ${LOCKFILE} ]; THEN
# RSYNC LOCK FILE DETECTED. ABORT SCRIPT.
ECHO "RESTORE RSYNC ABORTED"
ECHO "THIS SCRIPT TRIED TO RUN BUT DETECTED THE LOCK FILE: ${LOCKFILE}"
ECHO "PLEASE CHECK TO MAKE SURE THE FILE DOES NOT REMAIN WHEN RSYNC IS NOT ACTUALLY RUNNING."
F_SENDMAIL "RESTORE RSYNC ABORTED" "THIS SCRIPT TRIED TO RUN BUT DETECTED THE LOCK FILE: ${LOCKFILE}NNPLEASE CHECK TO MAKE SURE THE FILE DOES NOT REMAIN WHEN RSYNC IS NOT ACTUALLY RUNNING."
EXIT 1
ELSE
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` ${SCRIPTNAME}" > ${LOCKFILE}
FI
CLEAR
ECHO ""
# DETERMINE IF WE ARE GOING TO BACKUP EXISTING FOLDER OR NOT.
IF [ "$1" = "--NOBACKUP" ]; THEN
NOBACKUP=1
ELSE
NOBACKUP=0
F_CHECKSPACE
FI
## REQUIREMENT CHECK: SCRIPT MUST RUN AS ROOT USER.
IF [ "$(ID -U)" != "0" ]; THEN
## FATAL ERROR DETECTED: DOCUMENT PROBLEM AND TERMINATE SCRIPT.
ECHO "ERROR: ROOT USER REQUIRED FOR RESTORE."
ECHO ""
F_CLEANUP
EXIT 1
FI
IF [ ! -F ${RSYNCLOGFILE} ]; THEN
## FATAL ERROR DETECTED: DOCUMENT PROBLEM AND TERMINATE SCRIPT.
ECHO "ERROR: CANNOT FIND LOG: ${RSYNCLOGFILE}"
ECHO "THIS LOG FILE IS REQUIRED TO DETERMINE STATUS OF LAST RSYNC JOB."
ECHO ""
F_CLEANUP
EXIT 1
FI
ECHO "THIS RESTORE METHOD CAN ONLY WORK IF THE LAST RSYNC BACKUP WAS"
ECHO "THE 'OFFLINE' VERSION WHICH ALLOWS FOR A COMPLETE BACKUP."
ECHO ""
ECHO "THE 'ONLINE' VERSION IS ONLY A PARTIAL BACKUP AND WILL NOT WORK."
ECHO ""
READ -P "THE NEXT STEP WILL TRY TO AUTO-DETECT THE LAST BACKUP. CONTINUE (Y/N)? "
IF [ "${REPLY}" != "Y" ]; THEN
ECHO "SCRIPT CANCELLED."
ECHO ""
F_CLEANUP
EXIT 1
FI
ECHO ""
TAIL -N1 ${RSYNCLOGFILE} | GREP -Q "OFFLINE RSYNC BACKUP EXIT CODE"
IF [ $? -EQ 0 ]; THEN
ECHO "LAST RSYNC SEEMS TO HAVE BEEN A GOOD OFFLINE BACKUP"
ELSE
ECHO "WARNING: THIS SCRIPT DID NOT SEE THE OFFLINE ENTRY AT THE END OF THE LOG FILE."
FI
ECHO ""
ECHO "--------------------------------------------------------"
TAIL -N5 ${RSYNCLOGFILE}
ECHO "--------------------------------------------------------"
ECHO ""
READ -P "DO YOU SEE 'OFFLINE RSYNC BACKUP EXIT CODE: 0' IN THE LOG ABOVE (Y/N)? "
IF [ "${REPLY}" != "Y" ]; THEN
ECHO "SCRIPT CANCELLED."
ECHO ""
F_CLEANUP
EXIT 1
FI
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - RESTORE STARTED." | TEE -A ${LOGFILE}
STARTTIME="$(DATE +%S)"
## STOP ZIMBRA SERVICES.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- STOPPING ZIMBRA SERVICES." | TEE -A ${LOGFILE}
/ETC/INIT.D/ZIMBRA STOP
## KILL ANY ORPHANED ZIMBRA PROCESSES.
PKILL -9 -U ZIMBRA 1>/DEV/NULL 2>&1
IF [ ${NOBACKUP} -EQ 1 ]; THEN
## LEAVE CURRENT PRODUCTION FOLDER ALONE.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- 'NO BACKUP' OVERRIDE SPECIFIED, SKIPPING FOLDER MOVE." | TEE -A ${LOGFILE}
ELSE
## MOVE PRODUCTION FOLDER TO BACKUP LOCATION.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- MOVING ZIMBRA FROM ${ZIMBRADIR} TO ${OLDDIR}." | TEE -A ${LOGFILE}
MV ${ZIMBRADIR} ${OLDDIR}
RETURNVALUE=$?
IF [ ${RETURNVALUE} -NE 0 ]; THEN
## COULD NOT MOVE ZIMBRA TO BACKUP LOCATION.
## DOCUMENT ERROR AND TERMINATE SCRIPT.
ECHO ""
ECHO "ERROR: THE MOVE WAS NOT SUCCESSFUL. RETURN VALUE = ${RETURNVALUE}" | TEE -A ${LOGFILE}
ECHO ""
ECHO "COMMAND WAS 'MV ${ZIMBRADIR} ${OLDDIR}'" | TEE -A ${LOGFILE}
ECHO ""
ECHO "THE ZIMBRA SERVICES ARE CURRENTLY STOPPED AND AN UNKNOWN AMOUNT OF FILES WERE MOVED"
ECHO "FROM THE SOURCE. THAT MEANS THERE SOME FILES ARE STILL IN ${ZIMBRADIR}"
ECHO "AND SOME FILES WERE MOVED TO ${OLDDIR}"
ECHO "THIS NEEDS TO BE RESOLVED BEFORE YOU CAN START THE SERVICES BACK UP."
ECHO "EITHER MOVE THE FILES BACK OR DELETE ALL FILES AND RUN THE RESTORE."
F_CLEANUP
EXIT 99
FI
FI
## NOW THAT ZIMBRA IS OFFLINE, RSYNC CAN RESTORE ALL FILES.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- RESTORING FILES WITH RSYNC." | TEE -A ${LOGFILE}
RSYNC -APOGHK ${LOCALBACKUP} ${PRODROOT}
RETURNVALUE=$?
IF [ ${RETURNVALUE} -NE 0 ]; THEN
## RSYNC COMMAND FAILED. DISPLAY WARNING MESSAGE.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- ERROR: RSYNC RETURN VALUE = {$RETURNVALUE}" | TEE -A ${LOGFILE}
FI
IF [ ! -F ${ZIMBRADIR}/.INSTALL_HISTORY ]; THEN
## SOMETHING IS NOT RIGHT...AT LEAST THIS FILE SHOULD EXIST HERE.
## NOTE: THIS IS NOT A GUARENTEE ALL FILES WERE RESTORED, IT IS JUST A QUICK CHECK.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- ERROR: MISSING FILE(S). DID NOT FIND ${ZIMBRADIR}/.INSTALL_HISTORY" | TEE -A ${LOGFILE}
FI
## FIX PERMISSIONS.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- FIXING FILE OWNERSHIP AND PERMISSIONS." | TEE -A ${LOGFILE}
CHOWN -R ZIMBRA:ZIMBRA ${ZIMBRADIR}
${ZIMBRADIR}/LIBEXEC/ZMFIXPERMS
## START ZIMBRA SERVICES.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- STARTING ZIMBRA SERVICES." | TEE -A ${LOGFILE}
/ETC/INIT.D/ZIMBRA START
## CALCULATES DOWNTIME OF ZIMBRA SERVICES.
FINISHTIME="$(DATE +%S)"
ELAPSEDTIME="$(EXPR ${FINISHTIME} - ${STARTTIME})"
HOURS=$((${ELAPSEDTIME} / 3600))
ELAPSEDTIME=$((${ELAPSEDTIME} - ${HOURS} * 3600))
MINUTES=$((${ELAPSEDTIME} / 60))
SECONDS=$((${ELAPSEDTIME} - ${MINUTES} * 60))
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- ZIMBRA RESTORE TIME: ${HOURS} HOUR(S) ${MINUTES} MINUTE(S) ${SECONDS} SECOND(S)" | TEE -A ${LOGFILE}
## SHOW STATUS OF ZIMBRA SERVICES.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- STATUS OF ZIMBRA SERVICES:" | TEE -A ${LOGFILE}
SU - ZIMBRA -C "ZMCONTROL STATUS" | TEE -A ${LOGFILE}
IF [ -D ${OLDDIR} ]; THEN
ECHO -E "NNDON'T FORGET TO PURGE ${OLDDIR} ONCE EVERYTHING IS RUNNING SMOOTHLY AGAIN.NN"
FI
F_CLEANUP
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - RESTORE COMPLETED." | TEE -A ${LOGFILE}
SAMPLE OUTPUT FROM SCRIPT:
2011-10-18_16:26:40 - RESTORE STARTED.
2011-10-18_16:26:40 --- STOPPING ZIMBRA SERVICES.
HOST MAIL.MYDOMAIN.COM
STOPPING STATS...DONE.
STOPPING MTA...DONE.
STOPPING SPELL...DONE.
STOPPING SNMP...DONE.
STOPPING CBPOLICYD...DONE.
STOPPING ARCHIVING...DONE.
STOPPING ANTIVIRUS...DONE.
STOPPING ANTISPAM...DONE.
STOPPING IMAPPROXY...DONE.
STOPPING MEMCACHED...DONE.
STOPPING MAILBOX...DONE.
STOPPING LOGGER...DONE.
STOPPING ZMCONFIGD...DONE.
STOPPING LDAP...DONE.
2011-10-18_16:27:22 --- MOVING ZIMBRA FROM /OPT/ZIMBRA TO /TEMP/ZIMBRA.OLD.
2011-10-18_16:27:22 --- RESTORING FILES WITH RSYNC.
2011-10-18_16:31:53 --- FIXING FILE OWNERSHIP AND PERMISSIONS.
2011-10-18_16:31:55 --- STARTING ZIMBRA SERVICES.
HOST MAIL.MYDOMAIN.COM
STARTING LDAP...DONE.
STARTING ZMCONFIGD...DONE.
STARTING LOGGER...DONE.
STARTING MAILBOX...DONE.
STARTING ANTISPAM...DONE.
STARTING ANTIVIRUS...DONE.
STARTING SNMP...DONE.
STARTING SPELL...DONE.
STARTING MTA...DONE.
STARTING STATS...DONE.
2011-10-18_16:33:25 --- ZIMBRA RESTORE TIME: 0 HOUR(S) 6 MINUTE(S) 45 SECOND(S)
2011-10-18_16:33:25 --- STATUS OF ZIMBRA SERVICES:
HOST MAIL.MYDOMAIN.COM
ANTISPAM RUNNING
ANTIVIRUS RUNNING
LDAP RUNNING
LOGGER RUNNING
MAILBOX RUNNING
MTA RUNNING
SNMP RUNNING
SPELL RUNNING
STATS RUNNING
ZMCONFIGD RUNNING
2011-10-18_16:33:55 - RESTORE COMPLETED.
WE WILL USE THE LOCAL FOLDER USED FOR DOING DAILY RSYNC BACKUPS.
THE CAVEOT HERE IS THAT YOU ONLY WANT TO DO THIS IF THE LAST RSYNC WAS FROM THE OFFLINE RSYNC SCRIPT...MEANING IT IS A COMPLETE SNAPSHOT AND NOT FROM ANY OF THE ONLINE RSYNCS WHICH DID NOT COPY OPEN AND IN-USE FILES. IF THE LAST RSYNC WAS THE ONLINE VERSION, WE WILL NEED TO USE A DIFFERENT SCRIPT TO ACCESS REMOTE STORAGE.
THIS SCRIPT IS INTENDED TO BE RUN MANUALLY AS THE ROOT USER.
HERE ARE THE INSTRUCTIONS TO RESTORE THE CURRENTLY RUNNING SERVER USING THE SCRIPT BELOW:
BEFORE RUNNING THIS, MAKE SURE EVERYONE IS AWARE THAT ZIMBRA WILL BE GOING DOWN TO BE RESTORED.
AT THE LOGIN PROMPT, LOGIN WITH YOUR ADMINISTRATOR ACCOUNT (ADMINISTRATOR / MYADMINPASS) AND THEN TYPE SU AND THE ROOT PASSWORD (MYROOTPASS)
RUN THE SCRIPT BY TYPING /VAR/SCRIPTS/PROD/RESTORE-RSYNC-LOCAL.SH
IF YOU MISSED ANY OF THE OUTPUT ON THE SCREEN, YOU CAN VIEW THE LOG BY TYPING VI /VAR/TEMP/RESTORE-RSYNC.LOG
RESTORE-RSYNC-LOCAL.SH
#!/BIN/BASH
#############################################
## NAME : RESTORE-RSYNC-LOCAL.SH
## VERSION : 1.1
## DATE : 2011-11-08
## AUTHOR : LHAMMONDS
## PURPOSE : RESTORE ZIMBRA USING RSYNC AND THE LOCAL BACKUP.
## COMPATIBILITY : VERIFED ON UBUNTU SERVER 10.04.3 - 10.04.4 LTS, ZIMBRA 7.1.3 - 7.2.0 OSE
## REQUIREMENTS : MUST BE RUN AS ROOT USER, LAST RSYNC SHOULD BE THE OFFLINE VERSION.
## RUN FREQUENCY : MANUAL AS NEEDED.
## EXIT CODES : ERRORS DISPLAYED TO SCREEN.
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-10-18 LTH CREATED SCRIPT.
## 2011-10-31 LTH ADDED BETTER LOGGING, ERROR CHECKS, USER INPUT.
## 2011-11-08 LTH MOVE COMMON VARIABLES AND FUNTIONS TO EXTERNAL FILE.
#############################################
## IMPORT COMMON VARIABLES AND FUNCTIONS. ##
SOURCE /VAR/SCRIPTS/COMMON/STANDARD.CONF
LOGFILE="${TEMPDIR}/RESTORE-RSYNC.LOG"
LOCKFILE="${TEMPDIR}/RSYNC.LOCK"
RSYNCLOGFILE="${TEMPDIR}/RSYNC.LOG"
PRODROOT="/OPT"
OLDDIR="${BACKUPDIR}/ZIMBRA.OLD"
LOCALBACKUP="${BACKUPDIR}/ZIMBRA/ZIMBRA"
LOCALBACKUPDEV="/DEV/MAPPER/LVG-BAK"
NOBACKUP=0
#######################################
## FUNCTIONS ##
#######################################
FUNCTION F_CLEANUP()
{
IF [ -F ${LOCKFILE} ];THEN
## REMOVE LOCK FILE SO OTHER RSYNC JOBS CAN RUN.
RM ${LOCKFILE} 1>/DEV/NULL 2>&1
FI
}
FUNCTION F_CHECKSPACE()
{
## NEED TO CHECK AND SEE IF THERE IS ENOUGH SPACE AVAILABLE TO MOVE ZIMBRA TO A BACKUP LOCATION.
FREESPACE=`DF -K ${LOCALBACKUPDEV} | GREP ${LOCALBACKUPDEV} | AWK '{ PRINT $4 }'`
BACKUPSIZE=`DU -SK ${ZIMBRADIR} | AWK '{ PRINT $1 }'`
IF [ ${BACKUPSIZE} -GT ${FREESPACE} ]; THEN
ECHO "THERE IS NOT ENOUGH FREESPACE AVAILABLE TO ARCHIVE PRODUCTION ZIMBRA."
ECHO "ZIMBRA SIZE IS ${BACKUPSIZE} KB, FREE SPACE IS ${FREESPACE} KB"
ECHO ""
ECHO "TO OVERRIDE AND NOT MAKE A BACKUP 1ST, USE THE --NOBACKUP OPTION."
ECHO ""
ECHO "EXAMPLE: ${SCRIPTNAME} --NOBACKUP"
ECHO ""
F_CLEANUP
EXIT 1
FI
}
#######################################
## MAIN PROGRAM ##
#######################################
IF [ -F ${LOCKFILE} ]; THEN
# RSYNC LOCK FILE DETECTED. ABORT SCRIPT.
ECHO "RESTORE RSYNC ABORTED"
ECHO "THIS SCRIPT TRIED TO RUN BUT DETECTED THE LOCK FILE: ${LOCKFILE}"
ECHO "PLEASE CHECK TO MAKE SURE THE FILE DOES NOT REMAIN WHEN RSYNC IS NOT ACTUALLY RUNNING."
F_SENDMAIL "RESTORE RSYNC ABORTED" "THIS SCRIPT TRIED TO RUN BUT DETECTED THE LOCK FILE: ${LOCKFILE}NNPLEASE CHECK TO MAKE SURE THE FILE DOES NOT REMAIN WHEN RSYNC IS NOT ACTUALLY RUNNING."
EXIT 1
ELSE
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` ${SCRIPTNAME}" > ${LOCKFILE}
FI
CLEAR
ECHO ""
# DETERMINE IF WE ARE GOING TO BACKUP EXISTING FOLDER OR NOT.
IF [ "$1" = "--NOBACKUP" ]; THEN
NOBACKUP=1
ELSE
NOBACKUP=0
F_CHECKSPACE
FI
## REQUIREMENT CHECK: SCRIPT MUST RUN AS ROOT USER.
IF [ "$(ID -U)" != "0" ]; THEN
## FATAL ERROR DETECTED: DOCUMENT PROBLEM AND TERMINATE SCRIPT.
ECHO "ERROR: ROOT USER REQUIRED FOR RESTORE."
ECHO ""
F_CLEANUP
EXIT 1
FI
IF [ ! -F ${RSYNCLOGFILE} ]; THEN
## FATAL ERROR DETECTED: DOCUMENT PROBLEM AND TERMINATE SCRIPT.
ECHO "ERROR: CANNOT FIND LOG: ${RSYNCLOGFILE}"
ECHO "THIS LOG FILE IS REQUIRED TO DETERMINE STATUS OF LAST RSYNC JOB."
ECHO ""
F_CLEANUP
EXIT 1
FI
ECHO "THIS RESTORE METHOD CAN ONLY WORK IF THE LAST RSYNC BACKUP WAS"
ECHO "THE 'OFFLINE' VERSION WHICH ALLOWS FOR A COMPLETE BACKUP."
ECHO ""
ECHO "THE 'ONLINE' VERSION IS ONLY A PARTIAL BACKUP AND WILL NOT WORK."
ECHO ""
READ -P "THE NEXT STEP WILL TRY TO AUTO-DETECT THE LAST BACKUP. CONTINUE (Y/N)? "
IF [ "${REPLY}" != "Y" ]; THEN
ECHO "SCRIPT CANCELLED."
ECHO ""
F_CLEANUP
EXIT 1
FI
ECHO ""
TAIL -N1 ${RSYNCLOGFILE} | GREP -Q "OFFLINE RSYNC BACKUP EXIT CODE"
IF [ $? -EQ 0 ]; THEN
ECHO "LAST RSYNC SEEMS TO HAVE BEEN A GOOD OFFLINE BACKUP"
ELSE
ECHO "WARNING: THIS SCRIPT DID NOT SEE THE OFFLINE ENTRY AT THE END OF THE LOG FILE."
FI
ECHO ""
ECHO "--------------------------------------------------------"
TAIL -N5 ${RSYNCLOGFILE}
ECHO "--------------------------------------------------------"
ECHO ""
READ -P "DO YOU SEE 'OFFLINE RSYNC BACKUP EXIT CODE: 0' IN THE LOG ABOVE (Y/N)? "
IF [ "${REPLY}" != "Y" ]; THEN
ECHO "SCRIPT CANCELLED."
ECHO ""
F_CLEANUP
EXIT 1
FI
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - RESTORE STARTED." | TEE -A ${LOGFILE}
STARTTIME="$(DATE +%S)"
## STOP ZIMBRA SERVICES.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- STOPPING ZIMBRA SERVICES." | TEE -A ${LOGFILE}
/ETC/INIT.D/ZIMBRA STOP
## KILL ANY ORPHANED ZIMBRA PROCESSES.
PKILL -9 -U ZIMBRA 1>/DEV/NULL 2>&1
IF [ ${NOBACKUP} -EQ 1 ]; THEN
## LEAVE CURRENT PRODUCTION FOLDER ALONE.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- 'NO BACKUP' OVERRIDE SPECIFIED, SKIPPING FOLDER MOVE." | TEE -A ${LOGFILE}
ELSE
## MOVE PRODUCTION FOLDER TO BACKUP LOCATION.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- MOVING ZIMBRA FROM ${ZIMBRADIR} TO ${OLDDIR}." | TEE -A ${LOGFILE}
MV ${ZIMBRADIR} ${OLDDIR}
RETURNVALUE=$?
IF [ ${RETURNVALUE} -NE 0 ]; THEN
## COULD NOT MOVE ZIMBRA TO BACKUP LOCATION.
## DOCUMENT ERROR AND TERMINATE SCRIPT.
ECHO ""
ECHO "ERROR: THE MOVE WAS NOT SUCCESSFUL. RETURN VALUE = ${RETURNVALUE}" | TEE -A ${LOGFILE}
ECHO ""
ECHO "COMMAND WAS 'MV ${ZIMBRADIR} ${OLDDIR}'" | TEE -A ${LOGFILE}
ECHO ""
ECHO "THE ZIMBRA SERVICES ARE CURRENTLY STOPPED AND AN UNKNOWN AMOUNT OF FILES WERE MOVED"
ECHO "FROM THE SOURCE. THAT MEANS THERE SOME FILES ARE STILL IN ${ZIMBRADIR}"
ECHO "AND SOME FILES WERE MOVED TO ${OLDDIR}"
ECHO "THIS NEEDS TO BE RESOLVED BEFORE YOU CAN START THE SERVICES BACK UP."
ECHO "EITHER MOVE THE FILES BACK OR DELETE ALL FILES AND RUN THE RESTORE."
F_CLEANUP
EXIT 99
FI
FI
## NOW THAT ZIMBRA IS OFFLINE, RSYNC CAN RESTORE ALL FILES.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- RESTORING FILES WITH RSYNC." | TEE -A ${LOGFILE}
RSYNC -APOGHK ${LOCALBACKUP} ${PRODROOT}
RETURNVALUE=$?
IF [ ${RETURNVALUE} -NE 0 ]; THEN
## RSYNC COMMAND FAILED. DISPLAY WARNING MESSAGE.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- ERROR: RSYNC RETURN VALUE = {$RETURNVALUE}" | TEE -A ${LOGFILE}
FI
IF [ ! -F ${ZIMBRADIR}/.INSTALL_HISTORY ]; THEN
## SOMETHING IS NOT RIGHT...AT LEAST THIS FILE SHOULD EXIST HERE.
## NOTE: THIS IS NOT A GUARENTEE ALL FILES WERE RESTORED, IT IS JUST A QUICK CHECK.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- ERROR: MISSING FILE(S). DID NOT FIND ${ZIMBRADIR}/.INSTALL_HISTORY" | TEE -A ${LOGFILE}
FI
## FIX PERMISSIONS.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- FIXING FILE OWNERSHIP AND PERMISSIONS." | TEE -A ${LOGFILE}
CHOWN -R ZIMBRA:ZIMBRA ${ZIMBRADIR}
${ZIMBRADIR}/LIBEXEC/ZMFIXPERMS
## START ZIMBRA SERVICES.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- STARTING ZIMBRA SERVICES." | TEE -A ${LOGFILE}
/ETC/INIT.D/ZIMBRA START
## CALCULATES DOWNTIME OF ZIMBRA SERVICES.
FINISHTIME="$(DATE +%S)"
ELAPSEDTIME="$(EXPR ${FINISHTIME} - ${STARTTIME})"
HOURS=$((${ELAPSEDTIME} / 3600))
ELAPSEDTIME=$((${ELAPSEDTIME} - ${HOURS} * 3600))
MINUTES=$((${ELAPSEDTIME} / 60))
SECONDS=$((${ELAPSEDTIME} - ${MINUTES} * 60))
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- ZIMBRA RESTORE TIME: ${HOURS} HOUR(S) ${MINUTES} MINUTE(S) ${SECONDS} SECOND(S)" | TEE -A ${LOGFILE}
## SHOW STATUS OF ZIMBRA SERVICES.
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` --- STATUS OF ZIMBRA SERVICES:" | TEE -A ${LOGFILE}
SU - ZIMBRA -C "ZMCONTROL STATUS" | TEE -A ${LOGFILE}
IF [ -D ${OLDDIR} ]; THEN
ECHO -E "NNDON'T FORGET TO PURGE ${OLDDIR} ONCE EVERYTHING IS RUNNING SMOOTHLY AGAIN.NN"
FI
F_CLEANUP
ECHO "`DATE +%Y-%M-%D_%H:%M:%S` - RESTORE COMPLETED." | TEE -A ${LOGFILE}
SAMPLE OUTPUT FROM SCRIPT:
2011-10-18_16:26:40 - RESTORE STARTED.
2011-10-18_16:26:40 --- STOPPING ZIMBRA SERVICES.
HOST MAIL.MYDOMAIN.COM
STOPPING STATS...DONE.
STOPPING MTA...DONE.
STOPPING SPELL...DONE.
STOPPING SNMP...DONE.
STOPPING CBPOLICYD...DONE.
STOPPING ARCHIVING...DONE.
STOPPING ANTIVIRUS...DONE.
STOPPING ANTISPAM...DONE.
STOPPING IMAPPROXY...DONE.
STOPPING MEMCACHED...DONE.
STOPPING MAILBOX...DONE.
STOPPING LOGGER...DONE.
STOPPING ZMCONFIGD...DONE.
STOPPING LDAP...DONE.
2011-10-18_16:27:22 --- MOVING ZIMBRA FROM /OPT/ZIMBRA TO /TEMP/ZIMBRA.OLD.
2011-10-18_16:27:22 --- RESTORING FILES WITH RSYNC.
2011-10-18_16:31:53 --- FIXING FILE OWNERSHIP AND PERMISSIONS.
2011-10-18_16:31:55 --- STARTING ZIMBRA SERVICES.
HOST MAIL.MYDOMAIN.COM
STARTING LDAP...DONE.
STARTING ZMCONFIGD...DONE.
STARTING LOGGER...DONE.
STARTING MAILBOX...DONE.
STARTING ANTISPAM...DONE.
STARTING ANTIVIRUS...DONE.
STARTING SNMP...DONE.
STARTING SPELL...DONE.
STARTING MTA...DONE.
STARTING STATS...DONE.
2011-10-18_16:33:25 --- ZIMBRA RESTORE TIME: 0 HOUR(S) 6 MINUTE(S) 45 SECOND(S)
2011-10-18_16:33:25 --- STATUS OF ZIMBRA SERVICES:
HOST MAIL.MYDOMAIN.COM
ANTISPAM RUNNING
ANTIVIRUS RUNNING
LDAP RUNNING
LOGGER RUNNING
MAILBOX RUNNING
MTA RUNNING
SNMP RUNNING
SPELL RUNNING
STATS RUNNING
ZMCONFIGD RUNNING
2011-10-18_16:33:55 - RESTORE COMPLETED.
-
- Advanced member
- Posts: 148
- Joined: Sat Sep 13, 2014 2:14 am
My Notes for Installing Zimbra OSE on Ubuntu Server 10.04 LTS
Scenario #4 Restore existing server from an offsite location
/var/scripts/prod/rsync-restore.sh
#!/bin/bash
#############################################
## Name : rsync-restore.sh
## Version : 1.0
## Date : 2011-11-08
## Author : LHammonds
## Purpose : Restore Zimbra using rsync from a remote archive.
## Compatibility : Verified on Ubuntu Server 10.04.3 - 10.04.4 LTS, Zimbra 7.1.2 - 7.2.0 OSE
## Requirements : Must be root user, p7zip-full (if ARCHIVEMETHOD=tar.7z)
## Run Frequency : Manual as needed.
## Exit Codes :
## 0 = Success or non-critical problem
## 1 = Archive folder does not exist
## 2 = Archive extration failed
## 3 = Zimbra restore failure
## 99 = Move production to temp directory failure (bad)
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-11-08 LTH Created script.
#############################################
## Import common variables and functions. ##
source /var/scripts/common/standard.conf
LOGFILE="${TEMPDIR}/rsync-restore.log"
LOCKFILE="${TEMPDIR}/rsync.lock"
ARCHIVEDIR="${OFFSITEDIR}/zimbra"
OLDDIR="${BACKUPDIR}/zimbra.old"
NOBACKUP=0
#######################################
## FUNCTIONS ##
#######################################
function f_cleanup()
{
if [ -f ${LOCKFILE} ];then
## Remove lock file so other rsync jobs can run.
rm ${LOCKFILE} 1>/dev/null 2>&1
fi
}
function f_checkspace()
{
## Need to check and see if there is enough space available to move Zimbra to a backup location.
FREESPACE=`df -k ${BACKUPDIR} | grep ${BACKUPDIR} | awk '{ print $4 }'`
BACKUPSIZE=`du -sk ${ZIMBRADIR} | awk '{ print $1 }'`
if [ ${BACKUPSIZE} -gt ${FREESPACE} ]; then
echo "There is not enough freespace available to archive production Zimbra."
echo "Zimbra size is ${BACKUPSIZE} kb, Free space is ${FREESPACE} kb"
echo ""
echo "To override and not make a backup 1st, use the --nobackup option."
echo ""
echo "Example: ${SCRIPTNAME} --nobackup"
echo ""
f_cleanup
exit 1
fi
}
function f_emergencyexit()
{
## Purpose: Exit script as cleanly as possible.
## Parameter #1 = Error Code.
if [ -f ${REMOTEDIR}/online.txt ]; then
## Dismount the remote site.
f_umount
fi
echo -e "Zimbra restore aborted. EXIT CODE: ${1}
"
exit $1
}
#######################################
## MAIN PROGRAM ##
#######################################
if [ -f ${LOCKFILE} ]; then
## Restore lock file detected. Abort script.
echo "Restore aborted"
echo "This script tried to run but detected the lock file: ${LOCKFILE}"
echo "Please check to make sure the file does not remain when rsync or restore is not actually running."
f_sendmail "Zimbra Restore aborted" "This script tried to run but detected the lock file: ${LOCKFILE}
Please check to make sure the file does not remain when rsync/restore is not actually running."
exit 1
else
echo "`date +%Y-%m-%d_%H:%M:%S` ${SCRIPTNAME}" > ${LOCKFILE}
fi
clear
echo ""
## Determine if we are going to backup existing folder or not.
if [ "$1" = "--nobackup" ]; then
NOBACKUP=1
else
NOBACKUP=0
##
f_checkspace
fi
## Requirement Check: Script must run as root user.
if [ "$(id -u)" != "0" ]; then
## FATAL ERROR DETECTED: Document problem and terminate script.
echo "ERROR: Root user required for restore."
echo ""
f_cleanup
exit 1
fi
## Mount the remote site.
f_mount
## Check to make sure the archive folder exists.
if [ ! -d "${ARCHIVEDIR}" ]; then
## ERROR: Archive folder does not exist.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: The archive folder does not exist! ${ARCHIVEDIR}, EC=1" | tee -a ${LOGFILE}
f_cleanup
f_emergencyexit 1
fi
## Define user prompt using the special PS3 variable.
PS3="Type number for the desired archive or 'q' to quit: "
echo " Z I M B R A R E S T O R E"
echo " ---------------------------"
## Get sorted list of all archives (newest at the bottom).
FILELIST=$(find ${ARCHIVEDIR}/*.${ARCHIVEMETHOD} -maxdepth 1 -type f | sort -f)
## Prompt user to select a file to use.
## NOTE: If it is a long list, user can scroll up if
## using PuTTY to see older files.
select GETFILE in ${FILELIST}; do
if [ "${GETFILE}" != "" ]; then
FILENAME=${GETFILE}
fi
break
done
if [ "${FILENAME}" = "" ]; then
## User opted to quit.
echo -e "Exiting restore program.
"
f_cleanup
f_umount
exit 0
fi
echo -e "
Selected file: ${FILENAME}
"
echo -e " This restore will shutdown Zimbra and make it"
echo -e " unavailable while it is being restored.
"
read -p "Are you absolutely sure you wish to restore (y/n)? "
if [ "${REPLY}" != "y" ]; then
echo -e "
Restore aborted.
"
f_cleanup
exit 0
fi
echo "`date +%Y-%m-%d_%H:%M:%S` - Restore started." | tee -a ${LOGFILE}
StartTime="$(date +%s)"
## Stop Zimbra Services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Stopping Zimbra services." | tee -a ${LOGFILE}
/etc/init.d/zimbra stop
## Kill any orphaned Zimbra processes.
pkill -9 -u zimbra 1>/dev/null 2>&1
if [ ${NOBACKUP} -eq 1 ]; then
## Leave current production folder alone.
echo "`date +%Y-%m-%d_%H:%M:%S` --- 'No Backup' override specified, skipping folder move." | tee -a ${LOGFILE}
else
## Move production folder to backup location.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Moving Zimbra from ${ZIMBRADIR} to ${OLDDIR}." | tee -a ${LOGFILE}
mv ${ZIMBRADIR} ${OLDDIR}
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Could not move Zimbra to backup location.
## Document error and terminate script.
echo ""
echo "ERROR: The move was not successful. Return value = ${RETURNVALUE}" | tee -a ${LOGFILE}
echo ""
echo "COMMAND was 'mv ${ZIMBRADIR} ${OLDDIR}'" | tee -a ${LOGFILE}
echo ""
echo "The Zimbra services are currently stopped and an unknown amount of files were moved"
echo "from the source. That means there some files are still in ${ZIMBRADIR}"
echo "and some files were moved to ${OLDDIR}"
echo "This needs to be resolved before you can start the services back up."
echo "Either move the files back or delete all files and run the restore."
f_cleanup
exit 99
fi
fi
## Now that Zimbra is offline, we can restore all files.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Restoring files from ${FILENAME}" | tee -a ${LOGFILE}
if [ ! -d ${ZIMBRADIR} ]; then
mkdir -p ${ZIMBRADIR}
fi
## Extract the entire contents of the archive back to its original location.
case "${ARCHIVEMETHOD}" in
tar.7z)
7za x -so -w/${TEMPDIR} ${FILENAME} | tar -C ${ZIMBRADIR} --extract --strip-components=4 --file -
;;
tgz)
tar --extract -C ${ZIMBRADIR} --strip-components=4 --file=${FILENAME}
;;
*)
tar --extract -C ${ZIMBRADIR} --strip-components=4 --file=${FILENAME}
;;
esac
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## tar extract command failed. Display warning message.
echo "`date +%Y-%m-%d_%H:%M:%S` --- ERROR: tar extract return value = {$RETURNVALUE}" | tee -a ${LOGFILE}
f_cleanup
f_emergencyexit 2
fi
if [ ! -f ${ZIMBRADIR}/.install_history ]; then
## Something is not right...at least this file should exist here.
## NOTE: This is not a guarentee all files were restored, it is just a quick check.
echo "`date +%Y-%m-%d_%H:%M:%S` --- ERROR: Missing file(s). Did not find ${ZIMBRADIR}/.install_history" | tee -a ${LOGFILE}
fi
## Fix permissions.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Fixing file ownership and permissions." | tee -a ${LOGFILE}
chown -R zimbra:zimbra ${ZIMBRADIR}
${ZIMBRADIR}/libexec/zmfixperms
## Start Zimbra services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Starting Zimbra services." | tee -a ${LOGFILE}
/etc/init.d/zimbra start
## Calculates downtime of Zimbra services.
FinishTime="$(date +%s)"
ElapsedTime="$(expr ${FinishTime} - ${StartTime})"
Hours=$((${ElapsedTime} / 3600))
ElapsedTime=$((${ElapsedTime} - ${Hours} * 3600))
Minutes=$((${ElapsedTime} / 60))
Seconds=$((${ElapsedTime} - ${Minutes} * 60))
echo "`date +%Y-%m-%d_%H:%M:%S` --- Zimbra restore time: ${Hours} hour(s) ${Minutes} minute(s) ${Seconds} second(s)" | tee -a ${LOGFILE}
## Show status of Zimbra services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Status of Zimbra services:" | tee -a ${LOGFILE}
su - zimbra -c "zmcontrol status" | tee -a ${LOGFILE}
if [ -d ${OLDDIR} ]; then
echo -e "
Don't forget to purge ${OLDDIR} once everything is running smoothly again.
"
fi
f_cleanup
## Dismount the remote site.
f_umount
echo "`date +%Y-%m-%d_%H:%M:%S` - Restore completed." | tee -a ${LOGFILE}
/var/scripts/prod/rsync-restore.sh
#!/bin/bash
#############################################
## Name : rsync-restore.sh
## Version : 1.0
## Date : 2011-11-08
## Author : LHammonds
## Purpose : Restore Zimbra using rsync from a remote archive.
## Compatibility : Verified on Ubuntu Server 10.04.3 - 10.04.4 LTS, Zimbra 7.1.2 - 7.2.0 OSE
## Requirements : Must be root user, p7zip-full (if ARCHIVEMETHOD=tar.7z)
## Run Frequency : Manual as needed.
## Exit Codes :
## 0 = Success or non-critical problem
## 1 = Archive folder does not exist
## 2 = Archive extration failed
## 3 = Zimbra restore failure
## 99 = Move production to temp directory failure (bad)
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-11-08 LTH Created script.
#############################################
## Import common variables and functions. ##
source /var/scripts/common/standard.conf
LOGFILE="${TEMPDIR}/rsync-restore.log"
LOCKFILE="${TEMPDIR}/rsync.lock"
ARCHIVEDIR="${OFFSITEDIR}/zimbra"
OLDDIR="${BACKUPDIR}/zimbra.old"
NOBACKUP=0
#######################################
## FUNCTIONS ##
#######################################
function f_cleanup()
{
if [ -f ${LOCKFILE} ];then
## Remove lock file so other rsync jobs can run.
rm ${LOCKFILE} 1>/dev/null 2>&1
fi
}
function f_checkspace()
{
## Need to check and see if there is enough space available to move Zimbra to a backup location.
FREESPACE=`df -k ${BACKUPDIR} | grep ${BACKUPDIR} | awk '{ print $4 }'`
BACKUPSIZE=`du -sk ${ZIMBRADIR} | awk '{ print $1 }'`
if [ ${BACKUPSIZE} -gt ${FREESPACE} ]; then
echo "There is not enough freespace available to archive production Zimbra."
echo "Zimbra size is ${BACKUPSIZE} kb, Free space is ${FREESPACE} kb"
echo ""
echo "To override and not make a backup 1st, use the --nobackup option."
echo ""
echo "Example: ${SCRIPTNAME} --nobackup"
echo ""
f_cleanup
exit 1
fi
}
function f_emergencyexit()
{
## Purpose: Exit script as cleanly as possible.
## Parameter #1 = Error Code.
if [ -f ${REMOTEDIR}/online.txt ]; then
## Dismount the remote site.
f_umount
fi
echo -e "Zimbra restore aborted. EXIT CODE: ${1}
"
exit $1
}
#######################################
## MAIN PROGRAM ##
#######################################
if [ -f ${LOCKFILE} ]; then
## Restore lock file detected. Abort script.
echo "Restore aborted"
echo "This script tried to run but detected the lock file: ${LOCKFILE}"
echo "Please check to make sure the file does not remain when rsync or restore is not actually running."
f_sendmail "Zimbra Restore aborted" "This script tried to run but detected the lock file: ${LOCKFILE}
Please check to make sure the file does not remain when rsync/restore is not actually running."
exit 1
else
echo "`date +%Y-%m-%d_%H:%M:%S` ${SCRIPTNAME}" > ${LOCKFILE}
fi
clear
echo ""
## Determine if we are going to backup existing folder or not.
if [ "$1" = "--nobackup" ]; then
NOBACKUP=1
else
NOBACKUP=0
##
f_checkspace
fi
## Requirement Check: Script must run as root user.
if [ "$(id -u)" != "0" ]; then
## FATAL ERROR DETECTED: Document problem and terminate script.
echo "ERROR: Root user required for restore."
echo ""
f_cleanup
exit 1
fi
## Mount the remote site.
f_mount
## Check to make sure the archive folder exists.
if [ ! -d "${ARCHIVEDIR}" ]; then
## ERROR: Archive folder does not exist.
echo "`date +%Y-%m-%d_%H:%M:%S` - ERROR: The archive folder does not exist! ${ARCHIVEDIR}, EC=1" | tee -a ${LOGFILE}
f_cleanup
f_emergencyexit 1
fi
## Define user prompt using the special PS3 variable.
PS3="Type number for the desired archive or 'q' to quit: "
echo " Z I M B R A R E S T O R E"
echo " ---------------------------"
## Get sorted list of all archives (newest at the bottom).
FILELIST=$(find ${ARCHIVEDIR}/*.${ARCHIVEMETHOD} -maxdepth 1 -type f | sort -f)
## Prompt user to select a file to use.
## NOTE: If it is a long list, user can scroll up if
## using PuTTY to see older files.
select GETFILE in ${FILELIST}; do
if [ "${GETFILE}" != "" ]; then
FILENAME=${GETFILE}
fi
break
done
if [ "${FILENAME}" = "" ]; then
## User opted to quit.
echo -e "Exiting restore program.
"
f_cleanup
f_umount
exit 0
fi
echo -e "
Selected file: ${FILENAME}
"
echo -e " This restore will shutdown Zimbra and make it"
echo -e " unavailable while it is being restored.
"
read -p "Are you absolutely sure you wish to restore (y/n)? "
if [ "${REPLY}" != "y" ]; then
echo -e "
Restore aborted.
"
f_cleanup
exit 0
fi
echo "`date +%Y-%m-%d_%H:%M:%S` - Restore started." | tee -a ${LOGFILE}
StartTime="$(date +%s)"
## Stop Zimbra Services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Stopping Zimbra services." | tee -a ${LOGFILE}
/etc/init.d/zimbra stop
## Kill any orphaned Zimbra processes.
pkill -9 -u zimbra 1>/dev/null 2>&1
if [ ${NOBACKUP} -eq 1 ]; then
## Leave current production folder alone.
echo "`date +%Y-%m-%d_%H:%M:%S` --- 'No Backup' override specified, skipping folder move." | tee -a ${LOGFILE}
else
## Move production folder to backup location.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Moving Zimbra from ${ZIMBRADIR} to ${OLDDIR}." | tee -a ${LOGFILE}
mv ${ZIMBRADIR} ${OLDDIR}
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Could not move Zimbra to backup location.
## Document error and terminate script.
echo ""
echo "ERROR: The move was not successful. Return value = ${RETURNVALUE}" | tee -a ${LOGFILE}
echo ""
echo "COMMAND was 'mv ${ZIMBRADIR} ${OLDDIR}'" | tee -a ${LOGFILE}
echo ""
echo "The Zimbra services are currently stopped and an unknown amount of files were moved"
echo "from the source. That means there some files are still in ${ZIMBRADIR}"
echo "and some files were moved to ${OLDDIR}"
echo "This needs to be resolved before you can start the services back up."
echo "Either move the files back or delete all files and run the restore."
f_cleanup
exit 99
fi
fi
## Now that Zimbra is offline, we can restore all files.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Restoring files from ${FILENAME}" | tee -a ${LOGFILE}
if [ ! -d ${ZIMBRADIR} ]; then
mkdir -p ${ZIMBRADIR}
fi
## Extract the entire contents of the archive back to its original location.
case "${ARCHIVEMETHOD}" in
tar.7z)
7za x -so -w/${TEMPDIR} ${FILENAME} | tar -C ${ZIMBRADIR} --extract --strip-components=4 --file -
;;
tgz)
tar --extract -C ${ZIMBRADIR} --strip-components=4 --file=${FILENAME}
;;
*)
tar --extract -C ${ZIMBRADIR} --strip-components=4 --file=${FILENAME}
;;
esac
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## tar extract command failed. Display warning message.
echo "`date +%Y-%m-%d_%H:%M:%S` --- ERROR: tar extract return value = {$RETURNVALUE}" | tee -a ${LOGFILE}
f_cleanup
f_emergencyexit 2
fi
if [ ! -f ${ZIMBRADIR}/.install_history ]; then
## Something is not right...at least this file should exist here.
## NOTE: This is not a guarentee all files were restored, it is just a quick check.
echo "`date +%Y-%m-%d_%H:%M:%S` --- ERROR: Missing file(s). Did not find ${ZIMBRADIR}/.install_history" | tee -a ${LOGFILE}
fi
## Fix permissions.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Fixing file ownership and permissions." | tee -a ${LOGFILE}
chown -R zimbra:zimbra ${ZIMBRADIR}
${ZIMBRADIR}/libexec/zmfixperms
## Start Zimbra services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Starting Zimbra services." | tee -a ${LOGFILE}
/etc/init.d/zimbra start
## Calculates downtime of Zimbra services.
FinishTime="$(date +%s)"
ElapsedTime="$(expr ${FinishTime} - ${StartTime})"
Hours=$((${ElapsedTime} / 3600))
ElapsedTime=$((${ElapsedTime} - ${Hours} * 3600))
Minutes=$((${ElapsedTime} / 60))
Seconds=$((${ElapsedTime} - ${Minutes} * 60))
echo "`date +%Y-%m-%d_%H:%M:%S` --- Zimbra restore time: ${Hours} hour(s) ${Minutes} minute(s) ${Seconds} second(s)" | tee -a ${LOGFILE}
## Show status of Zimbra services.
echo "`date +%Y-%m-%d_%H:%M:%S` --- Status of Zimbra services:" | tee -a ${LOGFILE}
su - zimbra -c "zmcontrol status" | tee -a ${LOGFILE}
if [ -d ${OLDDIR} ]; then
echo -e "
Don't forget to purge ${OLDDIR} once everything is running smoothly again.
"
fi
f_cleanup
## Dismount the remote site.
f_umount
echo "`date +%Y-%m-%d_%H:%M:%S` - Restore completed." | tee -a ${LOGFILE}
-
- Advanced member
- Posts: 148
- Joined: Sat Sep 13, 2014 2:14 am
My Notes for Installing Zimbra OSE on Ubuntu Server 10.04 LTS
Scenario #5 Restore to new server
** UNFINISHED **
** UNFINISHED **
-
- Advanced member
- Posts: 148
- Joined: Sat Sep 13, 2014 2:14 am
My Notes for Installing Zimbra OSE on Ubuntu Server 10.04 LTS
Crontab
I would not advise anyone to ever "edit" a live crontab schedule by typing "crontab -e" but rather edit a saved schedule file and then load the schedule file. This will allow you to make backups of the schedule so you can always go back to a known-good schedule or at least back to the way it was before you made a change...assuming you always work with a copy of the schedule 1st.
Here is my root crontab scheduling file:
/var/scripts/data/crontab.root
########################################
# Name: Crontab Schedule for root user
# Author: LHammonds
############# Update Log ###############
# 2011-10-29 - LTH - Created schedule
# 2011-11-22 - LTH - Added shell and path
# 2012-01-30 - LTH - Added time adjustment
# 2012-05-02 - LTH - Added check-space
# 2012-05-05 - LTH - Added check mailbox size
########################################
#
# Import Active Directory users (run every minute)
0-59 * * * * /var/scripts/prod/import-ad.sh > /dev/null 2>&1
#
# Update the Global Address List for iPhone usage.
#
0 23 * * * /var/scripts/prod/gal-sync.sh > /dev/null 2>&1
#
# Partial backup of Zimbra to a local folder without taking it offline.
#
0 8-18 * * * /var/scripts/prod/rsync-online.sh > /dev/null 2>&1
#
# Backup Zimbra to a local folder, archive and store offsite.
#
0 23 * * * /var/scripts/prod/rsync-offline.sh > /dev/null 2>&1
#
# Backup individual mailboxes to a local folder, archive and store offsite.
#
0 6-18 * * * /var/scripts/prod/zm-user-backup.sh > /dev/null 2>&1
#
# Daily check for available space on /opt
#
0 1 * * * /var/scripts/prod/check-storage.sh opt 5 1 > /dev/null 2>&1
#
# Daily check for available space on /var/backup
#
0 2 * * * /var/scripts/prod/check-storage.sh bak 5 1 > /dev/null 2>&1
#
# Daily check for available space on /var/temp
#
0 3 * * * /var/scripts/prod/check-storage.sh temp 5 1 > /dev/null 2>&1
#
# Daily check for mailbox size notifications
#
0 6 * * * /var/scripts/prod/mailbox-size-notification.sh > /dev/null 2>&1
Once you have created the file, make sure appropriate permissions are set by typing the following:
chown root:root /var/scripts/data/crontab.root
chmod 0600 /var/scripts/data/crontab.root
To enable the root schedule using this file, type the following:
crontab -u root /var/scripts/data/crontab.root
To disable the root schedule, type the following:
touch /tmp/deleteme
crontab -u root /tmp/deleteme
rm /tmp/deleteme
If you need to modify the schedule, make a backup copy 1st. For example:
cp /var/scripts/data/crontab.root /var/scripts/prod/2011-11-28-crontab.root
vi /var/scripts/data/crontab.root (make your changes)
crontab -u root /var/scripts/data/crontab.root
I would not advise anyone to ever "edit" a live crontab schedule by typing "crontab -e" but rather edit a saved schedule file and then load the schedule file. This will allow you to make backups of the schedule so you can always go back to a known-good schedule or at least back to the way it was before you made a change...assuming you always work with a copy of the schedule 1st.
Here is my root crontab scheduling file:
/var/scripts/data/crontab.root
########################################
# Name: Crontab Schedule for root user
# Author: LHammonds
############# Update Log ###############
# 2011-10-29 - LTH - Created schedule
# 2011-11-22 - LTH - Added shell and path
# 2012-01-30 - LTH - Added time adjustment
# 2012-05-02 - LTH - Added check-space
# 2012-05-05 - LTH - Added check mailbox size
########################################
#
# Import Active Directory users (run every minute)
0-59 * * * * /var/scripts/prod/import-ad.sh > /dev/null 2>&1
#
# Update the Global Address List for iPhone usage.
#
0 23 * * * /var/scripts/prod/gal-sync.sh > /dev/null 2>&1
#
# Partial backup of Zimbra to a local folder without taking it offline.
#
0 8-18 * * * /var/scripts/prod/rsync-online.sh > /dev/null 2>&1
#
# Backup Zimbra to a local folder, archive and store offsite.
#
0 23 * * * /var/scripts/prod/rsync-offline.sh > /dev/null 2>&1
#
# Backup individual mailboxes to a local folder, archive and store offsite.
#
0 6-18 * * * /var/scripts/prod/zm-user-backup.sh > /dev/null 2>&1
#
# Daily check for available space on /opt
#
0 1 * * * /var/scripts/prod/check-storage.sh opt 5 1 > /dev/null 2>&1
#
# Daily check for available space on /var/backup
#
0 2 * * * /var/scripts/prod/check-storage.sh bak 5 1 > /dev/null 2>&1
#
# Daily check for available space on /var/temp
#
0 3 * * * /var/scripts/prod/check-storage.sh temp 5 1 > /dev/null 2>&1
#
# Daily check for mailbox size notifications
#
0 6 * * * /var/scripts/prod/mailbox-size-notification.sh > /dev/null 2>&1
Once you have created the file, make sure appropriate permissions are set by typing the following:
chown root:root /var/scripts/data/crontab.root
chmod 0600 /var/scripts/data/crontab.root
To enable the root schedule using this file, type the following:
crontab -u root /var/scripts/data/crontab.root
To disable the root schedule, type the following:
touch /tmp/deleteme
crontab -u root /tmp/deleteme
rm /tmp/deleteme
If you need to modify the schedule, make a backup copy 1st. For example:
cp /var/scripts/data/crontab.root /var/scripts/prod/2011-11-28-crontab.root
vi /var/scripts/data/crontab.root (make your changes)
crontab -u root /var/scripts/data/crontab.root