mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-01-27 10:20:10 +00:00
Improve error on empty or non dict config file (#3238)
Test if config (file) parsed with yaml_load() contains a valid Mapping object, otherwise Patroni throws an explicit exception. It also makes the Patroni output more explicit when using that kind of "invalid" configuration. ``` console $ touch /tmp/patroni.yaml $ patroni --validate-config /tmp/patroni.yaml /tmp/patroni.yaml does not contain a dict invalid config file /tmp/patroni.yaml ``` reportUnnecessaryIsInstance is explicitly ignored since we can't determine what yaml_safeload can bring from a YAML config (list, dict,...).
This commit is contained in:
@@ -188,6 +188,7 @@ class Config(object):
|
||||
|
||||
:raises:
|
||||
:class:`ConfigParseError`: if *path* is invalid.
|
||||
:class:`ConfigParseError`: if *path* does not contain dict (empty file or no mapping values).
|
||||
"""
|
||||
if os.path.isfile(path):
|
||||
files = [path]
|
||||
@@ -202,7 +203,10 @@ class Config(object):
|
||||
for fname in files:
|
||||
with open(fname) as f:
|
||||
config = yaml.safe_load(f)
|
||||
patch_config(overall_config, config)
|
||||
if not isinstance(config, dict):
|
||||
logger.error('%s does not contain a dict', fname)
|
||||
raise ConfigParseError(f'invalid config file {fname}')
|
||||
patch_config(overall_config, cast(Dict[Any, Any], config))
|
||||
return overall_config
|
||||
|
||||
def _load_config_file(self) -> Dict[str, Any]:
|
||||
|
||||
@@ -158,6 +158,35 @@ class TestConfig(unittest.TestCase):
|
||||
def test_invalid_path(self):
|
||||
self.assertRaises(ConfigParseError, Config, 'postgres0')
|
||||
|
||||
@patch('os.path.exists', Mock(return_value=True))
|
||||
@patch('os.path.isfile', Mock(side_effect=lambda fname: fname != 'postgres0'))
|
||||
@patch('os.path.isdir', Mock(return_value=True))
|
||||
@patch('os.listdir', Mock(return_value=['00-empty.yml', '00-base.yml']))
|
||||
@patch('patroni.config.logger')
|
||||
def test_invalid_empty_config_file(self, mock_logger):
|
||||
def open_mock(fname, *args, **kwargs):
|
||||
if fname.endswith('00-base.yml'):
|
||||
return io.StringIO(
|
||||
u'''
|
||||
test: True
|
||||
test2:
|
||||
child-1: somestring
|
||||
child-2: 5
|
||||
child-3: False
|
||||
test3: True
|
||||
test4:
|
||||
- abc: 3
|
||||
- abc: 4
|
||||
''')
|
||||
elif fname.endswith('00-empty.yml'):
|
||||
return io.StringIO(u'''---''')
|
||||
|
||||
with patch('builtins.open', MagicMock(side_effect=open_mock)):
|
||||
self.assertRaises(ConfigParseError, Config, 'postgres0')
|
||||
mock_logger.error.assert_called_once_with(
|
||||
'%s does not contain a dict',
|
||||
'postgres0\\00-empty.yml' if sys.platform == 'win32' else 'postgres0/00-empty.yml')
|
||||
|
||||
@patch.object(Config, 'get')
|
||||
@patch('patroni.config.logger')
|
||||
def test__validate_tags(self, mock_logger, mock_get):
|
||||
|
||||
Reference in New Issue
Block a user