Silence annoying warnings when checking for node uniqueness (#2878)

WARNING messages are produced by `urllib3` if Patroni is quickly restarted.
Instead we will check that the node is listen on a given port. This fact is actually enough to detect names clashes, while HTTP request could raise an exception is a few other cases, what might case false negatives.

Close https://github.com/zalando/patroni/issues/2881
This commit is contained in:
Alexander Kukushkin
2023-09-26 11:16:38 +02:00
parent 4a4a7dab45
commit dbbe065a27
2 changed files with 13 additions and 7 deletions
+8 -3
View File
@@ -65,6 +65,8 @@ class Patroni(AbstractPatroniDaemon):
def ensure_unique_name(self) -> None:
"""A helper method to prevent splitbrain from operator naming error."""
from urllib.parse import urlparse
from urllib3.connection import HTTPConnection
from patroni.dcs import Member
cluster = self.dcs.get_cluster()
@@ -74,9 +76,12 @@ class Patroni(AbstractPatroniDaemon):
if not isinstance(member, Member):
return
try:
_ = self.request(member, endpoint="/liveness", timeout=3)
logger.fatal("Can't start; there is already a node named '%s' running", self.config['name'])
sys.exit(1)
parts = urlparse(member.api_url)
if isinstance(parts.hostname, str):
connection = HTTPConnection(parts.hostname, port=parts.port or 80, timeout=3)
connection.connect()
logger.fatal("Can't start; there is already a node named '%s' running", self.config['name'])
sys.exit(1)
except Exception:
return
+5 -4
View File
@@ -40,7 +40,7 @@ class MockFrozenImporter(object):
@patch('time.sleep', Mock())
@patch('subprocess.call', Mock(return_value=0))
@patch('patroni.psycopg.connect', psycopg_connect)
@patch('urllib3.PoolManager.request', Mock(side_effect=Exception))
@patch('urllib3.connection.HTTPConnection.connect', Mock(side_effect=Exception))
@patch.object(ConfigHandler, 'append_pg_hba', Mock())
@patch.object(ConfigHandler, 'write_postgresql_conf', Mock())
@patch.object(ConfigHandler, 'write_recovery_conf', Mock())
@@ -64,7 +64,7 @@ class TestPatroni(unittest.TestCase):
self.assertRaises(SystemExit, _main)
@patch('pkgutil.iter_importers', Mock(return_value=[MockFrozenImporter()]))
@patch('urllib3.PoolManager.request', Mock(side_effect=Exception))
@patch('urllib3.connection.HTTPConnection.connect', Mock(side_effect=Exception))
@patch('sys.frozen', Mock(return_value=True), create=True)
@patch.object(HTTPServer, '__init__', Mock())
@patch.object(etcd.Client, 'read', etcd_read)
@@ -108,6 +108,7 @@ class TestPatroni(unittest.TestCase):
@patch('os.getpid')
@patch('multiprocessing.Process')
@patch('patroni.__main__.patroni_main', Mock())
@patch('sys.argv', ['patroni.py', 'postgres0.yml'])
def test_patroni_main(self, mock_process, mock_getpid):
mock_getpid.return_value = 2
_main()
@@ -233,8 +234,8 @@ class TestPatroni(unittest.TestCase):
)
with patch('patroni.dcs.AbstractDCS.get_cluster', Mock(return_value=bad_cluster)):
# If the api of the running node cannot be reached, this implies unique name
with patch.object(self.p, 'request', Mock(side_effect=ConnectionError)):
with patch('urllib3.connection.HTTPConnection.connect', Mock(side_effect=ConnectionError)):
self.assertIsNone(self.p.ensure_unique_name())
# Only if the api of the running node is reachable do we throw an error
with patch.object(self.p, 'request', Mock()):
with patch('urllib3.connection.HTTPConnection.connect', Mock()):
self.assertRaises(SystemExit, self.p.ensure_unique_name)