Merge "Use EngineFacade from oslo_db.enginefacade"
This commit is contained in:
commit
50c00d5315
@ -19,6 +19,7 @@ from oslo_config import cfg
|
|||||||
from oslo_db import options
|
from oslo_db import options
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
|
from nova.db.sqlalchemy import api as sqlalchemy_api
|
||||||
from nova import debugger
|
from nova import debugger
|
||||||
from nova import paths
|
from nova import paths
|
||||||
from nova import rpc
|
from nova import rpc
|
||||||
@ -46,7 +47,7 @@ _DEFAULT_LOGGING_CONTEXT_FORMAT = ('%(asctime)s.%(msecs)03d %(process)d '
|
|||||||
'%(message)s')
|
'%(message)s')
|
||||||
|
|
||||||
|
|
||||||
def parse_args(argv, default_config_files=None):
|
def parse_args(argv, default_config_files=None, configure_db=True):
|
||||||
log.set_defaults(_DEFAULT_LOGGING_CONTEXT_FORMAT, _DEFAULT_LOG_LEVELS)
|
log.set_defaults(_DEFAULT_LOGGING_CONTEXT_FORMAT, _DEFAULT_LOG_LEVELS)
|
||||||
log.register_options(CONF)
|
log.register_options(CONF)
|
||||||
options.set_defaults(CONF, connection=_DEFAULT_SQL_CONNECTION,
|
options.set_defaults(CONF, connection=_DEFAULT_SQL_CONNECTION,
|
||||||
@ -58,3 +59,6 @@ def parse_args(argv, default_config_files=None):
|
|||||||
version=version.version_string(),
|
version=version.version_string(),
|
||||||
default_config_files=default_config_files)
|
default_config_files=default_config_files)
|
||||||
rpc.init(CONF)
|
rpc.init(CONF)
|
||||||
|
|
||||||
|
if configure_db:
|
||||||
|
sqlalchemy_api.configure(CONF)
|
||||||
|
@ -22,6 +22,7 @@ import copy
|
|||||||
from keystoneclient import auth
|
from keystoneclient import auth
|
||||||
from keystoneclient import service_catalog
|
from keystoneclient import service_catalog
|
||||||
from oslo_context import context
|
from oslo_context import context
|
||||||
|
from oslo_db.sqlalchemy import enginefacade
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
import six
|
import six
|
||||||
@ -60,6 +61,7 @@ class _ContextAuthPlugin(auth.BaseAuthPlugin):
|
|||||||
region_name=region_name)
|
region_name=region_name)
|
||||||
|
|
||||||
|
|
||||||
|
@enginefacade.transaction_context_provider
|
||||||
class RequestContext(context.RequestContext):
|
class RequestContext(context.RequestContext):
|
||||||
"""Security context and request information.
|
"""Security context and request information.
|
||||||
|
|
||||||
|
@ -22,14 +22,13 @@ import copy
|
|||||||
import datetime
|
import datetime
|
||||||
import functools
|
import functools
|
||||||
import sys
|
import sys
|
||||||
import threading
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_db import api as oslo_db_api
|
from oslo_db import api as oslo_db_api
|
||||||
from oslo_db import exception as db_exc
|
from oslo_db import exception as db_exc
|
||||||
from oslo_db import options as oslo_db_options
|
from oslo_db import options as oslo_db_options
|
||||||
from oslo_db.sqlalchemy import session as db_session
|
from oslo_db.sqlalchemy import enginefacade
|
||||||
from oslo_db.sqlalchemy import update_match
|
from oslo_db.sqlalchemy import update_match
|
||||||
from oslo_db.sqlalchemy import utils as sqlalchemyutils
|
from oslo_db.sqlalchemy import utils as sqlalchemyutils
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
@ -130,20 +129,16 @@ CONF.import_opt('until_refresh', 'nova.quota')
|
|||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
_ENGINE_FACADE = {'main': None, 'api': None}
|
main_context_manager = enginefacade.transaction_context()
|
||||||
_MAIN_FACADE = 'main'
|
api_context_manager = enginefacade.transaction_context()
|
||||||
_API_FACADE = 'api'
|
|
||||||
_LOCK = threading.Lock()
|
|
||||||
|
|
||||||
|
|
||||||
def _create_facade(conf_group):
|
def _get_db_conf(conf_group):
|
||||||
|
kw = dict(
|
||||||
# NOTE(dheeraj): This fragment is copied from oslo.db
|
connection=conf_group.connection,
|
||||||
return db_session.EngineFacade(
|
|
||||||
sql_connection=conf_group.connection,
|
|
||||||
slave_connection=conf_group.slave_connection,
|
slave_connection=conf_group.slave_connection,
|
||||||
sqlite_fk=False,
|
sqlite_fk=False,
|
||||||
autocommit=True,
|
__autocommit=True,
|
||||||
expire_on_commit=False,
|
expire_on_commit=False,
|
||||||
mysql_sql_mode=conf_group.mysql_sql_mode,
|
mysql_sql_mode=conf_group.mysql_sql_mode,
|
||||||
idle_timeout=conf_group.idle_timeout,
|
idle_timeout=conf_group.idle_timeout,
|
||||||
@ -155,39 +150,31 @@ def _create_facade(conf_group):
|
|||||||
connection_trace=conf_group.connection_trace,
|
connection_trace=conf_group.connection_trace,
|
||||||
max_retries=conf_group.max_retries,
|
max_retries=conf_group.max_retries,
|
||||||
retry_interval=conf_group.retry_interval)
|
retry_interval=conf_group.retry_interval)
|
||||||
|
return kw
|
||||||
|
|
||||||
|
|
||||||
def _create_facade_lazily(facade, conf_group):
|
def configure(conf):
|
||||||
global _LOCK, _ENGINE_FACADE
|
main_context_manager.configure(**_get_db_conf(conf.database))
|
||||||
if _ENGINE_FACADE[facade] is None:
|
api_context_manager.configure(**_get_db_conf(conf.api_database))
|
||||||
with _LOCK:
|
|
||||||
if _ENGINE_FACADE[facade] is None:
|
|
||||||
_ENGINE_FACADE[facade] = _create_facade(conf_group)
|
|
||||||
return _ENGINE_FACADE[facade]
|
|
||||||
|
|
||||||
|
|
||||||
def get_engine(use_slave=False):
|
def get_engine(use_slave=False):
|
||||||
conf_group = CONF.database
|
return main_context_manager._factory.get_legacy_facade().get_engine(
|
||||||
facade = _create_facade_lazily(_MAIN_FACADE, conf_group)
|
use_slave=use_slave)
|
||||||
return facade.get_engine(use_slave=use_slave)
|
|
||||||
|
|
||||||
|
|
||||||
def get_api_engine():
|
def get_api_engine():
|
||||||
conf_group = CONF.api_database
|
return api_context_manager._factory.get_legacy_facade().get_engine()
|
||||||
facade = _create_facade_lazily(_API_FACADE, conf_group)
|
|
||||||
return facade.get_engine()
|
|
||||||
|
|
||||||
|
|
||||||
def get_session(use_slave=False, **kwargs):
|
def get_session(use_slave=False, **kwargs):
|
||||||
conf_group = CONF.database
|
return main_context_manager._factory.get_legacy_facade().get_session(
|
||||||
facade = _create_facade_lazily(_MAIN_FACADE, conf_group)
|
use_slave=use_slave, **kwargs)
|
||||||
return facade.get_session(use_slave=use_slave, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def get_api_session(**kwargs):
|
def get_api_session(**kwargs):
|
||||||
conf_group = CONF.api_database
|
return api_context_manager._factory.get_legacy_facade().get_session(
|
||||||
facade = _create_facade_lazily(_API_FACADE, conf_group)
|
**kwargs)
|
||||||
return facade.get_session(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
_SHADOW_TABLE_PREFIX = 'shadow_'
|
_SHADOW_TABLE_PREFIX = 'shadow_'
|
||||||
@ -270,6 +257,9 @@ def model_query(context, model,
|
|||||||
'allow_none', restriction includes project_id = None.
|
'allow_none', restriction includes project_id = None.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if hasattr(context, 'session'):
|
||||||
|
session = context.session
|
||||||
|
|
||||||
if session is None:
|
if session is None:
|
||||||
if CONF.database.slave_connection == '':
|
if CONF.database.slave_connection == '':
|
||||||
use_slave = False
|
use_slave = False
|
||||||
|
@ -39,6 +39,7 @@ _TRUE_VALUES = ('True', 'true', '1', 'yes')
|
|||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
DB_SCHEMA = {'main': "", 'api': ""}
|
DB_SCHEMA = {'main': "", 'api': ""}
|
||||||
|
SESSION_CONFIGURED = False
|
||||||
|
|
||||||
|
|
||||||
class ServiceFixture(fixtures.Fixture):
|
class ServiceFixture(fixtures.Fixture):
|
||||||
@ -195,6 +196,12 @@ class Timeout(fixtures.Fixture):
|
|||||||
class Database(fixtures.Fixture):
|
class Database(fixtures.Fixture):
|
||||||
def __init__(self, database='main'):
|
def __init__(self, database='main'):
|
||||||
super(Database, self).__init__()
|
super(Database, self).__init__()
|
||||||
|
# NOTE(pkholkin): oslo_db.enginefacade is configured in tests the same
|
||||||
|
# way as it is done for any other service that uses db
|
||||||
|
global SESSION_CONFIGURED
|
||||||
|
if not SESSION_CONFIGURED:
|
||||||
|
session.configure(CONF)
|
||||||
|
SESSION_CONFIGURED = True
|
||||||
self.database = database
|
self.database = database
|
||||||
if database == 'main':
|
if database == 'main':
|
||||||
self.get_engine = session.get_engine
|
self.get_engine = session.get_engine
|
||||||
|
@ -56,7 +56,7 @@ class ConfFixture(config_fixture.Config):
|
|||||||
self.conf.set_default('use_ipv6', True)
|
self.conf.set_default('use_ipv6', True)
|
||||||
self.conf.set_default('vlan_interface', 'eth0')
|
self.conf.set_default('vlan_interface', 'eth0')
|
||||||
self.conf.set_default('auth_strategy', 'noauth2')
|
self.conf.set_default('auth_strategy', 'noauth2')
|
||||||
config.parse_args([], default_config_files=[])
|
config.parse_args([], default_config_files=[], configure_db=False)
|
||||||
self.conf.set_default('connection', "sqlite://", group='database')
|
self.conf.set_default('connection', "sqlite://", group='database')
|
||||||
self.conf.set_default('connection', "sqlite://", group='api_database')
|
self.conf.set_default('connection', "sqlite://", group='api_database')
|
||||||
self.conf.set_default('sqlite_synchronous', False, group='database')
|
self.conf.set_default('sqlite_synchronous', False, group='database')
|
||||||
|
@ -501,6 +501,65 @@ class ModelQueryTestCase(DbTestCase):
|
|||||||
session=mock.MagicMock())
|
session=mock.MagicMock())
|
||||||
self.assertFalse(mock_get_session.called)
|
self.assertFalse(mock_get_session.called)
|
||||||
|
|
||||||
|
@mock.patch.object(sqlalchemy_api, 'get_session')
|
||||||
|
@mock.patch.object(sqlalchemyutils, 'model_query')
|
||||||
|
def test_model_query_use_context_session(self, mock_model_query,
|
||||||
|
mock_get_session):
|
||||||
|
@sqlalchemy_api.main_context_manager.reader
|
||||||
|
def fake_method(context):
|
||||||
|
session = context.session
|
||||||
|
sqlalchemy_api.model_query(context, models.Instance)
|
||||||
|
return session
|
||||||
|
|
||||||
|
session = fake_method(self.context)
|
||||||
|
self.assertFalse(mock_get_session.called)
|
||||||
|
mock_model_query.assert_called_once_with(models.Instance, session,
|
||||||
|
None, deleted=False)
|
||||||
|
|
||||||
|
|
||||||
|
class EngineFacadeTestCase(DbTestCase):
|
||||||
|
@mock.patch.object(sqlalchemy_api, 'get_session')
|
||||||
|
def test_use_single_context_session_writer(self, mock_get_session):
|
||||||
|
# Checks that session in context would not be overwritten by
|
||||||
|
# annotation @sqlalchemy_api.main_context_manager.writer if annotation
|
||||||
|
# is used twice.
|
||||||
|
|
||||||
|
@sqlalchemy_api.main_context_manager.writer
|
||||||
|
def fake_parent_method(context):
|
||||||
|
session = context.session
|
||||||
|
return fake_child_method(context), session
|
||||||
|
|
||||||
|
@sqlalchemy_api.main_context_manager.writer
|
||||||
|
def fake_child_method(context):
|
||||||
|
session = context.session
|
||||||
|
sqlalchemy_api.model_query(context, models.Instance)
|
||||||
|
return session
|
||||||
|
|
||||||
|
parent_session, child_session = fake_parent_method(self.context)
|
||||||
|
self.assertFalse(mock_get_session.called)
|
||||||
|
self.assertEqual(parent_session, child_session)
|
||||||
|
|
||||||
|
@mock.patch.object(sqlalchemy_api, 'get_session')
|
||||||
|
def test_use_single_context_session_reader(self, mock_get_session):
|
||||||
|
# Checks that session in context would not be overwritten by
|
||||||
|
# annotation @sqlalchemy_api.main_context_manager.reader if annotation
|
||||||
|
# is used twice.
|
||||||
|
|
||||||
|
@sqlalchemy_api.main_context_manager.reader
|
||||||
|
def fake_parent_method(context):
|
||||||
|
session = context.session
|
||||||
|
return fake_child_method(context), session
|
||||||
|
|
||||||
|
@sqlalchemy_api.main_context_manager.reader
|
||||||
|
def fake_child_method(context):
|
||||||
|
session = context.session
|
||||||
|
sqlalchemy_api.model_query(context, models.Instance)
|
||||||
|
return session
|
||||||
|
|
||||||
|
parent_session, child_session = fake_parent_method(self.context)
|
||||||
|
self.assertFalse(mock_get_session.called)
|
||||||
|
self.assertEqual(parent_session, child_session)
|
||||||
|
|
||||||
|
|
||||||
class AggregateDBApiTestCase(test.TestCase):
|
class AggregateDBApiTestCase(test.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -968,44 +1027,44 @@ class SqlAlchemyDbApiNoDbTestCase(test.NoDBTestCase):
|
|||||||
op = sqlalchemy_api._get_regexp_op_for_connection('notdb:///')
|
op = sqlalchemy_api._get_regexp_op_for_connection('notdb:///')
|
||||||
self.assertEqual('LIKE', op)
|
self.assertEqual('LIKE', op)
|
||||||
|
|
||||||
@mock.patch.object(sqlalchemy_api, '_create_facade_lazily')
|
@mock.patch.object(sqlalchemy_api.main_context_manager._factory,
|
||||||
|
'get_legacy_facade')
|
||||||
def test_get_engine(self, mock_create_facade):
|
def test_get_engine(self, mock_create_facade):
|
||||||
mock_facade = mock.MagicMock()
|
mock_facade = mock.MagicMock()
|
||||||
mock_create_facade.return_value = mock_facade
|
mock_create_facade.return_value = mock_facade
|
||||||
|
|
||||||
sqlalchemy_api.get_engine()
|
sqlalchemy_api.get_engine()
|
||||||
mock_create_facade.assert_called_once_with(sqlalchemy_api._MAIN_FACADE,
|
mock_create_facade.assert_called_once_with()
|
||||||
CONF.database)
|
|
||||||
mock_facade.get_engine.assert_called_once_with(use_slave=False)
|
mock_facade.get_engine.assert_called_once_with(use_slave=False)
|
||||||
|
|
||||||
@mock.patch.object(sqlalchemy_api, '_create_facade_lazily')
|
@mock.patch.object(sqlalchemy_api.api_context_manager._factory,
|
||||||
|
'get_legacy_facade')
|
||||||
def test_get_api_engine(self, mock_create_facade):
|
def test_get_api_engine(self, mock_create_facade):
|
||||||
mock_facade = mock.MagicMock()
|
mock_facade = mock.MagicMock()
|
||||||
mock_create_facade.return_value = mock_facade
|
mock_create_facade.return_value = mock_facade
|
||||||
|
|
||||||
sqlalchemy_api.get_api_engine()
|
sqlalchemy_api.get_api_engine()
|
||||||
mock_create_facade.assert_called_once_with(sqlalchemy_api._API_FACADE,
|
mock_create_facade.assert_called_once_with()
|
||||||
CONF.api_database)
|
|
||||||
mock_facade.get_engine.assert_called_once_with()
|
mock_facade.get_engine.assert_called_once_with()
|
||||||
|
|
||||||
@mock.patch.object(sqlalchemy_api, '_create_facade_lazily')
|
@mock.patch.object(sqlalchemy_api.main_context_manager._factory,
|
||||||
|
'get_legacy_facade')
|
||||||
def test_get_session(self, mock_create_facade):
|
def test_get_session(self, mock_create_facade):
|
||||||
mock_facade = mock.MagicMock()
|
mock_facade = mock.MagicMock()
|
||||||
mock_create_facade.return_value = mock_facade
|
mock_create_facade.return_value = mock_facade
|
||||||
|
|
||||||
sqlalchemy_api.get_session()
|
sqlalchemy_api.get_session()
|
||||||
mock_create_facade.assert_called_once_with(sqlalchemy_api._MAIN_FACADE,
|
mock_create_facade.assert_called_once_with()
|
||||||
CONF.database)
|
|
||||||
mock_facade.get_session.assert_called_once_with(use_slave=False)
|
mock_facade.get_session.assert_called_once_with(use_slave=False)
|
||||||
|
|
||||||
@mock.patch.object(sqlalchemy_api, '_create_facade_lazily')
|
@mock.patch.object(sqlalchemy_api.api_context_manager._factory,
|
||||||
|
'get_legacy_facade')
|
||||||
def test_get_api_session(self, mock_create_facade):
|
def test_get_api_session(self, mock_create_facade):
|
||||||
mock_facade = mock.MagicMock()
|
mock_facade = mock.MagicMock()
|
||||||
mock_create_facade.return_value = mock_facade
|
mock_create_facade.return_value = mock_facade
|
||||||
|
|
||||||
sqlalchemy_api.get_api_session()
|
sqlalchemy_api.get_api_session()
|
||||||
mock_create_facade.assert_called_once_with(sqlalchemy_api._API_FACADE,
|
mock_create_facade.assert_called_once_with()
|
||||||
CONF.api_database)
|
|
||||||
mock_facade.get_session.assert_called_once_with()
|
mock_facade.get_session.assert_called_once_with()
|
||||||
|
|
||||||
@mock.patch.object(sqlalchemy_api, '_instance_get_by_uuid')
|
@mock.patch.object(sqlalchemy_api, '_instance_get_by_uuid')
|
||||||
|
Loading…
Reference in New Issue
Block a user