Compare commits

..
7 Commits
Author SHA1 Message Date
Oleksii KliukinandGitHub 720d08d1b4 Bump up to 1.2.4 (#409) 2017-03-06 12:48:56 +01:00
Dr Nic WilliamsandOleksii Kliukin d39bd4363d shorter, more correct spelling of navigate [fixes #394] (#407) 2017-03-04 13:42:10 +01:00
Lauri AppleandGitHub 48e1b976b3 Merge pull request #398 from zalando/LappleApple-patch-1
Update README.rst
2017-02-16 18:23:56 +01:00
Lauri AppleandGitHub fb17eeaf94 Update README.rst
adjusted the Helm chart language to be more precise, and fixed a broken link at the end
2017-02-16 17:43:45 +01:00
Alexander KukushkinandGitHub 0443844f65 Make it possible to compare xlog location against replica (#396) 2017-02-16 17:07:34 +01:00
Alexander KukushkinandGitHub 3ece35c0a6 Reassemble postgresql parameters when major version became known (#395)
* Reassemble postgresql parameters when major version became known

Otherwise we were writing some "unknown" parameters into postgresql.conf
and postgres was refusing to start. Only 9.3 was affected.

In addition to that move rename of wal_level from hot_standby to replica
into get_server_parameters method. Now this rename is handled in a
single place.

* Bump etcd and consul versions
2017-02-16 17:07:21 +01:00
Alexander KukushkinandGitHub 1ed91a93c6 Handle EtcdEventIndexCleared and EtcdWatcherCleared exceptions (#387)
If this case it doesn't make sense to retry, because it brings nothing
but produces a log of exceptions in the log...
2017-02-16 17:07:09 +01:00
8 changed files with 27 additions and 15 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ python:
- "3.4" # 2.7 and 3.5 are preinstalled by default
env:
global:
- ETCDVERSION=3.0.15 ZKVERSION=3.4.9 CONSULVERSION=0.7.2
- ETCDVERSION=3.0.17 ZKVERSION=3.4.9 CONSULVERSION=0.7.4
- PYVERSIONS="2.7 3.4 3.5"
matrix:
- TEST_SUITE="python setup.py"
+3 -3
View File
@@ -3,7 +3,7 @@
Patroni: A Template for PostgreSQL HA with ZooKeeper, etcd or Consul
------------------------------------------------------------
You can find a version of this documentation that is searchable and also easier to navigagate at `patroni.readthedocs.io <https://patroni.readthedocs.io>`__.
You can find a version of this documentation that is searchable and also easier to navigate at `patroni.readthedocs.io <https://patroni.readthedocs.io>`__.
There are many ways to run high availability with PostgreSQL; for a list, see the `PostgreSQL Documentation <https://wiki.postgresql.org/wiki/Replication,_Clustering,_and_Connection_Pooling>`__.
@@ -12,7 +12,7 @@ Patroni is a template for you to create your own customized, high-availability s
We call Patroni a "template" because it is far from being a one-size-fits-all or plug-and-play replication system. It will have its own caveats. Use wisely.
**Note to Kubernetes users**: We're currently developing Patroni to be as useful as possible for teams running Kubernetes on top of Google Compute Engine; Patroni can be the HA solution for Postgres in such an environment. To this end, we've created a `Helm Chart <https://github.com/kubernetes/charts/tree/master/incubator/patroni>`__ that enables you to deploy a five-node Patroni cluster using a Kubernetes PetSet.
**Note to Kubernetes users**: We're currently developing Patroni to be as useful as possible for teams running Kubernetes on top of Google Compute Engine; Patroni can be the HA solution for Postgres in such an environment. To this end, there is a `Helm chart <https://github.com/kubernetes/charts/tree/master/incubator/patroni>`__ that uses Patroni and `Spilo <https://github.com/zalando/spilo/>`__ to provision a five-node PostgreSQL HA cluster in a Kubernetes+GCE environment. (The Helm chart deploys Spilo Docker images, not just "bare" Patroni.)
.. contents::
:local:
@@ -95,7 +95,7 @@ Go `here <https://github.com/zalando/patroni/blob/master/docs/ENVIRONMENT.rst>`_
Replication Choices
===============
Patroni uses Postgres' streaming replication, which is asynchronous by default. Patroni's asynchronous replication configuration allows for ``maximum_lag_on_failover`` settings. This setting ensures failover will not occur if a follower is more than a certain number of bytes behind the leader. This setting should be increased or decreased based on business requirements. It's also possible to use synchronous replication for better durability guarantees. See `replication modes documentation <https://github.com/zalando/patroni/blob/master/docs/replication_modes.rst>` for details.
Patroni uses Postgres' streaming replication, which is asynchronous by default. Patroni's asynchronous replication configuration allows for ``maximum_lag_on_failover`` settings. This setting ensures failover will not occur if a follower is more than a certain number of bytes behind the leader. This setting should be increased or decreased based on business requirements. It's also possible to use synchronous replication for better durability guarantees. See `replication modes documentation <https://github.com/zalando/patroni/blob/master/docs/replication_modes.rst>`__ for details.
===============================
Applications Should Not Use Superusers
+2
View File
@@ -530,6 +530,8 @@ class Etcd(AbstractDCS):
except etcd.EtcdWatchTimedOut:
self._client.http.clear()
return False
except (etcd.EtcdEventIndexCleared, etcd.EtcdWatcherCleared): # Watch failed
return True # leave the loop, because watch with the same parameters will fail anyway
except etcd.EtcdException:
logger.exception('watch')
+5 -5
View File
@@ -177,6 +177,8 @@ class Postgresql(object):
parameters.pop('synchronous_standby_names', None)
else:
parameters['synchronous_standby_names'] = self._synchronous_standby_names
if self._major_version >= 9.6 and parameters['wal_level'] == 'hot_standby':
parameters['wal_level'] = 'replica'
return {k: v for k, v in parameters.items() if not self._major_version or
self._major_version >= self.CMDLINE_OPTIONS.get(k, (0, 1, 9.1))[2]}
@@ -249,8 +251,6 @@ class Postgresql(object):
elif r[0] in changes:
unit = changes['wal_segment_size'] if r[0] in ('min_wal_size', 'max_wal_size') else r[2]
new_value = changes.pop(r[0])
if self._major_version >= 9.6 and r[0] == 'wal_level' and new_value == 'hot_standby':
new_value = 'replica'
if new_value is None or not compare_values(r[3], unit, r[1], new_value):
if r[4] == 'postmaster':
pending_restart = True
@@ -435,6 +435,7 @@ class Postgresql(object):
if ret:
self.write_pg_hba(config.get('pg_hba', []))
self._major_version = self.get_major_version()
self._server_parameters = self.get_server_parameters(self.config)
else:
self.set_state('initdb failed')
return ret
@@ -697,9 +698,7 @@ class Postgresql(object):
self._write_postgresql_conf()
self.resolve_connection_addresses()
opts = {p: self._server_parameters[p] for p, v in self.CMDLINE_OPTIONS.items() if self._major_version >= v[2]}
if self._major_version >= 9.6 and opts['wal_level'] == 'hot_standby':
opts['wal_level'] = 'replica'
opts = {p: self._server_parameters[p] for p in self.CMDLINE_OPTIONS if p in self._server_parameters}
options = ['--{0}={1}'.format(p, v) for p, v in opts.items()]
start_initiated = time.time()
@@ -1209,6 +1208,7 @@ $$""".format(name, ' '.join(options)), name, password, password)
ret = self.create_replica(clone_member) == 0
if ret:
self._major_version = self.get_major_version()
self._server_parameters = self.get_server_parameters(self.config)
self.delete_trigger_file()
self.restore_configuration_files()
return ret
+10 -2
View File
@@ -133,8 +133,16 @@ class WALERestore(object):
with psycopg2.connect(self.master_connection) as con:
con.autocommit = True
with con.cursor() as cur:
cur.execute("SELECT pg_xlog_location_diff(pg_current_xlog_location(), %s)",
(backup_start_lsn,))
cur.execute("""SELECT CASE WHEN pg_is_in_recovery()
THEN GREATEST(
pg_xlog_location_diff(COALESCE(
pg_last_xlog_receive_location(), '0/0'), %s)::bigint,
pg_xlog_location_diff(
pg_last_xlog_replay_location(), %s)::bigint)
ELSE pg_xlog_location_diff(
pg_current_xlog_location(), %s)::bigint
END""", (backup_start_lsn, backup_start_lsn, backup_start_lsn))
diff_in_bytes = int(cur.fetchone()[0])
except psycopg2.Error:
logger.exception('could not determine difference with the master location')
+1 -1
View File
@@ -1 +1 @@
__version__ = '1.2.3'
__version__ = '1.2.4'
+3
View File
@@ -61,6 +61,8 @@ def etcd_watch(self, key, index=None, timeout=None, recursive=None):
return etcd.EtcdResult('delete', {})
elif timeout == 10.0:
raise etcd.EtcdException
elif timeout == 20.0:
raise etcd.EtcdEventIndexCleared
def etcd_write(self, key, value, **kwargs):
@@ -307,6 +309,7 @@ class TestEtcd(unittest.TestCase):
self.etcd.watch(20729, 1.5)
self.etcd.watch(20729, 4.5)
with patch.object(AbstractDCS, 'watch', Mock()):
self.assertTrue(self.etcd.watch(20729, 19.5))
self.etcd.watch(20729, 9.5)
def test_other_exceptions(self):
+2 -3
View File
@@ -41,8 +41,7 @@ class MockCursor(object):
('search_path', 'public', None, 'string', 'user'),
('port', '5433', None, 'integer', 'postmaster'),
('listen_addresses', '*', None, 'string', 'postmaster'),
('autovacuum', 'on', None, 'bool', 'sighup'),
('wal_level', 'replica', None, 'enum', 'postmaster')]
('autovacuum', 'on', None, 'bool', 'sighup')]
else:
self.results = [(None, None, None, None, None, None, None, None, None, None)]
@@ -766,7 +765,7 @@ class TestPostgresql(unittest.TestCase):
self.assertEquals(value_in_conf(), None)
def test_get_server_parameters(self):
config = {'synchronous_mode': True, 'parameters': {}, 'listen': '0'}
config = {'synchronous_mode': True, 'parameters': {'wal_level': 'hot_standby'}, 'listen': '0'}
self.p.get_server_parameters(config)
self.p.set_synchronous_standby('foo')
self.p.get_server_parameters(config)