mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-09-02 01:29:36 +00:00
Implement /history and /cluster endpoints (#1191)
The /history endpoint shows the content of the `history` key in DCS The /cluster endpoint show all cluster members and some service info like pending and scheduled restarts or switchovers. In addition to that implement `patronictl history` Close #586 Close #675 Close #1133
This commit is contained in:
+1
-1
@@ -100,7 +100,7 @@ class MockCursor(object):
|
||||
self.results = [(1, 2)]
|
||||
elif sql.startswith('SELECT pg_catalog.pg_is_in_recovery()'):
|
||||
self.results = [(False, 2)]
|
||||
elif sql.startswith('WITH replication_info AS ('):
|
||||
elif sql.startswith('SELECT pg_catalog.to_char'):
|
||||
replication_info = '[{"application_name":"walreceiver","client_addr":"1.2.3.4",' +\
|
||||
'"state":"streaming","sync_state":"async","sync_priority":0}]'
|
||||
self.results = [('', 0, '', '', '', '', False, replication_info)]
|
||||
|
||||
@@ -12,6 +12,7 @@ from patroni.utils import tzutc
|
||||
from six import BytesIO as IO
|
||||
from six.moves import BaseHTTPServer
|
||||
from . import psycopg2_connect, MockCursor
|
||||
from .test_ha import get_cluster_initialized_without_leader
|
||||
|
||||
|
||||
future_restart_time = datetime.datetime.now(tzutc) + datetime.timedelta(days=5)
|
||||
@@ -159,6 +160,7 @@ class TestRestApiHandler(unittest.TestCase):
|
||||
|
||||
def test_do_GET(self):
|
||||
MockRestApiServer(RestApiHandler, 'GET /replica')
|
||||
MockRestApiServer(RestApiHandler, 'GET /read-only')
|
||||
with patch.object(RestApiHandler, 'get_postgresql_status', Mock(return_value={})):
|
||||
MockRestApiServer(RestApiHandler, 'GET /replica')
|
||||
with patch.object(RestApiHandler, 'get_postgresql_status', Mock(return_value={'role': 'master'})):
|
||||
@@ -197,6 +199,17 @@ class TestRestApiHandler(unittest.TestCase):
|
||||
self.assertIsNotNone(MockRestApiServer(RestApiHandler, 'POST /restart HTTP/1.0'))
|
||||
MockRestApiServer(RestApiHandler, 'POST /restart HTTP/1.0\nAuthorization:')
|
||||
|
||||
@patch.object(MockPatroni, 'dcs')
|
||||
def test_do_GET_cluster(self, mock_dcs):
|
||||
mock_dcs.cluster = get_cluster_initialized_without_leader()
|
||||
mock_dcs.cluster.members[1].data['xlog_location'] = 11
|
||||
self.assertIsNotNone(MockRestApiServer(RestApiHandler, 'GET /cluster'))
|
||||
|
||||
@patch.object(MockPatroni, 'dcs')
|
||||
def test_do_GET_history(self, mock_dcs):
|
||||
mock_dcs.cluster = get_cluster_initialized_without_leader()
|
||||
self.assertIsNotNone(MockRestApiServer(RestApiHandler, 'GET /history'))
|
||||
|
||||
@patch.object(MockPatroni, 'dcs')
|
||||
def test_do_GET_config(self, mock_dcs):
|
||||
mock_dcs.cluster.config.data = {}
|
||||
|
||||
@@ -566,6 +566,13 @@ class TestCtl(unittest.TestCase):
|
||||
result = self.runner.invoke(ctl, ['version', 'dummy'])
|
||||
assert 'failed to get version' in result.output
|
||||
|
||||
@patch('patroni.ctl.get_dcs')
|
||||
def test_history(self, mock_get_dcs):
|
||||
mock_get_dcs.return_value.get_cluster = Mock()
|
||||
mock_get_dcs.return_value.get_cluster.return_value.history.lines = [[1, 67176, 'no recovery target specified']]
|
||||
result = self.runner.invoke(ctl, ['history'])
|
||||
assert 'Reason' in result.output
|
||||
|
||||
def test_format_pg_version(self):
|
||||
self.assertEqual(format_pg_version(100001), '10.1')
|
||||
self.assertEqual(format_pg_version(90605), '9.6.5')
|
||||
|
||||
+8
-8
@@ -19,7 +19,6 @@ class TestPatroniLogger(unittest.TestCase):
|
||||
logging.getLogger().handlers[:] = self._handlers
|
||||
|
||||
@patch('logging.FileHandler._open', Mock())
|
||||
@patch('logging.Handler.close', Mock(side_effect=Exception))
|
||||
def test_patroni_logger(self):
|
||||
config = {
|
||||
'log': {
|
||||
@@ -47,13 +46,14 @@ class TestPatroniLogger(unittest.TestCase):
|
||||
self.assertEqual(logger.log_handler.backupCount, config['log']['file_num'])
|
||||
|
||||
config['log'].pop('dir')
|
||||
logger.reload_config(config['log'])
|
||||
with patch.object(logging.Logger, 'makeRecord',
|
||||
Mock(side_effect=[logging.LogRecord('', logging.INFO, '', 0, '', (), None), Exception])):
|
||||
with patch('logging.Handler.close', Mock(side_effect=Exception)):
|
||||
logger.reload_config(config['log'])
|
||||
with patch.object(logging.Logger, 'makeRecord',
|
||||
Mock(side_effect=[logging.LogRecord('', logging.INFO, '', 0, '', (), None), Exception])):
|
||||
logging.error('test')
|
||||
logging.error('test')
|
||||
logging.error('test')
|
||||
with patch.object(Queue, 'put_nowait', Mock(side_effect=Full)):
|
||||
self.assertRaises(SystemExit, logger.shutdown)
|
||||
self.assertRaises(Exception, logger.shutdown)
|
||||
with patch.object(Queue, 'put_nowait', Mock(side_effect=Full)):
|
||||
self.assertRaises(SystemExit, logger.shutdown)
|
||||
self.assertRaises(Exception, logger.shutdown)
|
||||
self.assertLessEqual(logger.queue_size, 2) # "Failed to close the old log handler" could be still in the queue
|
||||
self.assertEqual(logger.records_lost, 0)
|
||||
|
||||
Reference in New Issue
Block a user