From f9504eb14a8bbbb2a9d103afef4d6fd76fab2b70 Mon Sep 17 00:00:00 2001 From: Tero Date: Wed, 2 Sep 2026 08:20:38 +0300 Subject: [PATCH] Add feature to ask deletion already exsisting snapshots on remote end --- README.md | 5 +++++ zfs-move-over-ssh.sh | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/README.md b/README.md index 2b163e4..ed03b6f 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,11 @@ Options: completed destination filesystems remain received. Re-running with the same source can create another timestamped snapshot; inspect both source and destination state before retrying. +- Before each receive, the script checks whether the remote destination already + has the matching `move-YYYYMMDD-HHMMSS` snapshot. If it does, the script asks + whether to delete that specific remote snapshot and retry the transfer. Type + `y` only after confirming it is an incomplete or disposable migration + snapshot; any other response stops the script without deleting it. - A successful transfer is not a destructive move. Verify applications and data on the destination, then perform any source cleanup separately. diff --git a/zfs-move-over-ssh.sh b/zfs-move-over-ssh.sh index a651470..4582d59 100644 --- a/zfs-move-over-ssh.sh +++ b/zfs-move-over-ssh.sh @@ -113,6 +113,24 @@ run() { fi } +remote_snapshot_exists() { + local remote_snapshot="$1" + ssh "${SSH_OPTIONS[@]}" "$REMOTE_HOST" \ + "sudo -n zfs list -H -o name -t snapshot '$remote_snapshot' >/dev/null 2>&1" +} + +remove_remote_snapshot() { + local remote_snapshot="$1" + local reply + + printf 'Remote snapshot %s already exists. Delete it and retry? [y/N] ' "$remote_snapshot" >&2 + read -r reply + [[ "$reply" =~ ^[Yy]([Ee][Ss])?$ ]] || die "remote snapshot was not deleted; stopping" + + ssh "${SSH_OPTIONS[@]}" "$REMOTE_HOST" "sudo -n zfs destroy '$remote_snapshot'" \ + || die "could not delete remote snapshot $remote_snapshot" +} + mapfile -t FILESYSTEMS < <(zfs list -H -o name -t filesystem -r "$SOURCE_POOL") ((${#FILESYSTEMS[@]} > 0)) || die "no filesystems found in $SOURCE_POOL" @@ -120,6 +138,7 @@ printf 'Migration snapshot: %s\n' "$SNAPSHOT_NAME" for filesystem in "${FILESYSTEMS[@]}"; do destination="$(map_destination "$filesystem")" snapshot="${filesystem}@${SNAPSHOT_NAME}" + remote_snapshot="${destination}@${SNAPSHOT_NAME}" printf 'Transferring %s to %s:%s\n' "$filesystem" "$REMOTE_HOST" "$destination" run zfs snapshot "$snapshot" @@ -129,6 +148,9 @@ for filesystem in "${FILESYSTEMS[@]}"; do printf ' %q' "${SSH_OPTIONS[@]}" "$REMOTE_HOST" "sudo -n zfs receive -uF '$destination'" >&2 printf '\n' >&2 else + if remote_snapshot_exists "$remote_snapshot"; then + remove_remote_snapshot "$remote_snapshot" + fi zfs send -p "$snapshot" | ssh "${SSH_OPTIONS[@]}" "$REMOTE_HOST" "sudo -n zfs receive -uF '$destination'" fi