Add "borgmatic check --force" flag to ignore configured check frequencies (#523).
This commit is contained in:
parent
b3682b61d1
commit
8fa90053cf
7 changed files with 51 additions and 12 deletions
3
NEWS
3
NEWS
|
@ -1,6 +1,7 @@
|
|||
1.6.2.dev0
|
||||
* #523: Reduce the default consistency check frequency and support configuring the frequency
|
||||
independently for each check. See the documentation for more information:
|
||||
independently for each check. Also add "borgmatic check --force" flag to ignore configured
|
||||
frequencies. See the documentation for more information:
|
||||
https://torsion.org/borgmatic/docs/how-to/deal-with-very-large-backups/#check-frequency
|
||||
* #536: Fix generate-borgmatic-config to support more complex schema changes like the new
|
||||
Healthchecks configuration options when the "--source" flag is used.
|
||||
|
|
|
@ -81,8 +81,8 @@ def parse_frequency(frequency):
|
|||
time_unit += 's'
|
||||
|
||||
if time_unit == 'months':
|
||||
number *= 4
|
||||
time_unit = 'weeks'
|
||||
number *= 30
|
||||
time_unit = 'days'
|
||||
elif time_unit == 'years':
|
||||
number *= 365
|
||||
time_unit = 'days'
|
||||
|
@ -93,11 +93,13 @@ def parse_frequency(frequency):
|
|||
raise ValueError(f"Could not parse consistency check frequency '{frequency}'")
|
||||
|
||||
|
||||
def filter_checks_on_frequency(location_config, consistency_config, borg_repository_id, checks):
|
||||
def filter_checks_on_frequency(
|
||||
location_config, consistency_config, borg_repository_id, checks, force
|
||||
):
|
||||
'''
|
||||
Given a location config, a consistency config with a "checks" sequence of dicts, a Borg
|
||||
repository ID, and sequence of checks, filter down those checks based on the configured
|
||||
"frequency" for each check as compared to its check time file.
|
||||
repository ID, a sequence of checks, and whether to force checks to run, filter down those
|
||||
checks based on the configured "frequency" for each check as compared to its check time file.
|
||||
|
||||
In other words, a check whose check time file's timestamp is too new (based on the configured
|
||||
frequency) will get cut from the returned sequence of checks. Example:
|
||||
|
@ -119,6 +121,9 @@ def filter_checks_on_frequency(location_config, consistency_config, borg_reposit
|
|||
'''
|
||||
filtered_checks = list(checks)
|
||||
|
||||
if force:
|
||||
return tuple(filtered_checks)
|
||||
|
||||
for check_config in consistency_config.get('checks', DEFAULT_CHECKS):
|
||||
check = check_config['name']
|
||||
if checks and check not in checks:
|
||||
|
@ -240,6 +245,7 @@ def check_archives(
|
|||
progress=None,
|
||||
repair=None,
|
||||
only_checks=None,
|
||||
force=None,
|
||||
):
|
||||
'''
|
||||
Given a local or remote repository path, a storage config dict, a consistency config dict,
|
||||
|
@ -269,6 +275,7 @@ def check_archives(
|
|||
consistency_config,
|
||||
borg_repository_id,
|
||||
parse_checks(consistency_config, only_checks),
|
||||
force,
|
||||
)
|
||||
check_last = consistency_config.get('check_last', None)
|
||||
lock_wait = None
|
||||
|
|
|
@ -346,7 +346,7 @@ def make_parsers():
|
|||
dest='repair',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='Attempt to repair any inconsistencies found (experimental and only for interactive use)',
|
||||
help='Attempt to repair any inconsistencies found (for interactive use)',
|
||||
)
|
||||
check_group.add_argument(
|
||||
'--only',
|
||||
|
@ -356,6 +356,12 @@ def make_parsers():
|
|||
action='append',
|
||||
help='Run a particular consistency check (repository, archives, data, or extract) instead of configured checks (subject to configured frequency, can specify flag multiple times)',
|
||||
)
|
||||
check_group.add_argument(
|
||||
'--force',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='Ignore configured check frequencies and run checks unconditionally',
|
||||
)
|
||||
check_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
|
||||
|
||||
extract_parser = subparsers.add_parser(
|
||||
|
|
|
@ -403,6 +403,7 @@ def run_actions(
|
|||
progress=arguments['check'].progress,
|
||||
repair=arguments['check'].repair,
|
||||
only_checks=arguments['check'].only,
|
||||
force=arguments['check'].force,
|
||||
)
|
||||
command.execute_hook(
|
||||
hooks.get('after_check'),
|
||||
|
|
|
@ -96,6 +96,9 @@ within `~/.borgmatic/checks`). If it hasn't been long enough, the check is
|
|||
skipped. And you still have to run `borgmatic check` (or just `borgmatic`) in
|
||||
order for checks to run, even when a `frequency` is configured!
|
||||
|
||||
If you want to temporarily ignore your configured frequencies, you can invoke
|
||||
`borgmatic check --force` to run checks unconditionally.
|
||||
|
||||
|
||||
### Disabling checks
|
||||
|
||||
|
@ -129,7 +132,7 @@ borgmatic check --only data --only extract
|
|||
|
||||
This is useful for running slow consistency checks on an infrequent basis,
|
||||
separate from your regular checks. It is still subject to any configured
|
||||
check frequencies.
|
||||
check frequencies unless the `--force` flag is used.
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
|
|
@ -83,8 +83,8 @@ def test_parse_checks_with_override_data_check_also_injects_archives():
|
|||
('2 days', module.datetime.timedelta(days=2)),
|
||||
('1 week', module.datetime.timedelta(weeks=1)),
|
||||
('2 weeks', module.datetime.timedelta(weeks=2)),
|
||||
('1 month', module.datetime.timedelta(weeks=4)),
|
||||
('2 months', module.datetime.timedelta(weeks=8)),
|
||||
('1 month', module.datetime.timedelta(days=30)),
|
||||
('2 months', module.datetime.timedelta(days=60)),
|
||||
('1 year', module.datetime.timedelta(days=365)),
|
||||
('2 years', module.datetime.timedelta(days=365 * 2)),
|
||||
),
|
||||
|
@ -113,12 +113,17 @@ def test_filter_checks_on_frequency_without_config_uses_default_checks():
|
|||
consistency_config={},
|
||||
borg_repository_id='repo',
|
||||
checks=('repository', 'archives'),
|
||||
force=False,
|
||||
) == ('repository', 'archives')
|
||||
|
||||
|
||||
def test_filter_checks_on_frequency_retains_unconfigured_check():
|
||||
assert module.filter_checks_on_frequency(
|
||||
location_config={}, consistency_config={}, borg_repository_id='repo', checks=('data',),
|
||||
location_config={},
|
||||
consistency_config={},
|
||||
borg_repository_id='repo',
|
||||
checks=('data',),
|
||||
force=False,
|
||||
) == ('data',)
|
||||
|
||||
|
||||
|
@ -130,6 +135,7 @@ def test_filter_checks_on_frequency_retains_check_without_frequency():
|
|||
consistency_config={'checks': [{'name': 'archives'}]},
|
||||
borg_repository_id='repo',
|
||||
checks=('archives',),
|
||||
force=False,
|
||||
) == ('archives',)
|
||||
|
||||
|
||||
|
@ -147,6 +153,7 @@ def test_filter_checks_on_frequency_retains_check_with_elapsed_frequency():
|
|||
consistency_config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
|
||||
borg_repository_id='repo',
|
||||
checks=('archives',),
|
||||
force=False,
|
||||
) == ('archives',)
|
||||
|
||||
|
||||
|
@ -162,6 +169,7 @@ def test_filter_checks_on_frequency_retains_check_with_missing_check_time_file()
|
|||
consistency_config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
|
||||
borg_repository_id='repo',
|
||||
checks=('archives',),
|
||||
force=False,
|
||||
) == ('archives',)
|
||||
|
||||
|
||||
|
@ -178,11 +186,22 @@ def test_filter_checks_on_frequency_skips_check_with_unelapsed_frequency():
|
|||
consistency_config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
|
||||
borg_repository_id='repo',
|
||||
checks=('archives',),
|
||||
force=False,
|
||||
)
|
||||
== ()
|
||||
)
|
||||
|
||||
|
||||
def test_filter_checks_on_frequency_restains_check_with_unelapsed_frequency_and_force():
|
||||
assert module.filter_checks_on_frequency(
|
||||
location_config={},
|
||||
consistency_config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
|
||||
borg_repository_id='repo',
|
||||
checks=('archives',),
|
||||
force=True,
|
||||
) == ('archives',)
|
||||
|
||||
|
||||
def test_make_check_flags_with_repository_check_returns_flag():
|
||||
flags = module.make_check_flags(('repository',))
|
||||
|
||||
|
|
|
@ -468,7 +468,9 @@ def test_run_actions_calls_hooks_for_check_action():
|
|||
flexmock(module.command).should_receive('execute_hook').twice()
|
||||
arguments = {
|
||||
'global': flexmock(monitoring_verbosity=1, dry_run=False),
|
||||
'check': flexmock(progress=flexmock(), repair=flexmock(), only=flexmock()),
|
||||
'check': flexmock(
|
||||
progress=flexmock(), repair=flexmock(), only=flexmock(), force=flexmock()
|
||||
),
|
||||
}
|
||||
|
||||
list(
|
||||
|
|
Loading…
Reference in a new issue