Merge "Add TLS support for MySQL driver"
This commit is contained in:
commit
d145b503ca
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Added TLS support for MySQL driver.
|
||||
|
||||
The following TLS-related options now can be specifed in the MySQL
|
||||
connection URL as query parameters
|
||||
|
||||
``ssl_ca``
|
||||
path to the CA bundle to use for verifying server certificate
|
||||
|
||||
``ssl_capath``
|
||||
path to folder with CA bundle files
|
||||
|
||||
``ssl_cert``
|
||||
path to client public key certificate file
|
||||
|
||||
``ssl_key``
|
||||
path to client private key file
|
||||
|
||||
``ssl_check_hostname``
|
||||
verify server hostname against its certificate,
|
||||
accepted values are "true", "1", "yes" or "false", "0", "no"
|
||||
(default is "true")
|
||||
|
||||
``ssl_verify_mode``
|
||||
whether to verify TLS connection
|
||||
accepted values are "true", "1", "yes", "required" or
|
||||
"false", "0", "no", "none", or
|
||||
"optional"
|
||||
|
||||
``ssl_cipher``
|
||||
list of permissible ciphers for connection encryption
|
|
@ -116,9 +116,23 @@ class MySQLDriver(coordination.CoordinationDriver):
|
|||
|
||||
The MySQL driver connection URI should look like::
|
||||
|
||||
mysql://USERNAME:PASSWORD@HOST[:PORT]/DBNAME[?unix_socket=SOCKET_PATH]
|
||||
mysql://USERNAME:PASSWORD@HOST[:PORT]/DBNAME[?OPTION1=VALUE1[&OPTION2=VALUE2[&...]]]
|
||||
|
||||
If not specified, PORT defaults to 3306.
|
||||
Available options are:
|
||||
|
||||
================== =======
|
||||
Name Default
|
||||
================== =======
|
||||
ssl_ca None
|
||||
ssl_capath None
|
||||
ssl_cert None
|
||||
ssl_key None
|
||||
ssl_cipher None
|
||||
ssl_verify_mode None
|
||||
ssl_check_hostname True
|
||||
unix_socket None
|
||||
================== =======
|
||||
|
||||
.. _MySQL: http://dev.mysql.com/
|
||||
"""
|
||||
|
@ -182,6 +196,26 @@ class MySQLDriver(coordination.CoordinationDriver):
|
|||
username = parsed_url.username
|
||||
password = parsed_url.password
|
||||
unix_socket = options.get("unix_socket")
|
||||
ssl_opt_names = (
|
||||
"ca",
|
||||
"capath",
|
||||
"cert",
|
||||
"key",
|
||||
"cipher",
|
||||
"verify_mode",
|
||||
)
|
||||
ssl_args = {}
|
||||
for o in ssl_opt_names:
|
||||
value = options.get("ssl_" + o)
|
||||
if value:
|
||||
ssl_args[o] = value
|
||||
check_hostname = options.get("ssl_check_hostname")
|
||||
if check_hostname is not None:
|
||||
check_hostname = check_hostname.lower()
|
||||
if check_hostname in ("true", "1", "yes"):
|
||||
ssl_args["check_hostname"] = True
|
||||
elif check_hostname in ("false", "0", "no"):
|
||||
ssl_args["check_hostname"] = False
|
||||
|
||||
try:
|
||||
if unix_socket:
|
||||
|
@ -190,6 +224,7 @@ class MySQLDriver(coordination.CoordinationDriver):
|
|||
user=username,
|
||||
passwd=password,
|
||||
database=dbname,
|
||||
ssl=ssl_args,
|
||||
defer_connect=defer_connect)
|
||||
else:
|
||||
return pymysql.Connect(host=host,
|
||||
|
@ -197,6 +232,7 @@ class MySQLDriver(coordination.CoordinationDriver):
|
|||
user=username,
|
||||
passwd=password,
|
||||
database=dbname,
|
||||
ssl=ssl_args,
|
||||
defer_connect=defer_connect)
|
||||
except (pymysql.err.OperationalError, pymysql.err.InternalError) as e:
|
||||
utils.raise_with_cause(coordination.ToozConnectionError,
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from unittest import mock
|
||||
|
||||
from oslo_utils import encodeutils
|
||||
from testtools import testcase
|
||||
|
@ -52,3 +53,35 @@ class TestMySQLDriver(testcase.TestCase):
|
|||
def test_connect_failure_invalid_hostname_and_port_provided(self):
|
||||
c = self._create_coordinator("mysql://invalidhost:54/test")
|
||||
self.assertRaises(coordination.ToozConnectionError, c.start)
|
||||
|
||||
@mock.patch("pymysql.Connect")
|
||||
def test_parsing_tls_settings(self, sql_mock):
|
||||
c = self._create_coordinator(
|
||||
"mysql://invalidhost:54/test"
|
||||
"?ssl_ca=/ca/not/there"
|
||||
"&ssl_capath=/capath/not/there"
|
||||
"&ssl_check_hostname=False"
|
||||
"&ssl_verify_mode=yes"
|
||||
"&ssl_cert=/cert/not/there"
|
||||
"&ssl_key=/key/not/there"
|
||||
"&ssl_cipher=spam,ham"
|
||||
)
|
||||
c.start()
|
||||
sql_mock.assert_called_once_with(
|
||||
host="invalidhost",
|
||||
port=54,
|
||||
user=None,
|
||||
passwd=None,
|
||||
database="test",
|
||||
defer_connect=False,
|
||||
ssl=dict(
|
||||
ca="/ca/not/there",
|
||||
capath="/capath/not/there",
|
||||
check_hostname=False,
|
||||
verify_mode="yes",
|
||||
cert="/cert/not/there",
|
||||
key="/key/not/there",
|
||||
cipher="spam,ham"
|
||||
)
|
||||
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue