Attempt to repair any inconsistencies found during a consistency check via "borgmatic check --repair" flag (#266).
This commit is contained in:
parent
0c6c61a272
commit
2ab9daaa0f
5 changed files with 38 additions and 7 deletions
2
NEWS
2
NEWS
|
@ -2,6 +2,8 @@
|
||||||
* #235: Pass extra options directly to particular Borg commands, handy for Borg options that
|
* #235: Pass extra options directly to particular Borg commands, handy for Borg options that
|
||||||
borgmatic does not yet support natively. Use "extra_borg_options" in the storage configuration
|
borgmatic does not yet support natively. Use "extra_borg_options" in the storage configuration
|
||||||
section.
|
section.
|
||||||
|
* #266: Attempt to repair any inconsistencies found during a consistency check via
|
||||||
|
"borgmatic check --repair" flag.
|
||||||
|
|
||||||
1.4.16
|
1.4.16
|
||||||
* #256: Fix for "before_backup" hook not triggering an error when the command contains "borg" and
|
* #256: Fix for "before_backup" hook not triggering an error when the command contains "borg" and
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.borg import extract
|
from borgmatic.borg import extract
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command, execute_command_without_capture
|
||||||
|
|
||||||
DEFAULT_CHECKS = ('repository', 'archives')
|
DEFAULT_CHECKS = ('repository', 'archives')
|
||||||
DEFAULT_PREFIX = '{hostname}-'
|
DEFAULT_PREFIX = '{hostname}-'
|
||||||
|
@ -91,12 +91,13 @@ def check_archives(
|
||||||
consistency_config,
|
consistency_config,
|
||||||
local_path='borg',
|
local_path='borg',
|
||||||
remote_path=None,
|
remote_path=None,
|
||||||
|
repair=None,
|
||||||
only_checks=None,
|
only_checks=None,
|
||||||
):
|
):
|
||||||
'''
|
'''
|
||||||
Given a local or remote repository path, a storage config dict, a consistency config dict,
|
Given a local or remote repository path, a storage config dict, a consistency config dict,
|
||||||
local/remote commands to run, and an optional list of checks to use instead of configured
|
local/remote commands to run, whether to attempt a repair, and an optional list of checks
|
||||||
checks, check the contained Borg archives for consistency.
|
to use instead of configured checks, check the contained Borg archives for consistency.
|
||||||
|
|
||||||
If there are no consistency checks to run, skip running them.
|
If there are no consistency checks to run, skip running them.
|
||||||
'''
|
'''
|
||||||
|
@ -106,9 +107,7 @@ def check_archives(
|
||||||
extra_borg_options = storage_config.get('extra_borg_options', {}).get('check', '')
|
extra_borg_options = storage_config.get('extra_borg_options', {}).get('check', '')
|
||||||
|
|
||||||
if set(checks).intersection(set(DEFAULT_CHECKS + ('data',))):
|
if set(checks).intersection(set(DEFAULT_CHECKS + ('data',))):
|
||||||
remote_path_flags = ('--remote-path', remote_path) if remote_path else ()
|
|
||||||
lock_wait = storage_config.get('lock_wait', None)
|
lock_wait = storage_config.get('lock_wait', None)
|
||||||
lock_wait_flags = ('--lock-wait', str(lock_wait)) if lock_wait else ()
|
|
||||||
|
|
||||||
verbosity_flags = ()
|
verbosity_flags = ()
|
||||||
if logger.isEnabledFor(logging.INFO):
|
if logger.isEnabledFor(logging.INFO):
|
||||||
|
@ -120,14 +119,21 @@ def check_archives(
|
||||||
|
|
||||||
full_command = (
|
full_command = (
|
||||||
(local_path, 'check')
|
(local_path, 'check')
|
||||||
|
+ (('--repair',) if repair else ())
|
||||||
+ _make_check_flags(checks, check_last, prefix)
|
+ _make_check_flags(checks, check_last, prefix)
|
||||||
+ remote_path_flags
|
+ (('--remote-path', remote_path) if remote_path else ())
|
||||||
+ lock_wait_flags
|
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
|
||||||
+ verbosity_flags
|
+ verbosity_flags
|
||||||
+ (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
|
+ (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
|
||||||
+ (repository,)
|
+ (repository,)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# The Borg repair option trigger an interactive prompt, which won't work when output is
|
||||||
|
# captured.
|
||||||
|
if repair:
|
||||||
|
execute_command_without_capture(full_command, error_on_warnings=True)
|
||||||
|
return
|
||||||
|
|
||||||
execute_command(full_command, error_on_warnings=True)
|
execute_command(full_command, error_on_warnings=True)
|
||||||
|
|
||||||
if 'extract' in checks:
|
if 'extract' in checks:
|
||||||
|
|
|
@ -266,6 +266,13 @@ def parse_arguments(*unparsed_arguments):
|
||||||
add_help=False,
|
add_help=False,
|
||||||
)
|
)
|
||||||
check_group = check_parser.add_argument_group('check arguments')
|
check_group = check_parser.add_argument_group('check arguments')
|
||||||
|
check_group.add_argument(
|
||||||
|
'--repair',
|
||||||
|
dest='repair',
|
||||||
|
default=False,
|
||||||
|
action='store_true',
|
||||||
|
help='Attempt to repair any inconsistencies found (experimental and only for interactive use)',
|
||||||
|
)
|
||||||
check_group.add_argument(
|
check_group.add_argument(
|
||||||
'--only',
|
'--only',
|
||||||
metavar='CHECK',
|
metavar='CHECK',
|
||||||
|
|
|
@ -230,6 +230,7 @@ def run_actions(
|
||||||
consistency,
|
consistency,
|
||||||
local_path=local_path,
|
local_path=local_path,
|
||||||
remote_path=remote_path,
|
remote_path=remote_path,
|
||||||
|
repair=arguments['check'].repair,
|
||||||
only_checks=arguments['check'].only,
|
only_checks=arguments['check'].only,
|
||||||
)
|
)
|
||||||
if 'extract' in arguments:
|
if 'extract' in arguments:
|
||||||
|
|
|
@ -158,6 +158,21 @@ def test_make_check_flags_with_default_checks_and_prefix_includes_prefix_flag():
|
||||||
assert flags == ('--prefix', 'foo-')
|
assert flags == ('--prefix', 'foo-')
|
||||||
|
|
||||||
|
|
||||||
|
def test_check_archives_with_repair_calls_borg_with_repair_parameter():
|
||||||
|
checks = ('repository',)
|
||||||
|
consistency_config = {'check_last': None}
|
||||||
|
flexmock(module).should_receive('_parse_checks').and_return(checks)
|
||||||
|
flexmock(module).should_receive('_make_check_flags').and_return(())
|
||||||
|
flexmock(module).should_receive('execute_command').never()
|
||||||
|
flexmock(module).should_receive('execute_command_without_capture').with_args(
|
||||||
|
('borg', 'check', '--repair', 'repo'), error_on_warnings=True
|
||||||
|
).once()
|
||||||
|
|
||||||
|
module.check_archives(
|
||||||
|
repository='repo', storage_config={}, consistency_config=consistency_config, repair=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'checks',
|
'checks',
|
||||||
(
|
(
|
||||||
|
|
Loading…
Reference in a new issue