Merge branch 'master' of github.com:zalando/patroni into feature/disable-automatic-failover

This commit is contained in:
Alexander Kukushkin
2016-08-26 11:09:43 +02:00
6 changed files with 150 additions and 203 deletions
+2 -2
View File
@@ -182,8 +182,8 @@ class Ha(object):
is_master = json['role'] == 'master' is_master = json['role'] == 'master'
xlog_location = None if is_master else json['xlog']['replayed_location'] xlog_location = None if is_master else json['xlog']['replayed_location']
return (member, True, not is_master, xlog_location, json.get('tags', {})) return (member, True, not is_master, xlog_location, json.get('tags', {}))
except: except Exception as e:
logger.exception('request failed: GET %s', member.api_url) logger.warning("request failed: GET %s (%s)", member.api_url, e)
return (member, False, None, 0, {}) return (member, False, None, 0, {})
def fetch_nodes_statuses(self, members): def fetch_nodes_statuses(self, members):
+6 -6
View File
@@ -503,6 +503,12 @@ class Postgresql(object):
self._state = value self._state = value
def start(self, block_callbacks=False): def start(self, block_callbacks=False):
# make sure we close all connections established against
# the former node, otherwise, we might get a stalled one
# after kill -9, which would report incorrect data to
# patroni.
self.close_connection()
if self.is_running(): if self.is_running():
logger.error('Cannot start PostgreSQL because one is already running.') logger.error('Cannot start PostgreSQL because one is already running.')
return True return True
@@ -559,12 +565,6 @@ class Postgresql(object):
return 'not accessible or not healty' return 'not accessible or not healty'
def stop(self, mode='fast', block_callbacks=False, checkpoint=True): def stop(self, mode='fast', block_callbacks=False, checkpoint=True):
# make sure we close all connections established against
# the former node, otherwise, we might get a stalled one
# after kill -9, which would report incorrect data to
# patroni.
self.close_connection()
if not self.is_running(): if not self.is_running():
if not block_callbacks: if not block_callbacks:
self.set_state('stopped') self.set_state('stopped')
+8 -6
View File
@@ -4,10 +4,12 @@ name: postgresql0
restapi: restapi:
listen: 127.0.0.1:8008 listen: 127.0.0.1:8008
connect_address: 127.0.0.1:8008
# certfile: /etc/ssl/certs/ssl-cert-snakeoil.pem
# keyfile: /etc/ssl/private/ssl-cert-snakeoil.key
# authentication: # authentication:
# username: username # username: username
# password: password # password: password
connect_address: 127.0.0.1:8008
etcd: etcd:
host: 127.0.0.1:4001 host: 127.0.0.1:4001
@@ -30,11 +32,11 @@ bootstrap:
# max_wal_senders: 5 # max_wal_senders: 5
# max_replication_slots: 5 # max_replication_slots: 5
# wal_log_hints: "on" # wal_log_hints: "on"
archive_mode: "on" # archive_mode: "on"
archive_timeout: 1800s # archive_timeout: 1800s
archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f # archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f
recovery_conf: # recovery_conf:
restore_command: cp ../wal_archive/%f %p # restore_command: cp ../wal_archive/%f %p
# some desired options for 'initdb' # some desired options for 'initdb'
initdb: # Note: It needs to be a list (some options need values, others are switches) initdb: # Note: It needs to be a list (some options need values, others are switches)
+62 -90
View File
@@ -1,105 +1,77 @@
ttl: &ttl 30 scope: batman
loop_wait: &loop_wait 10 #namespace: /service/
scope: &scope batman name: postgresql1
restapi: restapi:
listen: 127.0.0.1:8009 listen: 127.0.0.1:8009
connect_address: 127.0.0.1:8009 connect_address: 127.0.0.1:8009
# auth: 'username:password'
# certfile: /etc/ssl/certs/ssl-cert-snakeoil.pem # certfile: /etc/ssl/certs/ssl-cert-snakeoil.pem
# keyfile: /etc/ssl/private/ssl-cert-snakeoil.key # keyfile: /etc/ssl/private/ssl-cert-snakeoil.key
# authentication:
# username: username
# password: password
etcd: etcd:
scope: *scope
ttl: *ttl
host: 127.0.0.1:4001 host: 127.0.0.1:4001
#discovery_srv: my-etcd.domain
#consul: bootstrap:
# scope: *scope # this section will be written into Etcd:/<namespace>/<scope>/config after initializing new cluster
# ttl: *ttl # and all other cluster members will use it as a `global configuration`
# host: 127.0.0.1:8500 dcs:
#zookeeper: ttl: 30
# scope: *scope loop_wait: 10
# session_timeout: *ttl retry_timeout: 10
# reconnect_timeout: *loop_wait maximum_lag_on_failover: 1048576
# hosts: postgresql:
# - 127.0.0.1:2181 use_pg_rewind: true
# - 127.0.0.2:2181 # use_slots: true
#exhibitor: parameters:
# poll_interval: 300 # wal_level: hot_standby
# port: 8181 # hot_standby: "on"
# hosts: # wal_keep_segments: 8
# - host1 # max_wal_senders: 5
# - host2 # max_replication_slots: 5
# - host3 # wal_log_hints: "on"
# archive_mode: "on"
# archive_timeout: 1800s
# archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f
# recovery_conf:
# restore_command: cp ../wal_archive/%f %p
# some desired options for 'initdb'
initdb: # Note: It needs to be a list (some options need values, others are switches)
- encoding: UTF8
- data-checksums
pg_hba: # Add following lines to pg_hba.conf after running 'initdb'
- host replication replicator 127.0.0.1/32 md5
- host all all 0.0.0.0/0 md5
# - hostssl all all 0.0.0.0/0 md5
# Some additional users users which needs to be created after initializing new cluster
users:
admin:
password: admin
options:
- createrole
- createdb
postgresql: postgresql:
name: postgresql1
scope: *scope
listen: 127.0.0.1:5433 listen: 127.0.0.1:5433
connect_address: 127.0.0.1:5433 connect_address: 127.0.0.1:5433
data_dir: data/postgresql1 data_dir: data/postgresql1
maximum_lag_on_failover: 1048576 # 1 megabyte in bytes # bin_dir:
use_slots: True
pgpass: /tmp/pgpass1 pgpass: /tmp/pgpass1
initdb: ## We allow the following options to be passed on to initdb authentication:
# - auth: authmethod replication:
# - auth-host: authmethod username: replicator
# - auth-local: authmethod password: rep-pass
- encoding: UTF8 superuser:
# - data-checksums # When pg_rewind is needed on 9.3, this needs to be enabled username: postgres
# - locale: locale password: zalando
# - lc-collate: locale
# - lc-ctype: locale
# - lc-messages: locale
# - lc-monetary: locale
# - lc-numeric: locale
# - lc-time: locale
# - text-search-config: CFG
# - xlogdir: directory
# - debug
# - noclean
pg_rewind:
username: postgres
password: zalando
pg_hba:
- host replication replicator 127.0.0.1/32 md5
- host all all 0.0.0.0/0 md5
# - hostssl all all 0.0.0.0/0 md5
replication:
username: replicator
password: rep-pass
superuser:
username: postgres
password: zalando
admin:
username: admin
password: admin
# commented-out example for wal-e provisioning
create_replica_method:
- basebackup
# - wal_e
# commented-out example for wal-e provisioning
#wal_e:
#command: /patroni/scripts/wale_restore.py
#env_dir: /home/postgres/etc/wal-e.d/env
#threshold_megabytes: 10240
#threshold_backup_size_percentage: 30
#retries: 2
#use_iam: 1
#recovery_conf:
#restore_command: envdir /etc/wal-e.d/env wal-e wal-fetch "%f" "%p" -p 1
recovery_conf:
restore_command: cp ../wal_archive/%f %p
parameters: parameters:
archive_mode: "on"
wal_level: hot_standby
archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f
max_wal_senders: 10
wal_keep_segments: 8
archive_timeout: 1800s
max_replication_slots: 10
hot_standby: "on"
wal_log_hints: "on"
unix_socket_directories: '.' unix_socket_directories: '.'
tags: tags:
nofailover: False nofailover: false
noloadbalance: False noloadbalance: false
clonefrom: False clonefrom: false
+63 -91
View File
@@ -1,106 +1,78 @@
ttl: &ttl 30 scope: batman
loop_wait: &loop_wait 10 #namespace: /service/
scope: &scope batman name: postgresql2
restapi: restapi:
listen: 127.0.0.1:8010 listen: 127.0.0.1:8010
connect_address: 127.0.0.1:8010 connect_address: 127.0.0.1:8010
auth: 'username:password'
# certfile: /etc/ssl/certs/ssl-cert-snakeoil.pem # certfile: /etc/ssl/certs/ssl-cert-snakeoil.pem
# keyfile: /etc/ssl/private/ssl-cert-snakeoil.key # keyfile: /etc/ssl/private/ssl-cert-snakeoil.key
authentication:
username: username
password: password
etcd: etcd:
scope: *scope
ttl: *ttl
host: 127.0.0.1:4001 host: 127.0.0.1:4001
#discovery_srv: my-etcd.domain
#consul: bootstrap:
# scope: *scope # this section will be written into Etcd:/<namespace>/<scope>/config after initializing new cluster
# ttl: *ttl # and all other cluster members will use it as a `global configuration`
# host: 127.0.0.1:8500 dcs:
#zookeeper: ttl: 30
# scope: *scope loop_wait: 10
# session_timeout: *ttl retry_timeout: 10
# reconnect_timeout: *loop_wait maximum_lag_on_failover: 1048576
# hosts: postgresql:
# - 127.0.0.1:2181 use_pg_rewind: true
# - 127.0.0.2:2181 # use_slots: true
#exhibitor: parameters:
# poll_interval: 300 # wal_level: hot_standby
# port: 8181 # hot_standby: "on"
# hosts: # wal_keep_segments: 8
# - host1 # max_wal_senders: 5
# - host2 # max_replication_slots: 5
# - host3 # wal_log_hints: "on"
# archive_mode: "on"
# archive_timeout: 1800s
# archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f
# recovery_conf:
# restore_command: cp ../wal_archive/%f %p
# some desired options for 'initdb'
initdb: # Note: It needs to be a list (some options need values, others are switches)
- encoding: UTF8
- data-checksums
pg_hba: # Add following lines to pg_hba.conf after running 'initdb'
- host replication replicator 127.0.0.1/32 md5
- host all all 0.0.0.0/0 md5
# - hostssl all all 0.0.0.0/0 md5
# Some additional users users which needs to be created after initializing new cluster
users:
admin:
password: admin
options:
- createrole
- createdb
postgresql: postgresql:
name: postgresql2
scope: *scope
listen: 127.0.0.1:5434 listen: 127.0.0.1:5434
connect_address: 127.0.0.1:5434 connect_address: 127.0.0.1:5434
data_dir: data/postgresql2 data_dir: data/postgresql2
maximum_lag_on_failover: 1048576 # 1 megabyte in bytes # bin_dir:
use_slots: True
pgpass: /tmp/pgpass2 pgpass: /tmp/pgpass2
initdb: ## We allow the following options to be passed on to initdb authentication:
# - auth: authmethod replication:
# - auth-host: authmethod username: replicator
# - auth-local: authmethod password: rep-pass
- encoding: UTF8 superuser:
# - data-checksums # When pg_rewind is needed on 9.3, this needs to be enabled username: postgres
# - locale: locale password: zalando
# - lc-collate: locale
# - lc-ctype: locale
# - lc-messages: locale
# - lc-monetary: locale
# - lc-numeric: locale
# - lc-time: locale
# - text-search-config: CFG
# - xlogdir: directory
# - debug
# - noclean
pg_rewind:
username: postgres
password: zalando
pg_hba:
- host replication replicator 127.0.0.1/32 md5
- host all all 0.0.0.0/0 md5
# - hostssl all all 0.0.0.0/0 md5
replication:
username: replicator
password: rep-pass
superuser:
username: postgres
password: zalando
admin:
username: admin
password: admin
# commented-out example for wal-e provisioning
create_replica_method:
- basebackup
# - wal_e
# commented-out example for wal-e provisioning
#wal_e:
#command: /patroni/scripts/wale_restore.py
#env_dir: /home/postgres/etc/wal-e.d/env
#threshold_megabytes: 10240
#threshold_backup_size_percentage: 30
#retries: 2
#use_iam: 1
#recovery_conf:
#restore_command: envdir /etc/wal-e.d/env wal-e wal-fetch "%f" "%p" -p 1
recovery_conf:
restore_command: cp ../wal_archive/%f %p
parameters: parameters:
archive_mode: "on"
wal_level: hot_standby
archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f
max_wal_senders: 10
wal_keep_segments: 8
archive_timeout: 1800s
max_replication_slots: 10
hot_standby: "on"
wal_log_hints: "on"
unix_socket_directories: '.' unix_socket_directories: '.'
tags: tags:
nofailover: False nofailover: false
noloadbalance: False noloadbalance: false
clonefrom: False clonefrom: false
replicatefrom: postgresql1 replicatefrom: postgres1
+9 -8
View File
@@ -188,7 +188,8 @@ class TestRestApiHandler(unittest.TestCase):
post = request + '\nContent-Length: ' post = request + '\nContent-Length: '
def make_request(request): def make_request(request=None, **kwargs):
request = json.dumps(kwargs) if request is None else request
return '{0}{1}\n\n{2}'.format(post, len(request), request) return '{0}{1}\n\n{2}'.format(post, len(request), request)
# empty request # empty request
@@ -198,26 +199,26 @@ class TestRestApiHandler(unittest.TestCase):
request = make_request('foobar=baz') request = make_request('foobar=baz')
MockRestApiServer(RestApiHandler, request) MockRestApiServer(RestApiHandler, request)
# wrong role # wrong role
request = make_request('{"schedule": "2016-08-20 12:45TZ+1", "role": "unknown", "postgres_version": "9.5.3"}') request = make_request(schedule=future_restart_time.isoformat(), role='unknown', postgres_version='9.5.3')
MockRestApiServer(RestApiHandler, request) MockRestApiServer(RestApiHandler, request)
# wrong version # wrong version
request = make_request('{"schedule": "2016-08-20 12:45TZ+1", "role": "master", "postgres_version": "9.5.3.1"}') request = make_request(schedule=future_restart_time.isoformat(), role='master', postgres_version='9.5.3.1')
MockRestApiServer(RestApiHandler, request) MockRestApiServer(RestApiHandler, request)
# unknown filter # unknown filter
request = make_request('{"schedule": "2016-08-29 12:45TZ+1", "batman": "lives"}') request = make_request(schedule=future_restart_time.isoformat(), batman='lives')
MockRestApiServer(RestApiHandler, request) MockRestApiServer(RestApiHandler, request)
# incorrect schedule # incorrect schedule
request = make_request('{"schedule": "2016-08-42 12:45TZ+1", "role": "master"}') request = make_request(schedule='2016-08-42 12:45TZ+1', role='master')
MockRestApiServer(RestApiHandler, request) MockRestApiServer(RestApiHandler, request)
# everything fine, but the schedule is missing # everything fine, but the schedule is missing
request = make_request('{"role": "master", "postgres_version": "9.5.2"}') request = make_request(role='master', postgres_version='9.5.2')
MockRestApiServer(RestApiHandler, request) MockRestApiServer(RestApiHandler, request)
for retval in (True, False): for retval in (True, False):
with patch.object(MockHa, 'schedule_future_restart', Mock(return_value=retval)): with patch.object(MockHa, 'schedule_future_restart', Mock(return_value=retval)):
request = make_request('{"schedule": "2016-08-29 12:45TZ+1"}') request = make_request(schedule=future_restart_time.isoformat())
MockRestApiServer(RestApiHandler, request) MockRestApiServer(RestApiHandler, request)
with patch.object(MockHa, 'restart', Mock(return_value=(retval, "foo"))): with patch.object(MockHa, 'restart', Mock(return_value=(retval, "foo"))):
request = make_request('{"role": "master", "postgres_version": "9.5.2"}') request = make_request(role='master', postgres_version='9.5.2')
MockRestApiServer(RestApiHandler, request) MockRestApiServer(RestApiHandler, request)
def test_do_DELETE_restart(self): def test_do_DELETE_restart(self):