Merge "make sure to rebuild claim on recreate" into stable/newton
This commit is contained in:
commit
ae45c4a72a
@ -2660,7 +2660,28 @@ class ComputeManager(manager.Manager):
|
|||||||
|
|
||||||
LOG.info(_LI("Rebuilding instance"), context=context,
|
LOG.info(_LI("Rebuilding instance"), context=context,
|
||||||
instance=instance)
|
instance=instance)
|
||||||
if scheduled_node is not None:
|
|
||||||
|
# NOTE(gyee): there are three possible scenarios.
|
||||||
|
#
|
||||||
|
# 1. instance is being rebuilt on the same node. In this case,
|
||||||
|
# recreate should be False and scheduled_node should be None.
|
||||||
|
# 2. instance is being rebuilt on a node chosen by the
|
||||||
|
# scheduler (i.e. evacuate). In this case, scheduled_node should
|
||||||
|
# be specified and recreate should be True.
|
||||||
|
# 3. instance is being rebuilt on a node chosen by the user. (i.e.
|
||||||
|
# force evacuate). In this case, scheduled_node is not specified
|
||||||
|
# and recreate is set to True.
|
||||||
|
#
|
||||||
|
# For scenarios #2 and #3, we must do rebuild claim as server is
|
||||||
|
# being evacuated to a different node.
|
||||||
|
if recreate or scheduled_node is not None:
|
||||||
|
if scheduled_node is None:
|
||||||
|
# NOTE(mriedem): On a recreate (evacuate), we need to update
|
||||||
|
# the instance's host and node properties to reflect it's
|
||||||
|
# destination node for the recreate, and to make a rebuild
|
||||||
|
# claim.
|
||||||
|
compute_node = self._get_compute_info(context, self.host)
|
||||||
|
scheduled_node = compute_node.hypervisor_hostname
|
||||||
rt = self._get_resource_tracker(scheduled_node)
|
rt = self._get_resource_tracker(scheduled_node)
|
||||||
rebuild_claim = rt.rebuild_claim
|
rebuild_claim = rt.rebuild_claim
|
||||||
else:
|
else:
|
||||||
@ -2670,19 +2691,8 @@ class ComputeManager(manager.Manager):
|
|||||||
if image_ref:
|
if image_ref:
|
||||||
image_meta = self.image_api.get(context, image_ref)
|
image_meta = self.image_api.get(context, image_ref)
|
||||||
|
|
||||||
# NOTE(mriedem): On a recreate (evacuate), we need to update
|
|
||||||
# the instance's host and node properties to reflect it's
|
|
||||||
# destination node for the recreate.
|
|
||||||
if not scheduled_node:
|
if not scheduled_node:
|
||||||
if recreate:
|
scheduled_node = instance.node
|
||||||
try:
|
|
||||||
compute_node = self._get_compute_info(context, self.host)
|
|
||||||
scheduled_node = compute_node.hypervisor_hostname
|
|
||||||
except exception.ComputeHostNotFound:
|
|
||||||
LOG.exception(_LE('Failed to get compute_info for %s'),
|
|
||||||
self.host)
|
|
||||||
else:
|
|
||||||
scheduled_node = instance.node
|
|
||||||
|
|
||||||
with self._error_out_instance_on_exception(context, instance):
|
with self._error_out_instance_on_exception(context, instance):
|
||||||
try:
|
try:
|
||||||
|
@ -11345,14 +11345,7 @@ class EvacuateHostTestCase(BaseTestCase):
|
|||||||
mock.patch.object(self.compute, '_get_compute_info',
|
mock.patch.object(self.compute, '_get_compute_info',
|
||||||
side_effect=fake_get_compute_info)
|
side_effect=fake_get_compute_info)
|
||||||
) as (mock_inst, mock_get):
|
) as (mock_inst, mock_get):
|
||||||
self._rebuild()
|
self.assertRaises(exception.ComputeHostNotFound, self._rebuild)
|
||||||
|
|
||||||
# Should be on destination host
|
|
||||||
instance = db.instance_get(self.context, self.inst.id)
|
|
||||||
self.assertEqual(instance['host'], self.compute.host)
|
|
||||||
self.assertIsNone(instance['node'])
|
|
||||||
self.assertTrue(mock_inst.called)
|
|
||||||
self.assertTrue(mock_get.called)
|
|
||||||
|
|
||||||
def test_rebuild_on_host_node_passed(self):
|
def test_rebuild_on_host_node_passed(self):
|
||||||
patch_get_info = mock.patch.object(self.compute, '_get_compute_info')
|
patch_get_info = mock.patch.object(self.compute, '_get_compute_info')
|
||||||
@ -11540,15 +11533,21 @@ class EvacuateHostTestCase(BaseTestCase):
|
|||||||
network_info=mock.ANY,
|
network_info=mock.ANY,
|
||||||
block_device_info=mock.ANY)
|
block_device_info=mock.ANY)
|
||||||
|
|
||||||
def test_rebuild_migration_passed_in(self):
|
@mock.patch('nova.compute.manager.ComputeManager._get_compute_info')
|
||||||
|
@mock.patch('nova.compute.manager.ComputeManager._get_resource_tracker')
|
||||||
|
def test_rebuild_migration_passed_in(self, get_rt, get_compute):
|
||||||
migration = mock.Mock(spec=objects.Migration)
|
migration = mock.Mock(spec=objects.Migration)
|
||||||
|
|
||||||
patch_spawn = mock.patch.object(self.compute.driver, 'spawn')
|
patch_spawn = mock.patch.object(self.compute.driver, 'spawn')
|
||||||
patch_on_disk = mock.patch.object(
|
patch_on_disk = mock.patch.object(
|
||||||
self.compute.driver, 'instance_on_disk', return_value=True)
|
self.compute.driver, 'instance_on_disk', return_value=True)
|
||||||
|
get_compute.return_value = objects.ComputeNode(
|
||||||
|
hypervisor_hostname=NODENAME)
|
||||||
with patch_spawn, patch_on_disk:
|
with patch_spawn, patch_on_disk:
|
||||||
self._rebuild(migration=migration)
|
self._rebuild(migration=migration)
|
||||||
|
|
||||||
|
get_rt.assert_called_once_with(NODENAME)
|
||||||
|
self.assertTrue(get_rt.return_value.rebuild_claim.called)
|
||||||
self.assertEqual('done', migration.status)
|
self.assertEqual('done', migration.status)
|
||||||
migration.save.assert_called_once_with()
|
migration.save.assert_called_once_with()
|
||||||
|
|
||||||
|
@ -2951,17 +2951,19 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
|
|||||||
node=dead_node)
|
node=dead_node)
|
||||||
instance.migration_context = None
|
instance.migration_context = None
|
||||||
with test.nested(
|
with test.nested(
|
||||||
|
mock.patch.object(self.compute, '_get_resource_tracker'),
|
||||||
mock.patch.object(self.compute, '_get_compute_info'),
|
mock.patch.object(self.compute, '_get_compute_info'),
|
||||||
mock.patch.object(self.compute, '_do_rebuild_instance_with_claim'),
|
mock.patch.object(self.compute, '_do_rebuild_instance_with_claim'),
|
||||||
mock.patch.object(objects.Instance, 'save'),
|
mock.patch.object(objects.Instance, 'save'),
|
||||||
mock.patch.object(self.compute, '_set_migration_status'),
|
mock.patch.object(self.compute, '_set_migration_status'),
|
||||||
) as (mock_get, mock_rebuild, mock_save, mock_set):
|
) as (mock_rt, mock_get, mock_rebuild, mock_save, mock_set):
|
||||||
mock_get.return_value.hypervisor_hostname = 'new-node'
|
mock_get.return_value.hypervisor_hostname = 'new-node'
|
||||||
self.compute.rebuild_instance(self.context, instance, None, None,
|
self.compute.rebuild_instance(self.context, instance, None, None,
|
||||||
None, None, None, None, True)
|
None, None, None, None, True)
|
||||||
mock_get.assert_called_once_with(mock.ANY, self.compute.host)
|
mock_get.assert_called_once_with(mock.ANY, self.compute.host)
|
||||||
self.assertEqual('new-node', instance.node)
|
self.assertEqual('new-node', instance.node)
|
||||||
mock_set.assert_called_once_with(None, 'done')
|
mock_set.assert_called_once_with(None, 'done')
|
||||||
|
mock_rt.assert_called_once_with('new-node')
|
||||||
|
|
||||||
def test_rebuild_default_impl(self):
|
def test_rebuild_default_impl(self):
|
||||||
def _detach(context, bdms):
|
def _detach(context, bdms):
|
||||||
|
Loading…
Reference in New Issue
Block a user