bundlewrap/bundles/zfs/files/zfs-auto-snapshot
2023-02-05 17:30:58 +01:00

84 lines
2.6 KiB
Python

#!/usr/bin/env python3
import re
from datetime import datetime
from json import loads
from subprocess import check_call, check_output
from sys import argv
def list_datasets():
datasets = set()
for line in check_output(['zfs', 'list', '-H', '-o', 'name']).splitlines():
line = line.decode('UTF-8')
for prefix in metadata.get('snapshot_never', set()):
if line.startswith(prefix):
break
else:
datasets.add(line)
return datasets
def get_filtered_snapshots_for_dataset(ds):
all_snapshots = check_output(['zfs', 'list', '-H', '-o', 'name', '-t', 'snapshot']).decode('UTF-8').splitlines()
prefix = '{}@zfs-auto-snap_{}-'.format(ds, label)
snapshots = set()
for i in sorted(all_snapshots):
if i.startswith(prefix):
snapshots.add(i)
return snapshots
def delete_snapshot(snap):
assert '@' in snap, 'BUG! Dataset "{}" has no @!'.format(snap)
print('deleting snapshot {}'.format(snap))
check_call(['zfs', 'destroy', snap])
def create_snapshot(ds, label, now):
check_call(['zfs', 'snapshot', '{}@zfs-auto-snap_{}-{}'.format(ds, label, now)])
print('created snapshot {}@zfs-auto-snap_{}-{}'.format(ds, label, now))
label = argv[1]
with open('/etc/zfs-snapshot-config.json', 'r') as fp:
metadata = loads(fp.read())
default_retain = metadata['retain_defaults'][label]
now = datetime.now().strftime('%F-%H%M')
snapshots_created = False
for ds in list_datasets():
retain = int(metadata.get('retain_per_dataset', {}).get(ds, {}).get(label, default_retain))
if retain > 0:
create_snapshot(ds, label, now)
snapshots_created = True
existing_snapshots = get_filtered_snapshots_for_dataset(ds)
if retain > 0:
# Why +1 here? Because we're specifying the amount of hours we want
# to go back in time, not the amount of snapshots we want to keep.
# Stating '1 month' does mean 'i want to be able to go back atleast
# one monthly snapshot', not 'keep one monthly snapshot'. If we only
# kept one snapshot, that wouldn't be possible for most of the time,
# because the monthly snapshot is actually less than a month old.
snapshots_to_keep = retain+1
for snapshot in sorted(existing_snapshots)[:-snapshots_to_keep]:
delete_snapshot(snapshot)
else:
for snapshot in existing_snapshots:
delete_snapshot(snapshot)
with open('/var/tmp/zfs-auto-snapshot.status', 'w') as fp:
fp.write('{}\n'.format(datetime.now().strftime('%s') if snapshots_created else 0))