mirror of
https://projects.torsion.org/witten/borgmatic.git
synced 2025-01-08 17:43:09 +00:00
1110 lines
40 KiB
Python
1110 lines
40 KiB
Python
import pytest
|
|
from flexmock import flexmock
|
|
|
|
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('{')
|
|
|
|
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": [{}]}')
|
|
|
|
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',
|
|
'--permission',
|
|
'r',
|
|
'--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',
|
|
'--permission',
|
|
'r',
|
|
'--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')
|
|
|
|
|
|
def test_remove_data_source_dumps_unmounts_and_remove_snapshots():
|
|
config = {'lvm': {}}
|
|
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.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).and_return('/run/borgmatic')
|
|
flexmock(module.glob).should_receive('glob').replace_with(lambda path: [path])
|
|
flexmock(module.os.path).should_receive('isdir').and_return(True)
|
|
flexmock(module.shutil).should_receive('rmtree')
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume1',
|
|
).once()
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume2',
|
|
).once()
|
|
flexmock(module).should_receive('get_snapshots').and_return(
|
|
(
|
|
module.Snapshot('lvolume1_borgmatic-1234', '/dev/lvolume1'),
|
|
module.Snapshot('lvolume2_borgmatic-1234', '/dev/lvolume2'),
|
|
module.Snapshot('nonborgmatic', '/dev/nonborgmatic'),
|
|
),
|
|
)
|
|
flexmock(module).should_receive('remove_snapshot').with_args('lvremove', '/dev/lvolume1').once()
|
|
flexmock(module).should_receive('remove_snapshot').with_args('lvremove', '/dev/lvolume2').once()
|
|
flexmock(module).should_receive('remove_snapshot').with_args(
|
|
'nonborgmatic', '/dev/nonborgmatic'
|
|
).never()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=config['lvm'],
|
|
config=config,
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=False,
|
|
)
|
|
|
|
|
|
def test_remove_data_source_dumps_bails_for_missing_lvm_configuration():
|
|
flexmock(module).should_receive('get_logical_volumes').never()
|
|
flexmock(module.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).never()
|
|
flexmock(module).should_receive('unmount_snapshot').never()
|
|
flexmock(module).should_receive('remove_snapshot').never()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=None,
|
|
config={'source_directories': '/mnt/lvolume'},
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=False,
|
|
)
|
|
|
|
|
|
def test_remove_data_source_dumps_bails_for_missing_lsblk_command():
|
|
config = {'lvm': {}}
|
|
flexmock(module).should_receive('get_logical_volumes').and_raise(FileNotFoundError)
|
|
flexmock(module.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).never()
|
|
flexmock(module).should_receive('unmount_snapshot').never()
|
|
flexmock(module).should_receive('remove_snapshot').never()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=config['lvm'],
|
|
config=config,
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=False,
|
|
)
|
|
|
|
|
|
def test_remove_data_source_dumps_bails_for_lsblk_command_error():
|
|
config = {'lvm': {}}
|
|
flexmock(module).should_receive('get_logical_volumes').and_raise(
|
|
module.subprocess.CalledProcessError(1, 'wtf')
|
|
)
|
|
flexmock(module.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).never()
|
|
flexmock(module).should_receive('unmount_snapshot').never()
|
|
flexmock(module).should_receive('remove_snapshot').never()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=config['lvm'],
|
|
config=config,
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=False,
|
|
)
|
|
|
|
|
|
def test_remove_data_source_dumps_with_missing_snapshot_directory_skips_unmount():
|
|
config = {'lvm': {}}
|
|
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.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).and_return('/run/borgmatic')
|
|
flexmock(module.glob).should_receive('glob').replace_with(lambda path: [path])
|
|
flexmock(module.os.path).should_receive('isdir').with_args(
|
|
'/run/borgmatic/lvm_snapshots'
|
|
).and_return(False)
|
|
flexmock(module.shutil).should_receive('rmtree').never()
|
|
flexmock(module).should_receive('unmount_snapshot').never()
|
|
flexmock(module).should_receive('get_snapshots').and_return(
|
|
(
|
|
module.Snapshot('lvolume1_borgmatic-1234', '/dev/lvolume1'),
|
|
module.Snapshot('lvolume2_borgmatic-1234', '/dev/lvolume2'),
|
|
),
|
|
)
|
|
flexmock(module).should_receive('remove_snapshot').with_args('lvremove', '/dev/lvolume1').once()
|
|
flexmock(module).should_receive('remove_snapshot').with_args('lvremove', '/dev/lvolume2').once()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=config['lvm'],
|
|
config=config,
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=False,
|
|
)
|
|
|
|
|
|
def test_remove_data_source_dumps_with_missing_snapshot_mount_path_skips_unmount():
|
|
config = {'lvm': {}}
|
|
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.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).and_return('/run/borgmatic')
|
|
flexmock(module.glob).should_receive('glob').replace_with(lambda path: [path])
|
|
flexmock(module.os.path).should_receive('isdir').with_args(
|
|
'/run/borgmatic/lvm_snapshots'
|
|
).and_return(True)
|
|
flexmock(module.os.path).should_receive('isdir').with_args(
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume1'
|
|
).and_return(False)
|
|
flexmock(module.os.path).should_receive('isdir').with_args(
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume2'
|
|
).and_return(True)
|
|
flexmock(module.shutil).should_receive('rmtree')
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume1',
|
|
).never()
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume2',
|
|
).once()
|
|
flexmock(module).should_receive('get_snapshots').and_return(
|
|
(
|
|
module.Snapshot('lvolume1_borgmatic-1234', '/dev/lvolume1'),
|
|
module.Snapshot('lvolume2_borgmatic-1234', '/dev/lvolume2'),
|
|
),
|
|
)
|
|
flexmock(module).should_receive('remove_snapshot').with_args('lvremove', '/dev/lvolume1').once()
|
|
flexmock(module).should_receive('remove_snapshot').with_args('lvremove', '/dev/lvolume2').once()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=config['lvm'],
|
|
config=config,
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=False,
|
|
)
|
|
|
|
|
|
def test_remove_data_source_dumps_with_successful_mount_point_removal_skips_unmount():
|
|
config = {'lvm': {}}
|
|
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.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).and_return('/run/borgmatic')
|
|
flexmock(module.glob).should_receive('glob').replace_with(lambda path: [path])
|
|
flexmock(module.os.path).should_receive('isdir').with_args(
|
|
'/run/borgmatic/lvm_snapshots'
|
|
).and_return(True)
|
|
flexmock(module.os.path).should_receive('isdir').with_args(
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume1'
|
|
).and_return(True).and_return(False)
|
|
flexmock(module.os.path).should_receive('isdir').with_args(
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume2'
|
|
).and_return(True).and_return(True)
|
|
flexmock(module.shutil).should_receive('rmtree')
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume1',
|
|
).never()
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume2',
|
|
).once()
|
|
flexmock(module).should_receive('get_snapshots').and_return(
|
|
(
|
|
module.Snapshot('lvolume1_borgmatic-1234', '/dev/lvolume1'),
|
|
module.Snapshot('lvolume2_borgmatic-1234', '/dev/lvolume2'),
|
|
),
|
|
)
|
|
flexmock(module).should_receive('remove_snapshot').with_args('lvremove', '/dev/lvolume1').once()
|
|
flexmock(module).should_receive('remove_snapshot').with_args('lvremove', '/dev/lvolume2').once()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=config['lvm'],
|
|
config=config,
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=False,
|
|
)
|
|
|
|
|
|
def test_remove_data_source_dumps_bails_for_missing_umount_command():
|
|
config = {'lvm': {}}
|
|
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.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).and_return('/run/borgmatic')
|
|
flexmock(module.glob).should_receive('glob').replace_with(lambda path: [path])
|
|
flexmock(module.os.path).should_receive('isdir').and_return(True)
|
|
flexmock(module.shutil).should_receive('rmtree')
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume1',
|
|
).and_raise(FileNotFoundError)
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume2',
|
|
).never()
|
|
flexmock(module).should_receive('get_snapshots').never()
|
|
flexmock(module).should_receive('remove_snapshot').never()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=config['lvm'],
|
|
config=config,
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=False,
|
|
)
|
|
|
|
|
|
def test_remove_data_source_dumps_bails_for_umount_command_error():
|
|
config = {'lvm': {}}
|
|
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.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).and_return('/run/borgmatic')
|
|
flexmock(module.glob).should_receive('glob').replace_with(lambda path: [path])
|
|
flexmock(module.os.path).should_receive('isdir').and_return(True)
|
|
flexmock(module.shutil).should_receive('rmtree')
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume1',
|
|
).and_raise(module.subprocess.CalledProcessError(1, 'wtf'))
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume2',
|
|
).never()
|
|
flexmock(module).should_receive('get_snapshots').never()
|
|
flexmock(module).should_receive('remove_snapshot').never()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=config['lvm'],
|
|
config=config,
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=False,
|
|
)
|
|
|
|
|
|
def test_remove_data_source_dumps_bails_for_missing_lvs_command():
|
|
config = {'lvm': {}}
|
|
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.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).and_return('/run/borgmatic')
|
|
flexmock(module.glob).should_receive('glob').replace_with(lambda path: [path])
|
|
flexmock(module.os.path).should_receive('isdir').and_return(True)
|
|
flexmock(module.shutil).should_receive('rmtree')
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume1',
|
|
).once()
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume2',
|
|
).once()
|
|
flexmock(module).should_receive('get_snapshots').and_raise(FileNotFoundError)
|
|
flexmock(module).should_receive('remove_snapshot').never()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=config['lvm'],
|
|
config=config,
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=False,
|
|
)
|
|
|
|
|
|
def test_remove_data_source_dumps_bails_for_lvs_command_error():
|
|
config = {'lvm': {}}
|
|
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.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).and_return('/run/borgmatic')
|
|
flexmock(module.glob).should_receive('glob').replace_with(lambda path: [path])
|
|
flexmock(module.os.path).should_receive('isdir').and_return(True)
|
|
flexmock(module.shutil).should_receive('rmtree')
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume1',
|
|
).once()
|
|
flexmock(module).should_receive('unmount_snapshot').with_args(
|
|
'umount',
|
|
'/run/borgmatic/lvm_snapshots/mnt/lvolume2',
|
|
).once()
|
|
flexmock(module).should_receive('get_snapshots').and_raise(
|
|
module.subprocess.CalledProcessError(1, 'wtf')
|
|
)
|
|
flexmock(module).should_receive('remove_snapshot').never()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=config['lvm'],
|
|
config=config,
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=False,
|
|
)
|
|
|
|
|
|
def test_remove_data_source_with_dry_run_skips_snapshot_unmount_and_delete():
|
|
config = {'lvm': {}}
|
|
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.borgmatic.config.paths).should_receive(
|
|
'replace_temporary_subdirectory_with_glob'
|
|
).and_return('/run/borgmatic')
|
|
flexmock(module.glob).should_receive('glob').replace_with(lambda path: [path])
|
|
flexmock(module.os.path).should_receive('isdir').and_return(True)
|
|
flexmock(module.shutil).should_receive('rmtree').never()
|
|
flexmock(module).should_receive('unmount_snapshot').never()
|
|
flexmock(module).should_receive('get_snapshots').and_return(
|
|
(
|
|
module.Snapshot('lvolume1_borgmatic-1234', '/dev/lvolume1'),
|
|
module.Snapshot('lvolume2_borgmatic-1234', '/dev/lvolume2'),
|
|
module.Snapshot('nonborgmatic', '/dev/nonborgmatic'),
|
|
),
|
|
).once()
|
|
flexmock(module).should_receive('remove_snapshot').never()
|
|
|
|
module.remove_data_source_dumps(
|
|
hook_config=config['lvm'],
|
|
config=config,
|
|
log_prefix='test',
|
|
borgmatic_runtime_directory='/run/borgmatic',
|
|
dry_run=True,
|
|
)
|