-
-
Save smedir/bf6ba200cc060f1d8443e349fb4dc7c5 to your computer and use it in GitHub Desktop.
Simple pacman hook to take ZFS snapshots
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Trigger] | |
Operation=Install | |
Operation=Upgrade | |
Operation=Remove | |
Type=Package | |
Target=* | |
[Action] | |
When=PreTransaction | |
Exec=/usr/local/bin/pacman-snapshots.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
DATE="$(date --utc --iso-8601=seconds)" | |
EPOCH="$(date --utc --date "$DATE" +%s)" | |
SNAPSHOT_DATE="$(date --utc --date "$DATE" +%Y%m%dT%H%M%SZ)" | |
# datasets you'd like to take snapshots of. note '-r' is used to take snapshots recursively | |
DATASETS=( \ | |
tank/data \ | |
tank/root \ | |
) | |
# how many days you'd like to keep the snapshots | |
KEEP_DAYS=7 | |
KEEP_SECONDS=$(( KEEP_DAYS * 24 * 3600 )) | |
# skip taking new snapshots if the last one was taken within THROTTLE_SECONDS | |
THROTTLE_SECONDS=900 | |
# prefix of snapshot names, make sure it doesn't conflict with others | |
SNAPSHOT_PREFIX="pacman" | |
# input: a/b@pacman-20181212T211523Z | |
# output: 2018-12-12 21:15:23 | |
function get_snapshot_date() { | |
snapshot_name="$1" | |
# shellcheck disable=SC2001 | |
snapshot_date="$(sed "s/.*$SNAPSHOT_PREFIX-\(....\)\(..\)\(..\)T\(..\)\(..\)\(..\)Z/\1-\2-\3 \4:\5:\6/" <<< "$snapshot_name")" | |
printf '%s' "$snapshot_date" | |
} | |
# input: a/b@pacman-20181212T211523Z | |
# output: 1544609723 | |
function get_snapshot_epoch() { | |
snapshot_name="$1" | |
# shellcheck disable=SC2001 | |
snapshot_date="$(get_snapshot_date "$snapshot_name")" | |
snapshot_epoch="$(date --utc --date "$snapshot_date" +%s)" | |
printf '%s' "$snapshot_epoch" | |
} | |
last_snapshot="$(zfs list -t snapshot -S creation -o name -H | rg "@$SNAPSHOT_PREFIX" | head -n 1)" | |
if [[ -n "$last_snapshot" ]]; then | |
last_snapshot_epoch="$(get_snapshot_epoch "$last_snapshot")" | |
if [[ $(( EPOCH - last_snapshot_epoch )) -lt "$THROTTLE_SECONDS" ]]; then | |
printf 'Last snapshot %s was created at %s (%s), skipping creating new ones\n' "$last_snapshot" "$(get_snapshot_date "$last_snapshot")" "$last_snapshot_epoch" | |
exit 0 | |
fi | |
fi | |
zfs list -t snapshot -S creation -o name -H | rg "@$SNAPSHOT_PREFIX" | while read -r snapshot; do | |
snapshot_epoch="$(get_snapshot_epoch "$snapshot")" | |
if [[ $(( EPOCH - snapshot_epoch )) -gt $KEEP_SECONDS ]]; then | |
printf 'Destroying snapshot %s\n' "$snapshot" | |
zfs destroy "$snapshot" | |
else | |
# remove this if it's too annoying | |
printf 'Keeping snapshot %s created at %s (%s)\n' "$snapshot" "$(get_snapshot_date "$snapshot")" "$snapshot_epoch" | |
fi | |
done | |
for dataset in "${DATASETS[@]}"; do | |
snapshot="$dataset@$SNAPSHOT_PREFIX-$SNAPSHOT_DATE" | |
printf 'Creating snapshot %s\n' "$snapshot" | |
zfs snapshot -r "$snapshot" | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment