Fix abnormal quota usage after restore by admin

At environment which enabled soft delete at nova conf,
if one instance of normal project be restored by admin,
the usage of instance's flavor will be add to quota of admin.
The reason is that obtain of quota from admin context.
Now passing project_id and user_id which get from instance
to amend owner of quota.

Change-Id: I0e0f6085a6b0a0b9d1072cc2daffd85f54830fff
Closes-bug: #1482444
This commit is contained in:
Zheng Yue 2015-08-11 10:59:43 +08:00
parent 38f9906d4b
commit c474b44bdc
2 changed files with 35 additions and 5 deletions

View File

@ -386,7 +386,7 @@ class API(base.Base):
return headroom
def _check_num_instances_quota(self, context, instance_type, min_count,
max_count):
max_count, project_id=None, user_id=None):
"""Enforce quota limits on number of instances created."""
# Determine requested cores and ram
@ -398,7 +398,8 @@ class API(base.Base):
try:
quotas = objects.Quotas(context)
quotas.reserve(instances=max_count,
cores=req_cores, ram=req_ram)
cores=req_cores, ram=req_ram,
project_id=project_id, user_id=user_id)
except exception.OverQuota as exc:
# OK, we exceeded quota; let's figure out why...
quotas = exc.kwargs['quotas']
@ -1911,8 +1912,10 @@ class API(base.Base):
"""Restore a previously deleted (but not reclaimed) instance."""
# Reserve quotas
flavor = instance.get_flavor()
project_id, user_id = quotas_obj.ids_from_instance(context, instance)
num_instances, quotas = self._check_num_instances_quota(
context, flavor, 1, 1)
context, flavor, 1, 1,
project_id=project_id, user_id=user_id)
self._record_action_start(context, instance, instance_actions.RESTORE)

View File

@ -2463,8 +2463,31 @@ class _ComputeAPIUnitTestMixIn(object):
@mock.patch('nova.objects.Quotas.reserve')
@mock.patch('nova.objects.Instance.save')
@mock.patch('nova.objects.InstanceAction.action_start')
def test_restore(self, action_start, instance_save, quota_reserve,
quota_commit):
def test_restore_by_admin(self, action_start, instance_save,
quota_reserve, quota_commit):
admin_context = context.RequestContext('admin_user',
'admin_project',
True)
instance = self._create_instance_obj()
instance.vm_state = vm_states.SOFT_DELETED
instance.task_state = None
instance.save()
with mock.patch.object(self.compute_api, 'compute_rpcapi') as rpc:
self.compute_api.restore(admin_context, instance)
rpc.restore_instance.assert_called_once_with(admin_context,
instance)
self.assertEqual(instance.task_state, task_states.RESTORING)
self.assertEqual(1, quota_commit.call_count)
quota_reserve.assert_called_once_with(instances=1,
cores=instance.flavor.vcpus, ram=instance.flavor.memory_mb,
project_id=instance.project_id, user_id=instance.user_id)
@mock.patch('nova.objects.Quotas.commit')
@mock.patch('nova.objects.Quotas.reserve')
@mock.patch('nova.objects.Instance.save')
@mock.patch('nova.objects.InstanceAction.action_start')
def test_restore_by_instance_owner(self, action_start, instance_save,
quota_reserve, quota_commit):
instance = self._create_instance_obj()
instance.vm_state = vm_states.SOFT_DELETED
instance.task_state = None
@ -2473,8 +2496,12 @@ class _ComputeAPIUnitTestMixIn(object):
self.compute_api.restore(self.context, instance)
rpc.restore_instance.assert_called_once_with(self.context,
instance)
self.assertEqual(instance.project_id, self.context.project_id)
self.assertEqual(instance.task_state, task_states.RESTORING)
self.assertEqual(1, quota_commit.call_count)
quota_reserve.assert_called_once_with(instances=1,
cores=instance.flavor.vcpus, ram=instance.flavor.memory_mb,
project_id=instance.project_id, user_id=instance.user_id)
def test_external_instance_event(self):
instances = [