From 77911144c75497e31e43015c3a1a8fe27c2727b4 Mon Sep 17 00:00:00 2001 From: Alexander Kukushkin Date: Wed, 27 May 2015 14:44:52 +0200 Subject: [PATCH 1/3] Improve test of governor against real config files --- tests/test_etcd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_etcd.py b/tests/test_etcd.py index 8b3d60b2..8f2280e6 100644 --- a/tests/test_etcd.py +++ b/tests/test_etcd.py @@ -28,7 +28,7 @@ def requests_get(url, **kwargs): if url.startswith('http://local'): raise requests.exceptions.RequestException() response = MockResponse() - if url.startswith('http://remote'): + if url.startswith('http://remote') or url.startswith('http://127.0.0.1'): response.content = '{"action":"get","node":{"key":"/service/batman5","dir":true,"nodes":[{"key":"/service/batman5/initialize","value":"postgresql0","modifiedIndex":1582,"createdIndex":1582},{"key":"/service/batman5/leader","value":"postgresql1","expiration":"2015-05-15T09:11:00.037397538Z","ttl":21,"modifiedIndex":20728,"createdIndex":20434},{"key":"/service/batman5/optime","dir":true,"nodes":[{"key":"/service/batman5/optime/leader","value":"2164261704","modifiedIndex":20729,"createdIndex":20729}],"modifiedIndex":20437,"createdIndex":20437},{"key":"/service/batman5/members","dir":true,"nodes":[{"key":"/service/batman5/members/postgresql1","value":"postgres://replicator:rep-pass@127.0.0.1:5434/postgres","expiration":"2015-05-15T09:10:59.949384522Z","ttl":21,"modifiedIndex":20727,"createdIndex":20727},{"key":"/service/batman5/members/postgresql0","value":"postgres://replicator:rep-pass@127.0.0.1:5433/postgres","expiration":"2015-05-15T09:11:09.611860899Z","ttl":30,"modifiedIndex":20730,"createdIndex":20730}],"modifiedIndex":1581,"createdIndex":1581}],"modifiedIndex":1581,"createdIndex":1581}}' elif url.startswith('http://other'): response.status_code = 404 From 5a817fad0dde86a7f0d454d17c532b94253dc7d9 Mon Sep 17 00:00:00 2001 From: Alexander Kukushkin Date: Wed, 27 May 2015 14:46:35 +0200 Subject: [PATCH 2/3] Store in etcd endpoint of restapi In order to have backward compatibility connection url of restapi is passed as application_name parameter in connection url of database. Value in etcd will look like: postgres://user:passwd@host:5432/postgres?application_name=http://host:8080/governor Sure, this is a hack, but I guess it worth it. --- governor.py | 8 +++++--- helpers/api.py | 10 ++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/governor.py b/governor.py index 4e097920..85cd28e0 100755 --- a/governor.py +++ b/governor.py @@ -35,9 +35,12 @@ class Governor: self.etcd = Etcd(config['etcd']) self.postgresql = Postgresql(config['postgresql']) self.ha = Ha(self.postgresql, self.etcd) + host, port = config['restapi']['listen'].split(':') + self.api = RestApiServer(self, config['restapi']) def touch_member(self, ttl=None): - return self.etcd.touch_member(self.postgresql.name, self.postgresql.connection_string, ttl) + connection_string = self.postgresql.connection_string + '?application_name=' + self.api.connection_string + return self.etcd.touch_member(self.postgresql.name, connection_string, ttl) def initialize(self): # wait for etcd to be available @@ -65,6 +68,7 @@ class Governor: self.postgresql.load_replication_slots() def run(self): + self.api.start() while True: self.touch_member() logging.info(self.ha.run_cycle()) @@ -86,8 +90,6 @@ def main(): governor = Governor(config) try: governor.initialize() - host, port = config['restapi']['listen'].split(':') - RestApiServer(governor, host, int(port)).start() governor.run() finally: governor.touch_member(300) # schedule member removal diff --git a/helpers/api.py b/helpers/api.py index 83aa619b..c723e47b 100644 --- a/helpers/api.py +++ b/helpers/api.py @@ -34,7 +34,7 @@ class RestApiHandler(BaseHTTPRequestHandler): def get_postgresql_status(self): if not self.server.governor.postgresql.is_running(): return {'running': False} - cursor = self.server.cursor() + cursor = self.server._cursor() cursor.execute("""SELECT to_char(pg_postmaster_start_time(), 'YYYY-MM-DD HH24:MI:SS.MS TZ'), pg_is_in_recovery(), CASE WHEN pg_is_in_recovery() @@ -59,14 +59,16 @@ class RestApiHandler(BaseHTTPRequestHandler): class RestApiServer(HTTPServer, Thread): - def __init__(self, governor, listen_address='0.0.0.0', listen_port=8080): - HTTPServer.__init__(self, (listen_address, listen_port), RestApiHandler) + def __init__(self, governor, config): + self.connection_string = 'http://{}/governor'.format(config.get('connect_address', None) or config['listen']) + host, port = config['listen'].split(':') + HTTPServer.__init__(self, (host, int(port)), RestApiHandler) Thread.__init__(self, target=self.serve_forever) self.governor = governor self._cursor_holder = None self.daemon = True - def cursor(self): + def _cursor(self): if not self._cursor_holder or self._cursor_holder.closed: self._cursor_holder = self.governor.postgresql.connection().cursor() return self._cursor_holder From bdc4374ae3d6fd6fa6303dc7965cf7aeee3fc4cf Mon Sep 17 00:00:00 2001 From: Alexander Kukushkin Date: Wed, 27 May 2015 14:51:41 +0200 Subject: [PATCH 3/3] connect address for rest api could be different from listen address --- postgres0.yml | 1 + postgres1.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/postgres0.yml b/postgres0.yml index 3f4b4761..8757538f 100644 --- a/postgres0.yml +++ b/postgres0.yml @@ -1,6 +1,7 @@ loop_wait: 10 restapi: listen: 127.0.0.1:8008 + connect_address: 127.0.0.1:8008 etcd: scope: batman ttl: 30 diff --git a/postgres1.yml b/postgres1.yml index c2d4ce29..a0afe20f 100644 --- a/postgres1.yml +++ b/postgres1.yml @@ -1,6 +1,7 @@ loop_wait: 10 restapi: listen: 127.0.0.1:8009 + connect_address: 127.0.0.1:8009 etcd: scope: batman ttl: 30