utcfromtimestamp is deprecated and its warning ended up in the check output; it also compared a UTC snapshot time with local now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RywMtsL8qXG7GDY3MHq9Uh
48 lines
1.5 KiB
Python
48 lines
1.5 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import json
|
|
from subprocess import check_output
|
|
from datetime import datetime, timedelta, timezone
|
|
|
|
|
|
now = datetime.now(timezone.utc)
|
|
two_days_ago = now - timedelta(days=2)
|
|
|
|
with open('/etc/backup-freshness-check.json', 'r') as file:
|
|
config = json.load(file)
|
|
|
|
local_datasets = check_output(['zfs', 'list', '-H', '-o', 'name']).decode().splitlines()
|
|
errors = set()
|
|
|
|
for dataset in config['datasets']:
|
|
if f'tank/{dataset}' not in local_datasets:
|
|
errors.add(f'dataset "{dataset}" not present at all')
|
|
continue
|
|
|
|
snapshots = [
|
|
snapshot
|
|
for snapshot in check_output(['zfs', 'list', '-H', '-o', 'name', '-t', 'snapshot', f'tank/{dataset}', '-s', 'creation']).decode().splitlines()
|
|
if f"@{config['prefix']}" in snapshot
|
|
]
|
|
|
|
if not snapshots:
|
|
errors.add(f'dataset "{dataset}" has no backup snapshots')
|
|
continue
|
|
|
|
newest_backup_snapshot = snapshots[-1]
|
|
snapshot_datetime = datetime.fromtimestamp(
|
|
int(check_output(['zfs', 'list', '-p', '-H', '-o', 'creation', '-t', 'snapshot', newest_backup_snapshot]).decode()),
|
|
timezone.utc,
|
|
)
|
|
|
|
if snapshot_datetime < two_days_ago:
|
|
days_ago = (now - snapshot_datetime).days
|
|
errors.add(f'dataset "{dataset}" has not been backed up for {days_ago} days')
|
|
continue
|
|
|
|
if errors:
|
|
for error in errors:
|
|
print(error)
|
|
exit(2)
|
|
else:
|
|
print(f"all {len(config['datasets'])} datasets have fresh backups.")
|