summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--oslo_db/sqlalchemy/engines.py20
-rw-r--r--oslo_db/tests/sqlalchemy/test_sqlalchemy.py46
2 files changed, 66 insertions, 0 deletions
diff --git a/oslo_db/sqlalchemy/engines.py b/oslo_db/sqlalchemy/engines.py
index 601be76..a9ac662 100644
--- a/oslo_db/sqlalchemy/engines.py
+++ b/oslo_db/sqlalchemy/engines.py
@@ -100,6 +100,24 @@ def _setup_logging(connection_debug=0):
logger.setLevel(logging.WARNING)
+def _vet_url(url):
+ if "+" not in url.drivername and not url.drivername.startswith("sqlite"):
+ if url.drivername.startswith("mysql"):
+ LOG.warning(
+ "URL %r does not contain a '+drivername' portion, "
+ "and will make use of a default driver. "
+ "A full dbname+drivername:// protocol is recommended. "
+ "For MySQL, it is strongly recommended that mysql+pymysql:// "
+ "be specified for maximum service compatibility", url
+ )
+ else:
+ LOG.warning(
+ "URL %r does not contain a '+drivername' portion, "
+ "and will make use of a default driver. "
+ "A full dbname+drivername:// protocol is recommended.", url
+ )
+
+
def create_engine(sql_connection, sqlite_fk=False, mysql_sql_mode=None,
idle_timeout=3600,
connection_debug=0, max_pool_size=None, max_overflow=None,
@@ -112,6 +130,8 @@ def create_engine(sql_connection, sqlite_fk=False, mysql_sql_mode=None,
url = sqlalchemy.engine.url.make_url(sql_connection)
+ _vet_url(url)
+
engine_args = {
"pool_recycle": idle_timeout,
'convert_unicode': True,
diff --git a/oslo_db/tests/sqlalchemy/test_sqlalchemy.py b/oslo_db/tests/sqlalchemy/test_sqlalchemy.py
index a37cdc6..bcbad45 100644
--- a/oslo_db/tests/sqlalchemy/test_sqlalchemy.py
+++ b/oslo_db/tests/sqlalchemy/test_sqlalchemy.py
@@ -664,6 +664,52 @@ class CreateEngineTest(oslo_test.BaseTestCase):
engines._thread_yield
)
+ def test_warn_on_missing_driver(self):
+
+ warnings = mock.Mock()
+
+ def warn_interpolate(msg, args):
+ # test the interpolation itself to ensure the password
+ # is concealed
+ warnings.warning(msg % args)
+
+ with mock.patch(
+ "oslo_db.sqlalchemy.engines.LOG.warning",
+ warn_interpolate):
+
+ engines._vet_url(
+ url.make_url("mysql://scott:tiger@some_host/some_db"))
+ engines._vet_url(url.make_url(
+ "mysql+mysqldb://scott:tiger@some_host/some_db"))
+ engines._vet_url(url.make_url(
+ "mysql+pymysql://scott:tiger@some_host/some_db"))
+ engines._vet_url(url.make_url(
+ "postgresql+psycopg2://scott:tiger@some_host/some_db"))
+ engines._vet_url(url.make_url(
+ "postgresql://scott:tiger@some_host/some_db"))
+
+ self.assertEqual(
+ [
+ mock.call.warning(
+ "URL mysql://scott:***@some_host/some_db does not contain "
+ "a '+drivername' portion, "
+ "and will make use of a default driver. "
+ "A full dbname+drivername:// protocol is recommended. "
+ "For MySQL, it is strongly recommended that "
+ "mysql+pymysql:// "
+ "be specified for maximum service compatibility",
+
+ ),
+ mock.call.warning(
+ "URL postgresql://scott:***@some_host/some_db does not "
+ "contain a '+drivername' portion, "
+ "and will make use of a default driver. "
+ "A full dbname+drivername:// protocol is recommended."
+ )
+ ],
+ warnings.mock_calls
+ )
+
class ProcessGuardTest(test_base.DbTestCase):
def test_process_guard(self):