[Samba] script for VFS module shadow_copy
Christian Schwamborn
christian.schwamborn at nswit.de
Thu Nov 23 11:22:09 GMT 2006
Am Donnerstag, den 16.11.2006, 22:53 +0100 schrieb Volker Lendecke:
> On Thu, Nov 16, 2006 at 02:32:43PM +0100, Christian Schwamborn wrote:
> > OK, here it comes ...
> > it's not really finished, but I will work on it if I can spare some
> > time.
>
> No attachment around...
>
> Volker
>
curious, seems something has eaten the attachment, I will past it
directly into the mesage. I hope its readable.
Chris
#!/bin/bash
#
# written by Christian Schwamborn
# bugs and suggestions to:
# christian.schwamborn[you-know-what-comes-here]nswit.de
#
# published under GNU General Public License v.2
# version 1.0.1 (2006-11-21)
#
# You are using this scrip at your own risk, the author is not
responsible
# for data damage or losses in any way.
#
# What this is:
# You can use this script to create and manage snapshots for the Samba
# VFS module shadow_copy.
#
# How to use:
# The script provides some commanline parameters which are usefull for
# start/stop scrips (i.e. mount and unmount). Other parameters are
usefull
# for cronjobs - add this, for a usual snapshot scenario (without
trailing #)
# to your crontab:
#
# 0 12 * * 1-5 root /usr/local/sbin/smbsnap autosnap 0 0
# 0 7 * * 2-5 root /usr/local/sbin/smbsnap autosnap 0 1
# 0 7 * * 1 root /usr/local/sbin/smbsnap autosnap 0 2
# 3,33 * * * * root /usr/local/sbin/smbsnap autoresize all
#
# This takes snapshots at 7:00 and 12:00 every workday and checks every
hour
# if a snapshot needs to be resized.
#
# The script has some flaws:
# -This script currently works only with LVM2, no EVMS support yet
# -XFS should be easy to implement, but it isn't yet
# -You must not use dashes in your volumegroups or logical volumes
# -Be carefull with the configuration, the parameters are not
completely
# checked right now, as the same for the command line parameters
# -You have to keep track of the freespace of your volumegroups
# -Be aware, that if your snapshots grow faster than you assumed, they
will
# become unusable. With the configuration shown above, this script
checks
# every 30 minutes if the snapshots are in the need of a resize. If
# someone has a better idea how to check the snapshots than
periodical,
# let me know plaese.
#
# This script is written for the bash, other shells might work, it also
uses
# some external commands: mount, umount, grep, date, bc, logger,
lvcreate,
# lvremove, lvresize
#
# There are currently three variables that have to be configured:
# -SnapVolumes is an array, every element of that array represents a
logical
# volume that is configured for snapshots. Each element is a comma
seperated
# list, which consists of the logical volume itself
(i.e. /dev/GROUP1/foo),
# the start size of the snapshot (in megabytes), the freespace which
should
# be maintained (in megabytes) and the space added, when a snapshot
is
# resized (also in megabytes).
# The number of an element is used as a reference when calling the
script
# -SnapSets is also an array, currently every element just represents
the
# age (in days) of a snapshot of the specific snapshot-set.
# -OffDays is a simple string with the none work days.
#
# The script will figure out by itself where to mount the snapshots, but
the
# original logical volumes has to be mounted fist.
#
# Copy and adjust the following three variables (without #) to a blank
file in
# /etc/samba and name it smbsnap.conf. If you place the configuration
file
# elsewhere, make sure to adjust the path below.
#
# SnapVolumes=('/dev/GROUP/foo,2000,500,1000'
'/dev/GROUP/bar,3000,1000,2000')
# SnapSets=(3 5 25)
# OffDays="Sat Sun"
#
###############################################################################
. /etc/samba/smbsnap.conf
export LANG=en_US.UTF-8
export LANGUAGE=en_US:en
SnapDate=$(date +%Y.%m.%d-%H.%M).00
[ -z "${1}" ] || Command=${1}
[ -z "${2}" ] || LVolume=${2}
[ -z "${3}" ] || SnapSet=${3}
# process a single snapshot
# arguments: Command
# needs: SnapShot, VolumePath, SnapSets, OffDays, FreeSize, ReSize
# provides: na.
# local: cmd, SnapShotPath, CurrSnapSets, Count, Expire,
Parameters, SnapState, CurrSize, FillPercet, CurrFreeSize
function DoSnap()
{
cmd=${1}
SnapShotPath=${VolumePath}/@GMT-$(echo ${SnapShot##*/} | cut -f3-4 -d
\-)
case ${cmd} in
# to mount snapshots
mount)
[ -d ${SnapShotPath} ] || mkdir ${SnapShotPath} || \
logger "${0}: ***error*** - unable to create mountpoint for
${SnapShot}"
if mount | grep -q ${SnapShotPath}; then
logger "${0}: ***error*** - snapshot ${SnapShot} is allready
mounted to ${SnapShotPath}"
else
mount ${SnapShot} ${SnapShotPath} -o ro >/dev/null 2>&1 || \
logger "${0}: ***error*** - can not mount ${SnapShot} to
${SnapShotPath}"
fi
;;
# to unmount a snapshots
umount)
if mount | grep -q ${SnapShotPath}; then
umount -f -l ${SnapShotPath} >/dev/null 2>&1 || \
logger "${0}: ***error*** - can not unmount ${SnapShot} mounted to
${SnapShotPath}"
else
logger "${0}: ***error*** - snapshot ${SnapShot} is not mounted to
${SnapShotPath}"
fi
;;
# to remove expired snapshots
clean)
CurrSnapSet=$(echo ${SnapShot##*/} | cut -f2 -d\-)
if [ ${CurrSnapSet} -ge 0 ] && [ ${CurrSnapSet} -lt
${#SnapSets[@]} ]; then
Expire=$(echo ${SnapSets[${CurrSnapSet}]} | cut -f1 -d,)
# add off-days, if any, to the expire time; we just count work-days
declare -i Count=1
while [ ${Expire} -ge ${Count} ];do
echo ${OffDays} | grep -q $(date -d "-${Count} day" +%a) &&
Expire=$((${Expire} + 1))
Count=$((${Count} + 1))
done
# compare date now minus expire-time with the snapshot-date
if [ $(( $(date +%s) - ${Expire}*24*60*60 - 12*60*60)) -gt \
$(date -d "$(echo ${SnapShot##*/} | cut -f3 -d\- | tr \. \-) \
$(echo ${SnapShot##*/} | cut -f4 -d\- | tr \. \:)" +%s) ]; then
# unmount snapshot
if mount | grep -q ${SnapShotPath}; then
umount -f ${SnapShotPath} >/dev/null 2>&1 || \
logger "${0}: ***error*** - can not unmount ${SnapShot} mounted
to ${SnapShotPath}"
fi
if ! mount | grep -q ${SnapShotPath}; then
# remove mount-directory
if [ -d ${SnapShotPath} ]; then
rmdir ${SnapShotPath} || \
logger "${0}: ***error*** - unable to remove mountpoint for
${SnapShot}"
fi
# finally remove snapshot
if lvremove -f ${SnapShot} >/dev/null 2>&1;then
logger "${0}: successfully removed outdated snapshot
${SnapShot}"
else
logger "${0}: ***error*** - can not remove logical volume
${SnapShot}"
fi
fi
fi
else
logger "${0}: ***error*** - snapshot-set #${CurrSnapSet} of snaphot
${SnapShot} is not configured"
fi
;;
# to check periodical if the snapshots have to be resized
autoresize)
Parameters="--options lv_size,snap_percent --noheadings --nosuffix
--separator , --unbuffered --units m"
SnapState=$(lvs ${Parameters} ${SnapShot})
CurrSize=$(echo ${SnapState} | cut -f1 -d,)
FillPercet=$(echo ${SnapState} | cut -f2 -d,)
CurrFreeSize=$(echo "${CurrSize}-${CurrSize}/100*${FillPercet}" |
bc)
if ! [ $(echo "${CurrFreeSize} > ${FreeSize}" | bc) -eq 1 ]; then
if lvresize -L +${ReSize}M ${SnapShot} >/dev/null 2>&1; then
logger "${0}: successfully resized snapshot ${SnapShot}"
else
logger "${0}: ***error*** - an error occurred while resizing
${SnapShot}"
fi
fi
;;
esac
}
# invoked if all snapshots of a volume are processed
# arguments: Command
# needs: VolumeDevice, VolumePath, SnapSet & functions: DoSnap
# provides: SnapShot
# local: snapset_tmp, cmd
function DoAllSnaps()
{
cmd=${1}
[ -z "${SnapSet}" ] || snapset_tmp="${SnapSet}-"
# checkout if the configured volume exists and is mounted
if [ -b ${VolumeDevice} ]; then
if mount | grep -q "${VolumePath} "; then
# process all snapshots of the volume and, if given, of a specific
snapshot-set
for SnapShot in ${VolumeDevice}-${snapset_tmp}*; do
if [ ${SnapShot} = "${VolumeDevice}-${snapset_tmp}*" ]; then
logger "${0}: ***error*** - no backupset #${SnapSet} found for
${VolumeDevice}"
else
DoSnap ${cmd}
fi
done
else
logger "${0}: ***error*** - logical volume ${VolumeDevice} not
mounted to ${VolumePath}"
fi
else
logger "${0}: ***error*** - logical volume ${VolumeDevice} does not
exist"
fi
}
# creates a new snapshot and mounts it
# arguments: na.
# needs: VolumeDevice, VolumePath, SnapSet, SnapSize, SnapDate &
functions: DoAllSnaps, DoSnap
# provides: SnapShot
# local: na.
function MakeSnap ()
{
case ${SnapSet} in
[0-9])
if [ "${Command}" = "autosnap" ]; then DoAllSnaps "clean"; fi
SnapShot=${VolumeDevice}-${SnapSet}-${SnapDate}
if lvcreate -L${SnapSize}M -s -n ${SnapShot##*/} ${VolumeDevice}
>/dev/null 2>&1; then
logger "${0}: successfully created new snapshot ${SnapShot}"
else
logger "${0}: ***error*** - an error occurred while creating
snapshot ${SnapShot}"
fi
DoSnap "mount"
;;
*)
echo "usage: ${0} snap|autosnap <LV number | all> <Snap-Set Number>"
;;
esac
}
# sets some variables and splits the way for certain commands
# arguments: one object of the array SnapVolumes
# needs: Command, & functions: DoAllSnaps MakeSnap
# provides: SnapVolume, VolumeDevice, PVGroupName, LVolumeName,
VolumePath, SnapSize, FreeSize, ReSize
# local: na.
function SecondChoice ()
{
SnapVolume=${1}
VolumeDevice=$(echo ${SnapVolume} | cut -f1 -d,)
PVGroupName=$(echo ${VolumeDevice} | cut -f3 -d/)
LVolumeName=$(echo ${VolumeDevice} | cut -f4 -d/)
VolumePath=$(mount | grep ^/dev[[:alnum:]/]*
${PVGroupName}.${LVolumeName}[\ ] | cut -f3 -d' ')
SnapSize=$(echo ${SnapVolume} | cut -f2 -d,)
FreeSize=$(echo ${SnapVolume} | cut -f3 -d,)
ReSize=$(echo ${SnapVolume} | cut -f4 -d,)
case ${Command} in
mount|umount|clean|autoresize)
DoAllSnaps ${Command}
;;
snap|autosnap)
MakeSnap
;;
esac
}
# decides if all configured volumes are processed or just a specific one
# arguments: na.
# needs: Command, LVolume, SnapVolumes & functions: SecondChoice
# provides: na.
# local: snp
case ${Command} in
mount|umount|snap|clean|autosnap|autoresize)
case ${LVolume} in
all)
for snp in ${SnapVolumes[@]}; do
SecondChoice ${snp}
done
;;
[0-9])
if [ ${LVolume} -ge 0 ] && [ ${LVolume} -lt ${#SnapVolumes[@]} ];
then
SecondChoice ${SnapVolumes[LVolume]}
else
logger "${0}: ***error*** - there is no configured logical volume #
${LVolume} for snapshots"
fi
;;
*)
echo "usage: ${0} <command> <LV number | all> [<Snap-Set Number>]"
;;
esac
;;
*)
echo "usage: ${0} <command> <LV number | all> [<Snap-Set Number>]"
echo
echo " valid commands are:"
echo " mount - to mount snapshots"
echo " umount - to unmount snapshots"
echo " snap - to make a new snapshot"
echo " clean - to cleanup outdated snapshots"
echo " autosnap - normally used for cronjobs to cleanup"
echo " outdates snapshots an create a new one"
echo " autoresize - for a periodical check if snapshots"
echo " needs to be resized"
echo
echo " <LV number> is the number of a logical volume, configured
for"
echo " snapshots in SnapVolumes, or simply 'all' for all
volumes"
echo " <Snap-Set Number> is the number of the snapshot-set,
configured"
echo " in SnapSet. It is optional, except for the commands
'snap' and"
echo " 'autosnap'"
echo
;;
esac
More information about the samba
mailing list