· 4 years ago · Sep 12, 2021, 11:34 AM
1#!/usr/bin/env python3
2
3import os
4import os.path
5import glob
6import datetime
7import shutil
8import time
9import sys
10import subprocess
11
12from b2sdk.v2 import (
13 B2Api,
14 InMemoryAccountInfo,
15 Synchronizer,
16 NewerFileSyncMode,
17 KeepOrDeleteMode,
18 SyncReport,
19)
20from b2sdk.sync.folder import LocalFolder, B2Folder
21
22BUCKET="..."
23KEY_ID="..."
24KEY="..."
25
26current = sorted(list(map(lambda f: os.path.basename(f), glob.glob("/snapshots/*"))))
27last = os.path.basename(sorted(list(glob.glob("/snapshots/*")))[-1])
28now = datetime.datetime.utcnow()
29suffix = last.split("_")[0]
30new = f"{now.year}-{now.month:02}-{now.day:02}-{now.hour:02}:{now.minute:02}_{suffix}"
31
32# `.` prefix to ensure atomicity of snapshot encoding and keep them sorted first
33subprocess.run(
34 f"btrfs subvolume snapshot -r / /snapshots/.{new}",
35 shell=True,
36 check=True,
37)
38
39snap_name = f"{new}.snapshot.zst.aes256"
40subprocess.run(
41 f"btrfs send -p /snapshots/{last} /snapshots/.{new} | zstd --adapt -T0 | openssl enc -aes-256-cbc -pbkdf2 -pass file:/root/backup/password > /tmp/{snap_name}",
42 shell=True,
43 check=True,
44)
45
46# mv does not sometimes discard metadata, unlike pythonic ways to move files
47subprocess.run(
48 f"mv /tmp/{snap_name} /home/janis/torrents/snapshots/",
49 shell=True,
50 check=True,
51)
52subprocess.run(
53 f"mv /snapshots/.{new} /snapshots/{new}",
54 shell=True,
55 check=True,
56)
57
58api = B2Api(InMemoryAccountInfo())
59api.authorize_account("production", KEY_ID, KEY)
60s = Synchronizer(
61 max_workers=8,
62 newer_file_mode=NewerFileSyncMode.REPLACE,
63 keep_days_or_delete=KeepOrDeleteMode.DELETE,
64)
65s.sync_folders(
66 LocalFolder("/home/janis/torrents/snapshots/"),
67 B2Folder(BUCKET, "", api),
68 int(round(time.time() * 1000)),
69 SyncReport(sys.stdout, True),
70)
71