Merge branches with ssl and basic-auth support together

This commit is contained in:
Alexander Kukushkin
2015-09-10 16:49:55 +02:00
5 changed files with 71 additions and 80 deletions
+46 -78
View File
@@ -52,94 +52,62 @@ YAML Configuration
For an example file, see ``postgres0.yml``. Below is an explanation of
settings:
- *ttl*: the TTL to acquire the leader lock. Think of it as the length
of time before automatic failover process is initiated.
- *ttl*: the TTL to acquire the leader lock. Think of it as the length of time before automatic failover process is initiated.
- *loop\_wait*: the number of seconds the loop will sleep
- *restapi*
- *listen*: ip address + port that Patroni will listen to provide
health-check information for haproxy.
- *connect\_address*: ip address + port through which restapi is
accessible.
- *restapi*:
- *listen*: ip address + port that Patroni will listen to provide health-check information for haproxy.
- *connect\_address*: ip address + port through which restapi is accessible.
- *auth*: (optional) 'username:password' to protect some dangerous REST API endpoints.
- *certfile*: (optional) Specifies a file with the certificate in the PEM format. If certfile is not specified or empty API server will work without SSL.
- *keyfile*: (optional) Specifies a file with the secret key in the PEM format.
- *etcd*
- *scope*: the relative path used on etcd's http api for this
deployment, thus you can run multiple HA deployments from a single
etcd
- *ttl*: the TTL to acquire the leader lock. Think of it as the length
of time before automatic failover process is initiated.
- *host*: the host:port for the etcd endpoint
- *etcd*:
- *scope*: the relative path used on etcd's http api for this deployment, thus you can run multiple HA deployments from a single etcd
- *ttl*: the TTL to acquire the leader lock. Think of it as the length of time before automatic failover process is initiated.
- *host*: the host:port for the etcd endpoint
- *zookeeper*
- *scope*: the relative path used on etcd's http api for this
deployment, thus you can run multiple HA deployments from a single
etcd
- *session\_timeout*: the TTL to acquire the leader lock. Think of it
as the length of time before automatic failover process is initiated.
- *reconnect\_timeout*: how long we should try to reconnect to
ZooKeeper after connection loss. After this timeout we assume that we
don't have lock anymore and will restart in read-only mode.
- *hosts*: list of ZooKeeper cluster members in format: [
'host1:port1', 'host2:port2', 'etc...']
- *exhibitor*: if you are running ZooKeeper cluster under Exhibitor
supervisory the following section could be interesting for you
- *zookeeper*:
- *scope*: the relative path used on etcd's http api for this deployment, thus you can run multiple HA deployments from a single etcd
- *session\_timeout*: the TTL to acquire the leader lock. Think of it as the length of time before automatic failover process is initiated.
- *reconnect\_timeout*: how long we should try to reconnect to ZooKeeper after connection loss. After this timeout we assume that we don't have lock anymore and will restart in read-only mode.
- *hosts*: list of ZooKeeper cluster members in format: ['host1:port1', 'host2:port2', 'etc...']
- *exhibitor*: if you are running ZooKeeper cluster under Exhibitor supervisory the following section could be interesting for you
- *poll\_interval*: how often list of ZooKeeper and Exhibitor nodes should be updated from Exhibitor
- *port*: Exhibitor port
- *hosts*: initial list of Exhibitor (ZooKeeper) nodes in format: ['host1', 'host2', 'etc...' ]. This list would be updated automatically when Exhibitor (ZooKeeper) cluster topology changes.
- *poll\_interval*: how often list of ZooKeeper and Exhibitor nodes
should be updated from Exhibitor
- *port*: Exhibitor port
- *hosts*: initial list of Exhibitor (ZooKeeper) nodes in format: [
'host1', 'host2', 'etc...' ]. This list would be updated
automatically when Exhibitor (ZooKeeper) cluster topology changes.
- *postgresql*:
- *name*: the name of the Postgres host, must be unique for the cluster
- *listen*: ip address + port that Postgres listening. Must be accessible from other nodes in the cluster if using streaming replication.
- *connect\_address*: ip address + port through which Postgres is accessible from other nodes and applications.
- *data\_dir*: file path to initialize and store Postgres data files
- *maximum\_lag\_on\_failover*: the maximum bytes a follower may lag
- *use\_slots*: whether or not to use replication_slots. Must be False for PostgreSQL 9.3, and you should comment out max_replication_slots. before it is not eligible become leader
- *pg\_hba*: list of lines which should be added to pg\_hba.conf
- *- host all all 0.0.0.0/0 md5*
- *postgresql*
- *name*: the name of the Postgres host, must be unique for the cluster
- *listen*: ip address + port that Postgres listening. Must be
accessible from other nodes in the cluster if using streaming
replication.
- *connect\_address*: ip address + port through which Postgres is
accessible from other nodes and applications.
- *data\_dir*: file path to initialize and store Postgres data files
- *maximum\_lag\_on\_failover*: the maximum bytes a follower may lag
- *use\_slots*: whether or not to use replication_slots. Must be False for PostgreSQL 9.3, and you should comment out max_replication_slots.
before it is not eligible become leader
- *pg\_hba*: list of lines which should be added to pg\_hba.conf
- *replication*:
- *username*: replication username, user will be created during initialization
- *password*: replication password, user will be created during initialization
- *network*: network setting for replication in pg\_hba.conf
- *- host all all 0.0.0.0/0 md5*
- *callbacks* callback scripts to run on certain actions. Patroni will pass current action, role and cluster name. See scripts/aws.py as an example on how to write them.
- *on\_start*: a script to run when the cluster starts
- *on\_stop*: a script to run when the cluster stops
- *on\_restart*: a script to run when the cluster restarts
- *on\_reload*: a script to run when configuration reload is triggered
- *on\_role\_change*: a script to run when the cluster is being promoted or demoted
- *replication*
- *superuser*:
- *password*: password for postgres user. It would be set during initialization
- *username*: replication username, user will be created during
initialization
- *password*: replication password, user will be created during
initialization
- *network*: network setting for replication in pg\_hba.conf
- *admin*:
- *username*: admin username, user will be created during initialization. It would have CREATEDB and CREATEROLE privileges
- *password*: admin password, user will be created during initialization.
- *callbacks* callback scripts to run on certain actions. Patroni will
pass current action, role and cluster name. See scripts/aws.py as an
example on how to write them.
- *on\_start*: a script to run when the cluster starts
- *on\_stop*: a script to run when the cluster stops
- *on\_restart*: a script to run when the cluster restarts
- *on\_reload*: a script to run when configuration reload is
triggered
- *on\_role\_change*: a script to run when the cluster is being
promoted or demoted
- *superuser*
- *password*: password for postgres user. It would be set during
initialization
- *admin*:
- *username*: admin username, user will be created during
initialization. It would have CREATEDB and CREATEROLE privileges
- *password*: admin password, user will be created during
initialization.
- *recovery\_conf*: additional configuration settings written to recovery.conf when configuring follower
- *parameters*: list of configuration settings for Postgres. Many of these are required for replication to work.
- *recovery\_conf*: additional configuration settings written to recovery.conf when configuring follower
- *parameters*: list of configuration settings for Postgres. Many of these are required for replication to work.
Replication choices
-------------------
+13 -1
View File
@@ -107,11 +107,23 @@ class RestApiServer(ThreadingMixIn, HTTPServer, Thread):
def __init__(self, patroni, config):
self._auth_key = base64.b64encode(config['auth'].encode('utf-8')).decode('utf-8') if 'auth' in config else None
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
+2
View File
@@ -5,6 +5,8 @@ restapi:
listen: 127.0.0.1:8008
connect_address: 127.0.0.1:8008
auth: 'username:password'
# certfile: /etc/ssl/certs/ssl-cert-snakeoil.pem
# keyfile: /etc/ssl/private/ssl-cert-snakeoil.key
etcd:
scope: *scope
ttl: *ttl
+2
View File
@@ -5,6 +5,8 @@ restapi:
listen: 127.0.0.1:8009
connect_address: 127.0.0.1:8009
auth: 'username:password'
# certfile: /etc/ssl/certs/ssl-cert-snakeoil.pem
# keyfile: /etc/ssl/private/ssl-cert-snakeoil.key
etcd:
scope: *scope
ttl: *ttl
+8 -1
View File
@@ -1,5 +1,6 @@
import psycopg2
import unittest
import ssl
from patroni.api import RestApiHandler, RestApiServer
from six import BytesIO as IO
@@ -15,6 +16,10 @@ def throws(*args, **kwargs):
raise psycopg2.OperationalError()
def ssl_wrap_socket(socket, *args, **kwargs):
return socket
class Mock_BaseServer__is_shut_down:
def set(self):
@@ -51,7 +56,8 @@ class MockRequest:
class MockRestApiServer(RestApiServer):
def __init__(self, Handler, path, *args):
super(MockRestApiServer, self).__init__(MockPatroni(), {'listen': '127.0.0.1:8008', 'auth': 'test:test'})
config = {'listen': '127.0.0.1:8008', 'auth': 'test:test', 'certfile': 'dumb'}
super(MockRestApiServer, self).__init__(MockPatroni(), config)
if len(args) > 0:
self.query = args[0]
Handler(MockRequest(path), ('0.0.0.0', 8080), self)
@@ -68,6 +74,7 @@ class TestRestApiHandler(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
def test_do_GET(self):
MockRestApiServer(RestApiHandler, b'GET /')