From e670122c805176a3689a7ddc8849a557038bde58 Mon Sep 17 00:00:00 2001 From: Alexander Kukushkin Date: Thu, 21 Feb 2019 11:37:50 +0100 Subject: [PATCH] Use create_replica_methods from standby_cluster for replica bootstrap (#981) It might happen that the standby cluster is configured to be created and replay WAL files from the different source than when it is running not in standby mode. This is necessary to avoid writing WAL files and backups into the old place after promotion. The easiest way to achieve such behavior is passing RemoteMember object to `Postgresql.clone` method instead of the usual Member object. --- patroni/ha.py | 15 +++++++++++---- tests/test_ha.py | 3 ++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/patroni/ha.py b/patroni/ha.py index a7d4ec6d..50250a15 100644 --- a/patroni/ha.py +++ b/patroni/ha.py @@ -206,6 +206,9 @@ class Ha(object): return self.dcs.touch_member(data) def clone(self, clone_member=None, msg='(without leader)'): + if self.is_standby_cluster() and not isinstance(clone_member, RemoteMember): + clone_member = self.get_remote_member(clone_member) + if self.state_handler.clone(clone_member): logger.info('bootstrapped %s', msg) cluster = self.dcs.get_cluster() @@ -1341,7 +1344,7 @@ class Ha(object): This usually happens on the master or if the node is running async action""" self.dcs.event.set() - def get_remote_master(self): + def get_remote_member(self, member=None): """ In case of standby cluster this will tel us from which remote master to stream. Config can be both patroni config or cluster.config.data @@ -1349,12 +1352,16 @@ class Ha(object): cluster_params = self.get_standby_cluster_config() if cluster_params: - unique_name = 'remote_master:{}'.format(uuid.uuid1()) + name = member.name if member else 'remote_master:{}'.format(uuid.uuid1()) data = {k: v for k, v in cluster_params.items() if k in RemoteMember.allowed_keys()} data['no_replication_slot'] = 'primary_slot_name' not in cluster_params - conn_kwargs = {k: cluster_params[k] for k in ('host', 'port') if k in cluster_params} + conn_kwargs = member.conn_kwargs() if member else \ + {k: cluster_params[k] for k in ('host', 'port') if k in cluster_params} if conn_kwargs: data['conn_kwargs'] = conn_kwargs - return RemoteMember(unique_name, data) + return RemoteMember(name, data) + + def get_remote_master(self): + return self.get_remote_member() diff --git a/tests/test_ha.py b/tests/test_ha.py index 758c6b17..e86eb261 100644 --- a/tests/test_ha.py +++ b/tests/test_ha.py @@ -211,7 +211,8 @@ class TestHa(unittest.TestCase): self.assertEqual(self.ha.run_cycle(), 'trying to bootstrap a new standby leader') @patch.object(Cluster, 'get_clone_member', - Mock(return_value=Member(0, 'test', 1, {'api_url': 'http://127.0.0.1:8011/patroni'}))) + Mock(return_value=Member(0, 'test', 1, {'api_url': 'http://127.0.0.1:8011/patroni', + 'conn_url': 'postgres://127.0.0.1:5432/postgres'}))) @patch.object(Postgresql, 'create_replica', Mock(return_value=0)) def test_start_as_cascade_replica_in_standby_cluster(self): self.p.data_directory_empty = true