--- sysutils/zfs-periodic/Makefile (revision 569248) +++ sysutils/zfs-periodic/Makefile (working copy) @@ -2,7 +2,7 @@ # $FreeBSD$ PORTNAME= zfs-periodic -PORTVERSION= 1.0.20130213 +PORTVERSION= 1.0.20160501 CATEGORIES= sysutils MAINTAINER= peter@pean.org @@ -10,11 +10,13 @@ USE_GITHUB= yes GH_ACCOUNT= ross -GH_TAGNAME= a481121 +GH_TAGNAME= 1af2ee1 NO_ARCH= yes NO_BUILD= yes +EXTRA_PATCHES= ${.CURDIR}/files/extra-patch-periodic:skip-property+clean_snapshots-per_dataset:-p0 + PERIODIC_DIRS= etc/periodic/hourly etc/periodic/daily \ etc/periodic/weekly etc/periodic/monthly \ etc/periodic --- sysutils/zfs-periodic/distinfo (revision 569248) +++ sysutils/zfs-periodic/distinfo (working copy) @@ -1,2 +1,3 @@ -SHA256 (ross-zfs-periodic-1.0.20130213-a481121_GH0.tar.gz) = e0d12bb3ff466e3aaabd09c2b9685b5e5ee5f91e0d62126c05ba33c60a7b9a9b -SIZE (ross-zfs-periodic-1.0.20130213-a481121_GH0.tar.gz) = 2527 +TIMESTAMP = 1616801827 +SHA256 (ross-zfs-periodic-1.0.20160501-1af2ee1_GH0.tar.gz) = a1d04a22b4f255636e6649d12cba304f4ed924fb4bdd39ecb428c1d75ffb9776 +SIZE (ross-zfs-periodic-1.0.20160501-1af2ee1_GH0.tar.gz) = 3331 --- sysutils/zfs-periodic/files/extra-patch-periodic:skip-property+clean_snapshots-per_dataset (nonexistent) +++ sysutils/zfs-periodic/files/extra-patch-periodic:skip-property+clean_snapshots-per_dataset (working copy) @@ -0,0 +1,203 @@ +--- etc/periodic/zfs-snapshot.orig 2016-01-05 01:44:44.000000000 +0100 ++++ etc/periodic/zfs-snapshot 2021-03-27 00:23:26.179216000 +0000 +@@ -3,6 +3,7 @@ + # take the appropriately named snapshot + create_snapshot() + { ++ local _skip _inherited + pool=$1 + + case "$type" in +@@ -28,7 +29,7 @@ + + # enumerate datasets under this pool or dataset, skip excluded datasets if requested + if [ -n "$skip" ]; then +- egrep="($(echo $skip | sed "s/ /|/g"))" ++ egrep="($(echo $skip | sed -E "s/[[:blank:]]+/|/g"))" + datasets=$(zfs list -r -H -o name $pool | egrep -v "$egrep") + else + datasets=$(zfs list -r -H -o name $pool) +@@ -36,9 +37,41 @@ + + # loop through datasets, do snapshots of each + for dataset in $datasets; do ++ # skip datasets with mountpoint property set to "none", these usually ++ # don't contain data but are used for properties inheritance only. ++ if zfs get -H -o value mountpoint $dataset 2>/dev/null | grep -q "^none" ++ then ++ echo " mountpoint property of $dataset is "none", skipping..." ++ continue ++ fi ++ _skip=$(zfs get -H -o value periodic:skip $dataset 2>/dev/null \ ++ | tr '[:blank:]' ',') ++ # check current dataset for user property periodic:skip ++ if [ X${_skip} != X- ]; then ++ _inherited="$(zfs get -H -o source periodic:skip $dataset 2>/dev/null\ ++ | grep -o "^inherited")" ++ # values of al(l|ways), true, 1, on, always, yes indicate that ++ # no snapshot is wanted - for children aswell - and indipendent of ++ # $type, while $type match does only exclude for the current type. ++ if echo ${_skip} | grep -qiE "(^|,)$type"; then ++ echo -n " periodic:skip property of $dataset" ++ echo " ${_inherited:-matches} \"$type\", skipping..." ++ continue ++ elif echo ${_skip} | grep -qiE -e "^(al|true|1|on|yes)"; then ++ echo -n " periodic:skip property of $dataset" ++ echo " ${_inherited:-matches} \"$_skip\", skipping..." ++ continue ++ fi ++ elif [ X${_skip} != X${_skip#base*} ] && [ -z "${_inherited}" ]; then ++ # value of "base" has to be ignored if user property was inherited, ++ # otherwise skip current dataset indipendently of $type ++ echo -n " periodic:skip property of $dataset matches" ++ echo " \"base\", skipping..." ++ continue ++ fi + snapshot="$dataset@$now" + # look for an existing snapshot with this name +- if zfs list $snapshot > /dev/null 2>&1; then ++ if [ -n "$(zfs list -H -o name $snapshot 2>/dev/null)" ]; then + echo " snapshot $snapshot already exists, skipping..." + else + echo " taking snapshot: $snapshot" +@@ -51,12 +84,7 @@ + delete_snapshot() + { + snapshot=$1 +- echo " destroying old snapshot, $snapshot" +- if ! echo $snapshot | grep -q @; then +- # refuse to destroy something that doesn't look like a snapshot +- echo >&2 " aborting: not a snapshot: $snapshot" +- exit 1 +- fi ++ echo " destroying old snapshot, $snapshot" + zfs destroy -r $snapshot + } + +@@ -68,55 +96,65 @@ + type=$3 + skip=$4 + +- # create the regex matching the type of snapshots we're currently working +- # on +- case "$type" in +- hourly) +- # hourly-2009-01-01-00 +- regex="^$pool@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]$" +- ;; +- daily) +- # daily-2009-01-01 +- regex="^$pool@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$" +- ;; +- weekly) +- # weekly-2009-01 +- regex="^$pool@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]" +- ;; +- monthly) +- # monthly-2009-01 +- regex="^$pool@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]" +- ;; +- yearly) +- # yearly-2009 +- regex="^$pool@$type-[0-9][0-9][0-9][0-9]" +- ;; +- *) +- echo "unknown snapshot type: $type" +- exit 1 +- esac +- + create_snapshot $pool $type ++ clean_snapshots $pool $type ++} + +- # get a list of all of the snapshots of this type sorted alpha, which +- # effectively is increasing date/time +- # (using sort as zfs's sort seems to have bugs) +- snapshots=`zfs list -H -o name -t snapshot | sort | grep $regex` +- # count them +- count=`echo $snapshots | wc -w` +- if [ $count -ge 0 ]; then +- # how many items should we delete +- delete=`expr $count - $keep` +- count=0 +- # walk through the snapshots, deleting them until we've trimmed deleted +- for snapshot in $snapshots; do +- if [ $count -ge $delete ]; then +- break +- fi +- delete_snapshot $snapshot +- count=`expr $count + 1` +- done +- fi ++clean_snapshots() ++{ ++ pool=$1 ++ ++ # loop through datasets, do look for number of snapshots each ++ for dataset in $datasets; do ++ ++ # create the regex matching the type of snapshots we're currently working ++ # on ++ case "$type" in ++ hourly) ++ # hourly-2009-01-01-00 ++ regex="^$dataset@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]$" ++ ;; ++ daily) ++ # daily-2009-01-01 ++ regex="^$dataset@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$" ++ ;; ++ weekly) ++ # weekly-2009-01 ++ regex="^$dataset@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]" ++ ;; ++ monthly) ++ # monthly-2009-01 ++ regex="^$dataset@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]" ++ ;; ++ yearly) ++ # yearly-2009 ++ regex="^$dataset@$type-[0-9][0-9][0-9][0-9]" ++ ;; ++ *) ++ echo "unknown snapshot type: $type" ++ exit 1 ++ esac ++ ++ # get a list of all of the snapshots of this type sorted alpha, which ++ # effectively is increasing date/time ++ # (using sort as zfs's sort seems to have bugs) ++ snapshots=`zfs list -H -o name -t snapshot | sort | grep $regex` ++ # count them ++ count=`echo $snapshots | wc -w` ++ if [ $count -ge 0 ]; then ++ # how many items should we delete ++ delete=`expr $count - $keep` ++ count=0 ++ # walk through the snapshots, deleting them until we've trimmed deleted ++ for snapshot in $snapshots; do ++ if [ $count -ge $delete ]; then ++ break ++ fi ++ delete_snapshot $snapshot ++ count=`expr $count + 1` ++ done ++ fi ++ done + } + + # take snapshots of type, for pools, keeping keep old ones, +@@ -130,6 +168,12 @@ + echo "" + echo "Doing zfs $type snapshots:" + for pool in $pools; do +- do_pool $pool $keep $type "$skip" ++ # Add top/parent dataset to $skip if pool is defiend with trailing / ++ if [ "${pool%/}" != "${pool}" ]; then ++ pool=${pool%/} ++ do_pool $pool $keep $type "${pool}\$${skip:+ ${skip}}" ++ else ++ do_pool $pool $keep $type "$skip" ++ fi + done + } --- sysutils/zfs-periodic/pkg-message (revision 569248) +++ sysutils/zfs-periodic/pkg-message (working copy) @@ -4,27 +4,59 @@ In order to enable periodic snapshots you need to add these lines to your /etc/periodic.conf +# +# Maintain ZFS snapshots with sysutils/zfs-periodic +# +# periodic(8) settings defining hourly run by cron(8) hourly_output="root" hourly_show_success="NO" hourly_show_info="YES" hourly_show_badconfig="NO" +# +# periodic(8) doesn't run hourly by default, /etc/crontab needs to be extended: +# (exapmle is representing business hours only!) +### Perform ([extended-]business) hourly maintenance [zfs-periodic]. +##13 7,9-13,15-17,19,21 * * 1-6 root periodic hourly +# + +# We want "hourly" snapshots, which represents the type of periodic handling. hourly_zfs_snapshot_enable="YES" -hourly_zfs_snapshot_pools="tank" -hourly_zfs_snapshot_keep=6 +# Pools whose datasets are to be periodically snapshoted. Trailing / means +# exclusion of the top dataset itself (the pool name parent dataset) +hourly_zfs_snapshot_pools="hostP0/ hostP1/" +# Number of previous snapshots of a type specific time series not to be deleted. +hourly_zfs_snapshot_keep=10 +# "zfs_snapshot_skip" represent RE exclude patterns (see re_format(7)) and is +# defined periodic-type based (hourly, daily, weekly, monthly). +# Any "skip"-match invalidates "periodic:skip", which is a zfs-periodic specific +# user property (zfspropos(8)). +# Supported values for the "periodic:skip" property are typical boolian true +# representations (yes,true,1,on), al*(l|ways) and "base". +# The latter prevents excluion of child datasets (source must match "local"). +# example: 'zfs set periodic:skip=always hostP0/liveBAKstor' +# example: 'zfs get -r periodic:skip hostPsys' +hourly_zfs_snapshot_skip="/_entities/jails/\. /netshares/Groups$ /netshares$" + +# We want "daily" snapshots daily_zfs_snapshot_enable="YES" -daily_zfs_snapshot_pools="tank" +daily_zfs_snapshot_pools="hostP0/ hostP1/" daily_zfs_snapshot_keep=7 +# We want "weekly" snapshots weekly_zfs_snapshot_enable="YES" -weekly_zfs_snapshot_pools="tank" +weekly_zfs_snapshot_pools="hostP0/ hostP1/" weekly_zfs_snapshot_keep=5 +weekly_zfs_snapshot_skip="/_entities/jails/\. /netshares/Groups$ /netshares$ /netshares/scratch /.backups" +# We want "monthly" snapshots monthly_zfs_snapshot_enable="YES" -monthly_zfs_snapshot_pools="tank" +monthly_zfs_snapshot_pools="hostP0/ hostP1/" monthly_zfs_snapshot_keep=2 +monthly_zfs_snapshot_skip="/_entities/jails/\. /netshares/Groups$ /netshares$ /netshares/scratch /.backups" +# As of a481121, "yearly" snapshots ar supported too +#yearly_zfs_snapshot_enable="YES" +#yearly_zfs_snapshot_pools="hostP0/ hostP1/" +#yearly_zfs_snapshot_keep=1 +#yearly_zfs_snapshot_skip="/_entities/jails/\. /netshares/Groups$ /netshares$ /netshares/scratch /.backups" -To get hourly snapshots you also need to add -something like this to /etc/crontab: - -2 * * * * root periodic hourly EOM } ]