This commit is contained in:
Edwin Eefting 2023-09-26 18:01:09 +02:00
parent a7d05a7064
commit 6e5a6764c5
No known key found for this signature in database
GPG Key ID: 0F3C35D8E9887737
3 changed files with 59 additions and 20 deletions

View File

@ -191,3 +191,36 @@ test_target1/test_source2/fs2 encryptionroot -
test_target1/test_source2/fs2/sub encryptionroot - -
""")
def test_raw_invalid_snapshot(self):
"""in raw mode, its not allowed to have any newer snaphots on target, #219"""
self.prepare_encrypted_dataset("11111111", "test_source1/fs1/encryptedsource")
with patch('time.strftime', return_value="test-20101111000000"):
self.assertFalse(ZfsAutobackup("test test_target1 --verbose --no-progress".split(" ")).run())
#this is invalid in raw mode
shelltest("zfs snapshot test_target1/test_source1/fs1/encryptedsource@incompatible")
with patch('time.strftime', return_value="test-20101111000001"):
#should fail because of incompatble snapshot
self.assertEqual(ZfsAutobackup("test test_target1 --verbose --no-progress --allow-empty".split(" ")).run(),1)
#should destroy incompatible and continue
self.assertFalse(ZfsAutobackup("test test_target1 --verbose --no-progress --no-snapshot --destroy-incompatible".split(" ")).run())
r = shelltest("zfs get -r -t filesystem encryptionroot test_target1")
self.assertMultiLineEqual(r,"""
NAME PROPERTY VALUE SOURCE
test_target1 encryptionroot - -
test_target1/test_source1 encryptionroot - -
test_target1/test_source1/fs1 encryptionroot - -
test_target1/test_source1/fs1/encryptedsource encryptionroot test_target1/test_source1/fs1/encryptedsource -
test_target1/test_source1/fs1/sub encryptionroot - -
test_target1/test_source2 encryptionroot - -
test_target1/test_source2/fs2 encryptionroot - -
test_target1/test_source2/fs2/sub encryptionroot - -
""")

View File

@ -105,3 +105,4 @@ test_target1/test_source2/fs2/sub@test-20101111000000
test_target1/test_source2/fs2/sub@test-20101111000001
""")

View File

@ -866,13 +866,16 @@ class ZfsDataset:
return start_snapshot
def find_incompatible_snapshots(self, common_snapshot):
def find_incompatible_snapshots(self, common_snapshot, raw):
"""returns a list of snapshots that is incompatible for a zfs recv onto
the common_snapshot. all direct followup snapshots with written=0 are
compatible.
in raw-mode nothing is compatible. issue #219
Args:
:type common_snapshot: ZfsDataset
:type raw: bool
"""
ret = []
@ -880,7 +883,7 @@ class ZfsDataset:
if common_snapshot and self.snapshots:
followup = True
for snapshot in self.snapshots[self.find_snapshot_index(common_snapshot) + 1:]:
if not followup or int(snapshot.properties['written']) != 0:
if raw or not followup or int(snapshot.properties['written']) != 0:
followup = False
ret.append(snapshot)
@ -983,7 +986,7 @@ class ZfsDataset:
else:
return resume_token
def _plan_sync(self, target_dataset, also_other_snapshots, guid_check):
def _plan_sync(self, target_dataset, also_other_snapshots, guid_check, raw):
"""plan where to start syncing and what to sync and what to keep
Args:
@ -991,13 +994,14 @@ class ZfsDataset:
:type target_dataset: ZfsDataset
:type also_other_snapshots: bool
:type guid_check: bool
:type raw: bool
"""
# determine common and start snapshot
target_dataset.debug("Determining start snapshot")
common_snapshot = self.find_common_snapshot(target_dataset, guid_check=guid_check)
start_snapshot = self.find_start_snapshot(common_snapshot, also_other_snapshots)
incompatible_target_snapshots = target_dataset.find_incompatible_snapshots(common_snapshot)
incompatible_target_snapshots = target_dataset.find_incompatible_snapshots(common_snapshot, raw)
# let thinner decide whats obsolete on source
source_obsoletes = []
@ -1058,11 +1062,26 @@ class ZfsDataset:
:type guid_check: bool
"""
self.verbose("sending to {}".format(target_dataset))
# self.verbose("-> {}".format(target_dataset))
#defaults for these settings if there is no encryption stuff going on:
send_properties = True
raw = False
write_embedded = True
# source dataset encrypted?
if self.properties.get('encryption', 'off')!='off':
# user wants to send it over decrypted?
if decrypt:
# when decrypting, zfs cant send properties
send_properties=False
else:
# keep data encrypted by sending it raw (including properties)
raw=True
(common_snapshot, start_snapshot, source_obsoletes, target_obsoletes, target_keeps,
incompatible_target_snapshots) = \
self._plan_sync(target_dataset=target_dataset, also_other_snapshots=also_other_snapshots, guid_check=guid_check)
self._plan_sync(target_dataset=target_dataset, also_other_snapshots=also_other_snapshots, guid_check=guid_check, raw=raw)
# NOTE: we do this because we dont want filesystems to fillup when backups keep failing.
# Also usefull with no_send to still cleanup stuff.
@ -1084,23 +1103,9 @@ class ZfsDataset:
if rollback:
target_dataset.rollback()
#defaults for these settings if there is no encryption stuff going on:
send_properties = True
raw = False
write_embedded = True
(active_filter_properties, active_set_properties) = self.get_allowed_properties(filter_properties, set_properties)
# source dataset encrypted?
if self.properties.get('encryption', 'off')!='off':
# user wants to send it over decrypted?
if decrypt:
# when decrypting, zfs cant send properties
send_properties=False
else:
# keep data encrypted by sending it raw (including properties)
raw=True
# encrypt at target?
if encrypt and not raw:
# filter out encryption properties to let encryption on the target take place