mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-08-30 16:19:24 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e754e0927e | ||
|
|
4a91063c82 | ||
|
|
9e545a95b4 | ||
|
|
168c361e59 | ||
|
|
200412fbba | ||
|
|
be187460f4 | ||
|
|
86420e20b4 | ||
|
|
dfd44628a6 | ||
|
|
02698acd69 |
@@ -34,9 +34,9 @@ Scenario: check local configuration reload
|
|||||||
Then I receive a response code 202
|
Then I receive a response code 202
|
||||||
|
|
||||||
Scenario: check dynamic configuration change via DCS
|
Scenario: check dynamic configuration change via DCS
|
||||||
Given I run patronictl.py edit-config -s 'ttl=10' -s 'loop_wait=2' -p 'max_connections=101' --force batman
|
Given I issue a PATCH request to http://127.0.0.1:8008/config with {"ttl": 10, "loop_wait": 2, "postgresql": {"parameters": {"max_connections": 101}}}
|
||||||
Then I receive a response returncode 0
|
Then I receive a response code 200
|
||||||
And I receive a response output "+loop_wait: 2"
|
And I receive a response loop_wait 2
|
||||||
And Response on GET http://127.0.0.1:8008/patroni contains pending_restart after 11 seconds
|
And Response on GET http://127.0.0.1:8008/patroni contains pending_restart after 11 seconds
|
||||||
When I issue a GET request to http://127.0.0.1:8008/config
|
When I issue a GET request to http://127.0.0.1:8008/config
|
||||||
Then I receive a response code 200
|
Then I receive a response code 200
|
||||||
@@ -65,8 +65,8 @@ Scenario: check API requests for the primary-replica pair in the pause mode
|
|||||||
Then postgres1 role is the secondary after 15 seconds
|
Then postgres1 role is the secondary after 15 seconds
|
||||||
|
|
||||||
Scenario: check the failover via the API in the pause mode
|
Scenario: check the failover via the API in the pause mode
|
||||||
Given I issue a POST request to http://127.0.0.1:8008/failover with {"leader": "postgres0", "candidate": "postgres1"}
|
Given I run patronictl.py failover batman --master postgres0 --candidate postgres1 --force
|
||||||
Then I receive a response code 200
|
Then I receive a response returncode 0
|
||||||
And postgres1 is a leader after 5 seconds
|
And postgres1 is a leader after 5 seconds
|
||||||
And postgres1 role is the primary after 10 seconds
|
And postgres1 role is the primary after 10 seconds
|
||||||
And postgres0 role is the secondary after 10 seconds
|
And postgres0 role is the secondary after 10 seconds
|
||||||
|
|||||||
+2
-2
@@ -300,8 +300,8 @@ class RestApiHandler(BaseHTTPRequestHandler):
|
|||||||
members = [m for m in cluster.members if m.name != cluster.leader.name and m.api_url]
|
members = [m for m in cluster.members if m.name != cluster.leader.name and m.api_url]
|
||||||
if not members:
|
if not members:
|
||||||
return 'failover is not possible: cluster does not have members except leader'
|
return 'failover is not possible: cluster does not have members except leader'
|
||||||
for st in self.server.patroni.ha.fetch_nodes_statuses(members):
|
for _, reachable, _, _, tags in self.server.patroni.ha.fetch_nodes_statuses(members):
|
||||||
if st.failover_limitation() is None:
|
if reachable and not tags.get('nofailover', False):
|
||||||
return None
|
return None
|
||||||
return 'failover is not possible: no good candidates have been found'
|
return 'failover is not possible: no good candidates have been found'
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -903,14 +903,14 @@ def apply_config_changes(before_editing, data, kvpairs):
|
|||||||
if prefix == ('postgresql', 'parameters'):
|
if prefix == ('postgresql', 'parameters'):
|
||||||
path = ['.'.join(path)]
|
path = ['.'.join(path)]
|
||||||
|
|
||||||
key = path[0]
|
|
||||||
if len(path) == 1:
|
if len(path) == 1:
|
||||||
if value is None:
|
if value is None:
|
||||||
config.pop(key, None)
|
config.pop(path[0], None)
|
||||||
else:
|
else:
|
||||||
config[key] = value
|
config[path[0]] = value
|
||||||
else:
|
else:
|
||||||
if not isinstance(config.get(key), dict):
|
key = path[0]
|
||||||
|
if key not in config:
|
||||||
config[key] = {}
|
config[key] = {}
|
||||||
set_path_value(config[key], path[1:], value, prefix + (key,))
|
set_path_value(config[key], path[1:], value, prefix + (key,))
|
||||||
if config[key] == {}:
|
if config[key] == {}:
|
||||||
@@ -1017,7 +1017,7 @@ def edit_config(obj, cluster_name, force, quiet, kvpairs, pgkvpairs, apply_filen
|
|||||||
return
|
return
|
||||||
|
|
||||||
if force or click.confirm('Apply these changes?'):
|
if force or click.confirm('Apply these changes?'):
|
||||||
if not dcs.set_config_value(json.dumps(changed_data), cluster.config.index):
|
if not dcs.set_config_value(json.dumps(changed_data), cluster.config.modify_index):
|
||||||
raise PatroniCtlException("Config modification aborted due to concurrent changes")
|
raise PatroniCtlException("Config modification aborted due to concurrent changes")
|
||||||
click.echo("Configuration changed")
|
click.echo("Configuration changed")
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -26,7 +26,6 @@ class _MemberStatus(namedtuple('_MemberStatus', 'member,reachable,in_recovery,wa
|
|||||||
in_recovery - `!True` if pg_is_in_recovery() == true
|
in_recovery - `!True` if pg_is_in_recovery() == true
|
||||||
wal_position - value of `replayed_location` or `location` from JSON, dependin on its role.
|
wal_position - value of `replayed_location` or `location` from JSON, dependin on its role.
|
||||||
tags - dictionary with values of different tags (i.e. nofailover)
|
tags - dictionary with values of different tags (i.e. nofailover)
|
||||||
watchdog_failed - indicates that watchdog is required by configuration but not available or failed
|
|
||||||
"""
|
"""
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_api_response(cls, member, json):
|
def from_api_response(cls, member, json):
|
||||||
@@ -364,7 +363,7 @@ class Ha(object):
|
|||||||
# Somebody else updated sync state, it may be due to us losing the lock. To be safe, postpone
|
# Somebody else updated sync state, it may be due to us losing the lock. To be safe, postpone
|
||||||
# promotion until next cycle. TODO: trigger immediate retry of run_cycle
|
# promotion until next cycle. TODO: trigger immediate retry of run_cycle
|
||||||
return 'Postponing promotion because synchronous replication state was updated by somebody else'
|
return 'Postponing promotion because synchronous replication state was updated by somebody else'
|
||||||
self.state_handler.set_synchronous_standby('*' if self.is_synchronous_mode_strict() else None)
|
self.state_handler.set_synchronous_standby(None)
|
||||||
self.state_handler.promote()
|
self.state_handler.promote()
|
||||||
return promote_message
|
return promote_message
|
||||||
|
|
||||||
|
|||||||
@@ -1137,7 +1137,7 @@ class Postgresql(object):
|
|||||||
with open(self._pg_hba_conf, 'w') as f:
|
with open(self._pg_hba_conf, 'w') as f:
|
||||||
f.write(self._CONFIG_WARNING_HEADER)
|
f.write(self._CONFIG_WARNING_HEADER)
|
||||||
for address, t in addresses.items():
|
for address, t in addresses.items():
|
||||||
f.write('{0}\t{1}\t{2}\t{3}\ttrust\n'.format(t, 'all',
|
f.write('{0}\t{1}\t{2}\t{3}\ttrust\n'.format(t, self._database,
|
||||||
self._superuser.get('username') or 'all', address))
|
self._superuser.get('username') or 'all', address))
|
||||||
elif not self._server_parameters.get('hba_file') and self.config.get('pg_hba'):
|
elif not self._server_parameters.get('hba_file') and self.config.get('pg_hba'):
|
||||||
with open(self._pg_hba_conf, 'w') as f:
|
with open(self._pg_hba_conf, 'w') as f:
|
||||||
@@ -1396,12 +1396,8 @@ class Postgresql(object):
|
|||||||
for f in self._configuration_to_save:
|
for f in self._configuration_to_save:
|
||||||
config_file = os.path.join(self._config_dir, f)
|
config_file = os.path.join(self._config_dir, f)
|
||||||
backup_file = os.path.join(self._data_dir, f + '.backup')
|
backup_file = os.path.join(self._data_dir, f + '.backup')
|
||||||
if not os.path.isfile(config_file):
|
if not os.path.isfile(config_file) and os.path.isfile(backup_file):
|
||||||
if os.path.isfile(backup_file):
|
shutil.copy(backup_file, config_file)
|
||||||
shutil.copy(backup_file, config_file)
|
|
||||||
# Previously we didn't backup pg_ident.conf, if file is missing just create empty
|
|
||||||
elif f == 'pg_ident.conf':
|
|
||||||
open(config_file, 'w').close()
|
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.exception('unable to restore configuration files from backup')
|
logger.exception('unable to restore configuration files from backup')
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
__version__ = '1.3.3'
|
__version__ = '1.3'
|
||||||
|
|||||||
+2
-3
@@ -6,7 +6,6 @@ import unittest
|
|||||||
from mock import Mock, patch
|
from mock import Mock, patch
|
||||||
from patroni.api import RestApiHandler, RestApiServer
|
from patroni.api import RestApiHandler, RestApiServer
|
||||||
from patroni.dcs import ClusterConfig, Member
|
from patroni.dcs import ClusterConfig, Member
|
||||||
from patroni.ha import _MemberStatus
|
|
||||||
from patroni.utils import tzutc
|
from patroni.utils import tzutc
|
||||||
from six import BytesIO as IO
|
from six import BytesIO as IO
|
||||||
from six.moves import BaseHTTPServer
|
from six.moves import BaseHTTPServer
|
||||||
@@ -39,7 +38,7 @@ class MockPostgresql(object):
|
|||||||
|
|
||||||
|
|
||||||
class MockWatchdog(object):
|
class MockWatchdog(object):
|
||||||
is_healthy = False
|
is_healthy = True
|
||||||
|
|
||||||
|
|
||||||
class MockHa(object):
|
class MockHa(object):
|
||||||
@@ -65,7 +64,7 @@ class MockHa(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fetch_nodes_statuses(members):
|
def fetch_nodes_statuses(members):
|
||||||
return [_MemberStatus(None, True, None, None, {}, False)]
|
return [[None, True, None, None, {}]]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def schedule_future_restart(data):
|
def schedule_future_restart(data):
|
||||||
|
|||||||
@@ -135,7 +135,6 @@ class TestWatchdog(unittest.TestCase):
|
|||||||
self.assertIsNone(wd.disable())
|
self.assertIsNone(wd.disable())
|
||||||
self.assertIsNone(wd.keepalive())
|
self.assertIsNone(wd.keepalive())
|
||||||
|
|
||||||
@patch('platform.system', Mock(return_value='Linux'))
|
|
||||||
def test_config_reload(self):
|
def test_config_reload(self):
|
||||||
watchdog = Watchdog({'ttl': 30, 'loop_wait': 15, 'watchdog': {'mode': 'required'}})
|
watchdog = Watchdog({'ttl': 30, 'loop_wait': 15, 'watchdog': {'mode': 'required'}})
|
||||||
self.assertTrue(watchdog.activate())
|
self.assertTrue(watchdog.activate())
|
||||||
|
|||||||
Reference in New Issue
Block a user