Browse code

Switch to Python3, add --delete-only and --verbose

Lorenz Hüdepohl authored on03/05/2015 23:00:52 • Lorenz Hüdepohl committed on04/05/2015 10:07:53
Showing1 changed files
... ...
@@ -1,4 +1,4 @@
1
-#!/usr/bin/python
1
+#!/usr/bin/python3
2 2
 # coding=utf8
3 3
 #
4 4
 # The MIT License (MIT)
... ...
@@ -25,21 +25,23 @@
25 25
 
26 26
 import sys
27 27
 import datetime
28
-from subprocess import Popen, PIPE, check_call
29 28
 import argparse
29
+import locale
30
+from subprocess import Popen, PIPE, check_call
31
+from shutil import which
30 32
 
31 33
 parser = argparse.ArgumentParser(
32 34
             formatter_class=argparse.RawTextHelpFormatter,
33 35
             description='''
34
-  Use with cron to make periodic ZFS snapshots, with the option of keeping
35
-  only a limited number of old snapshots.
36
+ Use with cron to make periodic ZFS snapshots, with the option of keeping
37
+ only a limited number of old snapshots.
36 38
 
37
-  For every ZFS filesystem that has the user property 'autosnapshot:TAGNAME'
38
-  a snapshot is created. The value must be a positive number or the string
39
-  "keep-all", which is used as the number of old snapshots to keep. If there
40
-  are more, the oldest are destroyed.
39
+ For every ZFS filesystem that has the user property 'autosnapshot:TAGNAME'
40
+ a snapshot is created. The value must be a positive number or the string
41
+ "keep-all", which is used as the number of old snapshots to keep. If there
42
+ are more, the oldest are destroyed.
41 43
 
42
-  Example:
44
+ Example:
43 45
 
44 46
    Setup properties:
45 47
 
... ...
@@ -56,28 +58,45 @@ parser = argparse.ArgumentParser(
56 58
     */5 * * * * zfs_auto_snapshot 5min
57 59
 ''')
58 60
 
59
-parser.add_argument('tagname', metavar='TAGNAME', type=str)
61
+parser.add_argument('tagname', metavar='TAGNAME', type=str,
62
+                help='Consider all filesystems with an \'autosnapshot:TAGNAME\'\nproperty')
63
+
64
+parser.add_argument('-v', '--verbose', action="store_true",
65
+		help='Echo the commands that are issued.')
66
+
67
+parser.add_argument('-d', '--delete-only', action="store_true",
68
+                help='Do not make a new snapshot, but delete any old\nsurplus snapshots found.')
60 69
 
61 70
 parser.add_argument('-n', '--dry-run', action="store_true",
62 71
 		help='Only echo the commands that would be issued,\ndo not actually do anything.')
63 72
 
64 73
 args = parser.parse_args()
65 74
 
66
-if args.dry_run:
67
-    zfs = ["echo", "/usr/sbin/zfs"]
68
-else:
69
-    zfs = ["/usr/sbin/zfs"]
70 75
 
71
-zfs_props = Popen(["/usr/sbin/zfs", "get", "-t", "filesystem", "autosnapshot:{0}".format(args.tagname), "-H"],
76
+zfs = which("zfs")
77
+
78
+if not zfs:
79
+    raise Exception("No 'zfs' executable found in your PATH")
80
+
81
+def call(cmdargs):
82
+    if args.verbose or args.dry_run:
83
+        print(" ".join(cmdargs))
84
+    if not args.dry_run:
85
+        check_call(cmdargs)
86
+
87
+zfs_props = Popen([zfs, "get", "-t", "filesystem", "autosnapshot:{0}".format(args.tagname), "-H"],
72 88
         stdout=PIPE)
73 89
 
90
+encoding = locale.getdefaultlocale()[1]
91
+
74 92
 for line in zfs_props.stdout:
75
-    fs, prop, number, source = line.split("\t")
93
+    fs, prop, number, source = line.decode(encoding).split("\t")
76 94
     if number != "-":
77
-        # Create new snapshot
78
-        new_snapshot = "{0}@autosnapshot-{1}-{2}".format(fs, args.tagname,
79
-                            datetime.datetime.now().strftime("%Y-%m-%d-%H:%M"))
80
-        check_call(zfs + ["snapshot", new_snapshot])
95
+        if not args.delete_only:
96
+            # Create new snapshot
97
+            new_snapshot = "{0}@autosnapshot-{1}-{2}".format(fs, args.tagname,
98
+                                datetime.datetime.now().strftime("%Y-%m-%d-%H:%M"))
99
+            call([zfs, "snapshot", new_snapshot])
81 100
 
82 101
         # Delete oldest snapshots
83 102
         if number == "keep-all":
... ...
@@ -90,10 +109,10 @@ for line in zfs_props.stdout:
90 109
 
91 110
         snapshots = []
92 111
 
93
-        zfs_snapshots = Popen(["/usr/sbin/zfs", "list", "-t", "snapshot", "-d", "1", fs, "-H"], stdout=PIPE)
112
+        zfs_snapshots = Popen([zfs, "list", "-t", "snapshot", "-d", "1", fs, "-H"], stdout=PIPE)
94 113
 
95 114
         for line_snapshots in zfs_snapshots.stdout:
96
-            snapname, rest = line_snapshots.split("\t", 1)
115
+            snapname, rest = line_snapshots.decode(encoding).split("\t", 1)
97 116
             if snapname.startswith("{0}@autosnapshot-{1}-".format(fs, args.tagname)):
98 117
                 snapshots.append(snapname)
99 118
 
... ...
@@ -106,4 +125,4 @@ for line in zfs_props.stdout:
106 125
             # Delete this old snapshot
107 126
             if not d.startswith("{0}@autosnapshot-{1}-".format(fs, args.tagname)):
108 127
                 raise Exception("Invalid snapshot name '{0}', does not start with '{1}@autosnapshot-{2}-'".format(d, fs, args.tagname))
109
-            check_call(zfs + ["destroy", d])
128
+            call([zfs, "destroy", d])