Merge branch 'pr605' into pr-merger

This commit is contained in:
Christoph Klaffl 2023-03-20 21:14:02 +01:00
commit 59544de134
No known key found for this signature in database
GPG Key ID: 8FC1D76EED4970D2
3 changed files with 81 additions and 3 deletions

View File

@ -338,11 +338,11 @@ As of 1.4.18, syncoid also automatically supports and enables resume of interrup
+ --force-delete
Remove target datasets recursively (WARNING: this will also affect child datasets with matching snapshots/bookmarks), if there are no matching snapshots/bookmarks.
Remove target datasets recursively (WARNING: this will also affect child datasets with matching snapshots/bookmarks), if there are no matching snapshots/bookmarks. Also removes conflicting snapshots if the replication would fail because of a snapshot which has the same name between source and target but different contents.
+ --no-clone-handling
This argument tells syncoid to not recreate clones on the targe on initial sync and doing a normal replication instead.
This argument tells syncoid to not recreate clones on the target on initial sync and doing a normal replication instead.
+ --dumpsnaps

32
syncoid
View File

@ -796,6 +796,36 @@ sub syncdataset {
if ($exitcode < 2) { $exitcode = 2; }
return 0;
}
} elsif ($args{'force-delete'} && $stdout =~ /\Qdestination already exists\E/) {
(my $existing) = $stdout =~ m/^cannot restore to ([^:]*): destination already exists$/g;
if ($existing eq "") {
warn "CRITICAL ERROR: $synccmd failed: $?";
if ($exitcode < 2) { $exitcode = 2; }
return 0;
}
if (!$quiet) { print "WARN: removing existing destination: $existing\n"; }
my $rcommand = '';
my $mysudocmd = '';
my $existingescaped = escapeshellparam($existing);
if ($targethost ne '') { $rcommand = "$sshcmd $targethost"; }
if (!$targetisroot) { $mysudocmd = $sudocmd; }
my $prunecmd = "$mysudocmd $zfscmd destroy $existingescaped; ";
if ($targethost ne '') {
$prunecmd = escapeshellparam($prunecmd);
}
my $ret = system("$rcommand $prunecmd");
if ($ret != 0) {
warn "CRITICAL ERROR: $rcommand $prunecmd failed: $?";
if ($exitcode < 2) { $exitcode = 2; }
return 0;
} else {
# redo sync and skip snapshot creation (already taken)
return syncdataset($sourcehost, $sourcefs, $targethost, $targetfs, undef, 1);
}
} else {
warn "CRITICAL ERROR: $synccmd failed: $?";
if ($exitcode < 2) { $exitcode = 2; }
@ -1975,4 +2005,4 @@ Options:
--no-clone-handling Don't try to recreate clones on target
--no-privilege-elevation Bypass the root check, for use with ZFS permission delegation
--force-delete Remove target datasets recursively, if there are no matching snapshots/bookmarks
--force-delete Remove target datasets recursively, if there are no matching snapshots/bookmarks (also overwrites conflicting named snapshots)

View File

@ -0,0 +1,48 @@
#!/bin/bash
# test replication with deletion of conflicting snapshot on target
set -x
set -e
. ../../common/lib.sh
POOL_IMAGE="/tmp/syncoid-test-8.zpool"
POOL_SIZE="200M"
POOL_NAME="syncoid-test-8"
TARGET_CHECKSUM="ee439200c9fa54fc33ce301ef64d4240a6c5587766bfeb651c5cf358e11ec89d -"
truncate -s "${POOL_SIZE}" "${POOL_IMAGE}"
zpool create -m none -f "${POOL_NAME}" "${POOL_IMAGE}"
function cleanUp {
zpool export "${POOL_NAME}"
}
# export pool in any case
trap cleanUp EXIT
zfs create "${POOL_NAME}"/src
zfs snapshot "${POOL_NAME}"/src@duplicate
# initial replication
../../../syncoid -r --debug --compress=none "${POOL_NAME}"/src "${POOL_NAME}"/dst
# recreate snapshot with the same name on src
zfs destroy "${POOL_NAME}"/src@duplicate
zfs snapshot "${POOL_NAME}"/src@duplicate
sleep 1
../../../syncoid -r --force-delete --debug --compress=none "${POOL_NAME}"/src "${POOL_NAME}"/dst || exit 1
# verify
output1=$(zfs list -t snapshot -r -H -o guid,name "${POOL_NAME}"/src | sed 's/@syncoid_.*$'/@syncoid_/)
checksum1=$(echo "${output1}" | shasum -a 256)
output2=$(zfs list -t snapshot -r -H -o guid,name "${POOL_NAME}"/dst | sed 's/@syncoid_.*$'/@syncoid_/ | sed 's/dst/src/')
checksum2=$(echo "${output2}" | shasum -a 256)
if [ "${checksum1}" != "${checksum2}" ]; then
exit 1
fi
exit 0