Make servers API use cell-targeted context
This makes the servers API look up the CellMapping for the instance in question and target the context to the appropriate cell for the subsequent call into compute/api. Note that just as with get() and get_all(), we need to avoid going direct to the cell database and thus short-circuiting the replication in the case of cellsv1. Related to blueprint cells-aware-api Change-Id: If63a4fa7349890a6e7ac0fa3fe12917dc53334d0
This commit is contained in:
@@ -1135,9 +1135,16 @@ class ServersController(wsgi.Controller):
|
||||
def _get_instance(self, context, instance_uuid):
|
||||
try:
|
||||
attrs = ['system_metadata', 'metadata']
|
||||
return objects.Instance.get_by_uuid(context, instance_uuid,
|
||||
expected_attrs=attrs)
|
||||
except exception.InstanceNotFound as e:
|
||||
if not CONF.cells.enable:
|
||||
# NOTE(danms): We can't target a cell database if we're
|
||||
# in cellsv1 otherwise we'll short-circuit the replication.
|
||||
mapping = objects.InstanceMapping.get_by_instance_uuid(
|
||||
context, instance_uuid)
|
||||
nova_context.set_target_cell(context, mapping.cell_mapping)
|
||||
return objects.Instance.get_by_uuid(
|
||||
context, instance_uuid, expected_attrs=attrs)
|
||||
except (exception.InstanceNotFound,
|
||||
exception.InstanceMappingNotFound) as e:
|
||||
raise webob.exc.HTTPNotFound(explanation=e.format_message())
|
||||
|
||||
@wsgi.response(202)
|
||||
|
||||
+21
-5
@@ -358,19 +358,35 @@ def authorize_quota_class_context(context, class_name):
|
||||
raise exception.Forbidden()
|
||||
|
||||
|
||||
def set_target_cell(context, cell_mapping):
|
||||
"""Adds database connection information to the context
|
||||
for communicating with the given target_cell.
|
||||
|
||||
This is used for permanently targeting a cell in a context.
|
||||
Use this when you want all subsequent code to target a cell.
|
||||
|
||||
:param context: The RequestContext to add connection information
|
||||
:param cell_mapping: An objects.CellMapping object
|
||||
"""
|
||||
# avoid circular import
|
||||
from nova import db
|
||||
db_connection_string = cell_mapping.database_connection
|
||||
context.db_connection = db.create_context_manager(db_connection_string)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def target_cell(context, cell_mapping):
|
||||
"""Adds database connection information to the context
|
||||
"""Temporarily adds database connection information to the context
|
||||
for communicating with the given target cell.
|
||||
|
||||
This context manager makes a temporary change to the context
|
||||
and restores it when complete.
|
||||
|
||||
:param context: The RequestContext to add connection information
|
||||
:param cell_mapping: A objects.CellMapping object
|
||||
"""
|
||||
original_db_connection = context.db_connection
|
||||
# avoid circular import
|
||||
from nova import db
|
||||
db_connection_string = cell_mapping.database_connection
|
||||
context.db_connection = db.create_context_manager(db_connection_string)
|
||||
set_target_cell(context, cell_mapping)
|
||||
try:
|
||||
yield context
|
||||
finally:
|
||||
|
||||
@@ -291,6 +291,9 @@ class SingleCellSimple(fixtures.Fixture):
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
'nova.context.target_cell',
|
||||
self._fake_target_cell))
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
'nova.context.set_target_cell',
|
||||
lambda c, m: None))
|
||||
|
||||
def _fake_hostmapping_get(self, *args):
|
||||
return {'id': 1,
|
||||
|
||||
@@ -25,6 +25,7 @@ from nova import db
|
||||
from nova import exception
|
||||
from nova import policy
|
||||
from nova import test
|
||||
from nova.tests import fixtures as nova_fixtures
|
||||
from nova.tests.unit.api.openstack import fakes
|
||||
from nova.tests import uuidsentinel as uuids
|
||||
|
||||
@@ -35,6 +36,7 @@ class ServerStartStopTestV21(test.TestCase):
|
||||
super(ServerStartStopTestV21, self).setUp()
|
||||
self._setup_controller()
|
||||
self.req = fakes.HTTPRequest.blank('')
|
||||
self.useFixture(nova_fixtures.SingleCellSimple())
|
||||
self.stub_out('nova.db.instance_get_by_uuid',
|
||||
fakes.fake_instance_get())
|
||||
|
||||
@@ -132,6 +134,7 @@ class ServerStartStopPolicyEnforcementV21(test.TestCase):
|
||||
self.controller = server_v21.ServersController(
|
||||
extension_info=ext_info)
|
||||
self.req = fakes.HTTPRequest.blank('')
|
||||
self.useFixture(nova_fixtures.SingleCellSimple())
|
||||
self.stub_out(
|
||||
'nova.db.instance_get_by_uuid',
|
||||
fakes.fake_instance_get(
|
||||
|
||||
@@ -189,6 +189,25 @@ class ServersControllerTest(ControllerTest):
|
||||
use_admin_context=use_admin_context,
|
||||
version=self.wsgi_api_version)
|
||||
|
||||
@mock.patch('nova.objects.Instance.get_by_uuid')
|
||||
@mock.patch('nova.objects.InstanceMapping.get_by_instance_uuid')
|
||||
def test_cellsv1_instance_lookup_no_target(self, mock_get_im,
|
||||
mock_get_inst):
|
||||
self.flags(enable=True, group='cells')
|
||||
ctxt = context.RequestContext('fake', 'fake')
|
||||
self.controller._get_instance(ctxt, 'foo')
|
||||
self.assertFalse(mock_get_im.called)
|
||||
self.assertIsNone(ctxt.db_connection)
|
||||
|
||||
@mock.patch('nova.objects.Instance.get_by_uuid')
|
||||
@mock.patch('nova.objects.InstanceMapping.get_by_instance_uuid')
|
||||
def test_instance_lookup_targets(self, mock_get_im, mock_get_inst):
|
||||
ctxt = context.RequestContext('fake', 'fake')
|
||||
mock_get_im.return_value.cell_mapping.database_connection = uuids.cell1
|
||||
self.controller._get_instance(ctxt, 'foo')
|
||||
mock_get_im.assert_called_once_with(ctxt, 'foo')
|
||||
self.assertIsNotNone(ctxt.db_connection)
|
||||
|
||||
def test_requested_networks_prefix(self):
|
||||
self.flags(use_neutron=True)
|
||||
uuid = 'br-00000000-0000-0000-0000-000000000000'
|
||||
@@ -1761,6 +1780,7 @@ class ServersControllerRebuildInstanceTest(ControllerTest):
|
||||
self.req.headers["content-type"] = "application/json"
|
||||
self.req_user_id = self.req.environ['nova.context'].user_id
|
||||
self.req_project_id = self.req.environ['nova.context'].project_id
|
||||
self.useFixture(nova_fixtures.SingleCellSimple())
|
||||
|
||||
def fake_get(ctrl, ctxt, uuid):
|
||||
if uuid == 'test_inst':
|
||||
|
||||
Reference in New Issue
Block a user