Repository: zalando/patroni
Pull request #3082 (2024-06-14 14:32:12)

Don't socket.getaddrinfo() from config_generator.py
the get_address() function was called when config_generator.py is loaded because it was required to initialize _HOSTNAME and _IP properties of AbstractConfigGenerator and in some cases making unit tests very slow.

coveralls: ## Pull Request Test Coverage Report for [Build 9517842524](https://coveralls.io/builds/68093245)


### Details

* **3** of **3**   **(100.0%)**  changed or added relevant lines in **1** file are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage remained the same at **99.862%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/68093245/badge)](https://coveralls.io/builds/68093245) |
| :-- | --: |
| Change from base [Build 9512567968](https://coveralls.io/builds/68085944): |  0.0% |
| Covered Lines: | 13758 |
| Relevant Lines: | 13777 |

---
##### 💛  - [Coveralls](https://coveralls.io)

hughcapet: 👍 
CyberDem0n: :+1:

Patch:
diff --git a/patroni/config_generator.py b/patroni/config_generator.py
index e898c92a..027db1dc 100644
--- a/patroni/config_generator.py
+++ b/patroni/config_generator.py
@@ -72,8 +72,6 @@ class AbstractConfigGenerator(abc.ABC):
     :ivar config: dictionary used for the generated configuration storage.
     """
 
-    _HOSTNAME, _IP = get_address()
-
     def __init__(self, output_file: Optional[str]) -> None:
         """Set up the output file (if passed), helper vars and the minimal config structure.
 
@@ -92,12 +90,14 @@ class AbstractConfigGenerator(abc.ABC):
         :returns: dictionary with the values gathered from Patroni env, hopefully defined hostname and ip address
                   (otherwise set to :data:`~patroni.config_generator.NO_VALUE_MSG`), and some sane defaults.
         """
+        _HOSTNAME, _IP = get_address()
+
         template_config: Dict[str, Any] = {
             'scope': NO_VALUE_MSG,
-            'name': cls._HOSTNAME,
+            'name': _HOSTNAME,
             'restapi': {
-                'connect_address': cls._IP + ':8008',
-                'listen': cls._IP + ':8008'
+                'connect_address': _IP + ':8008',
+                'listen': _IP + ':8008'
             },
             'log': {
                 'type': PatroniLogger.DEFAULT_TYPE,
@@ -108,8 +108,8 @@ class AbstractConfigGenerator(abc.ABC):
             },
             'postgresql': {
                 'data_dir': NO_VALUE_MSG,
-                'connect_address': cls._IP + ':5432',
-                'listen': cls._IP + ':5432',
+                'connect_address': _IP + ':5432',
+                'listen': _IP + ':5432',
                 'bin_dir': '',
                 'authentication': {
                     'superuser': {
@@ -400,8 +400,9 @@ class RunningClusterConfigGenerator(AbstractConfigGenerator):
             else:
                 self.config['bootstrap']['dcs']['postgresql']['parameters'][param] = value
 
+        connect_ip = self.config['postgresql']['connect_address'].rsplit(':')[0]
         connect_port = self.parsed_dsn.get('port', os.getenv('PGPORT', helper_dict['port']))
-        self.config['postgresql']['connect_address'] = f'{self._IP}:{connect_port}'
+        self.config['postgresql']['connect_address'] = f'{connect_ip}:{connect_port}'
         self.config['postgresql']['listen'] = f'{helper_dict["listen_addresses"]}:{helper_dict["port"]}'
 
     def _set_su_params(self) -> None:


Test patch:
diff --git a/tests/test_config_generator.py b/tests/test_config_generator.py
index d6311a03..1ee0fb7f 100644
--- a/tests/test_config_generator.py
+++ b/tests/test_config_generator.py
@@ -32,8 +32,7 @@ def mock_open(*args, **kwargs):
 @patch('subprocess.check_output', Mock(return_value=b"postgres (PostgreSQL) 16.2"))
 @patch('psutil.Process.exe', Mock(return_value='/bin/dir/from/running/postgres'))
 @patch('psutil.Process.__init__', Mock(return_value=None))
-@patch.object(AbstractConfigGenerator, '_HOSTNAME', HOSTNAME)
-@patch.object(AbstractConfigGenerator, '_IP', IP)
+@patch('patroni.config_generator.get_address', Mock(return_value=(HOSTNAME, IP)))
 class TestGenerateConfig(unittest.TestCase):
 
     def setUp(self):