I know there is a ruby one in the ports, and it is more sophisticated. Here is a simpler SH implementation.
You can add 'snapshot-all.s' into your crontab.
NOTICE: these scripts are very ALPHA. You MUST NOT use them
on production systems or file systems with important data.
----- snapshot.conf ---
I placed it under /opt/zfs/conf
This has a very simple format.
EXCLUDES: file systems you don't want to snapshot, in one line.
MAX_DATES: an integer. a MAX_DATES day older file system will be removed.
MAX_SHOTS: an integer. a file system can only have MAX_SHOTS snapshots.
----- snapshot.s -----
main snapshot script.
I placed it under /opt/zfs/rc.s/
----- snapshot-all.s -----
I placed it under /opt/zfs/rc.s/
Notice it executes 'snapshot.s', and needs 'snapshot.conf',
so make sure this script can find the two scripts above.
You can add 'snapshot-all.s' into your crontab.
NOTICE: these scripts are very ALPHA. You MUST NOT use them
on production systems or file systems with important data.
----- snapshot.conf ---
I placed it under /opt/zfs/conf
This has a very simple format.
EXCLUDES: file systems you don't want to snapshot, in one line.
MAX_DATES: an integer. a MAX_DATES day older file system will be removed.
MAX_SHOTS: an integer. a file system can only have MAX_SHOTS snapshots.
Code:
# ZFS snapshot configuration for pluton.
#
# $Rev: 229 $
# $Date: 2009-01-03 16:52:03 +0800 (Sat, 03 Jan 2009) $
#
# excludes
EXCLUDES=rpool/opt rpool/var
# max dates for each file system
MAX_DATES=3
# max shots for each file system
MAX_SHOTS=6
----- snapshot.s -----
main snapshot script.
I placed it under /opt/zfs/rc.s/
Code:
#!/bin/sh
#
# $Rev: 231 $
# $Date: 2009-01-03 17:56:58 +0800 (Sat, 03 Jan 2009) $
#
# Use the command below to change time formats that
# ZFS file systems provide, into such a numerical
# format as '20081230-00:00:00', which can be handled
# well by scripting.
#
###################################################
# date -j \
# -f "%a %b %d %k:%M %Y" \
# "Tue Dec 30 10:03 2008" \
# "+%Y%m%d-%H:%M:%S"
##################################################
# for dates conversion.
export LANG="C"
export LC_ALL="C"
SCRIPT_VERSION=`grep '^# \$Rev.*\$$' ${0} | cut -d ' ' -f 3`
SCRIPT_NAME=`basename ${0}`
display_usage() {
echo "${SCRIPT_NAME}, version ${SCRIPT_VERSION}"
echo "Usage: ${SCRIPT_NAME} [-hv] [-m max_copies] [-d max_dates] [-f filesystem]"
echo "Automatic ZFS snapshoting script."
echo ""
}
ZFS_CMD=/sbin/zfs
ZPOOL_NAME=`/sbin/zpool list -H -o name`
ZFS_SNAPSHOT_CMD="${ZFS_CMD} snapshot"
ZFS_DESTROY_CMD="${ZFS_CMD} destroy"
ZFS_RENAME_CMD="${ZFS_CMD} rename"
ZFS_SNAPSHOT_DATES=5
ARG_FS=
ARG_VERB=0
ARG_DATES=${ZFS_SNAPSHOT_DATES}
while getopts "Vhvd:f:m:" CMDLINE; do
case "${CMDLINE}" in
h)
display_usage;
exit 1
;;
v)
ARG_VERB=1
;;
d)
ARG_DATES="$OPTARG"
;;
f)
ARG_FS="$OPTARG"
;;
m)
ARG_MAXS="$OPTARG"
;;
*)
display_usage;
exit 1
;;
esac
done
[ ${ARG_VERB} -eq 1 ] && echo "===> verbose: ${ARG_VERB}"
[ ${ARG_VERB} -eq 1 ] && echo "===> dates: ${ARG_DATES}"
[ ${ARG_VERB} -eq 1 ] && echo "===> snapshot: ${ARG_FS}"
[ ${ARG_VERB} -eq 1 ] && echo "===> max shots: ${ARG_MAXS}"
check_filesystem () {
if [ -z "${1}" ]; then
exit 0
fi
target=${1}
${ZFS_CMD} list -H -t filesystem -o name| grep -q "${target}"
results=$?
if [ ${results} -eq 1 ]; then
echo "===> No such ZFS file system: ${target}"
exit 0
fi
}
make_snapshot () {
snapshot_date=`date "+%Y%m%d-%H:%M:%S"`
target=${ZPOOL_NAME}/${1}@${snapshot_date}
${ZFS_SNAPSHOT_CMD} ${target} 2>&1 >/dev/null
[ ${ARG_VERB} -eq 1 ] && echo "===> ${ZFS_SNAPSHOT_CMD} ${target}"
}
###################
## now kick off.
check_filesystem ${ARG_FS}
old_dates=${ARG_DATES}
current_date=`date "+%Y%m%d"`
all_snapshots=`${ZFS_CMD} list -H -t snapshot -o name | grep "${ARG_FS}"`
fs_id=1
# s for snapshot
action=s
fs_shots=`${ZFS_CMD} list -H -t snapshot -o name | grep "${ARG_FS}" |wc -l | sed 's| ||g'`
target=`echo ${all_snapshots} | cut -d ' ' -f 1`
while [ ! -z "${target}" ]; do
creation_local=`${ZFS_CMD} list -H -o creation "${target}"`
creation_real=`date -j -f "%a %b %d %k:%M %Y" "${creation_local}" "+%Y%m%d"`
eval creation_minus=$(( ${current_date} - ${creation_real} ))
if [ ${ARG_VERB} -eq 1 ]; then
echo "===> snapshot name: ${target}"
echo "===> snapshot date 1: ${creation_local}"
echo "===> snapshot date 2: ${creation_real}"
echo "===> dates difference: ${creation_minus}"
fi
if [ ${creation_minus} -ge ${old_dates} ]; then
if [ ${ARG_VERB} -eq 1 ]; then
echo "===> Older snapshots detected, removing ..."
echo "===> ${ZFS_DESTROY_CMD} ${target}"
fi
# r for remove
action=r
fi
if [ ${fs_shots} -ge ${ARG_MAXS} ]; then
if [ ${ARG_VERB} -eq 1 ]; then
echo "===> More snapshots detected, removing ..."
echo "===> ${ZFS_DESTROY_CMD} ${target}"
fi
action=r
fi
case "${action}" in
r)
${ZFS_DESTROY_CMD} ${target} 2>&1 >/dev/null
eval fs_shots=$(( ${fs_shots} - 1))
action=s
;;
*)
;;
esac
eval fs_id=$(( ${fs_id} + 1 ))
target_next=`echo ${all_snapshots} | cut -d ' ' -f "${fs_id}"`
if [ "${target_next}" = "${target}" ]; then
target=
else
target=${target_next}
fi
done
if [ "${action}" = "s" ]; then
make_snapshot ${ARG_FS}
fi
----- snapshot-all.s -----
I placed it under /opt/zfs/rc.s/
Notice it executes 'snapshot.s', and needs 'snapshot.conf',
so make sure this script can find the two scripts above.
Code:
#!/bin/sh
#
# $Rev: 230 $
# $Date: 2009-01-03 17:48:21 +0800 (Sat, 03 Jan 2009) $
#
# snapshot all ZFS file systems that are not listed in snapshot.conf
# current it only handles a single ZFS pool system.
#
SCRIPT_NAME=`basename ${0}`
SCRIPT_VERSION=`grep '^# $Rev:.*\$$' ${0} | cut -d ' ' -f 3`
ARG_CONFIG=
ARG_VERB=0
display_usage () {
echo "${SCRIPT_NAME}: version ${SCRIPT_VERSION}"
echo "Usage: ${SCRIPT_NAME} [-v] [-c config_file]"
echo ""
}
while getopts "vc:" CMDLINE; do
case "${CMDLINE}" in
v)
ARG_VERB=1
;;
c)
ARG_CONFIG="${OPTARG}"
;;
*)
display_usage
exit 0
;;
esac
done
ZPOOL_NAME=`/sbin/zpool list -H -o name`
SNAPSHOT_CONFIG=${ARG_CONFIG:-/opt/zfs/conf/snapshot.conf}
SNAPSHOT_CMD=/opt/zfs/rc.s/snapshot.s
SNAPSHOT_FS=`/sbin/zfs list -H -t filesystem -o name`
if [ ! -f "${SNAPSHOT_CONFIG}" ]; then
[ ${ARG_VERB} -eq 1 ] && echo "===> No such config file: ${SNAPSHOT_CONFIG}"
exit 1
else
SNAPSHOT_EXCLUDES=`grep "EXCLUDES=" ${SNAPSHOT_CONFIG} | sed 's|EXCLUDES=||g'`
SNAPSHOT_MAXDATES=`grep "MAX_DATES=" ${SNAPSHOT_CONFIG} | sed 's|MAX_DATES=||g'`
SNAPSHOT_MAXSHOTS=`grep "MAX_SHOTS=" ${SNAPSHOT_CONFIG} | sed 's|MAX_SHOTS=||g'`
fi
for ex in ${SNAPSHOT_EXCLUDES}; do
SNAPSHOT_FS=`echo ${SNAPSHOT_FS} | sed "s|${ex}||g"`
done
fs_id=1
fs=`echo -n ${SNAPSHOT_FS} | cut -d ' ' -f 1`
while [ ! -z "${fs}" ]; do
if [ "${fs}" != "${ZPOOL_NAME}" ]; then
real_fs=`basename "${fs}"`
if [ ${ARG_VERB} -eq 1 ]; then
${SNAPSHOT_CMD} -v \
-m ${SNAPSHOT_MAXSHOTS} \
-d ${SNAPSHOT_MAXDATES} \
-f ${real_fs}
else
${SNAPSHOT_CMD} \
-m ${SNAPSHOT_MAXSHOTS} \
-d ${SNAPSHOT_MAXDATES} \
-f ${real_fs}
fi
fi
eval fs_id=$(( ${fs_id} + 1))
fs_next=`echo ${SNAPSHOT_FS} | cut -d ' ' -f ${fs_id}`
if [ "${fs_next}" = "${fs}" ]; then
fs=
else
fs=${fs_next}
fi
done