Add support for per-member tags.

Tags are labels assigned to individual members in order
to alter its default behavior, i.e. exclude from the
leader election or indicate a possibility to create base
backups from the member.

This commit only adds support for setting tags in the
configuration file, exposes the tags to DCS /member subkey
and returns the tags in a response of the API request. At
the moment the tag names are not validated, nor they are
interpreted in any way.

Support for setting tags via the API is also in the scope
of further work.
This commit is contained in:
Oleksii Kliukin
2015-10-21 15:51:21 +02:00
parent 57ace2009c
commit 2200a4ce8c
7 changed files with 20 additions and 1 deletions
+1
View File
@@ -18,6 +18,7 @@ class Patroni:
def __init__(self, config): def __init__(self, config):
self.nap_time = config['loop_wait'] self.nap_time = config['loop_wait']
self.tags = config.get('tags', dict())
self.postgresql = Postgresql(config['postgresql']) self.postgresql = Postgresql(config['postgresql'])
self.dcs = self.get_dcs(self.postgresql.name, config) self.dcs = self.get_dcs(self.postgresql.name, config)
host, port = config['restapi']['listen'].split(':') host, port = config['restapi']['listen'].split(':')
+5
View File
@@ -46,6 +46,7 @@ class RestApiHandler(BaseHTTPRequestHandler):
path = '/master' if self.path == '/' else self.path path = '/master' if self.path == '/' else self.path
response = self.get_postgresql_status() response = self.get_postgresql_status()
response.update(self.get_tags())
patroni = self.server.patroni patroni = self.server.patroni
cluster = patroni.dcs.cluster cluster = patroni.dcs.cluster
@@ -75,6 +76,7 @@ class RestApiHandler(BaseHTTPRequestHandler):
def do_GET_patroni(self): def do_GET_patroni(self):
response = self.get_postgresql_status(True) response = self.get_postgresql_status(True)
response.update(self.get_tags())
self.send_response(200) self.send_response(200)
self.send_header('Content-Type', 'application/json') self.send_header('Content-Type', 'application/json')
@@ -174,6 +176,9 @@ class RestApiHandler(BaseHTTPRequestHandler):
state = 'unknown' if state == 'running' else state state = 'unknown' if state == 'running' else state
return {'state': state} return {'state': state}
def get_tags(self):
return {'tags': self.server.patroni.tags}
class RestApiServer(ThreadingMixIn, HTTPServer, Thread): class RestApiServer(ThreadingMixIn, HTTPServer, Thread):
+2 -1
View File
@@ -50,7 +50,8 @@ class Ha:
'conn_url': self.state_handler.connection_string, 'conn_url': self.state_handler.connection_string,
'api_url': self.patroni.api.connection_string, 'api_url': self.patroni.api.connection_string,
'state': self.state_handler.state, 'state': self.state_handler.state,
'role': self.state_handler.role 'role': self.state_handler.role,
'tags': self.patroni.tags
} }
if data['state'] in ['running', 'restarting', 'starting']: if data['state'] in ['running', 'restarting', 'starting']:
try: try:
+5
View File
@@ -67,3 +67,8 @@ postgresql:
max_replication_slots: 5 max_replication_slots: 5
hot_standby: "on" hot_standby: "on"
wal_log_hints: "on" wal_log_hints: "on"
tags:
nofailover: False
noloadbalance: False
clonefrom: False
replicatefrom: 127.0.0.1
+5
View File
@@ -67,3 +67,8 @@ postgresql:
max_replication_slots: 5 max_replication_slots: 5
hot_standby: "on" hot_standby: "on"
wal_log_hints: "on" wal_log_hints: "on"
tags:
nofailover: False
noloadbalance: False
clonefrom: False
replicatefrom: 127.0.0.1
+1
View File
@@ -44,6 +44,7 @@ class MockPatroni:
postgresql = MockPostgresql() postgresql = MockPostgresql()
ha = MockHa() ha = MockHa()
dcs = Mock() dcs = Mock()
tags = {}
class MockRequest: class MockRequest:
+1
View File
@@ -82,6 +82,7 @@ class MockPatroni:
self.postgresql = p self.postgresql = p
self.dcs = d self.dcs = d
self.api = Mock() self.api = Mock()
self.tags = {}
self.api.connection_string = 'http://127.0.0.1:8008' self.api.connection_string = 'http://127.0.0.1:8008'