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
This commit is contained in:
Chris Dent 2018-02-06 20:10:31 +00:00
parent afcf078715
commit 5dff348da2
13 changed files with 82 additions and 23 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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