-
Notifications
You must be signed in to change notification settings - Fork 16
/
zfs-snapshot
executable file
·142 lines (131 loc) · 3.63 KB
/
zfs-snapshot
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/bin/sh
# take the appropriately named snapshot
create_snapshot()
{
pool=$1
case "$type" in
quarter_hourly)
now=`date +"$type-%Y-%m-%d-%H-%M"`
;;
hourly)
now=`date +"$type-%Y-%m-%d-%H"`
;;
daily)
now=`date +"$type-%Y-%m-%d"`
;;
weekly)
now=`date +"$type-%Y-%U"`
;;
monthly)
now=`date +"$type-%Y-%m"`
;;
yearly)
now=`date +"$type-%Y"`
;;
*)
echo "unknown snapshot type: $type"
exit 1
esac
# enumerate datasets under this pool or dataset, skip excluded datasets if requested
if [ -n "$skip" ]; then
egrep="($(echo $skip | sed "s/ /|/g"))"
datasets=$(zfs list -r -H -o name $pool | egrep -v "$egrep")
else
datasets=$(zfs list -r -H -o name $pool)
fi
# loop through datasets, do snapshots of each
for dataset in $datasets; do
snapshot="$dataset@$now"
# look for an existing snapshot with this name
if zfs list $snapshot > /dev/null 2>&1; then
echo " snapshot $snapshot already exists, skipping..."
else
echo " taking snapshot: $snapshot"
zfs snapshot $snapshot
fi
done
}
# delete the named snapshot
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
zfs destroy -r $snapshot
}
# take a type snapshot of pool, keeping keep old ones
do_pool()
{
pool=$1
keep=$2
type=$3
skip=$4
# create the regex matching the type of snapshots we're currently working
# on
case "$type" in
quarter_hourly)
# quarter_hourly-2009-01-01-00-15
regex="^$pool@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]$"
;;
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
# 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
}
# take snapshots of type, for pools, keeping keep old ones,
do_snapshots()
{
pools=$1
keep=$2
type=$3
skip=$4
echo ""
echo "Doing zfs $type snapshots:"
for pool in $pools; do
do_pool $pool $keep $type "$skip"
done
}