What we wanted to achieve was:
- Better management of parallel processes: in previous versions of the script each process pool was awaited for it's complete end, first for users and then for folders. In "our" version the process pool is "global" so if export of users is almost done and leaves a queue or more free then the script begins exporting public folders.
- Checking of free process slot was tough intense and required in internal array for checking. In our version checking is more "gentle" and can be set up a wait time between checks
- Export rotation was based on daynames. In our version directory tree is slightly different (mailnode comes first) and is based upon dates in the form YYYYMMDD. Number of rotated exports is a count back in days: older exports previous than <current_date> minus <number of exports to keep> are deleted. Of course we use this to backup on a regular daily basis.
- We felt the need of an email report
I post it here in the hope might help someone.
Feel free to suggest improvements or bug fixes.
Code: Select all
#!/bin/bash
##############################################################################
## IMPORTANT: This script is not supported by Scalix. Use at your own risk. ##
##############################################################################
#
# NAME: sxstoreexp - Perform a full/partial export of a Scalix Server
# message store
#
# SYNOPSIS: sxstoreexp
#
# DESCRIPTION:
# Through the meaning of this script you'll be able to perform a full or
# partial export of the contents of your Scalix Message Store.
# This script is useful for disk backups of Scalix's Storage area and is
# intended to minimize disk space occupation.
#
# When job is done a detailed report is sent to system administrator
# or any other email address you might find useful.
#
# Derived from:
# http://www.scalix.com/wiki/index.php?title=HowTos/AutoBackupScript
# http://www.scalix.com/community/viewtopic.php?t=1922
#
# Give credit to the following contributors:
# (please do not remove - add your name if you contribute)
#
# * Jon Allie <jon@jonallie.com>
# * Ianaré Sévi <ianare@gmail.com>
# * Dirk Ahrnke <da@it25.de>
# * Andrea Lanfranchi (BaldBoy) <andrea.lanfranchi@isiweb.it>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# Those who do not know how to use snail mail: The GPL is here:
# http://www.gnu.org/licenses/gpl.html
#
###############################################################################
#
# Variables:
# Following variables declaration can be fulfilled with constants. In this
# case you will be able to invoke the command without specifying related
# mandatory parameters. In either case specifying parameters from command
# line bring variable constants to be overwritten (command line arguments
# are MORE IMPORTANT than values specified here).
#
# Target directory where to place exported items
# (eg. /tmp/sxstorebackup)
# Note that many subdirs will be created below the target you specify here
# Related command argument switch -t | --target
#
EXP_TARGET=/home/Isiweb/ScalixBackup
# Do you want to export users' mailboxes ? By setting following value to Y
# your request will be satisfied. :)
#
EXP_USERS=Y # Y | N
# Do you also want to export Public Folder's content ? If so then set
# the following to Y
#
EXP_PUBLIC=Y # Y | N
# If you plan to use this script for backup purpouses you might find
# useful to rotate backup plans. The following setting indicates how
# many exports you want to keep on disk. Every export will be placed
# in a subdirectory of EXP_TARGET named in the form YYYYMMDD. When a
# directory date is older than <current-date> minus number of days
# set in EXP_ROTATE parameter then that directory will be deleted.
# Keep in mind that every export may consist of a huge amount
# of data so ... take care of your disk space. YOU'RE WARNED!!
# A value of 0 (zero) means no rotation.
EXP_ROTATE=7
# Do you want a mail report of the job to be delivered to someone ?
# Say that here. Please note that multiple email address may be specified,
# as separated by a comma. An empty value means no report is sent.
#
EXP_MAIL_REPORT_FROM="webmaster@isiweb.it"
EXP_MAIL_REPORT_TO="webmaster@isiweb.it"
EXP_MAIL_REPORT_SUBJECT="Scalix Store Export Report"
# This task can perform multiple parallel exports. This value sets how
# many export processes can be run at the same time.
# Note : increasing this number do not necessarily mean an equivalent
# increase of speed of the export tasks. Use with care, only if your
# server is well equipped and if you're exporting on target which is
# located on hardware volume(s) different from the one(s) hosting
# Scalix Storage Area.
#
EXP_PROCESSES=3
# Scalix's bin directory. This is where many of the Scalix utilities and
# commands live. Unless you're not on a standard Scalix installation
# do NOT change this value
#
SCALIX_BIN=/opt/scalix/bin
#
# Logging Facilities pointers
# You should not need to change these
#
STDLOG=/tmp/sxstoreexp.$$
STDERR=/tmp/sxstoreexp.$$.stderr
STDOUT=/tmp/sxstoreexp.$$.stdout
# --------------------------------------------------------------------------
# Here the program begins! DO NOT CHANGE ANYTHING BELOW THIS LINE UNLESS YOU
# KNOW WHAT YOU'RE DOING. Obviously you can look at the code and learn how
# much fun there's inside Linux
# --------------------------------------------------------------------------
# --------------------------------------------------------------------------
# Begin Functions
# --------------------------------------------------------------------------
function show_usage ()
{
echo "
Help not vailable yet
"
exit 1
}
function show_params ()
{
trace_std "
------------------------------------------------------------------------------
Running Params
- Scalix Directory ..... : $SCALIX_BIN
- Target Directory ..... : $EXP_TARGET
- Export User's Mboxes . : $EXP_USERS
- Export Public Folders : $EXP_PUBLIC
- Paralell Exp Processes : $EXP_PROCESSES
- Rotate Exports : $EXP_ROTATE
------------------------------------------------------------------------------
"
}
function pre_check ()
{
# Look for mandatory directories
for DIR in $SCALIX_BIN $EXP_TARGET
do
[ -d $DIR ] || trace_err "Required directory missing : $DIR"
done
}
function init()
{
# Extract default mailnode to extract from
SCALIX_MN=`$SCALIX_BIN/omshowmn | grep '**' | awk '{ print $2 }'`
eval set -- "$SCALIX_MN"
# Append to EXP_TARGET current MailNode
EXP_TARGET_FULL=$EXP_TARGET/$SCALIX_MN
if [ ! -d $EXP_TARGET_FULL ]
then
mkdir $EXP_TARGET_FULL
fi
# Append to EXP_TARGET_FULL current Date
DAYNUMBER=`date +%Y%m%d`
EXP_TARGET_FULL=$EXP_TARGET_FULL/$DAYNUMBER
if [ ! -d $EXP_TARGET_FULL ]
then
mkdir $EXP_TARGET_FULL
else
trace_std "Cleaning up $EXP_TARGET_FULL"
rm -dfr $EXP_TARGET_FULL
mkdir $EXP_TARGET_FULL
wait
fi
# Create Subfolders for objects storage
mkdir $EXP_TARGET_FULL/Users
mkdir $EXP_TARGET_FULL/Public_Folders
wait
# If we have to rotate exports than let's calculate
# which is the limit date for which we have to keep
# exports on disk
if [ "$EXP_ROTATE" != "0" ]
then
DATEFROM=`date -d "$EXP_ROTATE days ago" +%Y%m%d`
ls $EXP_TARGET/$SCALIX_MN/ | grep '[0-9]' | awk '{ if (int($1)<=int('$DATEFROM')) { print $1 }}' | while read OLDDIR
do
# Loop through each directory which is older than $DATEFROM date
trace_std "Removing old export directory : $OLDDIR"
rm -dfr $EXP_TARGET/$SCALIX_MN/$OLDDIR
wait
done
fi
}
function trace_err ()
{
echo "$1"
echo "`date +%x\ %X` $1" >> $STDERR
}
function trace_std ()
{
echo "$1"
echo "`date +%x\ %X` $1" >> $STDLOG
}
function exp_users()
{
# setup directory for output
DIR=$EXP_TARGET_FULL/Users
# Build users's list and loop through their names
$SCALIX_BIN/omshowu -m $SCALIX_MN|cut -f1 -d'/' | while read sc_username
do
# Create a version of the username without spaces and other crappy characters
nospaces=`echo $sc_username|sed -e "s/[ \.;=*'?_!]//g"`
# Build file name for user's mailbox
BACKUP_FILE="$DIR/${nospaces}.mbox.gz"
# Try to figure out how many processes slot we have free
# Be kind ... do not hammer
sleep 2
PIDS=$(pgrep sxmboxexp | grep '[0-9]' -c)
# Hmmm ... we have to wait until number of running
# processes gets below $EXP_PROCESSES watermark.
while [ $PIDS -ge $EXP_PROCESSES ]
do
# Be kind ... do not hammer
sleep 2
PIDS=$(pgrep sxmboxexp | grep '[0-9]' -c)
done
# If we have a process slot free then submit new queue
# Export user's mailbox using sxmboxexp
trace_std "Mailbox $SCALIX_MN/$sc_username : export queued ..."
$SCALIX_BIN/sxmboxexp -u "$sc_username/$SCALIX_MN" -a - -F | gzip -c > $BACKUP_FILE || trace_std "Error: mailbox $SCALIX_MN/$sc_username" &
done
# All queues submitted
trace_std "All mailbox export queues submitted ... "
}
function exp_folders()
{
# create directory for output
DIR=$EXP_TARGET_FULL/Public_Folders
IDX=$EXP_TARGET_FULL/Public_Folders/index.txt
touch $IDX
# Build PF list and loop through their names
$SCALIX_BIN/sxmboxlist --public $SCALIX_MN | grep '^F-' | sort | while read pfid pfname
do
# Build file name for user's mailbox
BACKUP_FILE="$DIR/$pfid.pflr.gz"
# Try to figure out how many processes slot we have free
# Be kind ... do not hammer
sleep 2
PIDS=$(pgrep sxmboxexp | grep '[0-9]' -c)
# Hmmm ... we have to wait until number of running
# processes gets below $EXP_PROCESSES watermark.
while [ $PIDS -ge $EXP_PROCESSES ]
do
# Be kind ... do not hammer
sleep 2
PIDS=$(pgrep sxmboxexp | grep '[0-9]' -c)
done
# If we have a process slot free then submit new queue
# Export user's mailbox using sxmboxexp
trace_std "Folder $SCALIX_MN/$pfname : export queued ..."
echo "$pfid --> $pfname" >> $IDX
$SCALIX_BIN/sxmboxexp -p -f $pfid -a - -F | gzip -c > $BACKUP_FILE || trace_std "Error: folder $SCALIX_MN/$pfname" &
done
# All queues submitted
trace_std "All folders export queues submitted ... "
}
# --------------------------------------------------------------------------
# End Functions
# --------------------------------------------------------------------------
if [ "$#" -eq 0 ]
then # No given options/arguments - running using hardcoded values
trace_std "No given params. Using hardcoded ones."
else
# process command line arguments
# -h | --help : show help
# -t | --target <dir> : target export
# -u | --users <Y|N> : export users
# -p | --public <Y|N> : export public folders
TEMP=`getopt -o ht:u::p: --long 'help',target:,users::,public: -n "$0" -- "$@"`
if [ $? != 0 ] ; then show_usage ; exit 1 ; fi
eval set -- "$TEMP"
while true ; do
case "$1" in
-h|--help) show_usage ; shift ;;
-t|--target) EXP_TARGET=$2; shift 2;;
-u|--users)
case "$2" in
"") EXP_USERS=Y; shift 2;;
"Y"|"N") EXP_USERS=$2; shift 2;;
*) show_usage;;
esac;;
-p|--public)
case "$2" in
"") EXP_PUBLIC=Y; shift 2;;
"Y"|"N") EXP_PUBLIC=$2; shift 2;;
*) show_usage;;
esac;;
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done
fi
# Show user which params will be used to perform this export
show_params
# Initialize logging facilities
rm -f $STDLOG $STDERR $STDOUT
touch $STDLOG $STDERR $STDOUT
# Check if everything is ok
pre_check
# Initialize
init
# If we have any error then exit
# We can now begin to export users' mailboxes
if [ "$EXP_USERS" = "Y" ]
then
exp_users
fi
# Do the same with public folders if required
if [ "$EXP_PUBLIC" = "Y" ]
then
exp_folders
fi
# Loop through active processes to monitor completion
PIDS=$(pgrep sxmboxexp | grep '[0-9]' -c)
while [ $PIDS != 0 ]
do
# Be kind ... do not hammer
sleep 2
PIDS=$(pgrep sxmboxexp | grep '[0-9]' -c)
done
# Job done !
trace_std "All queues completed!"
# Report Usage on Disk for this export
echo "
Report of disk usage after export operation
" >> $STDLOG
du $EXP_TARGET_FULL -h -s >> $STDLOG
# Report Usage on Disk for target directory
echo "
Report of disk usage for export target directory
" >> $STDLOG
du $EXP_TARGET -h -s >> $STDLOG
# Send Report to Admin(s)
if [ -s $MAINTLOG ]
then
mail -r $EXP_MAIL_REPORT_FROM -s "$($SCALIX_BIN/omcheckgc -h) - $EXP_MAIL_REPORT_SUBJECT" $EXP_MAIL_REPORT_TO < $STDLOG
fi
# Clean up logging facilities
rm -f $STDLOG $STDERR $STDOUT