From 6d6b504cb8ab34687040bebfa9844e1cd7354ff2 Mon Sep 17 00:00:00 2001 From: melrifa Date: Tue, 20 Apr 2021 02:43:05 -0500 Subject: [PATCH] Add support for patroni replication user socket connection (#1865) Close #1866 --- docs/SETTINGS.rst | 1 + features/environment.py | 1 + patroni/postgresql/config.py | 30 +++++++++++++----------------- tests/test_postgresql.py | 3 ++- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/SETTINGS.rst b/docs/SETTINGS.rst index cd951e68..75531dd9 100644 --- a/docs/SETTINGS.rst +++ b/docs/SETTINGS.rst @@ -293,6 +293,7 @@ PostgreSQL - **bin\_dir**: Path to PostgreSQL binaries (pg_ctl, pg_rewind, pg_basebackup, postgres). The default value is an empty string meaning that PATH environment variable will be used to find the executables. - **listen**: IP address + port that Postgres listens to; must be accessible from other nodes in the cluster, if you're using streaming replication. Multiple comma-separated addresses are permitted, as long as the port component is appended after to the last one with a colon, i.e. ``listen: 127.0.0.1,127.0.0.2:5432``. Patroni will use the first address from this list to establish local connections to the PostgreSQL node. - **use\_unix\_socket**: specifies that Patroni should prefer to use unix sockets to connect to the cluster. Default value is ``false``. If ``unix_socket_directories`` is defined, Patroni will use the first suitable value from it to connect to the cluster and fallback to tcp if nothing is suitable. If ``unix_socket_directories`` is not specified in ``postgresql.parameters``, Patroni will assume that the default value should be used and omit ``host`` from the connection parameters. + - **use\_unix\_socket\_repl**: specifies that Patroni should prefer to use unix sockets for replication user cluster connection. Default value is ``false``. If ``unix_socket_directories`` is defined, Patroni will use the first suitable value from it to connect to the cluster and fallback to tcp if nothing is suitable. If ``unix_socket_directories`` is not specified in ``postgresql.parameters``, Patroni will assume that the default value should be used and omit ``host`` from the connection parameters. - **pgpass**: path to the `.pgpass `__ password file. Patroni creates this file before executing pg\_basebackup, the post_init script and under some other circumstances. The location must be writable by Patroni. - **recovery\_conf**: additional configuration settings written to recovery.conf when configuring follower. - **custom\_conf** : path to an optional custom ``postgresql.conf`` file, that will be used in place of ``postgresql.base.conf``. The file must exist on all cluster nodes, be readable by PostgreSQL and will be included from its location on the real ``postgresql.conf``. Note that Patroni will not monitor this file for changes, nor backup it. However, its settings can still be overridden by Patroni's own configuration facilities - see :ref:`dynamic configuration ` for details. diff --git a/features/environment.py b/features/environment.py index 9a050923..d457ae12 100644 --- a/features/environment.py +++ b/features/environment.py @@ -180,6 +180,7 @@ class PatroniController(AbstractController): config['postgresql']['data_dir'] = self._data_dir config['postgresql']['basebackup'] = [{'checkpoint': 'fast'}] config['postgresql']['use_unix_socket'] = os.name != 'nt' # windows doesn't yet support unix-domain sockets + config['postgresql']['use_unix_socket_repl'] = os.name != 'nt' # windows doesn't yet support unix-domain sockets config['postgresql']['pgpass'] = os.path.join(tempfile.gettempdir(), 'pgpass_' + name) config['postgresql']['parameters'].update({ 'logging_collector': 'on', 'log_destination': 'csvlog', 'log_directory': self._output_dir, diff --git a/patroni/postgresql/config.py b/patroni/postgresql/config.py index d218b274..234b2523 100644 --- a/patroni/postgresql/config.py +++ b/patroni/postgresql/config.py @@ -877,25 +877,21 @@ class ConfigHandler(object): def resolve_connection_addresses(self): port = self._server_parameters['port'] tcp_local_address = self._get_tcp_local_address() - - local_address = {'port': port} - if self._config.get('use_unix_socket'): - unix_socket_directories = self._server_parameters.get('unix_socket_directories') - if unix_socket_directories is not None: - # fallback to tcp if unix_socket_directories is set, but there are no sutable values - local_address['host'] = self._get_unix_local_address(unix_socket_directories) or tcp_local_address - - # if unix_socket_directories is not specified, but use_unix_socket is set to true - do our best - # to use default value, i.e. don't specify a host neither in connection url nor arguments - else: - local_address['host'] = tcp_local_address - - self._local_address = local_address - self.local_replication_address = {'host': tcp_local_address, 'port': port} - netloc = self._config.get('connect_address') or tcp_local_address + ':' + port - self._postgresql.connection_string = uri('postgres', netloc, self._postgresql.database) + unix_socket_directories = self._server_parameters.get('unix_socket_directories') + # fallback to tcp if unix_socket_directories is set, but there are no sutable values + unix_local_address = unix_socket_directories and\ + self._get_unix_local_address(unix_socket_directories) or tcp_local_address + + tcp_local_address = {'host': tcp_local_address, 'port': port} + unix_local_address = {'host': unix_local_address, 'port': port} + + self._local_address = unix_local_address if self._config.get('use_unix_socket') else tcp_local_address + self.local_replication_address = unix_local_address\ + if self._config.get('use_unix_socket_repl') else tcp_local_address + + self._postgresql.connection_string = uri('postgres', netloc, self._postgresql.database) self._postgresql.set_connection_kwargs(self.local_connect_kwargs) def _get_pg_settings(self, names): diff --git a/tests/test_postgresql.py b/tests/test_postgresql.py index 2aa28383..a13dd73a 100644 --- a/tests/test_postgresql.py +++ b/tests/test_postgresql.py @@ -475,7 +475,8 @@ class TestPostgresql(BaseTestPostgresql): parameters = self._PARAMETERS.copy() parameters.pop('f.oo') parameters['wal_buffers'] = '512' - config = {'pg_hba': [''], 'pg_ident': [''], 'use_unix_socket': True, 'authentication': {}, + config = {'pg_hba': [''], 'pg_ident': [''], 'use_unix_socket': True, 'use_unix_socket_repl': True, + 'authentication': {}, 'retry_timeout': 10, 'listen': '*', 'krbsrvname': 'postgres', 'parameters': parameters} self.p.reload_config(config) mock_fetchone.side_effect = Exception