diff --git a/zfs-snapshot-backup.py b/zfs-snapshot-backup.py index ce79a1f..c1bd014 100755 --- a/zfs-snapshot-backup.py +++ b/zfs-snapshot-backup.py @@ -16,7 +16,10 @@ TMP_BACKUP_FOLDER = "/mnt/Datenspeicher/snap-backup-dataset/temporary-backups" def call(arguments, as_text=False): result = subprocess.run( - arguments, check=True, stdout=subprocess.PIPE, universal_newlines=as_text + arguments, + check=True, + stdout=subprocess.PIPE, + universal_newlines=as_text, ) return result.stdout @@ -50,13 +53,27 @@ def list_elab_snapshots(): return result -def gzip_filename(snapshot_name): - pool, name = snapshot_name.split("/", 1) - return f"{name}.gz" +def snapshot_short_name(full_snapshot_name): + pool, name = full_snapshot_name.split("/", 1) + return name -def gzip_filepath(snapshot_name): - return pathlib.Path(TMP_BACKUP_FOLDER) / gzip_filename(snapshot_name) +def gzip_filename(current, last=None): + current_name = snapshot_short_name(current) + if last is None: + return f"{current_name}.gz" + else: + last_name = snapshot_name(last) + return f"{last_name}.to.{current_name}.gz" + + +def extract_snapshot_name(filename): + parts = filename.split(".") + if len(parts) in (2, 4): + # snapshot1.gz or snapshot1.to.snapshot2.gz + return parts[-2] + else: + raise ValueError(f"Unknown Filename Format: {filename}") def list_remote_backups(members): @@ -65,7 +82,7 @@ def list_remote_backups(members): remote_sub_dir = f"{REMOTE_PATH}/{member}" try: backups = clean_split(remote_call(["ls", remote_sub_dir])) - result[member] = set(backups) + result[member] = set((extract_snapshot_name(i) for i in backups)) except subprocess.CalledProcessError: remote_call(["mkdir", remote_sub_dir]) result[member] = set() @@ -78,7 +95,7 @@ def backup_latest_snapshot(member, elab_snapshots, existing_backups): current_snapshot = snapshots[0] latest_backup = None for snapshot in snapshots: - if gzip_filename(snapshot) in existing_backups: + if snapshot_short_name(snapshot) in existing_backups: latest_backup = snapshot break if current_snapshot == latest_backup: @@ -88,16 +105,20 @@ def backup_latest_snapshot(member, elab_snapshots, existing_backups): elif latest_backup is None: # no snapshot was found in backups, make a full backup for consistency send_cmd = ["zfs", "send", current_snapshot] + gzip_tmp_filename = gzip_filename(current_snapshot) print(f" - full backup, latest snapshot: {current_snapshot}") else: # make an incremental backup print( f" - incremental backup, from: {latest_backup} to: {current_snapshot}" ) + gzip_tmp_filename = gzip_filename( + current=current_snapshot, last=latest_backup + ) send_cmd = ["zfs", "send", "-I", latest_backup, current_snapshot] # create the backup - tmp_gzip_filepath = gzip_filepath(current_snapshot) + tmp_gzip_filepath = pathlib.Path(TMP_BACKUP_FOLDER) / gzip_tmp_filename print(f" - generating temporary backup file {tmp_gzip_filepath.name}") with open(tmp_gzip_filepath, "wb") as file_handle: gzip_in = subprocess.Popen(