summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/compute/api.py48
-rw-r--r--nova/tests/compute/test_compute.py32
2 files changed, 75 insertions, 5 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 22ee82bbf..4b15a3e27 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -946,11 +946,10 @@ class API(base.Base):
if (old['vm_state'] != vm_states.SOFT_DELETED and
old['task_state'] not in (task_states.DELETING,
task_states.SOFT_DELETING)):
- reservations = QUOTAS.reserve(context,
- project_id=project_id,
- instances=-1,
- cores=-instance['vcpus'],
- ram=-instance['memory_mb'])
+ reservations = self._create_reservations(context,
+ old,
+ updated,
+ project_id)
if not host:
# Just update database, nothing else we can do
@@ -1026,6 +1025,45 @@ class API(base.Base):
reservations,
project_id=project_id)
+ def _create_reservations(self, context, old_instance, new_instance,
+ project_id):
+ instance_vcpus = old_instance['vcpus']
+ instance_memory_mb = old_instance['memory_mb']
+ # NOTE(wangpan): if the instance is resizing, and the resources
+ # are updated to new instance type, we should use
+ # the old instance type to create reservation.
+ # see https://bugs.launchpad.net/nova/+bug/1099729 for more details
+ if old_instance['task_state'] in (task_states.RESIZE_MIGRATED,
+ task_states.RESIZE_FINISH):
+ get_migration = self.db.migration_get_by_instance_and_status
+ try:
+ migration_ref = get_migration(context.elevated(),
+ old_instance['uuid'], 'post-migrating')
+ except exception.MigrationNotFoundByStatus:
+ migration_ref = None
+ if (migration_ref and
+ new_instance['instance_type_id'] ==
+ migration_ref['new_instance_type_id']):
+ old_inst_type_id = migration_ref['old_instance_type_id']
+ get_inst_type_by_id = instance_types.get_instance_type
+ try:
+ old_inst_type = get_inst_type_by_id(old_inst_type_id)
+ except exception.InstanceTypeNotFound:
+ LOG.warning(_("instance type %(old_inst_type_id)d "
+ "not found") % locals())
+ pass
+ else:
+ instance_vcpus = old_inst_type['vcpus']
+ instance_memory_mb = old_inst_type['memory_mb']
+ LOG.debug(_("going to delete a resizing instance"))
+
+ reservations = QUOTAS.reserve(context,
+ project_id=project_id,
+ instances=-1,
+ cores=-instance_vcpus,
+ ram=-instance_memory_mb)
+ return reservations
+
def _local_delete(self, context, instance, bdms):
LOG.warning(_("instance's host %s is down, deleting from "
"database") % instance['host'], instance=instance)
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index 691991f60..d8c500e80 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -3958,6 +3958,38 @@ class ComputeAPITestCase(BaseTestCase):
db.instance_destroy(self.context, instance['uuid'])
+ def test_delete_in_resizing(self):
+ def fake_quotas_reserve(context, expire=None, project_id=None,
+ **deltas):
+ old_type = instance_types.get_instance_type_by_name('m1.tiny')
+ # ensure using old instance type to create reservations
+ self.assertEqual(deltas['cores'], -old_type['vcpus'])
+ self.assertEqual(deltas['ram'], -old_type['memory_mb'])
+
+ self.stubs.Set(QUOTAS, 'reserve', fake_quotas_reserve)
+
+ instance, instance_uuid = self._run_instance(params={
+ 'host': CONF.host})
+
+ # create a fake migration record (manager does this)
+ new_inst_type = instance_types.get_instance_type_by_name('m1.small')
+ db.migration_create(self.context.elevated(),
+ {'instance_uuid': instance['uuid'],
+ 'old_instance_type_id': instance['instance_type_id'],
+ 'new_instance_type_id': new_inst_type['id'],
+ 'status': 'post-migrating'})
+
+ # update instance type to resized one
+ db.instance_update(self.context, instance['uuid'],
+ {'instance_type_id': new_inst_type['id'],
+ 'vcpus': new_inst_type['vcpus'],
+ 'memory_mb': new_inst_type['memory_mb'],
+ 'task_state': task_states.RESIZE_FINISH})
+
+ self.compute_api.delete(self.context, instance)
+
+ db.instance_destroy(self.context, instance['uuid'])
+
def test_delete_in_resized(self):
instance, instance_uuid = self._run_instance(params={
'host': CONF.host})