|
@@ -0,0 +1,617 @@
|
|
|
+from flexmock import flexmock
|
|
|
+import pytest
|
|
|
+
|
|
|
+from borgmatic.hooks.data_source import lvm as module
|
|
|
+
|
|
|
+
|
|
|
+def test_get_logical_volumes_filters_by_source_directories():
|
|
|
+ flexmock(module.borgmatic.execute).should_receive(
|
|
|
+ 'execute_command_and_capture_output'
|
|
|
+ ).and_return(
|
|
|
+ '''
|
|
|
+ {
|
|
|
+ "blockdevices": [
|
|
|
+ {
|
|
|
+ "name": "vgroup-notmounted",
|
|
|
+ "path": "/dev/mapper/vgroup-notmounted",
|
|
|
+ "mountpoint": null,
|
|
|
+ "type": "lvm"
|
|
|
+ }, {
|
|
|
+ "name": "vgroup-lvolume",
|
|
|
+ "path": "/dev/mapper/vgroup-lvolume",
|
|
|
+ "mountpoint": "/mnt/lvolume",
|
|
|
+ "type": "lvm"
|
|
|
+ }, {
|
|
|
+ "name": "vgroup-other",
|
|
|
+ "path": "/dev/mapper/vgroup-other",
|
|
|
+ "mountpoint": "/mnt/other",
|
|
|
+ "type": "lvm"
|
|
|
+ }, {
|
|
|
+ "name": "vgroup-notlvm",
|
|
|
+ "path": "/dev/mapper/vgroup-notlvm",
|
|
|
+ "mountpoint": "/mnt/notlvm",
|
|
|
+ "type": "notlvm"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ '''
|
|
|
+ )
|
|
|
+ contained = {'/mnt/lvolume', '/mnt/lvolume/subdir'}
|
|
|
+ flexmock(module.borgmatic.hooks.data_source.snapshot).should_receive(
|
|
|
+ 'get_contained_directories'
|
|
|
+ ).with_args(None, contained).never()
|
|
|
+ flexmock(module.borgmatic.hooks.data_source.snapshot).should_receive(
|
|
|
+ 'get_contained_directories'
|
|
|
+ ).with_args('/mnt/lvolume', contained).and_return(('/mnt/lvolume', '/mnt/lvolume/subdir'))
|
|
|
+ flexmock(module.borgmatic.hooks.data_source.snapshot).should_receive(
|
|
|
+ 'get_contained_directories'
|
|
|
+ ).with_args('/mnt/other', contained).and_return(())
|
|
|
+ flexmock(module.borgmatic.hooks.data_source.snapshot).should_receive(
|
|
|
+ 'get_contained_directories'
|
|
|
+ ).with_args('/mnt/notlvm', contained).never()
|
|
|
+
|
|
|
+ assert module.get_logical_volumes(
|
|
|
+ 'lsblk', source_directories=('/mnt/lvolume', '/mnt/lvolume/subdir')
|
|
|
+ ) == (
|
|
|
+ module.Logical_volume(
|
|
|
+ 'vgroup-lvolume',
|
|
|
+ '/dev/mapper/vgroup-lvolume',
|
|
|
+ '/mnt/lvolume',
|
|
|
+ ('/mnt/lvolume', '/mnt/lvolume/subdir'),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+def test_get_logical_volumes_with_invalid_lsblk_json_errors():
|
|
|
+ flexmock(module.borgmatic.execute).should_receive(
|
|
|
+ 'execute_command_and_capture_output'
|
|
|
+ ).and_return('{')
|
|
|
+
|
|
|
+ contained = {'/mnt/lvolume', '/mnt/lvolume/subdir'}
|
|
|
+ flexmock(module.borgmatic.hooks.data_source.snapshot).should_receive(
|
|
|
+ 'get_contained_directories'
|
|
|
+ ).never()
|
|
|
+
|
|
|
+ with pytest.raises(ValueError):
|
|
|
+ module.get_logical_volumes(
|
|
|
+ 'lsblk', source_directories=('/mnt/lvolume', '/mnt/lvolume/subdir')
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+def test_get_logical_volumes_with_lsblk_json_missing_keys_errors():
|
|
|
+ flexmock(module.borgmatic.execute).should_receive(
|
|
|
+ 'execute_command_and_capture_output'
|
|
|
+ ).and_return('{"block_devices": [{}]}')
|
|
|
+
|
|
|
+ contained = {'/mnt/lvolume', '/mnt/lvolume/subdir'}
|
|
|
+ flexmock(module.borgmatic.hooks.data_source.snapshot).should_receive(
|
|
|
+ 'get_contained_directories'
|
|
|
+ ).never()
|
|
|
+
|
|
|
+ with pytest.raises(ValueError):
|
|
|
+ module.get_logical_volumes(
|
|
|
+ 'lsblk', source_directories=('/mnt/lvolume', '/mnt/lvolume/subdir')
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+def test_snapshot_logical_volume_with_percentage_snapshot_name_uses_lvcreate_extents_flag():
|
|
|
+ flexmock(module.borgmatic.execute).should_receive('execute_command').with_args(
|
|
|
+ (
|
|
|
+ 'lvcreate',
|
|
|
+ '--snapshot',
|
|
|
+ '--extents',
|
|
|
+ '10%ORIGIN',
|
|
|
+ '--name',
|
|
|
+ 'snap',
|
|
|
+ '/dev/snap',
|
|
|
+ ),
|
|
|
+ output_log_level=object,
|
|
|
+ )
|
|
|
+
|
|
|
+ module.snapshot_logical_volume('lvcreate', 'snap', '/dev/snap', '10%ORIGIN')
|
|
|
+
|
|
|
+
|
|
|
+def test_snapshot_logical_volume_with_non_percentage_snapshot_name_uses_lvcreate_size_flag():
|
|
|
+ flexmock(module.borgmatic.execute).should_receive('execute_command').with_args(
|
|
|
+ (
|
|
|
+ 'lvcreate',
|
|
|
+ '--snapshot',
|
|
|
+ '--size',
|
|
|
+ '10TB',
|
|
|
+ '--name',
|
|
|
+ 'snap',
|
|
|
+ '/dev/snap',
|
|
|
+ ),
|
|
|
+ output_log_level=object,
|
|
|
+ )
|
|
|
+
|
|
|
+ module.snapshot_logical_volume('lvcreate', 'snap', '/dev/snap', '10TB')
|
|
|
+
|
|
|
+
|
|
|
+def test_dump_data_sources_snapshots_and_mounts_and_updates_source_directories():
|
|
|
+ config = {'lvm': {}}
|
|
|
+ source_directories = ['/mnt/lvolume1/subdir', '/mnt/lvolume2']
|
|
|
+ flexmock(module).should_receive('get_logical_volumes').and_return(
|
|
|
+ (
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume1',
|
|
|
+ device_path='/dev/lvolume1',
|
|
|
+ mount_point='/mnt/lvolume1',
|
|
|
+ contained_source_directories=('/mnt/lvolume1/subdir',),
|
|
|
+ ),
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume2',
|
|
|
+ device_path='/dev/lvolume2',
|
|
|
+ mount_point='/mnt/lvolume2',
|
|
|
+ contained_source_directories=('/mnt/lvolume2',),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ flexmock(module.os).should_receive('getpid').and_return(1234)
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').with_args(
|
|
|
+ 'lvcreate', 'lvolume1_borgmatic-1234', '/dev/lvolume1', module.DEFAULT_SNAPSHOT_SIZE
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').with_args(
|
|
|
+ 'lvcreate', 'lvolume2_borgmatic-1234', '/dev/lvolume2', module.DEFAULT_SNAPSHOT_SIZE
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ 'lvs', snapshot_name='lvolume1_borgmatic-1234'
|
|
|
+ ).and_return(
|
|
|
+ (module.Snapshot(name='lvolume1_borgmatic-1234', device_path='/dev/lvolume1_snap'),)
|
|
|
+ )
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ 'lvs', snapshot_name='lvolume2_borgmatic-1234'
|
|
|
+ ).and_return(
|
|
|
+ (module.Snapshot(name='lvolume2_borgmatic-1234', device_path='/dev/lvolume2_snap'),)
|
|
|
+ )
|
|
|
+ flexmock(module).should_receive('mount_snapshot').with_args(
|
|
|
+ 'mount', '/dev/lvolume1_snap', '/run/borgmatic/lvm_snapshots/mnt/lvolume1'
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('mount_snapshot').with_args(
|
|
|
+ 'mount', '/dev/lvolume2_snap', '/run/borgmatic/lvm_snapshots/mnt/lvolume2'
|
|
|
+ ).once()
|
|
|
+
|
|
|
+ assert (
|
|
|
+ module.dump_data_sources(
|
|
|
+ hook_config=config['lvm'],
|
|
|
+ config=config,
|
|
|
+ log_prefix='test',
|
|
|
+ config_paths=('test.yaml',),
|
|
|
+ borgmatic_runtime_directory='/run/borgmatic',
|
|
|
+ source_directories=source_directories,
|
|
|
+ dry_run=False,
|
|
|
+ )
|
|
|
+ == []
|
|
|
+ )
|
|
|
+
|
|
|
+ assert source_directories == [
|
|
|
+ '/run/borgmatic/lvm_snapshots/./mnt/lvolume1/subdir',
|
|
|
+ '/run/borgmatic/lvm_snapshots/./mnt/lvolume2',
|
|
|
+ ]
|
|
|
+
|
|
|
+
|
|
|
+def test_dump_data_sources_with_no_logical_volumes_skips_snapshots():
|
|
|
+ config = {'lvm': {}}
|
|
|
+ source_directories = ['/mnt/lvolume1/subdir', '/mnt/lvolume2']
|
|
|
+ flexmock(module).should_receive('get_logical_volumes').and_return(())
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').never()
|
|
|
+ flexmock(module).should_receive('mount_snapshot').never()
|
|
|
+
|
|
|
+ assert (
|
|
|
+ module.dump_data_sources(
|
|
|
+ hook_config=config['lvm'],
|
|
|
+ config=config,
|
|
|
+ log_prefix='test',
|
|
|
+ config_paths=('test.yaml',),
|
|
|
+ borgmatic_runtime_directory='/run/borgmatic',
|
|
|
+ source_directories=source_directories,
|
|
|
+ dry_run=False,
|
|
|
+ )
|
|
|
+ == []
|
|
|
+ )
|
|
|
+
|
|
|
+ assert source_directories == ['/mnt/lvolume1/subdir', '/mnt/lvolume2']
|
|
|
+
|
|
|
+
|
|
|
+def test_dump_data_sources_uses_snapshot_size_for_snapshot():
|
|
|
+ config = {'lvm': {'snapshot_size': '1000PB'}}
|
|
|
+ source_directories = ['/mnt/lvolume1/subdir', '/mnt/lvolume2']
|
|
|
+ flexmock(module).should_receive('get_logical_volumes').and_return(
|
|
|
+ (
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume1',
|
|
|
+ device_path='/dev/lvolume1',
|
|
|
+ mount_point='/mnt/lvolume1',
|
|
|
+ contained_source_directories=('/mnt/lvolume1/subdir',),
|
|
|
+ ),
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume2',
|
|
|
+ device_path='/dev/lvolume2',
|
|
|
+ mount_point='/mnt/lvolume2',
|
|
|
+ contained_source_directories=('/mnt/lvolume2',),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ flexmock(module.os).should_receive('getpid').and_return(1234)
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').with_args(
|
|
|
+ 'lvcreate',
|
|
|
+ 'lvolume1_borgmatic-1234',
|
|
|
+ '/dev/lvolume1',
|
|
|
+ '1000PB',
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').with_args(
|
|
|
+ 'lvcreate',
|
|
|
+ 'lvolume2_borgmatic-1234',
|
|
|
+ '/dev/lvolume2',
|
|
|
+ '1000PB',
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ 'lvs', snapshot_name='lvolume1_borgmatic-1234'
|
|
|
+ ).and_return(
|
|
|
+ (module.Snapshot(name='lvolume1_borgmatic-1234', device_path='/dev/lvolume1_snap'),)
|
|
|
+ )
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ 'lvs', snapshot_name='lvolume2_borgmatic-1234'
|
|
|
+ ).and_return(
|
|
|
+ (module.Snapshot(name='lvolume2_borgmatic-1234', device_path='/dev/lvolume2_snap'),)
|
|
|
+ )
|
|
|
+ flexmock(module).should_receive('mount_snapshot').with_args(
|
|
|
+ 'mount', '/dev/lvolume1_snap', '/run/borgmatic/lvm_snapshots/mnt/lvolume1'
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('mount_snapshot').with_args(
|
|
|
+ 'mount', '/dev/lvolume2_snap', '/run/borgmatic/lvm_snapshots/mnt/lvolume2'
|
|
|
+ ).once()
|
|
|
+
|
|
|
+ assert (
|
|
|
+ module.dump_data_sources(
|
|
|
+ hook_config=config['lvm'],
|
|
|
+ config=config,
|
|
|
+ log_prefix='test',
|
|
|
+ config_paths=('test.yaml',),
|
|
|
+ borgmatic_runtime_directory='/run/borgmatic',
|
|
|
+ source_directories=source_directories,
|
|
|
+ dry_run=False,
|
|
|
+ )
|
|
|
+ == []
|
|
|
+ )
|
|
|
+
|
|
|
+ assert source_directories == [
|
|
|
+ '/run/borgmatic/lvm_snapshots/./mnt/lvolume1/subdir',
|
|
|
+ '/run/borgmatic/lvm_snapshots/./mnt/lvolume2',
|
|
|
+ ]
|
|
|
+
|
|
|
+
|
|
|
+def test_dump_data_sources_uses_custom_commands():
|
|
|
+ config = {
|
|
|
+ 'lvm': {
|
|
|
+ 'lsblk_command': '/usr/local/bin/lsblk',
|
|
|
+ 'lvcreate_command': '/usr/local/bin/lvcreate',
|
|
|
+ 'lvs_command': '/usr/local/bin/lvs',
|
|
|
+ 'mount_command': '/usr/local/bin/mount',
|
|
|
+ },
|
|
|
+ }
|
|
|
+ source_directories = ['/mnt/lvolume1/subdir', '/mnt/lvolume2']
|
|
|
+ flexmock(module).should_receive('get_logical_volumes').and_return(
|
|
|
+ (
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume1',
|
|
|
+ device_path='/dev/lvolume1',
|
|
|
+ mount_point='/mnt/lvolume1',
|
|
|
+ contained_source_directories=('/mnt/lvolume1/subdir',),
|
|
|
+ ),
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume2',
|
|
|
+ device_path='/dev/lvolume2',
|
|
|
+ mount_point='/mnt/lvolume2',
|
|
|
+ contained_source_directories=('/mnt/lvolume2',),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ flexmock(module.os).should_receive('getpid').and_return(1234)
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').with_args(
|
|
|
+ '/usr/local/bin/lvcreate',
|
|
|
+ 'lvolume1_borgmatic-1234',
|
|
|
+ '/dev/lvolume1',
|
|
|
+ module.DEFAULT_SNAPSHOT_SIZE,
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').with_args(
|
|
|
+ '/usr/local/bin/lvcreate',
|
|
|
+ 'lvolume2_borgmatic-1234',
|
|
|
+ '/dev/lvolume2',
|
|
|
+ module.DEFAULT_SNAPSHOT_SIZE,
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ '/usr/local/bin/lvs', snapshot_name='lvolume1_borgmatic-1234'
|
|
|
+ ).and_return(
|
|
|
+ (module.Snapshot(name='lvolume1_borgmatic-1234', device_path='/dev/lvolume1_snap'),)
|
|
|
+ )
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ '/usr/local/bin/lvs', snapshot_name='lvolume2_borgmatic-1234'
|
|
|
+ ).and_return(
|
|
|
+ (module.Snapshot(name='lvolume2_borgmatic-1234', device_path='/dev/lvolume2_snap'),)
|
|
|
+ )
|
|
|
+ flexmock(module).should_receive('mount_snapshot').with_args(
|
|
|
+ '/usr/local/bin/mount', '/dev/lvolume1_snap', '/run/borgmatic/lvm_snapshots/mnt/lvolume1'
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('mount_snapshot').with_args(
|
|
|
+ '/usr/local/bin/mount', '/dev/lvolume2_snap', '/run/borgmatic/lvm_snapshots/mnt/lvolume2'
|
|
|
+ ).once()
|
|
|
+
|
|
|
+ assert (
|
|
|
+ module.dump_data_sources(
|
|
|
+ hook_config=config['lvm'],
|
|
|
+ config=config,
|
|
|
+ log_prefix='test',
|
|
|
+ config_paths=('test.yaml',),
|
|
|
+ borgmatic_runtime_directory='/run/borgmatic',
|
|
|
+ source_directories=source_directories,
|
|
|
+ dry_run=False,
|
|
|
+ )
|
|
|
+ == []
|
|
|
+ )
|
|
|
+
|
|
|
+ assert source_directories == [
|
|
|
+ '/run/borgmatic/lvm_snapshots/./mnt/lvolume1/subdir',
|
|
|
+ '/run/borgmatic/lvm_snapshots/./mnt/lvolume2',
|
|
|
+ ]
|
|
|
+
|
|
|
+
|
|
|
+def test_dump_data_sources_with_dry_run_skips_snapshots_and_does_not_touch_source_directories():
|
|
|
+ config = {'lvm': {}}
|
|
|
+ source_directories = ['/mnt/lvolume1/subdir', '/mnt/lvolume2']
|
|
|
+ flexmock(module).should_receive('get_logical_volumes').and_return(
|
|
|
+ (
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume1',
|
|
|
+ device_path='/dev/lvolume1',
|
|
|
+ mount_point='/mnt/lvolume1',
|
|
|
+ contained_source_directories=('/mnt/lvolume1/subdir',),
|
|
|
+ ),
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume2',
|
|
|
+ device_path='/dev/lvolume2',
|
|
|
+ mount_point='/mnt/lvolume2',
|
|
|
+ contained_source_directories=('/mnt/lvolume2',),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ flexmock(module.os).should_receive('getpid').and_return(1234)
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').never()
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ 'lvs', snapshot_name='lvolume1_borgmatic-1234'
|
|
|
+ ).and_return(
|
|
|
+ (module.Snapshot(name='lvolume1_borgmatic-1234', device_path='/dev/lvolume1_snap'),)
|
|
|
+ )
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ 'lvs', snapshot_name='lvolume2_borgmatic-1234'
|
|
|
+ ).and_return(
|
|
|
+ (module.Snapshot(name='lvolume2_borgmatic-1234', device_path='/dev/lvolume2_snap'),)
|
|
|
+ )
|
|
|
+ flexmock(module).should_receive('mount_snapshot').never()
|
|
|
+
|
|
|
+ assert (
|
|
|
+ module.dump_data_sources(
|
|
|
+ hook_config=config['lvm'],
|
|
|
+ config=config,
|
|
|
+ log_prefix='test',
|
|
|
+ config_paths=('test.yaml',),
|
|
|
+ borgmatic_runtime_directory='/run/borgmatic',
|
|
|
+ source_directories=source_directories,
|
|
|
+ dry_run=True,
|
|
|
+ )
|
|
|
+ == []
|
|
|
+ )
|
|
|
+
|
|
|
+ assert source_directories == [
|
|
|
+ '/mnt/lvolume1/subdir',
|
|
|
+ '/mnt/lvolume2',
|
|
|
+ ]
|
|
|
+
|
|
|
+
|
|
|
+def test_dump_data_sources_ignores_mismatch_between_source_directories_and_contained_source_directories():
|
|
|
+ config = {'lvm': {}}
|
|
|
+ source_directories = ['/hmm']
|
|
|
+ flexmock(module).should_receive('get_logical_volumes').and_return(
|
|
|
+ (
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume1',
|
|
|
+ device_path='/dev/lvolume1',
|
|
|
+ mount_point='/mnt/lvolume1',
|
|
|
+ contained_source_directories=('/mnt/lvolume1/subdir',),
|
|
|
+ ),
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume2',
|
|
|
+ device_path='/dev/lvolume2',
|
|
|
+ mount_point='/mnt/lvolume2',
|
|
|
+ contained_source_directories=('/mnt/lvolume2',),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ flexmock(module.os).should_receive('getpid').and_return(1234)
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').with_args(
|
|
|
+ 'lvcreate', 'lvolume1_borgmatic-1234', '/dev/lvolume1', module.DEFAULT_SNAPSHOT_SIZE
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').with_args(
|
|
|
+ 'lvcreate', 'lvolume2_borgmatic-1234', '/dev/lvolume2', module.DEFAULT_SNAPSHOT_SIZE
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ 'lvs', snapshot_name='lvolume1_borgmatic-1234'
|
|
|
+ ).and_return(
|
|
|
+ (module.Snapshot(name='lvolume1_borgmatic-1234', device_path='/dev/lvolume1_snap'),)
|
|
|
+ )
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ 'lvs', snapshot_name='lvolume2_borgmatic-1234'
|
|
|
+ ).and_return(
|
|
|
+ (module.Snapshot(name='lvolume2_borgmatic-1234', device_path='/dev/lvolume2_snap'),)
|
|
|
+ )
|
|
|
+ flexmock(module).should_receive('mount_snapshot').with_args(
|
|
|
+ 'mount', '/dev/lvolume1_snap', '/run/borgmatic/lvm_snapshots/mnt/lvolume1'
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('mount_snapshot').with_args(
|
|
|
+ 'mount', '/dev/lvolume2_snap', '/run/borgmatic/lvm_snapshots/mnt/lvolume2'
|
|
|
+ ).once()
|
|
|
+
|
|
|
+ assert (
|
|
|
+ module.dump_data_sources(
|
|
|
+ hook_config=config['lvm'],
|
|
|
+ config=config,
|
|
|
+ log_prefix='test',
|
|
|
+ config_paths=('test.yaml',),
|
|
|
+ borgmatic_runtime_directory='/run/borgmatic',
|
|
|
+ source_directories=source_directories,
|
|
|
+ dry_run=False,
|
|
|
+ )
|
|
|
+ == []
|
|
|
+ )
|
|
|
+
|
|
|
+ assert source_directories == [
|
|
|
+ '/hmm',
|
|
|
+ '/run/borgmatic/lvm_snapshots/./mnt/lvolume1/subdir',
|
|
|
+ '/run/borgmatic/lvm_snapshots/./mnt/lvolume2',
|
|
|
+ ]
|
|
|
+
|
|
|
+
|
|
|
+def test_dump_data_sources_with_missing_snapshot_errors():
|
|
|
+ config = {'lvm': {}}
|
|
|
+ source_directories = ['/mnt/lvolume1/subdir', '/mnt/lvolume2']
|
|
|
+ flexmock(module).should_receive('get_logical_volumes').and_return(
|
|
|
+ (
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume1',
|
|
|
+ device_path='/dev/lvolume1',
|
|
|
+ mount_point='/mnt/lvolume1',
|
|
|
+ contained_source_directories=('/mnt/lvolume1/subdir',),
|
|
|
+ ),
|
|
|
+ module.Logical_volume(
|
|
|
+ name='lvolume2',
|
|
|
+ device_path='/dev/lvolume2',
|
|
|
+ mount_point='/mnt/lvolume2',
|
|
|
+ contained_source_directories=('/mnt/lvolume2',),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ flexmock(module.os).should_receive('getpid').and_return(1234)
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').with_args(
|
|
|
+ 'lvcreate', 'lvolume1_borgmatic-1234', '/dev/lvolume1', module.DEFAULT_SNAPSHOT_SIZE
|
|
|
+ ).once()
|
|
|
+ flexmock(module).should_receive('snapshot_logical_volume').with_args(
|
|
|
+ 'lvcreate', 'lvolume2_borgmatic-1234', '/dev/lvolume2', module.DEFAULT_SNAPSHOT_SIZE
|
|
|
+ ).never()
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ 'lvs', snapshot_name='lvolume1_borgmatic-1234'
|
|
|
+ ).and_return(())
|
|
|
+ flexmock(module).should_receive('get_snapshots').with_args(
|
|
|
+ 'lvs', snapshot_name='lvolume2_borgmatic-1234'
|
|
|
+ ).never()
|
|
|
+ flexmock(module).should_receive('mount_snapshot').never()
|
|
|
+
|
|
|
+ with pytest.raises(ValueError):
|
|
|
+ module.dump_data_sources(
|
|
|
+ hook_config=config['lvm'],
|
|
|
+ config=config,
|
|
|
+ log_prefix='test',
|
|
|
+ config_paths=('test.yaml',),
|
|
|
+ borgmatic_runtime_directory='/run/borgmatic',
|
|
|
+ source_directories=source_directories,
|
|
|
+ dry_run=False,
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+def test_get_snapshots_lists_all_snapshots():
|
|
|
+ flexmock(module.borgmatic.execute).should_receive(
|
|
|
+ 'execute_command_and_capture_output'
|
|
|
+ ).and_return(
|
|
|
+ '''
|
|
|
+ {
|
|
|
+ "report": [
|
|
|
+ {
|
|
|
+ "lv": [
|
|
|
+ {"lv_name": "snap1", "lv_path": "/dev/snap1"},
|
|
|
+ {"lv_name": "snap2", "lv_path": "/dev/snap2"}
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "log": [
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ '''
|
|
|
+ )
|
|
|
+
|
|
|
+ assert module.get_snapshots('lvs') == (
|
|
|
+ module.Snapshot('snap1', '/dev/snap1'),
|
|
|
+ module.Snapshot('snap2', '/dev/snap2'),
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+def test_get_snapshots_with_snapshot_name_lists_just_that_snapshot():
|
|
|
+ flexmock(module.borgmatic.execute).should_receive(
|
|
|
+ 'execute_command_and_capture_output'
|
|
|
+ ).and_return(
|
|
|
+ '''
|
|
|
+ {
|
|
|
+ "report": [
|
|
|
+ {
|
|
|
+ "lv": [
|
|
|
+ {"lv_name": "snap1", "lv_path": "/dev/snap1"},
|
|
|
+ {"lv_name": "snap2", "lv_path": "/dev/snap2"}
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "log": [
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ '''
|
|
|
+ )
|
|
|
+
|
|
|
+ assert module.get_snapshots('lvs', snapshot_name='snap2') == (
|
|
|
+ module.Snapshot('snap2', '/dev/snap2'),
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+def test_get_snapshots_with_invalid_lvs_json_errors():
|
|
|
+ flexmock(module.borgmatic.execute).should_receive(
|
|
|
+ 'execute_command_and_capture_output'
|
|
|
+ ).and_return('{')
|
|
|
+
|
|
|
+ with pytest.raises(ValueError):
|
|
|
+ assert module.get_snapshots('lvs')
|
|
|
+
|
|
|
+
|
|
|
+def test_get_snapshots_with_lvs_json_missing_report_errors():
|
|
|
+ flexmock(module.borgmatic.execute).should_receive(
|
|
|
+ 'execute_command_and_capture_output'
|
|
|
+ ).and_return(
|
|
|
+ '''
|
|
|
+ {
|
|
|
+ "report": [],
|
|
|
+ "log": [
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ '''
|
|
|
+ )
|
|
|
+
|
|
|
+ with pytest.raises(ValueError):
|
|
|
+ assert module.get_snapshots('lvs')
|
|
|
+
|
|
|
+
|
|
|
+def test_get_snapshots_with_lvs_json_missing_keys_errors():
|
|
|
+ flexmock(module.borgmatic.execute).should_receive(
|
|
|
+ 'execute_command_and_capture_output'
|
|
|
+ ).and_return(
|
|
|
+ '''
|
|
|
+ {
|
|
|
+ "report": [
|
|
|
+ {
|
|
|
+ "lv": [
|
|
|
+ {}
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "log": [
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ '''
|
|
|
+ )
|
|
|
+
|
|
|
+ with pytest.raises(ValueError):
|
|
|
+ assert module.get_snapshots('lvs')
|