Merge "Moved quota headroom calculations into quota_reserve" into stable/havana

This commit is contained in:
Jenkins 2013-12-05 12:12:15 +00:00 committed by Gerrit Code Review
commit e99e9c1519
6 changed files with 137 additions and 38 deletions

View File

@ -330,10 +330,7 @@ class API(base.Base):
quotas = exc.kwargs['quotas']
usages = exc.kwargs['usages']
overs = exc.kwargs['overs']
headroom = dict((res, quotas[res] -
(usages[res]['in_use'] + usages[res]['reserved']))
for res in quotas.keys())
headroom = exc.kwargs['headroom']
allowed = headroom['instances']
# Reduce 'allowed' instances in line with the cores & ram headroom
@ -2306,10 +2303,7 @@ class API(base.Base):
quotas = exc.kwargs['quotas']
usages = exc.kwargs['usages']
overs = exc.kwargs['overs']
headroom = dict((res, quotas[res] -
(usages[res]['in_use'] + usages[res]['reserved']))
for res in quotas.keys())
headroom = exc.kwargs['headroom']
resource = overs[0]
used = quotas[resource] - headroom[resource]

View File

@ -3210,8 +3210,29 @@ def quota_reserve(context, resources, project_quotas, user_quotas, deltas,
usages = user_usages
usages = dict((k, dict(in_use=v['in_use'], reserved=v['reserved']))
for k, v in usages.items())
headroom = dict((res, user_quotas[res] -
(usages[res]['in_use'] + usages[res]['reserved']))
for res in user_quotas.keys())
# If quota_cores is unlimited [-1]:
# - set cores headroom based on instances headroom:
if user_quotas.get('cores') == -1:
if deltas['cores']:
hc = headroom['instances'] * deltas['cores']
headroom['cores'] = hc / deltas['instances']
else:
headroom['cores'] = headroom['instances']
# If quota_ram is unlimited [-1]:
# - set ram headroom based on instances headroom:
if user_quotas.get('ram') == -1:
if deltas['ram']:
hr = headroom['instances'] * deltas['ram']
headroom['ram'] = hr / deltas['instances']
else:
headroom['ram'] = headroom['instances']
raise exception.OverQuota(overs=sorted(overs), quotas=user_quotas,
usages=usages)
usages=usages, headroom=headroom)
return reservations

View File

@ -405,11 +405,22 @@ class DbQuotaDriver(object):
# Check the quotas and construct a list of the resources that
# would be put over limit by the desired values
overs = [key for key, val in values.items()
if (quotas[key] >= 0 and quotas[key] < val) or
if quotas[key] >= 0 and quotas[key] < val or
(user_quotas[key] >= 0 and user_quotas[key] < val)]
if overs:
headroom = {}
# Check project_quotas:
for key in quotas:
if quotas[key] >= 0 and quotas[key] < val:
headroom[key] = quotas[key]
# Check user quotas:
for key in user_quotas:
if (user_quotas[key] >= 0 and user_quotas[key] < val and
headroom.get(key) > user_quotas[key]):
headroom[key] = user_quotas[key]
raise exception.OverQuota(overs=sorted(overs), quotas=quotas,
usages={})
usages={}, headroom=headroom)
def reserve(self, context, resources, deltas, expire=None,
project_id=None, user_id=None):

View File

@ -171,8 +171,12 @@ def stub_out_instance_quota(stubs, allowed, quota, resource='instances'):
usages[resource]['in_use'] = (quotas[resource] * 0.9 -
allowed)
usages[resource]['reserved'] = quotas[resource] * 0.1
headroom = dict(
(res, value - (usages[res]['in_use'] + usages[res]['reserved']))
for res, value in quotas.iteritems()
)
raise exc.OverQuota(overs=[resource], quotas=quotas,
usages=usages)
usages=usages, headroom=headroom)
stubs.Set(QUOTAS, 'reserve', fake_reserve)

View File

@ -134,11 +134,14 @@ class _ComputeAPIUnitTestMixIn(object):
self.mox.StubOutWithMock(quota.QUOTAS, "limit_check")
self.mox.StubOutWithMock(quota.QUOTAS, "reserve")
quota_exception = exception.OverQuota(
quotas={'instances': 1, 'cores': 1, 'ram': 1},
usages=dict((r, {'in_use': 1, 'reserved': 1}) for r in
['instances', 'cores', 'ram']),
overs=['instances'])
quotas = {'instances': 1, 'cores': 1, 'ram': 1}
usages = dict((r, {'in_use': 1, 'reserved': 1}) for r in
['instances', 'cores', 'ram'])
headroom = dict((res, quotas[res] -
(usages[res]['in_use'] + usages[res]['reserved']))
for res in quotas.keys())
quota_exception = exception.OverQuota(quotas=quotas,
usages=usages, overs=['instances'], headroom=headroom)
for _unused in range(2):
self.compute_api._get_image(self.context, image_href).AndReturn(
@ -1022,9 +1025,16 @@ class _ComputeAPIUnitTestMixIn(object):
self.context, fake_flavor,
current_flavor).AndReturn(deltas)
usage = dict(in_use=0, reserved=0)
over_quota_args = dict(quotas={'resource': 0},
usages={'resource': usage},
overs=['resource'])
quotas = {'resource': 0}
usages = {'resource': usage}
overs = ['resource']
headroom = {'resource': quotas['resource'] -
(usages['resource']['in_use'] + usages['resource']['reserved'])}
over_quota_args = dict(quotas=quotas,
usages=usages,
overs=overs,
headroom=headroom)
self.compute_api._reserve_quota_delta(self.context, deltas,
project_id=fake_inst['project_id']).AndRaise(
exception.OverQuota(**over_quota_args))

View File

@ -79,12 +79,15 @@ class QuotaIntegrationTestCase(test.TestCase):
instance_uuids.append(instance['uuid'])
inst_type = flavors.get_flavor_by_name('m1.small')
image_uuid = 'cedef40a-ed67-4d10-800e-17455edce175'
self.assertRaises(exception.QuotaError, compute.API().create,
self.context,
min_count=1,
max_count=1,
instance_type=inst_type,
image_href=image_uuid)
try:
compute.API().create(self.context, min_count=1, max_count=1,
instance_type=inst_type, image_href=image_uuid)
except exception.QuotaError, e:
expected_kwargs = {'code': 413, 'resource': 'cores', 'req': 1,
'used': 4, 'allowed': 4, 'overs': 'cores,instances'}
self.assertEqual(e.kwargs, expected_kwargs)
else:
self.fail('Expected QuotaError exception')
for instance_uuid in instance_uuids:
db.instance_destroy(self.context, instance_uuid)
@ -92,12 +95,23 @@ class QuotaIntegrationTestCase(test.TestCase):
instance = self._create_instance(cores=4)
inst_type = flavors.get_flavor_by_name('m1.small')
image_uuid = 'cedef40a-ed67-4d10-800e-17455edce175'
self.assertRaises(exception.QuotaError, compute.API().create,
self.context,
min_count=1,
max_count=1,
instance_type=inst_type,
image_href=image_uuid)
try:
compute.API().create(self.context, min_count=1, max_count=1,
instance_type=inst_type, image_href=image_uuid)
except exception.QuotaError, e:
expected_kwargs = {'code': 413, 'resource': 'cores', 'req': 1,
'used': 4, 'allowed': 4, 'overs': 'cores'}
self.assertEqual(e.kwargs, expected_kwargs)
else:
self.fail('Expected QuotaError exception')
db.instance_destroy(self.context, instance['uuid'])
def test_many_cores_with_unlimited_quota(self):
# Setting cores quota to unlimited:
self.flags(quota_cores=-1)
instance = self._create_instance(cores=4)
inst_type = flavors.get_flavor_by_name('m1.small')
image_uuid = 'cedef40a-ed67-4d10-800e-17455edce175'
db.instance_destroy(self.context, instance['uuid'])
def test_too_many_addresses(self):
@ -2293,12 +2307,23 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase):
def test_quota_reserve_overs(self):
context = self._init_usages(4, 8, 10 * 1024, 4)
self.assertRaises(exception.OverQuota,
sqa_api.quota_reserve,
context, self.resources, self.quotas,
self.quotas, self.deltas, self.expire,
0, 0)
try:
sqa_api.quota_reserve(context, self.resources, self.quotas,
self.quotas, self.deltas, self.expire, 0, 0)
except exception.OverQuota, e:
expected_kwargs = {'code': 500,
'usages': {'instances': {'reserved': 0, 'in_use': 4},
'ram': {'reserved': 0, 'in_use': 10240},
'fixed_ips': {'reserved': 0, 'in_use': 4},
'cores': {'reserved': 0, 'in_use': 8}},
'headroom': {'cores': 2, 'ram': 0, 'fixed_ips': 1,
'instances': 1},
'overs': ['cores', 'fixed_ips', 'instances', 'ram'],
'quotas': {'cores': 10, 'ram': 10240,
'fixed_ips': 5, 'instances': 5}}
self.assertEqual(e.kwargs, expected_kwargs)
else:
self.fail('Expected OverQuota failure')
self.assertEqual(self.sync_called, set([]))
self.usages_list[0]["in_use"] = 4
self.usages_list[0]["reserved"] = 0
@ -2312,6 +2337,40 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase):
self.assertEqual(self.usages_created, {})
self.assertEqual(self.reservations_created, {})
def test_quota_reserve_cores_unlimited(self):
# Requesting 8 cores, quota_cores set to unlimited:
self.flags(quota_cores=-1)
context = self._init_usages(1, 8, 1 * 1024, 1)
self.assertEqual(self.sync_called, set([]))
self.usages_list[0]["in_use"] = 1
self.usages_list[0]["reserved"] = 0
self.usages_list[1]["in_use"] = 8
self.usages_list[1]["reserved"] = 0
self.usages_list[2]["in_use"] = 1 * 1024
self.usages_list[2]["reserved"] = 0
self.usages_list[3]["in_use"] = 1
self.usages_list[3]["reserved"] = 0
self.compare_usage(self.usages, self.usages_list)
self.assertEqual(self.usages_created, {})
self.assertEqual(self.reservations_created, {})
def test_quota_reserve_ram_unlimited(self):
# Requesting 10*1024 ram, quota_ram set to unlimited:
self.flags(quota_ram=-1)
context = self._init_usages(1, 1, 10 * 1024, 1)
self.assertEqual(self.sync_called, set([]))
self.usages_list[0]["in_use"] = 1
self.usages_list[0]["reserved"] = 0
self.usages_list[1]["in_use"] = 1
self.usages_list[1]["reserved"] = 0
self.usages_list[2]["in_use"] = 10 * 1024
self.usages_list[2]["reserved"] = 0
self.usages_list[3]["in_use"] = 1
self.usages_list[3]["reserved"] = 0
self.compare_usage(self.usages, self.usages_list)
self.assertEqual(self.usages_created, {})
self.assertEqual(self.reservations_created, {})
def test_quota_reserve_reduction(self):
context = self._init_usages(10, 20, 20 * 1024, 10)
self.deltas["instances"] = -2