Use db connection from RequestContext during queries

Now that db connections can be specified through the RequestContext,
any queries on tables that reside in cell dbs must use the methods
provided to create transaction context managers on-the-fly using the
db connection from the RequestContext instead of using the
"main_context_manager" for all accesses. The get_context_manager()
method returns the main_context_manager if no db connection is
found in the RequestContext, so things continue to work even when
no cell dbs exist.

The tables that reside in cell dbs are based on the Cells v2
database split doc [1].

Related to blueprint cells-db-connection-switching

[1] https://review.openstack.org/#/c/277543

Change-Id: I4452116ae0c88ba18672839f2856247092bf6b9a
This commit is contained in:
melanie witt 2016-01-25 23:21:28 +00:00 committed by melanie witt
parent c62159d0bf
commit 5572a50f6d
3 changed files with 243 additions and 123 deletions

File diff suppressed because it is too large Load Diff

View File

@ -197,7 +197,12 @@ class Timeout(fixtures.Fixture):
class Database(fixtures.Fixture):
def __init__(self, database='main'):
def __init__(self, database='main', connection=None):
"""Create a database fixture.
:param database: The type of database, 'main' or 'api'
:param connection: The connection string to use
"""
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
@ -207,7 +212,13 @@ class Database(fixtures.Fixture):
SESSION_CONFIGURED = True
self.database = database
if database == 'main':
self.get_engine = session.get_engine
if connection is not None:
ctxt_mgr = session.create_context_manager(
connection=connection)
facade = ctxt_mgr.get_legacy_facade()
self.get_engine = facade.get_engine
else:
self.get_engine = session.get_engine
elif database == 'api':
self.get_engine = session.get_api_engine

View File

@ -0,0 +1,63 @@
# 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.
import os
from oslo_utils import uuidutils
from nova import context
from nova import exception
from nova import objects
from nova import test
from nova.tests import fixtures
class ConnectionSwitchTestCase(test.NoDBTestCase):
test_filename = 'foo.db'
def setUp(self):
super(ConnectionSwitchTestCase, self).setUp()
self.addCleanup(self.cleanup)
def cleanup(self):
try:
os.remove(self.test_filename)
except OSError:
pass
def test_connection_switch(self):
# Use a file-based sqlite database so data will persist across new
# connections
fake_conn = 'sqlite:///' + self.test_filename
# The 'main' database connection will stay open, so in-memory is fine
self.useFixture(fixtures.Database(database='main'))
self.useFixture(fixtures.Database(connection=fake_conn))
# Make a request context with a cell mapping
mapping = objects.CellMapping(database_connection=fake_conn)
# In the tests, the admin context is required in order to read
# an Instance back after write, for some reason
ctxt = context.get_admin_context()
# Create an instance in the cell database
uuid = uuidutils.generate_uuid()
with context.target_cell(ctxt, mapping):
instance = objects.Instance(context=ctxt, uuid=uuid)
instance.create()
# Verify the instance is found in the cell database
inst = objects.Instance.get_by_uuid(ctxt, uuid)
self.assertEqual(uuid, inst.uuid)
# Verify the instance isn't found in the main database
self.assertRaises(exception.InstanceNotFound,
objects.Instance.get_by_uuid, ctxt, uuid)