Merge "Add TLS support for MySQL driver"

This commit is contained in:
Zuul 2022-07-15 21:00:16 +00:00 committed by Gerrit Code Review
commit d145b503ca
3 changed files with 103 additions and 1 deletions

View File

@ -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

View File

@ -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,

View File

@ -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"
)
)