From 37efaeae88f289e2da06bee32cf4d77005acd3ef Mon Sep 17 00:00:00 2001 From: Dan Helfman Date: Sat, 30 Nov 2024 10:55:30 -0800 Subject: [PATCH] Warn if Btrfs is configured but there are no Btrfs subvolumes detected (#251). --- borgmatic/hooks/data_source/btrfs.py | 8 ++++++-- borgmatic/hooks/data_source/zfs.py | 3 +++ tests/unit/hooks/data_source/test_zfs.py | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/borgmatic/hooks/data_source/btrfs.py b/borgmatic/hooks/data_source/btrfs.py index 7ab0f12f..3d812356 100644 --- a/borgmatic/hooks/data_source/btrfs.py +++ b/borgmatic/hooks/data_source/btrfs.py @@ -171,14 +171,18 @@ def dump_data_sources( If this is a dry run, then don't actually snapshot anything. ''' dry_run_label = ' (dry run; not actually snapshotting anything)' if dry_run else '' - logger.info(f'{log_prefix}: Snapshotting Btrfs datasets{dry_run_label}') + logger.info(f'{log_prefix}: Snapshotting Btrfs subvolumes{dry_run_label}') # Based on the configured source directories, determine Btrfs subvolumes to backup. btrfs_command = hook_config.get('btrfs_command', 'btrfs') findmnt_command = hook_config.get('findmnt_command', 'findmnt') + subvolumes = get_subvolumes(btrfs_command, findmnt_command, source_directories) + + if not subvolumes: + logger.warning(f'{log_prefix}: No Btrfs subvolumes found to snapshot{dry_run_label}') # Snapshot each subvolume, rewriting source directories to use their snapshot paths. - for subvolume_path in get_subvolumes(btrfs_command, findmnt_command, source_directories): + for subvolume_path in subvolumes: logger.debug(f'{log_prefix}: Creating Btrfs snapshot for {subvolume_path} subvolume') snapshot_path = make_snapshot_path(subvolume_path) diff --git a/borgmatic/hooks/data_source/zfs.py b/borgmatic/hooks/data_source/zfs.py index a9e44c9d..5f011a1c 100644 --- a/borgmatic/hooks/data_source/zfs.py +++ b/borgmatic/hooks/data_source/zfs.py @@ -148,6 +148,9 @@ def dump_data_sources( # Snapshot each dataset, rewriting source directories to use the snapshot paths. snapshot_name = f'{BORGMATIC_SNAPSHOT_PREFIX}{os.getpid()}' + if not requested_datasets: + logger.warning(f'{log_prefix}: No ZFS datasets found to snapshot{dry_run_label}') + for dataset_name, mount_point in requested_datasets: full_snapshot_name = f'{dataset_name}@{snapshot_name}' logger.debug(f'{log_prefix}: Creating ZFS snapshot {full_snapshot_name}{dry_run_label}') diff --git a/tests/unit/hooks/data_source/test_zfs.py b/tests/unit/hooks/data_source/test_zfs.py index cbb8cc9d..2eea24f7 100644 --- a/tests/unit/hooks/data_source/test_zfs.py +++ b/tests/unit/hooks/data_source/test_zfs.py @@ -97,6 +97,29 @@ def test_dump_data_sources_snapshots_and_mounts_and_updates_source_directories() assert source_directories == [snapshot_mount_path] +def test_dump_data_sources_snapshots_with_no_datasets_skips_snapshots(): + flexmock(module).should_receive('get_datasets_to_backup').and_return(()) + flexmock(module.os).should_receive('getpid').and_return(1234) + flexmock(module).should_receive('snapshot_dataset').never() + flexmock(module).should_receive('mount_snapshot').never() + source_directories = ['/mnt/dataset'] + + assert ( + module.dump_data_sources( + hook_config={}, + config={'source_directories': '/mnt/dataset', 'zfs': {}}, + log_prefix='test', + config_paths=('test.yaml',), + borgmatic_runtime_directory='/run/borgmatic', + source_directories=source_directories, + dry_run=False, + ) + == [] + ) + + assert source_directories == ['/mnt/dataset'] + + def test_dump_data_sources_uses_custom_commands(): flexmock(module).should_receive('get_datasets_to_backup').and_return( (('dataset', '/mnt/dataset'),)