Rename create_replica_method to create_replica_methods

To make it clear that it's actually an array
This commit is contained in:
erthalion
2018-06-12 11:33:13 +02:00
parent e5f2511764
commit d037aa8afd
4 changed files with 42 additions and 11 deletions

View File

@@ -131,7 +131,7 @@ PostgreSQL
- **pg\_ctl\_timeout**: How long should pg_ctl wait when doing ``start``, ``stop`` or ``restart``. Default value is 60 seconds.
- **use\_pg\_rewind**: try to use pg\_rewind on the former leader when it joins cluster as a replica.
- **remove\_data\_directory\_on\_rewind\_failure**: If this option is enabled, Patroni will remove postgres data directory and recreate replica. Otherwise it will try to follow the new leader. Default value is **false**.
- **replica\_method**: for each create_replica_method other than basebackup, you would add a configuration section of the same name. At a minimum, this should include "command" with a full path to the actual script to be executed. Other configuration parameters will be passed along to the script in the form "parameter=value".
- **replica\_method**: for each create_replica_methods other than basebackup, you would add a configuration section of the same name. At a minimum, this should include "command" with a full path to the actual script to be executed. Other configuration parameters will be passed along to the script in the form "parameter=value".
REST API
--------

View File

@@ -68,7 +68,7 @@ scripts to clone a new replica. Those are configured in the ``postgresql`` confi
.. code:: YAML
postgresql:
create_replica_method:
create_replica_methods:
- wal_e
- basebackup
wal_e:
@@ -80,7 +80,7 @@ scripts to clone a new replica. Those are configured in the ``postgresql`` confi
max-rate: '100M'
The ``create_replica_method`` defines available replica creation methods and the order of executing them. Patroni will
The ``create_replica_methods`` defines available replica creation methods and the order of executing them. Patroni will
stop on the first one that returns 0. Each method should define a separate section in the configuration file, listing the command
to execute and any custom parameters that should be passed to that command. All parameters will be passed in a
``--name=value`` format. Besides user-defined parameters, Patroni supplies a couple of cluster-specific ones:
@@ -99,8 +99,9 @@ A special ``no_master`` parameter, if defined, allows Patroni to call the replic
running master or replicas. In that case, an empty string will be passed in a connection string. This is useful for
restoring the formerly running cluster from the binary backup.
A ``basebackup`` method is a special case: it will be used if ``create_replica_method`` is empty, although it is possible
to list it explicitly among the ``create_replica_method`` methods. This method initializes a new replica with the
A ``basebackup`` method is a special case: it will be used if
``create_replica_methods`` is empty, although it is possible
to list it explicitly among the ``create_replica_methods`` methods. This method initializes a new replica with the
``pg_basebackup``, the base backup is taken from the master unless there are replicas with ``clonefrom`` tag, in which case one
of such replicas will be used as the origin for pg_basebackup. It works without any configuration; however, it is
possible to specify a ``basebackup`` configuration section. Same rules as with the other method configuration apply,

View File

@@ -180,6 +180,11 @@ class Postgresql(object):
if self._replace_pg_hba():
self.reload()
@property
def _create_replica_methods(self):
return (self.config.get('create_replica_methods', []) or
self.config.get('create_replica_method', []))
@property
def _configuration_to_save(self):
configuration = [os.path.basename(self._postgresql_conf)]
@@ -638,7 +643,7 @@ class Postgresql(object):
""" go through the replication methods to see if there are ones
that does not require a working replication connection.
"""
replica_methods = self.config.get('create_replica_method', [])
replica_methods = self._create_replica_methods
return any(self.replica_method_can_work_without_replication_connection(method) for method in replica_methods)
def create_replica(self, clone_member):
@@ -653,7 +658,7 @@ class Postgresql(object):
# get list of replica methods from config.
# If there is no configuration key, or no value is specified, use basebackup
replica_methods = self.config.get('create_replica_method') or ['basebackup']
replica_methods = self._create_replica_methods or ['basebackup']
if clone_member and clone_member.conn_url:
r = clone_member.conn_kwargs(self._replication)
@@ -1622,7 +1627,7 @@ $$""".format(name, ' '.join(options)), name, password, password)
def basebackup(self, conn_url, env, options):
# creates a replica data dir using pg_basebackup.
# this is the default, built-in create_replica_method
# this is the default, built-in create_replica_methods
# tries twice, then returns failure (as 1)
# uses "stream" as the xlog-method to avoid sync issues
# supports additional user-supplied options, those are not validated

View File

@@ -420,14 +420,14 @@ class TestPostgresql(unittest.TestCase):
def test_create_replica(self, mock_cancellable_subprocess_call):
self.p.delete_trigger_file = Mock(side_effect=OSError)
self.p.config['create_replica_method'] = ['wale', 'basebackup']
self.p.config['create_replica_methods'] = ['wale', 'basebackup']
self.p.config['wale'] = {'command': 'foo'}
mock_cancellable_subprocess_call.return_value = 0
self.assertEquals(self.p.create_replica(self.leader), 0)
del self.p.config['wale']
self.assertEquals(self.p.create_replica(self.leader), 0)
self.p.config['create_replica_method'] = ['basebackup']
self.p.config['create_replica_methods'] = ['basebackup']
self.p.config['basebackup'] = [{'max_rate': '100M'}, 'no-sync']
self.assertEquals(self.p.create_replica(self.leader), 0)
@@ -448,7 +448,7 @@ class TestPostgresql(unittest.TestCase):
self.p.config['basebackup'] = {"foo": "bar"}
self.assertEquals(self.p.create_replica(self.leader), 0)
self.p.config['create_replica_method'] = ['wale', 'basebackup']
self.p.config['create_replica_methods'] = ['wale', 'basebackup']
del self.p.config['basebackup']
mock_cancellable_subprocess_call.return_value = 1
self.assertEquals(self.p.create_replica(self.leader), 1)
@@ -465,6 +465,31 @@ class TestPostgresql(unittest.TestCase):
self.p.cancel()
self.assertEquals(self.p.create_replica(self.leader), 1)
@patch('time.sleep', Mock())
@patch.object(Postgresql, 'cancellable_subprocess_call')
@patch.object(Postgresql, 'remove_data_directory', Mock(return_value=True))
def test_create_replica_old_format(self, mock_cancellable_subprocess_call):
""" The same test as before but with old 'create_replica_method'
to test backward compatibility
"""
self.p.delete_trigger_file = Mock(side_effect=OSError)
self.p.config['create_replica_method'] = ['wale', 'basebackup']
self.p.config['wale'] = {'command': 'foo'}
mock_cancellable_subprocess_call.return_value = 0
self.assertEquals(self.p.create_replica(self.leader), 0)
del self.p.config['wale']
self.assertEquals(self.p.create_replica(self.leader), 0)
self.p.config['create_replica_method'] = ['basebackup']
self.p.config['basebackup'] = [{'max_rate': '100M'}, 'no-sync']
self.assertEquals(self.p.create_replica(self.leader), 0)
self.p.config['create_replica_method'] = ['wale', 'basebackup']
del self.p.config['basebackup']
mock_cancellable_subprocess_call.return_value = 1
self.assertEquals(self.p.create_replica(self.leader), 1)
def test_basebackup(self):
self.p.cancel()
self.p.basebackup(None, None, {'foo': 'bar'})