diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-01-29 17:22:30 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-01-30 09:08:48 -0500 |
commit | 9993efdeef4606f78182d084e4120a158a4e64b8 (patch) | |
tree | 1de4d8a89442aff58b2d23e25857ef8961ed8d2e /oslo_db/sqlalchemy | |
parent | 650779240e69d36b0f95969fd689bfa52dd80c73 (diff) | |
download | oslo-db-9993efdeef4606f78182d084e4120a158a4e64b8.tar.gz |
Allow connection query string to be passed separately.
The Nova project has made the decision to store the entire
contents of the "sql_connection" field in the database, with
alterations to the host value, such that various "cells" database
URLs can be located using Nova's database itself as a central
registry of database URLs.
This architecture has produced several problems. The first
is that it is impossible to apply parameters to the URL that
are local to the client machine; the leading example of this
is the MySQL "bind_host" variable, which must match the hostname
of the connecting host. Because cells puts these URLs into the
database and shares them with all controllers, we have to use a workaround
with the read_default_file parameter to specify a controller-local
file of options; this is not a standard thing
for other database drivers, and these parameters only apply to
the MySQL driver and not the SQLAlchemy engine.
The next issue is that it is inconvenient to add parameters
to the URL at all, once Nova has already been running, as one
must manually use Nova's command line tools
to alter all the URLs that have already been copied into the database
and alter the query parameters with each of those individually,
and then restart *all* services who will all receive the parameter
(no way to add params to just one controller).
Nova's "store the URL in the database" feature only needs to be able
to locate the host / database name of the alternate database,
and not change the URL tuning parameters. This patch adds a new
oslo.db parameter connection_parameters which allows the params to
be applied separately from the sql_connection parameter, so that
Nova can continue persisting sql_connection but the parameters remain
local to the nova.conf file. A URL parameter that truly had to remain
persisted in Nova's database (there aren't any) could still be applied
at the sql_connection level.
This feature is essential not just so that we can again place
simple parameters into controller-local files like "bind_host", but
also to allow for configuration of SQLAlchemy features such as
plugins that do connection pool monitoring.
Change-Id: Id4de4b09ec4719cbf8b372629fcf58cf368a33d4
Diffstat (limited to 'oslo_db/sqlalchemy')
-rw-r--r-- | oslo_db/sqlalchemy/enginefacade.py | 6 | ||||
-rw-r--r-- | oslo_db/sqlalchemy/engines.py | 20 |
2 files changed, 24 insertions, 2 deletions
diff --git a/oslo_db/sqlalchemy/enginefacade.py b/oslo_db/sqlalchemy/enginefacade.py index 80c320b..fe26b9a 100644 --- a/oslo_db/sqlalchemy/enginefacade.py +++ b/oslo_db/sqlalchemy/enginefacade.py @@ -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 diff --git a/oslo_db/sqlalchemy/engines.py b/oslo_db/sqlalchemy/engines.py index 2808ef4..05045ca 100644 --- a/oslo_db/sqlalchemy/engines.py +++ b/oslo_db/sqlalchemy/engines.py @@ -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 = { |