From 5dff348da2e170bda118ee8df9adf663918dca8c Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Tue, 6 Feb 2018 20:10:31 +0000 Subject: [PATCH] Isolate placement database config The placement database connection (which can use the same connection string as the api database) needs to be managed from its own module so that the nova db files are not imported as this eventually leads to importing object-related and other code which the placement service does not need. The wsgi application is now responsible for initializing the database configuration. Fixtures and a number of tests are updated to reflected the new location of the placement engine. The original parse_args needed to import RPC and database related modules that are not required in the placement context. A new _parse_args method is added to wsgi.py which does the minimal required work. Because we no longer use the central parse_args, the placement db sync in nova/cmd/manager.py must make a manual configuration of the context manager. blueprint placement-extract Change-Id: I2fff528060ec52a4a2e26a6484bdf18359b95f77 --- nova/api/openstack/placement/db_api.py | 40 +++++++++++++++++++ .../openstack/placement/objects/consumer.py | 2 +- .../openstack/placement/objects/project.py | 2 +- .../placement/objects/resource_provider.py | 2 +- nova/api/openstack/placement/objects/user.py | 2 +- nova/api/openstack/placement/wsgi.py | 27 ++++++++++++- nova/cmd/manage.py | 3 ++ nova/cmd/status.py | 3 +- nova/db/sqlalchemy/api.py | 11 ----- nova/db/sqlalchemy/migration.py | 3 +- nova/db/sqlalchemy/resource_class_cache.py | 2 +- nova/tests/fixtures.py | 6 ++- .../openstack/placement/db/test_consumer.py | 2 +- 13 files changed, 82 insertions(+), 23 deletions(-) create mode 100644 nova/api/openstack/placement/db_api.py diff --git a/nova/api/openstack/placement/db_api.py b/nova/api/openstack/placement/db_api.py new file mode 100644 index 000000000000..7fb199ed1c3d --- /dev/null +++ b/nova/api/openstack/placement/db_api.py @@ -0,0 +1,40 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +"""Database context manager for placement database connection, kept in its +own file so the nova db_api (which has cascading imports) is not imported. +""" + + +from oslo_db.sqlalchemy import enginefacade + + +placement_context_manager = enginefacade.transaction_context() + + +def _get_db_conf(conf_group, connection=None): + kw = dict(conf_group.items()) + if connection is not None: + kw['connection'] = connection + return kw + + +def configure(conf): + if conf.placement_database.connection is None: + placement_context_manager.configure( + **_get_db_conf(conf.api_database)) + else: + placement_context_manager.configure( + **_get_db_conf(conf.placement_database)) + + +def get_placement_engine(): + return placement_context_manager.get_legacy_facade().get_engine() diff --git a/nova/api/openstack/placement/objects/consumer.py b/nova/api/openstack/placement/objects/consumer.py index e4669a6cfb19..ba8ce65cf93e 100644 --- a/nova/api/openstack/placement/objects/consumer.py +++ b/nova/api/openstack/placement/objects/consumer.py @@ -15,10 +15,10 @@ from oslo_versionedobjects import base from oslo_versionedobjects import fields import sqlalchemy as sa +from nova.api.openstack.placement import db_api from nova.api.openstack.placement import exception from nova.api.openstack.placement.objects import project as project_obj from nova.api.openstack.placement.objects import user as user_obj -from nova.db.sqlalchemy import api as db_api from nova.db.sqlalchemy import api_models as models CONSUMER_TBL = models.Consumer.__table__ diff --git a/nova/api/openstack/placement/objects/project.py b/nova/api/openstack/placement/objects/project.py index d26f2c48621c..a6742da2fdce 100644 --- a/nova/api/openstack/placement/objects/project.py +++ b/nova/api/openstack/placement/objects/project.py @@ -16,8 +16,8 @@ from oslo_versionedobjects import base from oslo_versionedobjects import fields import sqlalchemy as sa +from nova.api.openstack.placement import db_api from nova.api.openstack.placement import exception -from nova.db.sqlalchemy import api as db_api from nova.db.sqlalchemy import api_models as models CONF = cfg.CONF diff --git a/nova/api/openstack/placement/objects/resource_provider.py b/nova/api/openstack/placement/objects/resource_provider.py index 89f9c766df58..97042e0b336e 100644 --- a/nova/api/openstack/placement/objects/resource_provider.py +++ b/nova/api/openstack/placement/objects/resource_provider.py @@ -37,11 +37,11 @@ from sqlalchemy import func from sqlalchemy import sql from sqlalchemy.sql import null +from nova.api.openstack.placement import db_api from nova.api.openstack.placement import exception from nova.api.openstack.placement.objects import consumer as consumer_obj from nova.api.openstack.placement.objects import project as project_obj from nova.api.openstack.placement.objects import user as user_obj -from nova.db.sqlalchemy import api as db_api from nova.db.sqlalchemy import api_models as models from nova.db.sqlalchemy import resource_class_cache as rc_cache from nova.i18n import _ diff --git a/nova/api/openstack/placement/objects/user.py b/nova/api/openstack/placement/objects/user.py index 4125596364e4..8d5af8473d6e 100644 --- a/nova/api/openstack/placement/objects/user.py +++ b/nova/api/openstack/placement/objects/user.py @@ -16,8 +16,8 @@ from oslo_versionedobjects import base from oslo_versionedobjects import fields import sqlalchemy as sa +from nova.api.openstack.placement import db_api from nova.api.openstack.placement import exception -from nova.db.sqlalchemy import api as db_api from nova.db.sqlalchemy import api_models as models CONF = cfg.CONF diff --git a/nova/api/openstack/placement/wsgi.py b/nova/api/openstack/placement/wsgi.py index 5f1c268d2ab4..364041b5e828 100644 --- a/nova/api/openstack/placement/wsgi.py +++ b/nova/api/openstack/placement/wsgi.py @@ -19,14 +19,24 @@ import os import os.path from oslo_log import log as logging +from oslo_utils import importutils +import pbr.version +from nova.api.openstack.placement import db_api from nova.api.openstack.placement import deploy +from nova.common import config from nova import conf -from nova import config + + +profiler = importutils.try_import('osprofiler.opts') + CONFIG_FILE = 'nova.conf' +version_info = pbr.version.VersionInfo('nova') + + def setup_logging(config): # Any dependent libraries that have unhelp debug levels should be # pinned to a higher default. @@ -47,10 +57,23 @@ def _get_config_file(env=None): return os.path.join(dirname, CONFIG_FILE) +def _parse_args(argv, default_config_files): + logging.register_options(conf.CONF) + + if profiler: + profiler.set_defaults(conf.CONF) + + config.set_middleware_defaults() + + conf.CONF(argv[1:], project='nova', version=version_info.version_string(), + default_config_files=default_config_files) + + def init_application(): # initialize the config system conffile = _get_config_file() - config.parse_args([], default_config_files=[conffile]) + _parse_args([], default_config_files=[conffile]) + db_api.configure(conf.CONF) # initialize the logging system setup_logging(conf.CONF) diff --git a/nova/cmd/manage.py b/nova/cmd/manage.py index 8dfc4cf20814..4fc11b846dbd 100644 --- a/nova/cmd/manage.py +++ b/nova/cmd/manage.py @@ -44,6 +44,7 @@ import six import six.moves.urllib.parse as urlparse from sqlalchemy.engine import url as sqla_url +from nova.api.openstack.placement import db_api as placement_db from nova.api.openstack.placement.objects import consumer as consumer_obj from nova.cmd import common as cmd_common import nova.conf @@ -853,6 +854,8 @@ class ApiDbCommands(object): # the placement sync to and with the api sync. result = True if CONF.placement_database.connection is not None: + # Establish the independent context manager for the placement db. + placement_db.configure(CONF) result = migration.db_sync(version, database='placement') return migration.db_sync(version2, database='api') and result diff --git a/nova/cmd/status.py b/nova/cmd/status.py index 1719bc9f7804..b9556a187972 100644 --- a/nova/cmd/status.py +++ b/nova/cmd/status.py @@ -35,6 +35,7 @@ from sqlalchemy import func as sqlfunc from sqlalchemy import MetaData, Table, and_, select from sqlalchemy.sql import false +from nova.api.openstack.placement import db_api as placement_db from nova.cmd import common as cmd_common import nova.conf from nova import config @@ -249,7 +250,7 @@ class UpgradeCommands(object): # and resource class, so we can simply count the number of inventories # records for the given resource class and those will uniquely identify # the number of resource providers we care about. - meta = MetaData(bind=db_session.get_placement_engine()) + meta = MetaData(bind=placement_db.get_placement_engine()) inventories = Table('inventories', meta, autoload=True) return select([sqlfunc.count()]).select_from( inventories).where( diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 8afd05304dca..f7e01ec2c459 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -79,7 +79,6 @@ LOG = logging.getLogger(__name__) main_context_manager = enginefacade.transaction_context() api_context_manager = enginefacade.transaction_context() -placement_context_manager = enginefacade.transaction_context() def _get_db_conf(conf_group, connection=None): @@ -100,12 +99,6 @@ def _context_manager_from_context(context): def configure(conf): main_context_manager.configure(**_get_db_conf(conf.database)) api_context_manager.configure(**_get_db_conf(conf.api_database)) - if conf.placement_database.connection is None: - placement_context_manager.configure( - **_get_db_conf(conf.api_database)) - else: - placement_context_manager.configure( - **_get_db_conf(conf.placement_database)) if profiler_sqlalchemy and CONF.profiler.enabled \ and CONF.profiler.trace_sqlalchemy: @@ -148,10 +141,6 @@ def get_api_engine(): return api_context_manager.get_legacy_facade().get_engine() -def get_placement_engine(): - return placement_context_manager.get_legacy_facade().get_engine() - - _SHADOW_TABLE_PREFIX = 'shadow_' _DEFAULT_QUOTA_NAME = 'default' PER_PROJECT_QUOTAS = ['fixed_ips', 'floating_ips', 'networks'] diff --git a/nova/db/sqlalchemy/migration.py b/nova/db/sqlalchemy/migration.py index a61748b1d74b..79d8423a07a1 100644 --- a/nova/db/sqlalchemy/migration.py +++ b/nova/db/sqlalchemy/migration.py @@ -24,6 +24,7 @@ from oslo_log import log as logging import sqlalchemy from sqlalchemy.sql import null +from nova.api.openstack.placement import db_api as placement_db from nova.db.sqlalchemy import api as db_session from nova import exception from nova.i18n import _ @@ -43,7 +44,7 @@ def get_engine(database='main', context=None): if database == 'api': return db_session.get_api_engine() if database == 'placement': - return db_session.get_placement_engine() + return placement_db.get_placement_engine() def db_sync(version=None, database='main', context=None): diff --git a/nova/db/sqlalchemy/resource_class_cache.py b/nova/db/sqlalchemy/resource_class_cache.py index 89dfa8cda610..fa0728ff431b 100644 --- a/nova/db/sqlalchemy/resource_class_cache.py +++ b/nova/db/sqlalchemy/resource_class_cache.py @@ -17,8 +17,8 @@ import sqlalchemy as sa # TODO(cdent): This file and its location is problematic for placement # extraction but we probably want to switch to os-resource-classes (like # os-traits) instead of moving it? +from nova.api.openstack.placement import db_api from nova.api.openstack.placement import exception -from nova.db.sqlalchemy import api as db_api from nova.db.sqlalchemy import api_models as models from nova import rc_fields as fields diff --git a/nova/tests/fixtures.py b/nova/tests/fixtures.py index 207047133498..d0d993370600 100644 --- a/nova/tests/fixtures.py +++ b/nova/tests/fixtures.py @@ -37,6 +37,7 @@ from requests import adapters from wsgi_intercept import interceptor from nova.api.openstack.compute import tenant_networks +from nova.api.openstack.placement import db_api as placement_db from nova.api.openstack import wsgi_app from nova.api import wsgi from nova.compute import rpcapi as compute_rpcapi @@ -580,6 +581,7 @@ class Database(fixtures.Fixture): global SESSION_CONFIGURED if not SESSION_CONFIGURED: session.configure(CONF) + placement_db.configure(CONF) SESSION_CONFIGURED = True self.database = database if database == 'main': @@ -593,7 +595,7 @@ class Database(fixtures.Fixture): elif database == 'api': self.get_engine = session.get_api_engine elif database == 'placement': - self.get_engine = session.get_placement_engine + self.get_engine = placement_db.get_placement_engine def _cache_schema(self): global DB_SCHEMA @@ -637,7 +639,7 @@ class DatabaseAtVersion(fixtures.Fixture): elif database == 'api': self.get_engine = session.get_api_engine elif database == 'placement': - self.get_engine = session.get_placement_engine + self.get_engine = placement_db.get_placement_engine def cleanup(self): engine = self.get_engine() diff --git a/nova/tests/functional/api/openstack/placement/db/test_consumer.py b/nova/tests/functional/api/openstack/placement/db/test_consumer.py index 67120270c5f0..af8c27fdd102 100644 --- a/nova/tests/functional/api/openstack/placement/db/test_consumer.py +++ b/nova/tests/functional/api/openstack/placement/db/test_consumer.py @@ -13,13 +13,13 @@ from oslo_config import cfg import sqlalchemy as sa +from nova.api.openstack.placement import db_api from nova.api.openstack.placement import exception from nova.api.openstack.placement.objects import consumer as consumer_obj from nova.api.openstack.placement.objects import project as project_obj from nova.api.openstack.placement.objects import resource_provider as rp_obj from nova.api.openstack.placement.objects import user as user_obj from nova import context -from nova.db.sqlalchemy import api as db_api from nova import test from nova.tests import fixtures from nova.tests.functional.api.openstack.placement.db import test_base as tb