Skip to content

Instantly share code, notes, and snippets.

@sandhose
Created June 27, 2019 21:17
Show Gist options
  • Save sandhose/bd7610b00b1395045c1566a86469a6a0 to your computer and use it in GitHub Desktop.
Save sandhose/bd7610b00b1395045c1566a86469a6a0 to your computer and use it in GitHub Desktop.
#!zsh
set -auo pipefail
# Save the current timestamp to compare dates later
local -i ts=$(date -j -f '%H:%M:%S' '00:00:00' '+%s')
# The name of the zfs property to check on datasets
local property=custom:prune-snapshot
local -a datasets=(
$(zfs list -H -o name,$property | awk -F '\t' -v value=true '$2 ~ value { print $1 }')
)
for dataset ($datasets) {
local -aU to_delete=() # List of snapshots to delete
local -aU kept=() # List of snapshots that have been kept
local -a snapshots=(
$(zfs list -H -d 1 -t snapshot -o name $dataset | awk -F '@' '{ print $2 }')
)
for snapshot ($snapshots) {
# First decompose the snapshot name and compute the delta
local -i year=${snapshot[1,4]}
local -i month=${snapshot[5,6]}
local -i quarter=$(((month / 4) + 1))
local -i day=${snapshot[7,8]}
local -i timestamp=$(date -j -f '%Y %m %d %H:%M:%S' "$year $month $day 00:00:00" '+%s')
local -i week=$(date -j -f '%s' $timestamp '+%U')
local -i diff=$(((ts - timestamp) / 60 / 60 / 24)) # Diff between the two timestamps in days
local -i has_day=0 has_week=0 has_month=0 has_quarter=0 has_year=0 delete=0
# Check if there is already a {yearly,quarterly,monthly,weekly,daily} snapshot
if (( ${kept[(I)$year]} )) { has_year=1 }
if (( ${kept[(I)$year-Q$quarter]} )) { has_quarter=1 }
if (( ${kept[(I)$year-$month]} )) { has_month=1 }
if (( ${kept[(I)$year-W$week]} )) { has_week=1 }
if (( ${kept[(I)$year-$month-$day]} )) { has_day=1 }
local s=(
dataset=$dataset
snapshot=$snapshot
has_day=$has_day
has_week=$has_week
has_month=$has_month
has_quarter=$has_quarter
has_year=$has_year
)
if (($diff < 7)) {
s+=(delete=$delete)
echo $s: less than a week >&2
} elif (($diff < 60)) {
if (($has_day)) {
delete=1
}
s+=(delete=$delete)
echo $s: less than two months >&2
} elif (($diff < 120)) {
if (($has_week)) {
delete=1
}
s+=(delete=$delete)
echo $s: less than four months >&2
} elif (($diff < (365 * 3))) {
if (($has_month)) {
delete=1
}
s+=(delete=$delete)
echo $s: less than three years >&2
} elif (($diff < (365 * 10))) {
if (($has_quarter)) {
delete=1
}
s+=(delete=$delete)
echo $s: less than ten years >&2
} else {
if (($has_year)) {
delete=1
}
s+=(delete=$delete)
echo $s: more than ten years >&2
}
if (($delete)) {
to_delete+=($snapshot)
} else {
kept+=($year $year-W$week $year-$month $year-Q$quarter $year-$month-$day)
}
}
local -a s=(
dataset=$dataset
to_delete_count=${#to_delete}
)
if (( ${#to_delete} > 0 )) {
echo "$s: Deleting ${#to_delete}" >&2
zfs destroy -d $dataset@${(j:,:)to_delete}
} else {
echo "$s: Nothing to do" >&2
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment