Fix revert migration if flavor deleted

After an instance is created, the flavor could be deleted.  But
operations still need to be able to occur against the VM when that
occurs.  A new test in Tempest showed that we had been using the
incorrect (and potentially deleted) flavor when a resize/migration was
reverting.

This change updates the code to use the flavor that is stored on the
instance itself.

Change-Id: I16254d8eb74a724e3e0a538f47259e9627c4233a
Closes-Bug: 1570748
This commit is contained in:
Drew Thorstensen 2016-04-29 10:12:33 -05:00
parent b2d2f6858d
commit e72a505860
2 changed files with 49 additions and 22 deletions

View File

@ -1213,6 +1213,45 @@ class TestPowerVMDriver(test.TestCase):
taskflow_fix.assert_tasks_added(self, expected)
self.san_lpar_name.assert_called_with('resize_' + self.inst.name)
@mock.patch('nova_powervm.virt.powervm.vm.power_on')
@mock.patch('nova_powervm.virt.powervm.vm.update')
@mock.patch('nova_powervm.virt.powervm.vm.power_off')
def test_finish_revert_migration(self, mock_off, mock_update, mock_on):
"""Validates that the finish revert migration works."""
mock_flavor = mock.Mock()
mock_instance = mock.Mock(flavor=mock_flavor)
# Validate with a default power on
self.drv.finish_revert_migration('context', mock_instance, None)
# Asserts
mock_off.assert_called_once_with(
self.apt, mock_instance, self.drv.host_uuid)
mock_update.assert_called_once_with(
self.apt, self.drv.host_wrapper, mock_instance, mock_flavor)
mock_on.assert_called_once_with(
self.apt, mock_instance, self.drv.host_uuid)
@mock.patch('nova_powervm.virt.powervm.vm.power_on')
@mock.patch('nova_powervm.virt.powervm.vm.update')
@mock.patch('nova_powervm.virt.powervm.vm.power_off')
def test_finish_revert_migration_no_power_on(self, mock_off, mock_update,
mock_on):
"""Validates that the finish revert migration works, no power_on."""
mock_flavor = mock.Mock()
mock_instance = mock.Mock(flavor=mock_flavor)
# Validate with power_on set to false
self.drv.finish_revert_migration(
'context', mock_instance, None, power_on=False)
# Asserts
mock_off.assert_called_once_with(
self.apt, mock_instance, self.drv.host_uuid)
mock_update.assert_called_once_with(
self.apt, self.drv.host_wrapper, mock_instance, mock_flavor)
self.assertFalse(mock_on.called)
@mock.patch('nova_powervm.virt.powervm.vm')
@mock.patch('nova_powervm.virt.powervm.tasks.vm.vm')
@mock.patch('nova_powervm.virt.powervm.tasks.vm.power')

View File

@ -1079,14 +1079,7 @@ class PowerVMDriver(driver.ComputeDriver):
disk_info = {}
# We may be passed a flavor that is in dict format, but the
# downstream code is expecting an object, so convert it.
if flavor and not isinstance(flavor, flavor_obj.Flavor):
flav_obj = flavor_obj.Flavor.get_by_id(context, flavor['id'])
else:
flav_obj = flavor
if flav_obj and flav_obj.root_gb < instance.root_gb:
if flavor and flavor.root_gb < instance.root_gb:
raise exception.InstanceFaultRollback(
exception.ResizeError(reason=_('Cannot reduce disk size.')))
@ -1121,10 +1114,10 @@ class PowerVMDriver(driver.ComputeDriver):
# latest.
flow.add(tf_vm.StoreNvram(self.nvram_mgr, instance,
immediate=True))
if flav_obj.root_gb > instance.root_gb:
if flavor.root_gb > instance.root_gb:
# Resize the root disk
flow.add(tf_stg.ExtendDisk(self.disk_dvr, context, instance,
dict(type='boot'), flav_obj.root_gb))
dict(type='boot'), flavor.root_gb))
# Disconnect any volumes that are attached. They are reattached
# on the new VM (or existing VM if this is just a resize.)
@ -1214,10 +1207,6 @@ class PowerVMDriver(driver.ComputeDriver):
raise exception.InstanceFaultRollback(
exception.ResizeError(reason=reason))
# Get the new flavor
flav_obj = flavor_obj.Flavor.get_by_id(
context, migration.new_instance_type_id)
# Extract the block devices.
bdms = self._extract_bdm(block_device_info)
@ -1237,13 +1226,13 @@ class PowerVMDriver(driver.ComputeDriver):
# This is just a resize.
new_name = self._gen_resize_name(instance, same_host=True)
flow.add(tf_vm.Resize(self.adapter, self.host_wrapper, instance,
flav_obj, name=new_name))
instance.flavor, name=new_name))
else:
# This is a migration over to another host. We have a lot of work.
# Create the LPAR
flow.add(tf_vm.Create(self.adapter, self.host_wrapper, instance,
flav_obj, stg_ftsk,
instance.flavor, stg_ftsk,
nvram_mgr=self.nvram_mgr))
# Create a flow for the network IO
@ -1319,18 +1308,17 @@ class PowerVMDriver(driver.ComputeDriver):
otherwise
"""
self._log_operation('revert resize/migration', instance)
# This method is always run on the source host, so we just need to
# revert the VM back to it's old sizings, if it was even changed
# at all. If it was a migration, then it wasn't changed but it
# shouldn't hurt to "update" it with the prescribed flavor. This
# makes it easy to handle both resize and migrate.
# Get the flavor from the instance, so we can revert it
admin_ctx = ctx.get_admin_context(read_deleted='yes')
flav_obj = flavor_obj.Flavor.get_by_id(
admin_ctx, instance.instance_type_id)
#
# The flavor should be the 'old' flavor now.
vm.power_off(self.adapter, instance, self.host_uuid)
vm.update(self.adapter, self.host_wrapper, instance, flav_obj)
vm.update(self.adapter, self.host_wrapper, instance,
instance.flavor)
if power_on:
vm.power_on(self.adapter, instance, self.host_uuid)