Deprecated configuration options warning logging.
This commit is contained in:
parent
e2c95327fb
commit
9cf27fa4ba
7 changed files with 140 additions and 51 deletions
5
NEWS
5
NEWS
|
@ -7,6 +7,11 @@
|
|||
* #720: Fix an error when dumping a MySQL database and the "exclude_nodump" option is set.
|
||||
* When merging two configuration files, error gracefully if the two files do not adhere to the same
|
||||
format.
|
||||
* BREAKING: Remove the deprecated (and silently ignored) "--successful" flag on the "list" action,
|
||||
as newer versions of Borg list successful (non-checkpoint) archives by default.
|
||||
* All deprecated configuration option values now generate warning logs.
|
||||
* Remove the deprecated (and non-functional) "--excludes" flag in favor of excludes within
|
||||
configuration.
|
||||
|
||||
1.7.15
|
||||
* #326: Add configuration options and command-line flags for backing up a database from one
|
||||
|
|
|
@ -14,7 +14,6 @@ ARCHIVE_FILTER_FLAGS_MOVED_TO_RLIST = ('prefix', 'match_archives', 'sort_by', 'f
|
|||
MAKE_FLAGS_EXCLUDES = (
|
||||
'repository',
|
||||
'archive',
|
||||
'successful',
|
||||
'paths',
|
||||
'find_paths',
|
||||
) + ARCHIVE_FILTER_FLAGS_MOVED_TO_RLIST
|
||||
|
|
|
@ -274,11 +274,6 @@ def make_parsers():
|
|||
default=config_paths,
|
||||
help=f"Configuration filenames or directories, defaults to: {' '.join(unexpanded_config_paths)}",
|
||||
)
|
||||
global_group.add_argument(
|
||||
'--excludes',
|
||||
dest='excludes_filename',
|
||||
help='Deprecated in favor of exclude_patterns within configuration',
|
||||
)
|
||||
global_group.add_argument(
|
||||
'-n',
|
||||
'--dry-run',
|
||||
|
@ -1098,12 +1093,6 @@ def make_parsers():
|
|||
metavar='PATTERN',
|
||||
help='Only list archive names matching this pattern',
|
||||
)
|
||||
list_group.add_argument(
|
||||
'--successful',
|
||||
default=True,
|
||||
action='store_true',
|
||||
help='Deprecated; no effect. Newer versions of Borg shows successful (non-checkpoint) archives by default.',
|
||||
)
|
||||
list_group.add_argument(
|
||||
'--sort-by', metavar='KEYS', help='Comma-separated list of sorting keys'
|
||||
)
|
||||
|
@ -1279,11 +1268,6 @@ def parse_arguments(*unparsed_arguments):
|
|||
f"Unrecognized argument{'s' if len(unknown_arguments) > 1 else ''}: {' '.join(unknown_arguments)}"
|
||||
)
|
||||
|
||||
if arguments['global'].excludes_filename:
|
||||
raise ValueError(
|
||||
'The --excludes flag has been replaced with exclude_patterns in configuration.'
|
||||
)
|
||||
|
||||
if 'create' in arguments and arguments['create'].list_files and arguments['create'].progress:
|
||||
raise ValueError(
|
||||
'With the create action, only one of --list (--files) and --progress flags can be used.'
|
||||
|
|
|
@ -12,52 +12,143 @@ def normalize(config_filename, config):
|
|||
location = config.get('location') or {}
|
||||
storage = config.get('storage') or {}
|
||||
consistency = config.get('consistency') or {}
|
||||
retention = config.get('retention') or {}
|
||||
hooks = config.get('hooks') or {}
|
||||
|
||||
# Upgrade exclude_if_present from a string to a list.
|
||||
exclude_if_present = location.get('exclude_if_present')
|
||||
if isinstance(exclude_if_present, str):
|
||||
logs.append(
|
||||
logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: The exclude_if_present option now expects a list value. String values for this option are deprecated and support will be removed from a future release.',
|
||||
)
|
||||
)
|
||||
)
|
||||
config['location']['exclude_if_present'] = [exclude_if_present]
|
||||
|
||||
# Upgrade various monitoring hooks from a string to a dict.
|
||||
healthchecks = hooks.get('healthchecks')
|
||||
if isinstance(healthchecks, str):
|
||||
logs.append(
|
||||
logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: The healthchecks hook now expects a mapping value. String values for this option are deprecated and support will be removed from a future release.',
|
||||
)
|
||||
)
|
||||
)
|
||||
config['hooks']['healthchecks'] = {'ping_url': healthchecks}
|
||||
|
||||
cronitor = hooks.get('cronitor')
|
||||
if isinstance(cronitor, str):
|
||||
logs.append(
|
||||
logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: The healthchecks hook now expects key/value pairs. String values for this option are deprecated and support will be removed from a future release.',
|
||||
)
|
||||
)
|
||||
)
|
||||
config['hooks']['cronitor'] = {'ping_url': cronitor}
|
||||
|
||||
pagerduty = hooks.get('pagerduty')
|
||||
if isinstance(pagerduty, str):
|
||||
logs.append(
|
||||
logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: The healthchecks hook now expects key/value pairs. String values for this option are deprecated and support will be removed from a future release.',
|
||||
)
|
||||
)
|
||||
)
|
||||
config['hooks']['pagerduty'] = {'integration_key': pagerduty}
|
||||
|
||||
cronhub = hooks.get('cronhub')
|
||||
if isinstance(cronhub, str):
|
||||
logs.append(
|
||||
logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: The healthchecks hook now expects key/value pairs. String values for this option are deprecated and support will be removed from a future release.',
|
||||
)
|
||||
)
|
||||
)
|
||||
config['hooks']['cronhub'] = {'ping_url': cronhub}
|
||||
|
||||
# Upgrade consistency checks from a list of strings to a list of dicts.
|
||||
checks = consistency.get('checks')
|
||||
if isinstance(checks, list) and len(checks) and isinstance(checks[0], str):
|
||||
logs.append(
|
||||
logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: The checks option now expects a list of key/value pairs. Lists of strings for this option are deprecated and support will be removed from a future release.',
|
||||
)
|
||||
)
|
||||
)
|
||||
config['consistency']['checks'] = [{'name': check_type} for check_type in checks]
|
||||
|
||||
# Rename various configuration options.
|
||||
numeric_owner = location.pop('numeric_owner', None)
|
||||
if numeric_owner is not None:
|
||||
logs.append(
|
||||
logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: The numeric_owner option has been renamed to numeric_ids. numeric_owner is deprecated and support will be removed from a future release.',
|
||||
)
|
||||
)
|
||||
)
|
||||
config['location']['numeric_ids'] = numeric_owner
|
||||
|
||||
bsd_flags = location.pop('bsd_flags', None)
|
||||
if bsd_flags is not None:
|
||||
logs.append(
|
||||
logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: The bsd_flags option has been renamed to flags. bsd_flags is deprecated and support will be removed from a future release.',
|
||||
)
|
||||
)
|
||||
)
|
||||
config['location']['flags'] = bsd_flags
|
||||
|
||||
remote_rate_limit = storage.pop('remote_rate_limit', None)
|
||||
if remote_rate_limit is not None:
|
||||
logs.append(
|
||||
logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: The remote_rate_limit option has been renamed to upload_rate_limit. remote_rate_limit is deprecated and support will be removed from a future release.',
|
||||
)
|
||||
)
|
||||
)
|
||||
config['storage']['upload_rate_limit'] = remote_rate_limit
|
||||
|
||||
# Upgrade remote repositories to ssh:// syntax, required in Borg 2.
|
||||
repositories = location.get('repositories')
|
||||
if repositories:
|
||||
if isinstance(repositories[0], str):
|
||||
logs.append(
|
||||
logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: The repositories option now expects a list of key/value pairs. Lists of strings for this option are deprecated and support will be removed from a future release.',
|
||||
)
|
||||
)
|
||||
)
|
||||
config['location']['repositories'] = [
|
||||
{'path': repository} for repository in repositories
|
||||
]
|
||||
|
@ -71,7 +162,7 @@ def normalize(config_filename, config):
|
|||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: Repository paths containing "~" are deprecated in borgmatic and no longer work in Borg 2.x+.',
|
||||
msg=f'{config_filename}: Repository paths containing "~" are deprecated in borgmatic and support will be removed from a future release.',
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -95,7 +186,7 @@ def normalize(config_filename, config):
|
|||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: Remote repository paths without ssh:// syntax are deprecated. Interpreting "{repository_path}" as "{rewritten_repository_path}"',
|
||||
msg=f'{config_filename}: Remote repository paths without ssh:// syntax are deprecated and support will be removed from a future release. Interpreting "{repository_path}" as "{rewritten_repository_path}"',
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -108,4 +199,15 @@ def normalize(config_filename, config):
|
|||
else:
|
||||
config['location']['repositories'].append(repository_dict)
|
||||
|
||||
if consistency.get('prefix') or retention.get('prefix'):
|
||||
logs.append(
|
||||
logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=logging.WARNING,
|
||||
levelname='WARNING',
|
||||
msg=f'{config_filename}: The prefix option is deprecated and support will be removed from a future release. Use archive_name_format or match_archives instead.',
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return logs
|
||||
|
|
|
@ -12,7 +12,6 @@ def test_parse_arguments_with_no_arguments_uses_defaults():
|
|||
|
||||
global_arguments = arguments['global']
|
||||
assert global_arguments.config_paths == config_paths
|
||||
assert global_arguments.excludes_filename is None
|
||||
assert global_arguments.verbosity == 0
|
||||
assert global_arguments.syslog_verbosity == 0
|
||||
assert global_arguments.log_file_verbosity == 0
|
||||
|
@ -71,7 +70,6 @@ def test_parse_arguments_with_verbosity_overrides_default():
|
|||
|
||||
global_arguments = arguments['global']
|
||||
assert global_arguments.config_paths == config_paths
|
||||
assert global_arguments.excludes_filename is None
|
||||
assert global_arguments.verbosity == 1
|
||||
assert global_arguments.syslog_verbosity == 0
|
||||
assert global_arguments.log_file_verbosity == 0
|
||||
|
@ -85,7 +83,6 @@ def test_parse_arguments_with_syslog_verbosity_overrides_default():
|
|||
|
||||
global_arguments = arguments['global']
|
||||
assert global_arguments.config_paths == config_paths
|
||||
assert global_arguments.excludes_filename is None
|
||||
assert global_arguments.verbosity == 0
|
||||
assert global_arguments.syslog_verbosity == 2
|
||||
|
||||
|
@ -98,7 +95,6 @@ def test_parse_arguments_with_log_file_verbosity_overrides_default():
|
|||
|
||||
global_arguments = arguments['global']
|
||||
assert global_arguments.config_paths == config_paths
|
||||
assert global_arguments.excludes_filename is None
|
||||
assert global_arguments.verbosity == 0
|
||||
assert global_arguments.syslog_verbosity == 0
|
||||
assert global_arguments.log_file_verbosity == -1
|
||||
|
@ -234,13 +230,6 @@ def test_parse_arguments_disallows_invalid_argument():
|
|||
module.parse_arguments('--posix-me-harder')
|
||||
|
||||
|
||||
def test_parse_arguments_disallows_deprecated_excludes_option():
|
||||
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
module.parse_arguments('--config', 'myconfig', '--excludes', 'myexcludes')
|
||||
|
||||
|
||||
def test_parse_arguments_disallows_encryption_mode_without_init():
|
||||
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ def test_parse_configuration_transforms_file_into_mapping():
|
|||
- /etc
|
||||
|
||||
repositories:
|
||||
- hostname.borg
|
||||
- path: hostname.borg
|
||||
|
||||
retention:
|
||||
keep_minutely: 60
|
||||
|
@ -83,7 +83,7 @@ def test_parse_configuration_passes_through_quoted_punctuation():
|
|||
- "/home/{escaped_punctuation}"
|
||||
|
||||
repositories:
|
||||
- test.borg
|
||||
- path: test.borg
|
||||
'''
|
||||
)
|
||||
|
||||
|
@ -106,7 +106,7 @@ def test_parse_configuration_with_schema_lacking_examples_does_not_raise():
|
|||
- /home
|
||||
|
||||
repositories:
|
||||
- hostname.borg
|
||||
- path: hostname.borg
|
||||
''',
|
||||
'''
|
||||
map:
|
||||
|
@ -135,7 +135,7 @@ def test_parse_configuration_inlines_include():
|
|||
- /home
|
||||
|
||||
repositories:
|
||||
- hostname.borg
|
||||
- path: hostname.borg
|
||||
|
||||
retention:
|
||||
!include include.yaml
|
||||
|
@ -168,7 +168,7 @@ def test_parse_configuration_merges_include():
|
|||
- /home
|
||||
|
||||
repositories:
|
||||
- hostname.borg
|
||||
- path: hostname.borg
|
||||
|
||||
retention:
|
||||
keep_daily: 1
|
||||
|
@ -221,7 +221,7 @@ def test_parse_configuration_raises_for_validation_error():
|
|||
location:
|
||||
source_directories: yes
|
||||
repositories:
|
||||
- hostname.borg
|
||||
- path: hostname.borg
|
||||
'''
|
||||
)
|
||||
|
||||
|
@ -237,7 +237,7 @@ def test_parse_configuration_applies_overrides():
|
|||
- /home
|
||||
|
||||
repositories:
|
||||
- hostname.borg
|
||||
- path: hostname.borg
|
||||
|
||||
local_path: borg1
|
||||
'''
|
||||
|
@ -265,7 +265,7 @@ def test_parse_configuration_applies_normalization():
|
|||
- /home
|
||||
|
||||
repositories:
|
||||
- hostname.borg
|
||||
- path: hostname.borg
|
||||
|
||||
exclude_if_present: .nobackup
|
||||
'''
|
||||
|
@ -280,4 +280,4 @@ def test_parse_configuration_applies_normalization():
|
|||
'exclude_if_present': ['.nobackup'],
|
||||
}
|
||||
}
|
||||
assert logs == []
|
||||
assert logs
|
||||
|
|
|
@ -9,7 +9,7 @@ from borgmatic.config import normalize as module
|
|||
(
|
||||
{'location': {'exclude_if_present': '.nobackup'}},
|
||||
{'location': {'exclude_if_present': ['.nobackup']}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'location': {'exclude_if_present': ['.nobackup']}},
|
||||
|
@ -39,22 +39,22 @@ from borgmatic.config import normalize as module
|
|||
(
|
||||
{'hooks': {'healthchecks': 'https://example.com'}},
|
||||
{'hooks': {'healthchecks': {'ping_url': 'https://example.com'}}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'hooks': {'cronitor': 'https://example.com'}},
|
||||
{'hooks': {'cronitor': {'ping_url': 'https://example.com'}}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'hooks': {'pagerduty': 'https://example.com'}},
|
||||
{'hooks': {'pagerduty': {'integration_key': 'https://example.com'}}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'hooks': {'cronhub': 'https://example.com'}},
|
||||
{'hooks': {'cronhub': {'ping_url': 'https://example.com'}}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'hooks': None},
|
||||
|
@ -64,12 +64,12 @@ from borgmatic.config import normalize as module
|
|||
(
|
||||
{'consistency': {'checks': ['archives']}},
|
||||
{'consistency': {'checks': [{'name': 'archives'}]}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'consistency': {'checks': ['archives']}},
|
||||
{'consistency': {'checks': [{'name': 'archives'}]}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'consistency': None},
|
||||
|
@ -79,17 +79,17 @@ from borgmatic.config import normalize as module
|
|||
(
|
||||
{'location': {'numeric_owner': False}},
|
||||
{'location': {'numeric_ids': False}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'location': {'bsd_flags': False}},
|
||||
{'location': {'flags': False}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'storage': {'remote_rate_limit': False}},
|
||||
{'storage': {'upload_rate_limit': False}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'location': {'repositories': ['foo@bar:/repo']}},
|
||||
|
@ -109,12 +109,12 @@ from borgmatic.config import normalize as module
|
|||
(
|
||||
{'location': {'repositories': ['ssh://foo@bar:1234/repo']}},
|
||||
{'location': {'repositories': [{'path': 'ssh://foo@bar:1234/repo'}]}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'location': {'repositories': ['file:///repo']}},
|
||||
{'location': {'repositories': [{'path': '/repo'}]}},
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'location': {'repositories': [{'path': 'foo@bar:/repo', 'label': 'foo'}]}},
|
||||
|
@ -131,6 +131,16 @@ from borgmatic.config import normalize as module
|
|||
{'location': {'repositories': [{'path': '/repo', 'label': 'foo'}]}},
|
||||
False,
|
||||
),
|
||||
(
|
||||
{'consistency': {'prefix': 'foo'}},
|
||||
{'consistency': {'prefix': 'foo'}},
|
||||
True,
|
||||
),
|
||||
(
|
||||
{'retention': {'prefix': 'foo'}},
|
||||
{'retention': {'prefix': 'foo'}},
|
||||
True,
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_normalize_applies_hard_coded_normalization_to_config(
|
||||
|
|
Loading…
Reference in a new issue