diff options
author | Jenkins <jenkins@review.openstack.org> | 2013-01-19 13:19:28 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2013-01-19 13:19:28 +0000 |
commit | b059944f844fe7ec2a8f1aad39fbf1d34b0817b3 (patch) | |
tree | f3b2ab3742d8f4d1e1e9d07dcd170ae44739bfbb | |
parent | ab04b00edfbb21131fd370325089e69d5fd8e1f0 (diff) | |
parent | 796716d4cc51f35a734aa1f9d70ea567c37b5a79 (diff) | |
download | nova-b059944f844fe7ec2a8f1aad39fbf1d34b0817b3.tar.gz nova-b059944f844fe7ec2a8f1aad39fbf1d34b0817b3.tar.xz nova-b059944f844fe7ec2a8f1aad39fbf1d34b0817b3.zip |
Merge "Fix wrong quota reservation when deleting resizing instance"
-rw-r--r-- | nova/compute/api.py | 48 | ||||
-rw-r--r-- | nova/tests/compute/test_compute.py | 32 |
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 596668048..092fd940a 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -3987,6 +3987,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}) |