summaryrefslogtreecommitdiff
path: root/modules/zfssnap
diff options
context:
space:
mode:
Diffstat (limited to 'modules/zfssnap')
-rw-r--r--modules/zfssnap/zfssnap.py22
1 files changed, 15 insertions, 7 deletions
diff --git a/modules/zfssnap/zfssnap.py b/modules/zfssnap/zfssnap.py
index b72174fc..e77f11f3 100644
--- a/modules/zfssnap/zfssnap.py
+++ b/modules/zfssnap/zfssnap.py
@@ -32,7 +32,7 @@ def _now():
32 32
33def _snap_name(item, time=_now()): 33def _snap_name(item, time=_now()):
34 suffix = re.sub(r'\+00:00$', r'Z', time.isoformat(timespec='seconds')) 34 suffix = re.sub(r'\+00:00$', r'Z', time.isoformat(timespec='seconds'))
35 return f'{item}@auto_{suffix}' 35 return f'{item}@{suffix}'
36 36
37def _log_cmd(*args): 37def _log_cmd(*args):
38 fmt_args = ' '.join(map(shlex.quote, args)) 38 fmt_args = ' '.join(map(shlex.quote, args))
@@ -53,8 +53,18 @@ def _get_items():
53 return items 53 return items
54 54
55def prune(config, dry_run, keep_newest): 55def prune(config, dry_run, keep_newest):
56 items = defaultdict(list) 56 prunable_snapshots = set()
57 args = ['zfs', 'get', '-H', '-p', '-o', 'name,value', '-t', 'snapshot', '-s', 'local' 'li.yggdrasil:is-auto-snapshot']
58 _log_cmd(*args)
59 with subprocess.Popen(args, stdout=subprocess.PIPE) as proc:
60 text_stdout = io.TextIOWrapper(proc.stdout)
61 reader = csv.reader(text_stdout, delimiter='\t', quoting=csv.QUOTE_NONE)
62 Row = namedtuple('Row', ['name', 'is_auto_snapshot'])
63 for row in map(Row._make, reader):
64 if bool(strtobool(row.is_auto_snapshot)):
65 prunable_snapshots.add(row.name)
57 66
67 items = defaultdict(list)
58 Snap = namedtuple('Snap', ['name', 'creation']) 68 Snap = namedtuple('Snap', ['name', 'creation'])
59 args = ['zfs', 'get', '-H', '-p', '-o', 'name,value', '-t', 'snapshot', 'creation'] 69 args = ['zfs', 'get', '-H', '-p', '-o', 'name,value', '-t', 'snapshot', 'creation']
60 _log_cmd(*args) 70 _log_cmd(*args)
@@ -63,12 +73,10 @@ def prune(config, dry_run, keep_newest):
63 reader = csv.reader(text_stdout, delimiter='\t', quoting=csv.QUOTE_NONE) 73 reader = csv.reader(text_stdout, delimiter='\t', quoting=csv.QUOTE_NONE)
64 Row = namedtuple('Row', ['name', 'timestamp']) 74 Row = namedtuple('Row', ['name', 'timestamp'])
65 for row in map(Row._make, reader): 75 for row in map(Row._make, reader):
66 creation = datetime.fromtimestamp(int(row.timestamp), timezone.utc) 76 if row.name is not in prunable_snapshots:
67 base_name, _, _ = row.name.rpartition('@')
68 expected_name = _snap_name(base_name, time=creation)
69 if expected_name != row.name:
70 # logger.debug(f'Skipping ‘{row.name}’ since it does not conform to naming scheme')
71 continue 77 continue
78
79 creation = datetime.fromtimestamp(int(row.timestamp), timezone.utc)
72 items[base_name].append(Snap(name=row.name, creation=creation)) 80 items[base_name].append(Snap(name=row.name, creation=creation))
73 81
74 kept_count = defaultdict(lambda: defaultdict(lambda: 0)) 82 kept_count = defaultdict(lambda: defaultdict(lambda: 0))