Resume verify aven if error exsists

This commit is contained in:
2026-09-04 09:10:14 +03:00
parent c968c0656e
commit 6e5f2ddde8
2 changed files with 66 additions and 19 deletions
+7 -2
View File
@@ -94,6 +94,11 @@ checking, and `--one-file-system`. It does not modify either host. Any
itemized `rsync` output identifies an extra, missing, changed, or itemized `rsync` output identifies an extra, missing, changed, or
metadata-different path. metadata-different path.
The verifier continues with the next filesystem when one dataset cannot be
checked. It prints an `ERROR` line for each failed dataset and summarizes the
number of uncheckable filesystems at the end, so one run shows all failures
encountered along the way.
Verification options: Verification options:
| Option | Description | | Option | Description |
@@ -116,8 +121,8 @@ Exit statuses:
| Status | Meaning | | Status | Meaning |
| --- | --- | | --- | --- |
| `0` | All checked filesystems are identical. | | `0` | All checked filesystems are identical. |
| `1` | One or more filesystem pairs have differences. | | `1` | All filesystem pairs were checked, but one or more have differences. |
| `2` | Verification could not run, for example because of missing commands, SSH or sudo access, unavailable datasets, or unmounted filesystems. | | `2` | One or more filesystem pairs could not be checked, for example because a dataset is unavailable or unmounted, or its SSH, sudo, or `rsync` comparison failed. The script continues and lists these errors before exiting. |
For a stable result, stop writes to the source and destination while the For a stable result, stop writes to the source and destination while the
verifier runs, or verify mounted clones of the same snapshots. The verifier verifier runs, or verify mounted clones of the same snapshots. The verifier
+59 -17
View File
@@ -8,8 +8,9 @@ usage() {
Usage: zfs-verify-over-ssh.sh [options] SOURCE_POOL REMOTE_HOST DESTINATION_ROOT Usage: zfs-verify-over-ssh.sh [options] SOURCE_POOL REMOTE_HOST DESTINATION_ROOT
Compare every mounted filesystem in SOURCE_POOL with its corresponding mounted Compare every mounted filesystem in SOURCE_POOL with its corresponding mounted
remote filesystem below DESTINATION_ROOT. The script is read-only and exits 1 remote filesystem below DESTINATION_ROOT. The script is read-only, continues
when it finds differences. after per-filesystem errors, and exits 1 when it finds differences or 2 when
one or more filesystems could not be checked.
Arguments: Arguments:
SOURCE_POOL Source ZFS pool, for example: tank SOURCE_POOL Source ZFS pool, for example: tank
@@ -105,14 +106,20 @@ require_mounted_filesystem() {
local mountpoint="$3" local mountpoint="$3"
local mounted="$4" local mounted="$4"
[[ "$mountpoint" != none && "$mountpoint" != legacy ]] \ if [[ "$mountpoint" == none || "$mountpoint" == legacy ]]; then
|| die "$host_label filesystem $filesystem has mountpoint=$mountpoint" printf 'ERROR %s filesystem %s has mountpoint=%s\n' "$host_label" "$filesystem" "$mountpoint" >&2
[[ "$mounted" == yes ]] \ return 1
|| die "$host_label filesystem $filesystem is not mounted at $mountpoint" fi
if [[ "$mounted" != yes ]]; then
printf 'ERROR %s filesystem %s is not mounted at %s\n' "$host_label" "$filesystem" "$mountpoint" >&2
return 1
fi
if [[ "$host_label" == local ]]; then if [[ "$host_label" == local ]]; then
[[ -d "$mountpoint" ]] \ if [[ ! -d "$mountpoint" ]]; then
|| die "local filesystem $filesystem is not mounted at $mountpoint" printf 'ERROR local filesystem %s is not mounted at %s\n' "$filesystem" "$mountpoint" >&2
return 1
fi
fi fi
} }
@@ -124,16 +131,39 @@ printf -v RSYNC_RSH '%q ' "${SSH_COMMAND[@]}"
REPORT_FILE="$(mktemp)" REPORT_FILE="$(mktemp)"
trap 'rm -f "$REPORT_FILE"' EXIT trap 'rm -f "$REPORT_FILE"' EXIT
DIFFERENCES=0 DIFFERENCES=0
ERRORS=0
for filesystem in "${FILESYSTEMS[@]}"; do verify_filesystem() {
local filesystem="$1"
destination="$(map_destination "$filesystem")" destination="$(map_destination "$filesystem")"
source_mountpoint="$(zfs get -H -o value mountpoint "$filesystem")" local source_mountpoint
source_mounted="$(zfs get -H -o value mounted "$filesystem")" local source_mounted
remote_mountpoint="$(get_remote_property mountpoint "$destination")" local remote_mountpoint
remote_mounted="$(get_remote_property mounted "$destination")" local remote_mounted
require_mounted_filesystem local "$filesystem" "$source_mountpoint" "$source_mounted" if ! source_mountpoint="$(zfs get -H -o value mountpoint "$filesystem" 2>&1)"; then
require_mounted_filesystem remote "$destination" "$remote_mountpoint" "$remote_mounted" printf 'ERROR %s: could not read local mountpoint: %s\n' "$filesystem" "$source_mountpoint" >&2
return 1
fi
if ! source_mounted="$(zfs get -H -o value mounted "$filesystem" 2>&1)"; then
printf 'ERROR %s: could not read local mounted state: %s\n' "$filesystem" "$source_mounted" >&2
return 1
fi
if ! remote_mountpoint="$(get_remote_property mountpoint "$destination" 2>&1)"; then
printf 'ERROR %s: could not read remote mountpoint for %s: %s\n' "$filesystem" "$destination" "$remote_mountpoint" >&2
return 1
fi
if ! remote_mounted="$(get_remote_property mounted "$destination" 2>&1)"; then
printf 'ERROR %s: could not read remote mounted state for %s: %s\n' "$filesystem" "$destination" "$remote_mounted" >&2
return 1
fi
if ! require_mounted_filesystem local "$filesystem" "$source_mountpoint" "$source_mounted"; then
return 1
fi
if ! require_mounted_filesystem remote "$destination" "$remote_mountpoint" "$remote_mounted"; then
return 1
fi
printf 'Verifying %s against %s:%s\n' "$filesystem" "$REMOTE_HOST" "$destination" printf 'Verifying %s against %s:%s\n' "$filesystem" "$REMOTE_HOST" "$destination"
: >"$REPORT_FILE" : >"$REPORT_FILE"
@@ -141,8 +171,8 @@ for filesystem in "${FILESYSTEMS[@]}"; do
--one-file-system --itemize-changes --out-format='%i %n%L' \ --one-file-system --itemize-changes --out-format='%i %n%L' \
-e "$RSYNC_RSH" --rsync-path='sudo -n rsync' \ -e "$RSYNC_RSH" --rsync-path='sudo -n rsync' \
"$source_mountpoint/" "$REMOTE_HOST:$remote_mountpoint/" >"$REPORT_FILE"; then "$source_mountpoint/" "$REMOTE_HOST:$remote_mountpoint/" >"$REPORT_FILE"; then
printf 'Unable to compare %s.\n' "$filesystem" >&2 printf 'ERROR %s: rsync comparison failed.\n' "$filesystem" >&2
exit 2 return 1
fi fi
if [[ -s "$REPORT_FILE" ]]; then if [[ -s "$REPORT_FILE" ]]; then
@@ -150,8 +180,20 @@ for filesystem in "${FILESYSTEMS[@]}"; do
cat "$REPORT_FILE" >&2 cat "$REPORT_FILE" >&2
DIFFERENCES=1 DIFFERENCES=1
fi fi
}
for filesystem in "${FILESYSTEMS[@]}"; do
if ! verify_filesystem "$filesystem"; then
((ERRORS += 1))
fi
done done
if ((ERRORS)); then
printf 'Verification incomplete: %d filesystem(s) could not be checked.\n' "$ERRORS" >&2
printf 'Review the ERROR lines above; checked filesystem differences are also listed above.\n' >&2
exit 2
fi
if ((DIFFERENCES)); then if ((DIFFERENCES)); then
printf 'Verification failed: source and remote filesystems differ.\n' >&2 printf 'Verification failed: source and remote filesystems differ.\n' >&2
exit 1 exit 1