Fix an error in the Btrfs hook when a "/" subvolume is configured in borgmatic's source directories (#959).
All checks were successful
build / test (push) Successful in 6m59s
build / docs (push) Successful in 2m7s

This commit is contained in:
Dan Helfman 2024-12-28 09:57:33 -08:00
parent 87e77ff2b7
commit d3409df84c
4 changed files with 45 additions and 8 deletions

4
NEWS
View File

@ -1,3 +1,7 @@
1.9.6.dev0
* #959: Fix an error in the Btrfs hook when a "/" subvolume is configured in borgmatic's source
directories.
1.9.5
* #418: Backup and restore databases that have the same name but with different ports, hostnames,
or hooks.

View File

@ -115,17 +115,15 @@ def get_subvolumes(btrfs_command, findmnt_command, source_directories=None):
BORGMATIC_SNAPSHOT_PREFIX = '.borgmatic-snapshot-'
def make_snapshot_path(subvolume_path): # pragma: no cover
def make_snapshot_path(subvolume_path):
'''
Given the path to a subvolume, make a corresponding snapshot path for it.
'''
return os.path.join(
subvolume_path,
f'{BORGMATIC_SNAPSHOT_PREFIX}{os.getpid()}',
# Included so that the snapshot ends up in the Borg archive at the "original" subvolume
# path.
subvolume_path.lstrip(os.path.sep),
)
# Included so that the snapshot ends up in the Borg archive at the "original" subvolume path.
) + subvolume_path.rstrip(os.path.sep)
def make_snapshot_exclude_path(subvolume_path): # pragma: no cover
@ -155,7 +153,7 @@ def make_snapshot_exclude_path(subvolume_path): # pragma: no cover
)
def make_borg_source_directory_path(subvolume_path, source_directory): # pragma: no cover
def make_borg_source_directory_path(subvolume_path, source_directory):
'''
Given the path to a subvolume and a source directory inside it, make a corresponding path for
the source directory within a snapshot path intended for giving to Borg.
@ -181,7 +179,7 @@ def snapshot_subvolume(btrfs_command, subvolume_path, snapshot_path): # pragma:
+ (
'subvolume',
'snapshot',
'-r', # Read-only,
'-r', # Read-only.
subvolume_path,
snapshot_path,
),

View File

@ -1,6 +1,6 @@
[project]
name = "borgmatic"
version = "1.9.5"
version = "1.9.6.dev0"
authors = [
{ name="Dan Helfman", email="witten@torsion.org" },
]

View File

@ -128,6 +128,41 @@ def test_get_subvolumes_without_source_directories_collects_all_subvolumes_from_
)
@pytest.mark.parametrize(
'subvolume_path,expected_snapshot_path',
(
('/foo/bar', '/foo/bar/.borgmatic-snapshot-1234/foo/bar'),
('/', '/.borgmatic-snapshot-1234'),
),
)
def test_make_snapshot_path_includes_stripped_subvolume_path(
subvolume_path, expected_snapshot_path
):
flexmock(module.os).should_receive('getpid').and_return(1234)
assert module.make_snapshot_path(subvolume_path) == expected_snapshot_path
@pytest.mark.parametrize(
'subvolume_path,source_directory_path,expected_path',
(
('/foo/bar', '/foo/bar/baz', '/foo/bar/.borgmatic-snapshot-1234/./foo/bar/baz'),
('/foo/bar', '/foo/bar', '/foo/bar/.borgmatic-snapshot-1234/./foo/bar'),
('/', '/foo', '/.borgmatic-snapshot-1234/./foo'),
('/', '/', '/.borgmatic-snapshot-1234/./'),
),
)
def test_make_borg_source_directory_path_includes_slashdot_hack_and_stripped_source_directory_path(
subvolume_path, source_directory_path, expected_path
):
flexmock(module.os).should_receive('getpid').and_return(1234)
assert (
module.make_borg_source_directory_path(subvolume_path, source_directory_path)
== expected_path
)
def test_dump_data_sources_snapshots_each_subvolume_and_updates_source_directories():
source_directories = ['/foo', '/mnt/subvol1']
config = {'btrfs': {}}