Merge "Allow connection query string to be passed separately."
This commit is contained in:
commit
9c6695969f
|
@ -146,6 +146,11 @@ database_opts = [
|
|||
'error before error is '
|
||||
'raised. Set to -1 to specify an infinite retry '
|
||||
'count.'),
|
||||
cfg.StrOpt('connection_parameters',
|
||||
default='',
|
||||
help='Optional URL parameters to append onto the connection '
|
||||
'URL at connect time; specify as '
|
||||
'param1=value1¶m2=value2&...'),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -149,7 +149,8 @@ class _TransactionFactory(object):
|
|||
'thread_checkin': _Default(True),
|
||||
'json_serializer': _Default(None),
|
||||
'json_deserializer': _Default(None),
|
||||
'logging_name': _Default(None)
|
||||
'logging_name': _Default(None),
|
||||
'connection_parameters': _Default(None)
|
||||
}
|
||||
self._maker_cfg = {
|
||||
'expire_on_commit': _Default(False),
|
||||
|
@ -219,6 +220,9 @@ class _TransactionFactory(object):
|
|||
:param connection_debug: engine logging level, defaults to 0. set to
|
||||
50 for INFO, 100 for DEBUG.
|
||||
|
||||
:param connection_parameters: additional parameters to append onto the
|
||||
database URL query string, pass as "param1=value1¶m2=value2&..."
|
||||
|
||||
:param max_pool_size: max size of connection pool, uses CONF for
|
||||
default
|
||||
|
||||
|
|
|
@ -104,6 +104,21 @@ def _setup_logging(connection_debug=0):
|
|||
logger.setLevel(logging.WARNING)
|
||||
|
||||
|
||||
def _extend_url_parameters(url, connection_parameters):
|
||||
for key, value in six.moves.urllib.parse.parse_qs(
|
||||
connection_parameters).items():
|
||||
if key in url.query:
|
||||
existing = url.query[key]
|
||||
if not isinstance(existing, list):
|
||||
url.query[key] = existing = utils.to_list(existing)
|
||||
existing.extend(value)
|
||||
value = existing
|
||||
else:
|
||||
url.query[key] = value
|
||||
if len(value) == 1:
|
||||
url.query[key] = value[0]
|
||||
|
||||
|
||||
def _vet_url(url):
|
||||
if "+" not in url.drivername and not url.drivername.startswith("sqlite"):
|
||||
if url.drivername.startswith("mysql"):
|
||||
|
@ -132,11 +147,14 @@ def create_engine(sql_connection, sqlite_fk=False, mysql_sql_mode=None,
|
|||
connection_trace=False, max_retries=10, retry_interval=10,
|
||||
thread_checkin=True, logging_name=None,
|
||||
json_serializer=None,
|
||||
json_deserializer=None):
|
||||
json_deserializer=None, connection_parameters=None):
|
||||
"""Return a new SQLAlchemy engine."""
|
||||
|
||||
url = sqlalchemy.engine.url.make_url(sql_connection)
|
||||
|
||||
if connection_parameters:
|
||||
_extend_url_parameters(url, connection_parameters)
|
||||
|
||||
_vet_url(url)
|
||||
|
||||
engine_args = {
|
||||
|
|
|
@ -213,6 +213,79 @@ class FakeDB2Engine(object):
|
|||
pass
|
||||
|
||||
|
||||
class QueryParamTest(test_base.DbTestCase):
|
||||
def _fixture(self):
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
def _mock_create_engine(*arg, **kw):
|
||||
return create_engine("sqlite://")
|
||||
|
||||
return mock.patch(
|
||||
"oslo_db.sqlalchemy.engines.sqlalchemy.create_engine",
|
||||
side_effect=_mock_create_engine)
|
||||
|
||||
def test_add_assorted_params(self):
|
||||
with self._fixture() as ce:
|
||||
engines.create_engine(
|
||||
"mysql+pymysql://foo:bar@bat",
|
||||
connection_parameters="foo=bar&bat=hoho&bat=param2")
|
||||
|
||||
self.assertEqual(
|
||||
ce.mock_calls[0][1][0].query,
|
||||
{'bat': ['hoho', 'param2'], 'foo': 'bar'}
|
||||
)
|
||||
|
||||
def test_add_no_params(self):
|
||||
with self._fixture() as ce:
|
||||
engines.create_engine(
|
||||
"mysql+pymysql://foo:bar@bat")
|
||||
|
||||
self.assertEqual(
|
||||
ce.mock_calls[0][1][0].query,
|
||||
{}
|
||||
)
|
||||
|
||||
def test_combine_params(self):
|
||||
with self._fixture() as ce:
|
||||
engines.create_engine(
|
||||
"mysql+pymysql://foo:bar@bat/"
|
||||
"?charset=utf8¶m_file=tripleo.cnf",
|
||||
connection_parameters="plugin=sqlalchemy_collectd&"
|
||||
"collectd_host=127.0.0.1&"
|
||||
"bind_host=192.168.1.5")
|
||||
|
||||
self.assertEqual(
|
||||
ce.mock_calls[0][1][0].query,
|
||||
{
|
||||
'bind_host': '192.168.1.5',
|
||||
'charset': 'utf8',
|
||||
'collectd_host': '127.0.0.1',
|
||||
'param_file': 'tripleo.cnf',
|
||||
'plugin': 'sqlalchemy_collectd'
|
||||
}
|
||||
)
|
||||
|
||||
def test_combine_multi_params(self):
|
||||
with self._fixture() as ce:
|
||||
engines.create_engine(
|
||||
"mysql+pymysql://foo:bar@bat/"
|
||||
"?charset=utf8¶m_file=tripleo.cnf&plugin=connmon",
|
||||
connection_parameters="plugin=sqlalchemy_collectd&"
|
||||
"collectd_host=127.0.0.1&"
|
||||
"bind_host=192.168.1.5")
|
||||
|
||||
self.assertEqual(
|
||||
ce.mock_calls[0][1][0].query,
|
||||
{
|
||||
'bind_host': '192.168.1.5',
|
||||
'charset': 'utf8',
|
||||
'collectd_host': '127.0.0.1',
|
||||
'param_file': 'tripleo.cnf',
|
||||
'plugin': ['connmon', 'sqlalchemy_collectd']
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class MySQLDefaultModeTestCase(test_base.MySQLOpportunisticTestCase):
|
||||
def test_default_is_traditional(self):
|
||||
with self.engine.connect() as conn:
|
||||
|
@ -357,6 +430,7 @@ class EngineFacadeTestCase(oslo_test.BaseTestCase):
|
|||
thread_checkin=mock.ANY,
|
||||
json_serializer=None,
|
||||
json_deserializer=None,
|
||||
connection_parameters='',
|
||||
logging_name=mock.ANY,
|
||||
)
|
||||
get_maker.assert_called_once_with(engine=create_engine(),
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Added new option connection_parameters which allows SQLAlchemy query
|
||||
parameters to be stated separately from the URL itself, to allow
|
||||
URL-persistence schemes like Nova cells to use controller-local
|
||||
query parameters that aren't broadcast to all other servers.
|
Loading…
Reference in New Issue