From 8f8e9c9b81514a1e2a0d55e899a741b6b39443c2 Mon Sep 17 00:00:00 2001 From: Alexander Kukushkin Date: Mon, 24 Oct 2022 10:23:06 +0200 Subject: [PATCH] Inptroduce postgresql.proxy_address (#2437) It will be written to member key in DCS as the `proxy_url` and could be used/useful for service discovery. --- docs/ENVIRONMENT.rst | 1 + docs/SETTINGS.rst | 1 + patroni/config.py | 6 ++++-- patroni/ha.py | 4 ++++ patroni/postgresql/config.py | 3 +++ patroni/validator.py | 1 + postgres0.yml | 2 ++ postgres1.yml | 1 + postgres2.yml | 1 + tests/__init__.py | 3 ++- tests/test_config.py | 1 + tests/test_validator.py | 1 + 12 files changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/ENVIRONMENT.rst b/docs/ENVIRONMENT.rst index 49deb143..d189b63f 100644 --- a/docs/ENVIRONMENT.rst +++ b/docs/ENVIRONMENT.rst @@ -123,6 +123,7 @@ PostgreSQL ---------- - **PATRONI\_POSTGRESQL\_LISTEN**: IP address + port that Postgres listens to. 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. - **PATRONI\_POSTGRESQL\_CONNECT\_ADDRESS**: IP address + port through which Postgres is accessible from other nodes and applications. +- **PATRONI\_POSTGRESQL\_PROXY\_ADDRESS**: IP address + port through which a connection pool (e.g. pgbouncer) running next to Postgres is accessible. The value is written to the member key in DCS as ``proxy_url`` and could be used/useful for service discovery. - **PATRONI\_POSTGRESQL\_DATA\_DIR**: The location of the Postgres data directory, either existing or to be initialized by Patroni. - **PATRONI\_POSTGRESQL\_CONFIG\_DIR**: The location of the Postgres configuration directory, defaults to the data directory. Must be writable by Patroni. - **PATRONI\_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. diff --git a/docs/SETTINGS.rst b/docs/SETTINGS.rst index e41bee02..3c783654 100644 --- a/docs/SETTINGS.rst +++ b/docs/SETTINGS.rst @@ -292,6 +292,7 @@ PostgreSQL - **on\_start**: run this script when the postgres starts. - **on\_stop**: run this script when the postgres stops. - **connect\_address**: IP address + port through which Postgres is accessible from other nodes and applications. + - **proxy\_address**: IP address + port through which a connection pool (e.g. pgbouncer) running next to Postgres is accessible. The value is written to the member key in DCS as ``proxy_url`` and could be used/useful for service discovery. - **create\_replica\_methods**: an ordered list of the create methods for turning a Patroni node into a new replica. "basebackup" is the default method; other methods are assumed to refer to scripts, each of which is configured as its own config item. See :ref:`custom replica creation methods documentation ` for further explanation. diff --git a/patroni/config.py b/patroni/config.py index 0ae9726a..23b5e38b 100644 --- a/patroni/config.py +++ b/patroni/config.py @@ -227,7 +227,8 @@ class Config(object): for name, value in (value or {}).items(): if name == 'parameters': config['postgresql'][name].update(self._process_postgresql_parameters(value)) - elif name not in ('connect_address', 'listen', 'data_dir', 'pgpass', 'authentication'): + elif name not in ('connect_address', 'proxy_address', 'listen', + 'config_dir', 'data_dir', 'pgpass', 'authentication'): config['postgresql'][name] = deepcopy(value) elif name == 'standby_cluster': for name, value in (value or {}).items(): @@ -271,7 +272,8 @@ class Config(object): 'cafile', 'ciphers', 'verify_client', 'http_extra_headers', 'https_extra_headers', 'allowlist', 'allowlist_include_members']) _set_section_values('ctl', ['insecure', 'cacert', 'certfile', 'keyfile', 'keyfile_password']) - _set_section_values('postgresql', ['listen', 'connect_address', 'config_dir', 'data_dir', 'pgpass', 'bin_dir']) + _set_section_values('postgresql', ['listen', 'connect_address', 'proxy_address', + 'config_dir', 'data_dir', 'pgpass', 'bin_dir']) _set_section_values('log', ['level', 'traceback_level', 'format', 'dateformat', 'max_queue_size', 'dir', 'file_size', 'file_num', 'loggers']) _set_section_values('raft', ['data_dir', 'self_addr', 'partner_addrs', 'password', 'bind_addr']) diff --git a/patroni/ha.py b/patroni/ha.py index 3ec672b9..ba4fd2cf 100644 --- a/patroni/ha.py +++ b/patroni/ha.py @@ -192,6 +192,10 @@ class Ha(object): 'version': self.patroni.version } + proxy_url = self.state_handler.proxy_url + if proxy_url: + data['proxy_url'] = proxy_url + if self.is_leader() and not self._rewind.checkpoint_after_promote(): data['checkpoint_after_promote'] = False tags = self.get_effective_tags() diff --git a/patroni/postgresql/config.py b/patroni/postgresql/config.py index 93143152..b732d01f 100644 --- a/patroni/postgresql/config.py +++ b/patroni/postgresql/config.py @@ -1017,6 +1017,9 @@ class ConfigHandler(object): if not local_connection_address_changed: self.resolve_connection_addresses() + proxy_addr = config.get('proxy_address') + self._postgresql.proxy_url = uri('postgres', proxy_addr, self._postgresql.database) if proxy_addr else None + if conf_changed: self.write_postgresql_conf() diff --git a/patroni/validator.py b/patroni/validator.py index 839a9016..d0e1fa01 100644 --- a/patroni/validator.py +++ b/patroni/validator.py @@ -370,6 +370,7 @@ schema = Schema({ "postgresql": { "listen": validate_host_port_listen_multiple_hosts, "connect_address": validate_connect_address, + "proxy_address": validate_connect_address, "authentication": { "replication": userattributes, "superuser": userattributes, diff --git a/postgres0.yml b/postgres0.yml index 33ead029..c10b847a 100644 --- a/postgres0.yml +++ b/postgres0.yml @@ -99,6 +99,8 @@ bootstrap: postgresql: listen: 127.0.0.1:5432 connect_address: 127.0.0.1:5432 + +# proxy_address: 127.0.0.1:5433 # The address of connection pool (e.g., pgbouncer) running next to Patroni/Postgres. Only for service discovery. data_dir: data/postgresql0 # bin_dir: # config_dir: diff --git a/postgres1.yml b/postgres1.yml index 6721a745..9e58ace8 100644 --- a/postgres1.yml +++ b/postgres1.yml @@ -93,6 +93,7 @@ bootstrap: postgresql: listen: 127.0.0.1:5433 connect_address: 127.0.0.1:5433 +# proxy_address: 127.0.0.1:5434 # The address of connection pool (e.g., pgbouncer) running next to Patroni/Postgres. Only for service discovery. data_dir: data/postgresql1 # bin_dir: # config_dir: diff --git a/postgres2.yml b/postgres2.yml index 824afd75..2b19bcd4 100644 --- a/postgres2.yml +++ b/postgres2.yml @@ -90,6 +90,7 @@ bootstrap: postgresql: listen: 127.0.0.1:5434 connect_address: 127.0.0.1:5434 +# proxy_address: 127.0.0.1:5435 # The address of connection pool (e.g., pgbouncer) running next to Patroni/Postgres. Only for service discovery. data_dir: data/postgresql2 # bin_dir: # config_dir: diff --git a/tests/__init__.py b/tests/__init__.py index 9a81108f..7d388853 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -188,7 +188,8 @@ class PostgresInit(unittest.TestCase): self.p = Postgresql({'name': 'postgresql0', 'scope': 'batman', 'data_dir': data_dir, 'config_dir': data_dir, 'retry_timeout': 10, 'krbsrvname': 'postgres', 'pgpass': os.path.join(data_dir, 'pgpass0'), - 'listen': '127.0.0.2, 127.0.0.3:5432', 'connect_address': '127.0.0.2:5432', + 'listen': '127.0.0.2, 127.0.0.3:5432', + 'connect_address': '127.0.0.2:5432', 'proxy_address': '127.0.0.2:5433', 'authentication': {'superuser': {'username': 'foo', 'password': 'test'}, 'replication': {'username': '', 'password': 'rep-pass'}, 'rewind': {'username': 'rewind', 'password': 'test'}}, diff --git a/tests/test_config.py b/tests/test_config.py index dddae174..e74a7be1 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -40,6 +40,7 @@ class TestConfig(unittest.TestCase): 'PATRONI_RESTAPI_ALLOWLIST_INCLUDE_MEMBERS': 'on', 'PATRONI_POSTGRESQL_LISTEN': '0.0.0.0:5432', 'PATRONI_POSTGRESQL_CONNECT_ADDRESS': '127.0.0.1:5432', + 'PATRONI_POSTGRESQL_PROXY_ADDRESS': '127.0.0.1:5433', 'PATRONI_POSTGRESQL_DATA_DIR': 'data/postgres0', 'PATRONI_POSTGRESQL_CONFIG_DIR': 'data/postgres0', 'PATRONI_POSTGRESQL_PGPASS': '/tmp/pgpass0', diff --git a/tests/test_validator.py b/tests/test_validator.py index 9ccc6a7d..244cd342 100644 --- a/tests/test_validator.py +++ b/tests/test_validator.py @@ -63,6 +63,7 @@ config = { "postgresql": { "listen": "127.0.0.2,::1:543", "connect_address": "127.0.0.2:543", + "proxy_address": "127.0.0.2:5433", "authentication": { "replication": {"username": "user"}, "superuser": {"username": "user"},