My original snapshot script
authorCarl N. Baldwin <carl@ecbaldwin.net>
Sun, 10 Feb 2008 03:33:33 +0000 (20:33 -0700)
committerCarl N. Baldwin <carl@ecbaldwin.net>
Sun, 10 Feb 2008 03:33:33 +0000 (20:33 -0700)
snap.sh [new file with mode: 0755]

diff --git a/snap.sh b/snap.sh
new file mode 100755 (executable)
index 0000000..c5d2985
--- /dev/null
+++ b/snap.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+exec >> /var/log/snap.log 2>&1
+
+# This script makes a number of assumptions about how I am handling things.
+#  * filesystems are mounted on the directory with the same name.  It is
+#    possible to mount them elsewhere in Solaris but I do not.
+#   * examples
+#     * "tank" is mounted on /tank
+#     * "tank/home" is mounted on /tank/home
+#  * this script only handles one zfs filesystem, a wrapper should be created
+#    to handle more
+#  * this script handles all snapshots that are named in this format:
+#    YYYY-MM-DD.hh.mm
+#   * It ignores other snapshots
+
+# This converts the YYYY-MM-DD.hh.mm format to an integer.
+datetime_to_minutes() {
+  perl -n -e '/(\d+)-(\d+)-(\d+)\.(\d+)\.(\d+)/; print $1 * 527040 + $2 * 44640 + $3 * 1440 + $4 * 60 + $5,"\n"'
+}
+
+datetime_to_minutes2() {
+  perl -n -e '/(\d+)-(\d+)-(\d+)\.(\d+)\.(\d+)/; $monthadj=int(($2-1)/3)-1; $minadj=int($5/15); $houradj=int($4/3); print $1 * 1048576 + ( $2 + $monthadj ) * 65536 + $3 * 2048 + ( $4 + $houradj ) * 64 + $5 + $minadj,"\n"'
+}
+
+# This number is the number of equally spaced snapshots that should exist over
+# any given period in the past.
+
+filesystem=$1
+numsnapshots=$2
+
+snapshotdir="/${filesystem}/.zfs/snapshot"
+
+# Get the various components of the date
+datetime=${ZFSDATETIME:-$(date +%Y-%m-%d.%H.%M)}
+
+# Create the snapshot for this minute
+echo "-I- Creating ${filesystem}@${datetime}"
+zfs snapshot "${filesystem}@${datetime}"
+
+lockdir="/tmp/zfs-admin-lock"
+if ! mkdir "$lockdir" >/dev/null 2>&1; then
+  exit 0
+fi
+cleanup() { rm -rf "$lockdir"; }
+trap cleanup EXIT
+
+minutes=$(echo $datetime | datetime_to_minutes)
+
+# Trim them down
+snapshots=$(ls -d ${snapshotdir}/????-??-??.??.?? 2>/dev/null)
+for snapshot in $snapshots; do
+  snapminutes=$(echo "$snapshot" | sed 's,.*/,,' | datetime_to_minutes)
+  snapminutes2=$(echo "$snapshot" | sed 's,.*/,,' | datetime_to_minutes2)
+  age=$((minutes - snapminutes))
+  window=1
+  while true; do
+    if [ $age -lt $((window * numsnapshots)) ]; then
+      case $((snapminutes2 % window)) in
+        0) ;;
+        *)
+          snapname=$(echo "$snapshot" |
+                       sed 's,/\(.*\)/.zfs/snapshot/\(.*\),\1@\2,')
+          echo "-I- Destroying $snapname"
+          zfs destroy "$snapname"
+        ;;
+      esac
+      break
+    fi
+    window=$((window*2))
+  done
+done