snap-sync: cleanup target snapper structure handling
- verify_snapper_structure: better variable parsing - handle situation of deleted snapper target structure - lineup variable names - ensure proper sync after snapper calls - snapper metadata updates - support multiple config option parameter - update dry-run processing - refuse to backup a snapshot to the target, if new source snap-id already exists on target subvolume - cleanup permission settings for backupdir
This commit is contained in:
133
bin/snap-sync
133
bin/snap-sync
@@ -81,10 +81,14 @@ check_snapper_failed_ids () {
|
||||
# "$progname backup in progress" (snapper description field)
|
||||
snapper_failed_ids=$(eval snapper -c $selected_config list -t single | awk '/'"$progname"' backup in progress/ {cnt++} END {print cnt}')
|
||||
if [ -n "$snapper_failed_ids" ]; then
|
||||
printf "\nNOTE: Previous failed %s backup snapshots found for '%s'.\n" "$progname" "$selected_config" | tee $PIPE
|
||||
get_answer_yes_no "Delete failed backup snapshots [y/N]? " "no"
|
||||
if [ "$answer" = "yes" ]; then
|
||||
if [ noconfirm ]; then
|
||||
snapper -c $selected_config delete $(snapper -c $selected_config list | awk '/'"$progname"' backup in progress/ {print $3}')
|
||||
else
|
||||
printf "\nNOTE: Previous failed %s backup snapshots found for '%s'.\n" "$progname" "$selected_config" | tee $PIPE
|
||||
get_answer_yes_no "Delete failed backup snapshots [y/N]? " "no"
|
||||
if [ "$answer" = "yes" ]; then
|
||||
snapper -c $selected_config delete $(snapper -c $selected_config list | awk '/'"$progname"' backup in progress/ {print $3}')
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -118,7 +122,7 @@ get_disk_infos () {
|
||||
fi
|
||||
|
||||
# we need at least one target disk
|
||||
if [ ${#disk_targets} -eq 0 ]; then die "no suitable target disk found \n"die
|
||||
if [ ${#disk_targets} -eq 0 ]; then die "no suitable target disk found"
|
||||
fi
|
||||
|
||||
# Posix Shells do not support Array. Therefore using ...
|
||||
@@ -229,7 +233,11 @@ parse_params () {
|
||||
shift 2
|
||||
;;
|
||||
-c|--config)
|
||||
selected_config="$2"
|
||||
if [ ${#selected_config} -gt 0 ]; then
|
||||
selected_config="${selected_config} ${2}"
|
||||
else
|
||||
selected_config="$2"
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
-d|--description)
|
||||
@@ -262,8 +270,12 @@ parse_params () {
|
||||
shift
|
||||
;;
|
||||
--config=*)
|
||||
selected_config=${1#*=}
|
||||
shift
|
||||
if [ ${#selected_config} -gt 0 ]; then
|
||||
selected_config="${selected_config} ${1#*=}"
|
||||
else
|
||||
selected_config="${1#*=}"
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
dryrun=1
|
||||
@@ -292,11 +304,11 @@ parse_params () {
|
||||
;;
|
||||
-*)
|
||||
printf "WARN: Unknown option (ignored): $1" >&2
|
||||
#shift
|
||||
exit 1
|
||||
die "Unknown option"
|
||||
;;
|
||||
*)
|
||||
die "Unknown option: $key\nRun '$progname -h' for valid options.\n"
|
||||
printf "Unknown option: %s\nRun '%s -h' for valid options.\n" $key $progname
|
||||
die "Unknown option"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
@@ -397,6 +409,11 @@ run_config () {
|
||||
else
|
||||
backup_root="$selected_target/$backupdir"
|
||||
fi
|
||||
else
|
||||
# use sane default
|
||||
if [ -z "$backup_root" ]; then
|
||||
backup_root="$selected_target"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
@@ -510,12 +527,7 @@ run_backup () {
|
||||
snapper_target_config=$(eval echo \$snapper_target_config_$i)
|
||||
snapper_target_snapshot=$(eval echo \$snapper_target_snapshot_$i)
|
||||
|
||||
if [ ! "$dryrun" ]; then
|
||||
verify_snapper_structure $backup_root $snapper_config $snapper_target_config $snapper_new_id
|
||||
else
|
||||
cmd="verify_snapper_structure $backup_root $snapper_config $snapper_target_config $snapper_new_id"
|
||||
printf "dryrun: %s\n" "$cmd"
|
||||
fi
|
||||
verify_snapper_structure "backup_root=$backup_root" "snapper_target_config=$snapper_target_config" "snapper_new_id=$snapper_new_id"
|
||||
|
||||
if [ -z "$snapper_sync_id" ]; then
|
||||
cmd="btrfs send $snapper_new_snapshot | $ssh btrfs receive $snapper_target_snapshot"
|
||||
@@ -525,7 +537,8 @@ run_backup () {
|
||||
cmd="btrfs send -v $snapper_new_snapshot | $ssh btrfs receive -v $snapper_target_snapshot"
|
||||
fi
|
||||
if [ ! "$dryrun" ]; then
|
||||
btrfs send "$snapper_new_snapshot" | $ssh btrfs receive "$snapper_target_snapshot" &>/dev/null
|
||||
btrfs send "$snapper_new_snapshot" | $ssh btrfs receive "$snapper_target_snapshot" &>/dev/null
|
||||
sync
|
||||
else
|
||||
cmd="btrfs send -v $snapper_new_snapshot | $ssh btrfs receive -v $snapper_target_snapshot"
|
||||
printf "dryrun: %s\n" "$cmd"
|
||||
@@ -543,6 +556,7 @@ run_backup () {
|
||||
printf "Deleting sync snapshot for %s ...\n" "$selected_config" | tee $PIPE
|
||||
fi
|
||||
snapper -c "$selected_config" delete "$snapper_sync_id"
|
||||
sync
|
||||
else
|
||||
printf "dryrun: btrfs send %s -c %s %s | %s btrfs receive %s %s\n" \
|
||||
"$verbose_flag" "$snapper_sync_snapshot" "$snapper_new_snapshot" \
|
||||
@@ -581,8 +595,10 @@ run_backup () {
|
||||
# Tag new snapshot as the latest
|
||||
printf "Tagging snapper metadata for configuration '%s' ...\n" "$selected_config" | tee $PIPE
|
||||
if [ ! "$dryrun" ]; then
|
||||
snapper -v -c "$selected_config" modify -d \"$description\" -u \"$userdata\" "$snapper_new_id"
|
||||
$ssh snapper -v -c "$snapper_target_config" modify -d \"$target_description\" -u \"$target_userdata\" "$snapper_new_id"
|
||||
eval snapper --verbose --config "$selected_config" modify --description \"$description\" --userdata \"$userdata\" "$snapper_new_id"
|
||||
sync
|
||||
$ssh snapper --verbose --config "$snapper_target_config" modify --description \"$target_description\" --userdata \"$target_userdata\" "$snapper_new_id"
|
||||
$ssh sync
|
||||
else
|
||||
cmd="snapper -v -c $selected_config modify -d $description -u $userdata $snapper_new_id"
|
||||
printf "dryrun: %s\n" "$cmd"
|
||||
@@ -737,46 +753,85 @@ EOF
|
||||
}
|
||||
|
||||
verify_snapper_structure () {
|
||||
local backup_root=$1
|
||||
local snapper_config=$2
|
||||
local snapper_subvol=$3
|
||||
local snapper_id=$4
|
||||
local backup_root=${1##backup_root=}
|
||||
local snapper_config=${2##snapper_target_config=}
|
||||
local snapper_id=${3##snapper_new_id=}
|
||||
|
||||
local snapper_snapshots=".snapshots"
|
||||
|
||||
if [ "$verbose" ]; then
|
||||
echo "Verify snapper filesystem structure on target ..."
|
||||
printf "Verify snapper filesystem structure on target ...\n"
|
||||
fi
|
||||
|
||||
# if not accessible, create backup-path
|
||||
if $ssh [ ! -d $backup_root ]; then
|
||||
if [ "$verbose" ]; then
|
||||
echo "Create backup-path $backup_root ..."
|
||||
if [ ! "$dryrun" ]; then
|
||||
if [ "$verbose" ]; then
|
||||
printf "Create backup-path %s ...\n" "$backup_root"
|
||||
fi
|
||||
$ssh mkdir --mode=0700 --parents $backup_root
|
||||
else
|
||||
printf "dryrun: Would create backup-path $backup_root %s ...\n" "$backup_root"
|
||||
fi
|
||||
$ssh mkdir --mode=0700 --parents $backup_root
|
||||
fi
|
||||
if $ssh [ ! -d $backup_root/$snapper_subvol ]; then
|
||||
|
||||
# verify that we have a snapper compatible structure for selected config on target
|
||||
if $ssh [ ! -d $backup_root/$snapper_config ]; then
|
||||
if $ssh [ ! -f $SNAPPER_TEMPLATES/snap-sync ]; then
|
||||
die "A snapper template %s to configure the snapper subvolume %s is missing in %s. Did you miss to install the package default template?\n" "snap-sync" "$snapper_config" "$SNAPPER_TEMPLATES"
|
||||
printf "A snapper template %s to configure the snapper subvolume %s is missing in %s.\n" "snap-sync" "$snapper_config" "$SNAPPER_TEMPLATES"
|
||||
printf "Did you miss to install the snap-sync's default snapper template?\n"
|
||||
die "snapper template %s to configure the snapper subvolume %s is missing in %s.\n" "snap-sync" "$snapper_config" "$SNAPPER_TEMPLATES"
|
||||
fi
|
||||
if [ "$verbose" ]; then
|
||||
printf "Create new snapper capable subvolume in '%s' ...\n" "$backup_root/$snapper_subvol"
|
||||
if [ ! "$dryrun" ]; then
|
||||
if [ "$verbose" ]; then
|
||||
printf "Create new snapper capable subvolume in '%s' ...\n" "$backup_root/$snapper_config"
|
||||
fi
|
||||
# TODO: test if there is any old snapper config
|
||||
create_config="btrfs subvolume create $backup_root/$snapper_config"
|
||||
$ssh $create_config || die "Snapper structure for config %s to hold target snapshots could not be created in directory on %s.\n" "$snapper_config" "$backup_root"
|
||||
# snapper-logic will create $backup_root/$snapper_config/.snapshots
|
||||
$ssh snapper --config $snapper_config create-config --template snap-sync $backup_root/$snapper_config
|
||||
$ssh chmod 0700 $backup_root/$snapper_config
|
||||
sync
|
||||
else
|
||||
printf "dryrun: Would create new snapper structure in '%s' ...\n" "$backup_root/$snapper_config"
|
||||
fi
|
||||
create_subvol="btrfs subvolume create $backup_root/$snapper_subvol"
|
||||
$ssh $create_subvol || die "BTRFS subvolume %s to hold snapshots for config %s could not be created in directory on %s.\n" "$snapper_subvol" "$snapper_config" "$backup_root"
|
||||
$ssh snapper --config $snapper_subvol create-config --template snap-sync $backup_root/$snapper_subvol
|
||||
$ssh chmod --mode=0700 $backup_root/$snapper_config
|
||||
$ssh chmod 0700 $backup_root/$snapper_subvol
|
||||
else
|
||||
if $ssh [ `stat --format=%i $backup_root/$snapper_subvol` -ne 256 ]; then
|
||||
die "%s needs to be a BTRFS subvolume. But given %s is just a directory.\n" "$snapper_subvol" "$backup_root/$snapper_subvol"
|
||||
cmd="$ssh stat --format=%i $backup_root/$snapper_config"
|
||||
if [ $(eval $cmd) -ne 256 ]; then
|
||||
die "%s needs to be a BTRFS subvolume. But given %s is just a directory.\n" "$snapper_config" "$backup_root/$snapper_config"
|
||||
fi
|
||||
# test if there is any restover/old snapper config
|
||||
if $ssh [ ! -d $backup_root/$snapper_config/$snapper_snapshots ]; then
|
||||
cmd="btrfs subvolume create $backup_root/$snapper_config/$snapper_snapshots"
|
||||
$ssh $cmd || die "Can't create subvolume %s in %s to hold target snapshots.\n" "$snapper_snapshots" "$backup_root/$snapper_config"
|
||||
fi
|
||||
fi
|
||||
|
||||
if $ssh [ ! -d $backup_root/$snapper_subvol/$snapper_snapshots/$snapper_id ]; then
|
||||
if [ "$verbose" ]; then
|
||||
echo "Create backup-path $backup_root/$snapper_subvol/$snapper_snapshots/$snapper_id"
|
||||
# verify that target snapshot id can take the new snapshot data
|
||||
if [ ! "$dryrun" ]; then
|
||||
if $ssh [ ! -d $backup_root/$snapper_config/$snapper_snapshots/$snapper_id ]; then
|
||||
if [ "$verbose" ]; then
|
||||
printf "Create path %s to store target snapshot.\n" "$backup_root/$snapper_config/$snapper_snapshots/$snapper_id"
|
||||
fi
|
||||
$ssh mkdir --mode=0700 $backup_root/$snapper_config/$snapper_snapshots/$snapper_id
|
||||
else
|
||||
if [ "$verbose" ]; then
|
||||
printf "Snapshot %s already in use on target %s.\n" "$snapper_id" "$backup_root/$snapper_config/$snapper_snapshots"
|
||||
fi
|
||||
printf "Cancel Snapshot creation: Former snapshot with id '%s' already exist in '%s'\n" "\
|
||||
$snapper_id" "$backup_root/$snapper_config/$snapper_snapshots"
|
||||
# cleanup generated snapper entry
|
||||
check_snapper_failed_ids
|
||||
die "Can't create new snapshot with given snapshot-id!"
|
||||
return=1
|
||||
fi
|
||||
$ssh mkdir --mode=0700 $backup_root/$snapper_subvol/$snapper_snapshots/$snapper_id
|
||||
else
|
||||
printf "dryrun: Would check/create path %s to store target snapshot ...\n" \
|
||||
"$backup_root/$snapper_config/$snapper_snapshots/$snapper_id"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user