mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-08-25 14:53:37 +00:00
Improve formatting of generated config and validation of ints (#2928)
- order sections similar to sample configs - add warnings and comments to `bootstrap.dcs` section. - add `tags` and `log` sections. - use discovered IPs in `postgresql.connect_address` and `postgresql.listen` - set `wal_level` to `replica` for PostgreSQL 9.6+ - make unit tests pass with python 3.6 - improve config validator so it doesn't complain when some ints are strings in YAML file.
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
import os
|
||||
import psutil
|
||||
import unittest
|
||||
import yaml
|
||||
|
||||
from . import MockConnect, MockCursor, MockConnectionInfo
|
||||
from copy import deepcopy
|
||||
from mock import MagicMock, Mock, PropertyMock, mock_open, patch
|
||||
from mock import MagicMock, Mock, PropertyMock, mock_open as _mock_open, patch
|
||||
|
||||
from patroni.__main__ import main as _main
|
||||
from patroni.config import Config
|
||||
from patroni.config_generator import AbstractConfigGenerator, get_address, NO_VALUE_MSG
|
||||
from patroni.log import PatroniLogger
|
||||
from patroni.utils import patch_config
|
||||
|
||||
from . import psycopg_connect
|
||||
@@ -17,6 +19,14 @@ HOSTNAME = 'test_hostname'
|
||||
IP = '1.9.8.4'
|
||||
|
||||
|
||||
def mock_open(*args, **kwargs):
|
||||
ret = _mock_open(*args, **kwargs)
|
||||
ret.return_value.__iter__ = lambda o: iter(o.readline, '')
|
||||
if not kwargs.get('read_data'):
|
||||
ret.return_value.readline = Mock(return_value=None)
|
||||
return ret
|
||||
|
||||
|
||||
@patch('patroni.psycopg.connect', psycopg_connect)
|
||||
@patch('builtins.open', MagicMock())
|
||||
@patch('subprocess.check_output', Mock(return_value=b"postgres (PostgreSQL) 16.2"))
|
||||
@@ -51,13 +61,23 @@ class TestGenerateConfig(unittest.TestCase):
|
||||
self.config = {
|
||||
'scope': self.environ['PATRONI_SCOPE'],
|
||||
'name': HOSTNAME,
|
||||
'log': {
|
||||
'level': PatroniLogger.DEFAULT_LEVEL,
|
||||
'traceback_level': PatroniLogger.DEFAULT_TRACEBACK_LEVEL,
|
||||
'format': PatroniLogger.DEFAULT_FORMAT,
|
||||
'max_queue_size': PatroniLogger.DEFAULT_MAX_QUEUE_SIZE
|
||||
},
|
||||
'restapi': {
|
||||
'connect_address': self.environ['PATRONI_RESTAPI_CONNECT_ADDRESS'],
|
||||
'listen': self.environ['PATRONI_RESTAPI_LISTEN']
|
||||
},
|
||||
'bootstrap': {
|
||||
'dcs': dynamic_config
|
||||
},
|
||||
'postgresql': {
|
||||
'connect_address': NO_VALUE_MSG + ':5432',
|
||||
'connect_address': IP + ':5432',
|
||||
'data_dir': NO_VALUE_MSG,
|
||||
'listen': NO_VALUE_MSG + ':5432',
|
||||
'listen': IP + ':5432',
|
||||
'pg_hba': ['host all all all md5',
|
||||
f'host replication {self.environ["PATRONI_REPLICATION_USERNAME"]} all md5'],
|
||||
'authentication': {'superuser': {'username': self.environ['PATRONI_SUPERUSER_USERNAME'],
|
||||
@@ -68,10 +88,6 @@ class TestGenerateConfig(unittest.TestCase):
|
||||
'bin_dir': self.environ['PATRONI_POSTGRESQL_BIN_DIR'],
|
||||
'bin_name': {'postgres': self.environ['PATRONI_POSTGRESQL_BIN_POSTGRES']},
|
||||
'parameters': {'password_encryption': 'md5'}
|
||||
},
|
||||
'restapi': {
|
||||
'connect_address': self.environ['PATRONI_RESTAPI_CONNECT_ADDRESS'],
|
||||
'listen': self.environ['PATRONI_RESTAPI_LISTEN']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +135,12 @@ class TestGenerateConfig(unittest.TestCase):
|
||||
},
|
||||
'rewind': None
|
||||
},
|
||||
},
|
||||
'tags': {
|
||||
'failover_priority': 1,
|
||||
'noloadbalance': False,
|
||||
'clonefrom': True,
|
||||
'nosync': False,
|
||||
}
|
||||
}
|
||||
patch_config(self.config, conf)
|
||||
@@ -139,22 +161,21 @@ class TestGenerateConfig(unittest.TestCase):
|
||||
]
|
||||
|
||||
@patch('os.makedirs')
|
||||
@patch('yaml.safe_dump')
|
||||
def test_generate_sample_config_pre_13_dir_creation(self, mock_config_dump, mock_makedir):
|
||||
def test_generate_sample_config_pre_13_dir_creation(self, mock_makedir):
|
||||
with patch('sys.argv', ['patroni.py', '--generate-sample-config', '/foo/bar.yml']), \
|
||||
patch('subprocess.check_output', Mock(return_value=b"postgres (PostgreSQL) 9.4.3")) as pg_bin_mock, \
|
||||
patch('builtins.open', _mock_open()) as mocked_file, \
|
||||
self.assertRaises(SystemExit) as e:
|
||||
_main()
|
||||
self.assertEqual(self.config, yaml.safe_load(mocked_file().write.call_args_list[0][0][0]))
|
||||
self.assertEqual(e.exception.code, 0)
|
||||
self.assertEqual(self.config, mock_config_dump.call_args[0][0])
|
||||
mock_makedir.assert_called_once()
|
||||
pg_bin_mock.assert_called_once_with([os.path.join(self.environ['PATRONI_POSTGRESQL_BIN_DIR'],
|
||||
self.environ['PATRONI_POSTGRESQL_BIN_POSTGRES']),
|
||||
'--version'])
|
||||
|
||||
@patch('os.makedirs', Mock())
|
||||
@patch('yaml.safe_dump')
|
||||
def test_generate_sample_config_16(self, mock_config_dump):
|
||||
def test_generate_sample_config_16(self):
|
||||
conf = {
|
||||
'bootstrap': {
|
||||
'dcs': {
|
||||
@@ -182,14 +203,15 @@ class TestGenerateConfig(unittest.TestCase):
|
||||
patch_config(self.config, conf)
|
||||
|
||||
with patch('sys.argv', ['patroni.py', '--generate-sample-config', '/foo/bar.yml']), \
|
||||
patch('builtins.open', _mock_open()) as mocked_file, \
|
||||
self.assertRaises(SystemExit) as e:
|
||||
_main()
|
||||
self.assertEqual(self.config, yaml.safe_load(mocked_file().write.call_args_list[0][0][0]))
|
||||
self.assertEqual(e.exception.code, 0)
|
||||
self.assertEqual(self.config, mock_config_dump.call_args[0][0])
|
||||
|
||||
@patch('os.makedirs', Mock())
|
||||
@patch('yaml.safe_dump')
|
||||
def test_generate_config_running_instance_16(self, mock_config_dump):
|
||||
@patch('sys.stdout')
|
||||
def test_generate_config_running_instance_16(self, mock_sys_stdout):
|
||||
self._set_running_instance_config_vals()
|
||||
|
||||
with patch('builtins.open', Mock(side_effect=self._get_running_instance_open_res())), \
|
||||
@@ -198,11 +220,11 @@ class TestGenerateConfig(unittest.TestCase):
|
||||
self.assertRaises(SystemExit) as e:
|
||||
_main()
|
||||
self.assertEqual(e.exception.code, 0)
|
||||
self.assertEqual(self.config, mock_config_dump.call_args[0][0])
|
||||
self.assertEqual(self.config, yaml.safe_load(mock_sys_stdout.write.call_args_list[0][0][0]))
|
||||
|
||||
@patch('os.makedirs', Mock())
|
||||
@patch('yaml.safe_dump')
|
||||
def test_generate_config_running_instance_16_connect_from_env(self, mock_config_dump):
|
||||
@patch('sys.stdout')
|
||||
def test_generate_config_running_instance_16_connect_from_env(self, mock_sys_stdout):
|
||||
self._set_running_instance_config_vals()
|
||||
# su auth params and connect host from env
|
||||
os.environ['PGCHANNELBINDING'] = \
|
||||
@@ -245,7 +267,7 @@ class TestGenerateConfig(unittest.TestCase):
|
||||
self.assertRaises(SystemExit) as e:
|
||||
_main()
|
||||
self.assertEqual(e.exception.code, 0)
|
||||
self.assertEqual(self.config, mock_config_dump.call_args[0][0])
|
||||
self.assertEqual(self.config, yaml.safe_load(mock_sys_stdout.write.call_args_list[0][0][0]))
|
||||
|
||||
def test_generate_config_running_instance_errors(self):
|
||||
# 1. Wrong DSN format
|
||||
|
||||
Reference in New Issue
Block a user