Merge "Add TLS support in etcd3 and etcd3gw drivers"
This commit is contained in:
commit
1880be2c00
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
The etcd3 and etcd3gw drivers now support TLS, by adding the ability to
|
||||||
|
specify ca_cert, cert_key and cert_cert files. For the etcd3gw driver,
|
||||||
|
this is controlled by specifying "etcd3+https" in the coordination URL.
|
|
@ -30,6 +30,7 @@ tooz.backends =
|
||||||
etcd = tooz.drivers.etcd:EtcdDriver
|
etcd = tooz.drivers.etcd:EtcdDriver
|
||||||
etcd3 = tooz.drivers.etcd3:Etcd3Driver
|
etcd3 = tooz.drivers.etcd3:Etcd3Driver
|
||||||
etcd3+http = tooz.drivers.etcd3gw:Etcd3Driver
|
etcd3+http = tooz.drivers.etcd3gw:Etcd3Driver
|
||||||
|
etcd3+https = tooz.drivers.etcd3gw:Etcd3Driver
|
||||||
kazoo = tooz.drivers.zookeeper:KazooDriver
|
kazoo = tooz.drivers.zookeeper:KazooDriver
|
||||||
zake = tooz.drivers.zake:ZakeDriver
|
zake = tooz.drivers.zake:ZakeDriver
|
||||||
memcached = tooz.drivers.memcached:MemcachedDriver
|
memcached = tooz.drivers.memcached:MemcachedDriver
|
||||||
|
@ -47,7 +48,7 @@ consul =
|
||||||
etcd =
|
etcd =
|
||||||
requests>=2.10.0 # Apache-2.0
|
requests>=2.10.0 # Apache-2.0
|
||||||
etcd3 =
|
etcd3 =
|
||||||
etcd3>=0.6.2 # Apache-2.0
|
etcd3>=0.12.0 # Apache-2.0
|
||||||
grpcio>=1.18.0
|
grpcio>=1.18.0
|
||||||
etcd3gw =
|
etcd3gw =
|
||||||
etcd3gw>=0.1.0 # Apache-2.0
|
etcd3gw>=0.1.0 # Apache-2.0
|
||||||
|
|
|
@ -9,3 +9,4 @@ coverage>=3.6 # Apache-2.0
|
||||||
fixtures>=3.0.0 # Apache-2.0/BSD
|
fixtures>=3.0.0 # Apache-2.0/BSD
|
||||||
pifpaf>=0.10.0 # Apache-2.0
|
pifpaf>=0.10.0 # Apache-2.0
|
||||||
stestr>=2.0.0
|
stestr>=2.0.0
|
||||||
|
ddt>=1.2.1 # MIT
|
||||||
|
|
|
@ -126,7 +126,9 @@ class Etcd3Driver(coordination.CoordinationDriverCachedRunWatchers,
|
||||||
================== =======
|
================== =======
|
||||||
Name Default
|
Name Default
|
||||||
================== =======
|
================== =======
|
||||||
protocol http
|
ca_cert None
|
||||||
|
cert_key None
|
||||||
|
cert_cert None
|
||||||
timeout 30
|
timeout 30
|
||||||
lock_timeout 30
|
lock_timeout 30
|
||||||
membership_timeout 30
|
membership_timeout 30
|
||||||
|
@ -147,8 +149,16 @@ class Etcd3Driver(coordination.CoordinationDriverCachedRunWatchers,
|
||||||
host = parsed_url.hostname or self.DEFAULT_HOST
|
host = parsed_url.hostname or self.DEFAULT_HOST
|
||||||
port = parsed_url.port or self.DEFAULT_PORT
|
port = parsed_url.port or self.DEFAULT_PORT
|
||||||
options = utils.collapse(options)
|
options = utils.collapse(options)
|
||||||
|
ca_cert = options.get('ca_cert')
|
||||||
|
cert_key = options.get('cert_key')
|
||||||
|
cert_cert = options.get('cert_cert')
|
||||||
timeout = int(options.get('timeout', self.DEFAULT_TIMEOUT))
|
timeout = int(options.get('timeout', self.DEFAULT_TIMEOUT))
|
||||||
self.client = etcd3.client(host=host, port=port, timeout=timeout)
|
self.client = etcd3.client(host=host,
|
||||||
|
port=port,
|
||||||
|
ca_cert=ca_cert,
|
||||||
|
cert_key=cert_key,
|
||||||
|
cert_cert=cert_cert,
|
||||||
|
timeout=timeout)
|
||||||
self.lock_timeout = int(options.get('lock_timeout', timeout))
|
self.lock_timeout = int(options.get('lock_timeout', timeout))
|
||||||
self.membership_timeout = int(options.get(
|
self.membership_timeout = int(options.get(
|
||||||
'membership_timeout', timeout))
|
'membership_timeout', timeout))
|
||||||
|
|
|
@ -169,15 +169,18 @@ class Etcd3Driver(coordination.CoordinationDriverWithExecutor):
|
||||||
|
|
||||||
The Etcd driver connection URI should look like::
|
The Etcd driver connection URI should look like::
|
||||||
|
|
||||||
etcd3+http://[HOST[:PORT]][?OPTION1=VALUE1[&OPTION2=VALUE2[&...]]]
|
etcd3+PROTOCOL://[HOST[:PORT]][?OPTION1=VALUE1[&OPTION2=VALUE2[&...]]]
|
||||||
|
|
||||||
If not specified, HOST defaults to localhost and PORT defaults to 2379.
|
The PROTOCOL can be http or https. If not specified, HOST defaults to
|
||||||
|
localhost and PORT defaults to 2379.
|
||||||
Available options are:
|
Available options are:
|
||||||
|
|
||||||
================== =======
|
================== =======
|
||||||
Name Default
|
Name Default
|
||||||
================== =======
|
================== =======
|
||||||
protocol http
|
ca_cert None
|
||||||
|
cert_key None
|
||||||
|
cert_cert None
|
||||||
timeout 30
|
timeout 30
|
||||||
lock_timeout 30
|
lock_timeout 30
|
||||||
membership_timeout 30
|
membership_timeout 30
|
||||||
|
@ -197,11 +200,21 @@ class Etcd3Driver(coordination.CoordinationDriverWithExecutor):
|
||||||
|
|
||||||
def __init__(self, member_id, parsed_url, options):
|
def __init__(self, member_id, parsed_url, options):
|
||||||
super(Etcd3Driver, self).__init__(member_id, parsed_url, options)
|
super(Etcd3Driver, self).__init__(member_id, parsed_url, options)
|
||||||
|
protocol = 'https' if parsed_url.scheme.endswith('https') else 'http'
|
||||||
host = parsed_url.hostname or self.DEFAULT_HOST
|
host = parsed_url.hostname or self.DEFAULT_HOST
|
||||||
port = parsed_url.port or self.DEFAULT_PORT
|
port = parsed_url.port or self.DEFAULT_PORT
|
||||||
options = utils.collapse(options)
|
options = utils.collapse(options)
|
||||||
|
ca_cert = options.get('ca_cert')
|
||||||
|
cert_key = options.get('cert_key')
|
||||||
|
cert_cert = options.get('cert_cert')
|
||||||
timeout = int(options.get('timeout', self.DEFAULT_TIMEOUT))
|
timeout = int(options.get('timeout', self.DEFAULT_TIMEOUT))
|
||||||
self.client = etcd3gw.client(host=host, port=port, timeout=timeout)
|
self.client = etcd3gw.client(host=host,
|
||||||
|
port=port,
|
||||||
|
protocol=protocol,
|
||||||
|
ca_cert=ca_cert,
|
||||||
|
cert_key=cert_key,
|
||||||
|
cert_cert=cert_cert,
|
||||||
|
timeout=timeout)
|
||||||
self.lock_timeout = int(options.get('lock_timeout', timeout))
|
self.lock_timeout = int(options.get('lock_timeout', timeout))
|
||||||
self.membership_timeout = int(options.get(
|
self.membership_timeout = int(options.get(
|
||||||
'membership_timeout', timeout))
|
'membership_timeout', timeout))
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright 2020 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import ddt
|
||||||
|
from testtools import testcase
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
import tooz.coordination
|
||||||
|
import tooz.drivers.etcd3 as etcd3_driver
|
||||||
|
import tooz.tests
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class TestEtcd3(testcase.TestCase):
|
||||||
|
FAKE_MEMBER_ID = tooz.tests.get_random_uuid()
|
||||||
|
|
||||||
|
@ddt.data({'coord_url': 'etcd3://',
|
||||||
|
'host': etcd3_driver.Etcd3Driver.DEFAULT_HOST,
|
||||||
|
'port': etcd3_driver.Etcd3Driver.DEFAULT_PORT,
|
||||||
|
'ca_cert': None,
|
||||||
|
'cert_key': None,
|
||||||
|
'cert_cert': None,
|
||||||
|
'timeout': etcd3_driver.Etcd3Driver.DEFAULT_TIMEOUT},
|
||||||
|
{'coord_url': ('etcd3://my_host:666?ca_cert=/my/ca_cert&'
|
||||||
|
'cert_key=/my/cert_key&cert_cert=/my/cert_cert&'
|
||||||
|
'timeout=42'),
|
||||||
|
'host': 'my_host',
|
||||||
|
'port': 666,
|
||||||
|
'ca_cert': '/my/ca_cert',
|
||||||
|
'cert_key': '/my/cert_key',
|
||||||
|
'cert_cert': '/my/cert_cert',
|
||||||
|
'timeout': 42})
|
||||||
|
@ddt.unpack
|
||||||
|
@mock.patch('etcd3.client')
|
||||||
|
def test_etcd3_client_init(self,
|
||||||
|
mock_etcd3_client,
|
||||||
|
coord_url,
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
ca_cert,
|
||||||
|
cert_key,
|
||||||
|
cert_cert,
|
||||||
|
timeout):
|
||||||
|
tooz.coordination.get_coordinator(coord_url, self.FAKE_MEMBER_ID)
|
||||||
|
mock_etcd3_client.assert_called_with(host=host,
|
||||||
|
port=port,
|
||||||
|
ca_cert=ca_cert,
|
||||||
|
cert_key=cert_key,
|
||||||
|
cert_cert=cert_cert,
|
||||||
|
timeout=timeout)
|
|
@ -0,0 +1,67 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright 2020 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import ddt
|
||||||
|
from testtools import testcase
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
import tooz.coordination
|
||||||
|
import tooz.drivers.etcd3gw as etcd3gw_driver
|
||||||
|
import tooz.tests
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class TestEtcd3Gw(testcase.TestCase):
|
||||||
|
FAKE_MEMBER_ID = tooz.tests.get_random_uuid()
|
||||||
|
|
||||||
|
@ddt.data({'coord_url': 'etcd3+http://',
|
||||||
|
'protocol': 'http',
|
||||||
|
'host': etcd3gw_driver.Etcd3Driver.DEFAULT_HOST,
|
||||||
|
'port': etcd3gw_driver.Etcd3Driver.DEFAULT_PORT,
|
||||||
|
'ca_cert': None,
|
||||||
|
'cert_key': None,
|
||||||
|
'cert_cert': None,
|
||||||
|
'timeout': etcd3gw_driver.Etcd3Driver.DEFAULT_TIMEOUT},
|
||||||
|
{'coord_url': ('etcd3+https://my_host:666?ca_cert=/my/ca_cert&'
|
||||||
|
'cert_key=/my/cert_key&cert_cert=/my/cert_cert&'
|
||||||
|
'timeout=42'),
|
||||||
|
'protocol': 'https',
|
||||||
|
'host': 'my_host',
|
||||||
|
'port': 666,
|
||||||
|
'ca_cert': '/my/ca_cert',
|
||||||
|
'cert_key': '/my/cert_key',
|
||||||
|
'cert_cert': '/my/cert_cert',
|
||||||
|
'timeout': 42})
|
||||||
|
@ddt.unpack
|
||||||
|
@mock.patch('etcd3gw.client')
|
||||||
|
def test_etcd3gw_client_init(self,
|
||||||
|
mock_etcd3gw_client,
|
||||||
|
coord_url,
|
||||||
|
protocol,
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
ca_cert,
|
||||||
|
cert_key,
|
||||||
|
cert_cert,
|
||||||
|
timeout):
|
||||||
|
tooz.coordination.get_coordinator(coord_url, self.FAKE_MEMBER_ID)
|
||||||
|
mock_etcd3gw_client.assert_called_with(host=host,
|
||||||
|
port=port,
|
||||||
|
protocol=protocol,
|
||||||
|
ca_cert=ca_cert,
|
||||||
|
cert_key=cert_key,
|
||||||
|
cert_cert=cert_cert,
|
||||||
|
timeout=timeout)
|
Loading…
Reference in New Issue