Target context for build notification in conductor

When sending notifications about an instance, it's possible the
notification payload will have attributes not already loaded on
the instance. In this case, a lazy-load will happen and if the
load method needs to lookup the instance (example: in the
_check_instance_exists_in_project method in the DB layer), the
InstanceNotFound exception will be raised and the notification
will fail to be sent.

This targets the instance context to the instance's cell when
calling the send notification method.

Closes-Bug: #1721670

Change-Id: I6b9eb120b6e7fcbf919a3791afe2d1f6a7bd3b60
(cherry picked from commit 54cf9f5a90)
This commit is contained in:
melanie witt 2017-10-05 23:55:58 +00:00
parent d288132dca
commit 594b33469b
2 changed files with 23 additions and 6 deletions

View File

@ -1109,12 +1109,14 @@ class ComputeTaskManager(base.Base):
scheduler_utils.populate_retry(filter_props, instance.uuid)
scheduler_utils.populate_filter_properties(filter_props,
host)
# send a state update notification for the initial create to
# show it going from non-existent to BUILDING
notifications.send_update_with_states(context, instance, None,
vm_states.BUILDING, None, None, service="conductor")
# TODO(melwitt): Maybe we should set_target_cell on the contexts
# once we map to a cell, and remove these separate with statements.
with obj_target_cell(instance, cell) as cctxt:
# send a state update notification for the initial create to
# show it going from non-existent to BUILDING
# This can lazy-load attributes on instance.
notifications.send_update_with_states(cctxt, instance, None,
vm_states.BUILDING, None, None, service="conductor")
objects.InstanceAction.action_start(
cctxt, instance.uuid, instance_actions.CREATE,
want_result=False)

View File

@ -1454,7 +1454,22 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
self.assertEqual(1, ephemeral[0].volume_size)
return instance_uuid
def test_schedule_and_build_instances(self):
@mock.patch('nova.notifications.send_update_with_states')
def test_schedule_and_build_instances(self, mock_notify):
# NOTE(melwitt): This won't work with call_args because the call
# arguments are recorded as references and not as copies of objects.
# So even though the notify method was called with Instance._context
# targeted, by the time we assert with call_args, the target_cell
# context manager has already exited and the referenced Instance
# object's _context.db_connection has been restored to None.
def fake_notify(ctxt, instance, *args, **kwargs):
# Assert the instance object is targeted when going through the
# notification code.
self.assertIsNotNone(ctxt.db_connection)
self.assertIsNotNone(instance._context.db_connection)
mock_notify.side_effect = fake_notify
instance_uuid = self._do_schedule_and_build_instances_test(
self.params)
cells = objects.CellMappingList.get_all(self.ctxt)