Add ability to test pool recovery

This commit is contained in:
2026-09-04 16:22:58 +03:00
parent 307aa55356
commit 2d6c410489
2 changed files with 129 additions and 1 deletions
+90
View File
@@ -0,0 +1,90 @@
#!/usr/bin/env bash
# Assess whether ZFS can rewind and import an exported or faulted pool.
set -euo pipefail
usage() {
cat <<'EOF'
Usage: sudo ./verify-zpool-recovery.sh [--directory <path>] [--apply] [pool]
Lists pools ZFS can discover, or checks whether a named pool can be recovered
with a transaction rewind. The default is a dry run and changes nothing.
Options:
-d, --directory <path> Search a specific directory for vdev devices.
--apply Import the named pool with rewind recovery.
-h, --help Show this help message.
Without a pool name, the script only lists importable pools. --apply requires
a pool name and imports it with datasets left unmounted.
EOF
}
die() {
printf 'Error: %s\n' "$*" >&2
exit 1
}
search_directory=
apply=false
pool=
while [[ $# -gt 0 ]]; do
case $1 in
-d|--directory)
[[ $# -ge 2 ]] || die "$1 requires a path."
search_directory=$2
shift 2
;;
--apply)
apply=true
shift
;;
-h|--help)
usage
exit 0
;;
-*)
die "unknown option '$1'."
;;
*)
[[ -z $pool ]] || die 'specify at most one pool name or GUID.'
pool=$1
shift
;;
esac
done
[[ $EUID -eq 0 ]] || die 'run as root (for example, with sudo).'
command -v zpool >/dev/null 2>&1 || die "required command 'zpool' was not found."
directory_args=()
if [[ -n $search_directory ]]; then
[[ -d $search_directory ]] || die "'$search_directory' is not a directory."
directory_args=(-d "$search_directory")
fi
if [[ -z $pool ]]; then
[[ $apply == false ]] || die '--apply requires a pool name or GUID.'
printf 'Discovering importable pools. This does not modify any pool.\n\n'
zpool import "${directory_args[@]}"
exit 0
fi
if zpool list -H -o name "$pool" >/dev/null 2>&1; then
die "'$pool' is already imported; inspect it with 'zpool status $pool'."
fi
if [[ $apply == false ]]; then
printf 'Dry-run rewind recovery check for pool %s. No changes will be made.\n\n' "$pool"
zpool import -nF "${directory_args[@]}" "$pool"
exit 0
fi
printf '\nWARNING: this will attempt to rewind and import pool:\n %s\n\n' "$pool"
printf 'This can discard the most recent transaction groups. Datasets will remain unmounted.\n'
read -r -p "Type exactly 'RECOVER $pool' to continue: " confirmation
[[ $confirmation == "RECOVER $pool" ]] || die 'confirmation did not match; no changes were made.'
zpool import -N -F "${directory_args[@]}" "$pool"
printf "Pool '%s' was imported without mounting datasets. Inspect it with:\n zpool status %s\n" "$pool" "$pool"