diff --git a/patroni/api.py b/patroni/api.py index d9a0f527..979b6cbb 100644 --- a/patroni/api.py +++ b/patroni/api.py @@ -52,11 +52,23 @@ class RestApiHandler(BaseHTTPRequestHandler): class RestApiServer(ThreadingMixIn, HTTPServer, Thread): def __init__(self, patroni, config): - self.connection_string = 'http://{}/patroni'.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._set_fd_cloexec(self.socket) + + protocol = 'http' + + # wrap socket with ssl if 'certfile' is defined in a config.yaml + # Sometime it's also needed to pass reference to a 'keyfile'. + options = {option: config[option] for option in ['certfile', 'keyfile'] if option in config} + if options.get('certfile', None): + import ssl + self.socket = ssl.wrap_socket(self.socket, server_side=True, **options) + protocol = 'https' + + self.connection_string = '{}://{}/patroni'.format(protocol, config.get('connect_address', config['listen'])) + self.patroni = patroni self.daemon = True diff --git a/tests/test_patroni.py b/tests/test_patroni.py index a45ebf62..68af3866 100644 --- a/tests/test_patroni.py +++ b/tests/test_patroni.py @@ -2,6 +2,7 @@ import datetime import patroni.zookeeper import psycopg2 import subprocess +import ssl import sys import time import unittest @@ -32,6 +33,10 @@ def time_sleep(*args): raise SleepException() +def ssl_wrap_socket(socket, *args, **kwargs): + return socket + + class Mock_BaseServer__is_shut_down: def set(self): @@ -62,8 +67,10 @@ class TestPatroni(unittest.TestCase): RestApiServer._BaseServer__is_shut_down = Mock_BaseServer__is_shut_down() RestApiServer._BaseServer__shutdown_request = True RestApiServer.socket = 0 + ssl.wrap_socket = ssl_wrap_socket with open('postgres0.yml', 'r') as f: config = yaml.load(f) + config['restapi']['certfile'] = 'dump' with patch.object(Client, 'machines') as mock_machines: mock_machines.__get__ = Mock(return_value=['http://remotehost:2379']) self.p = Patroni(config) @@ -147,3 +154,6 @@ class TestPatroni(unittest.TestCase): def test_schedule_next_run(self): self.p.next_run = time.time() - self.p.nap_time - 1 self.p.schedule_next_run() + + def test_api_connection_string(self): + self.assertTrue(self.p.api.connection_string.startswith('https://'))