Skip to content

Commit

Permalink
Clarify TooManyInstances exception message.
Browse files Browse the repository at this point in the history
Fixes LP 1031737.

Previously the message indicated the number of instances requested
and an incorrect indication of the headroom, in the case where ram
or cores was the resource gone over-quota (as opposed to the number
of raw instances).

Change-Id: I9f7f3203f0e644ba533940a87e496bfd09da0460
  • Loading branch information
Eoghan Glynn committed Aug 1, 2012
1 parent 37dee20 commit 54f4d3b
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 27 deletions.
16 changes: 10 additions & 6 deletions nova/compute/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ def _check_num_instances_quota(self, context, instance_type, min_count,
(usages[res]['in_use'] + usages[res]['reserved']))
for res in quotas.keys())

# Reduce 'allowed' to the minimum supported
allowed = headroom['instances']
# Reduce 'allowed' instances in line with the cores & ram headroom
if instance_type['vcpus']:
allowed = min(allowed,
headroom['cores'] // instance_type['vcpus'])
Expand All @@ -204,7 +204,6 @@ def _check_num_instances_quota(self, context, instance_type, min_count,
headroom['ram'] // instance_type['memory_mb'])

# Convert to the appropriate exception message
pid = context.project_id
if allowed <= 0:
msg = _("Cannot run any more instances of this type.")
allowed = 0
Expand All @@ -216,14 +215,19 @@ def _check_num_instances_quota(self, context, instance_type, min_count,
msg = (_("Can only run %s more instances of this type.") %
allowed)

used = quotas['instances'] - headroom['instances']
total_allowed = used + allowed
resource = overs[0]
used = quotas[resource] - headroom[resource]
total_allowed = used + headroom[resource]
overs = ','.join(overs)

pid = context.project_id
LOG.warn(_("%(overs)s quota exceeded for %(pid)s,"
" tried to run %(min_count)s instances. %(msg)s"), locals())
raise exception.TooManyInstances(overs=overs, req=min_count,
used=used, allowed=total_allowed)
requested = dict(instances=min_count, cores=req_cores, ram=req_ram)
raise exception.TooManyInstances(overs=overs,
req=requested[resource],
used=used, allowed=total_allowed,
resource=resource)

return max_count, reservations

Expand Down
2 changes: 1 addition & 1 deletion nova/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ class QuotaError(NovaException):

class TooManyInstances(QuotaError):
message = _("Quota exceeded for %(overs)s: Requested %(req)s,"
" but already used %(used)d of %(allowed)d instances")
" but already used %(used)d of %(allowed)d %(resource)s")


class VolumeSizeTooLarge(QuotaError):
Expand Down
30 changes: 22 additions & 8 deletions nova/tests/api/openstack/compute/test_servers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1344,7 +1344,7 @@ def return_servers_with_host(context, *args, **kwargs):
self.assertEqual(s['name'], 'server%d' % (i + 1))

def test_delete_server_instance(self):
fakes.stub_out_instance_quota(self.stubs, 0)
fakes.stub_out_instance_quota(self.stubs, 0, 10)
req = fakes.HTTPRequest.blank('/v2/fake/servers/%s' % FAKE_UUID)
req.method = 'DELETE'

Expand All @@ -1362,7 +1362,7 @@ def instance_destroy_mock(*args, **kwargs):
self.assertEqual(self.server_delete_called, True)

def test_delete_server_instance_while_building(self):
fakes.stub_out_instance_quota(self.stubs, 0)
fakes.stub_out_instance_quota(self.stubs, 0, 10)
req = fakes.HTTPRequest.blank('/v2/fake/servers/%s' % FAKE_UUID)
req.method = 'DELETE'

Expand Down Expand Up @@ -2393,11 +2393,12 @@ def test_create_location(self):

self.assertEqual(robj['Location'], selfhref)

def test_create_instance_above_quota(self):
fakes.stub_out_instance_quota(self.stubs, 0)
def _do_test_create_instance_above_quota(self, resource, allowed, quota,
expected_msg):
fakes.stub_out_instance_quota(self.stubs, allowed, quota, resource)
image_uuid = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77'
body = dict(server=dict(
name='server_test', imageRef=image_uuid, flavorRef=2,
name='server_test', imageRef=image_uuid, flavorRef=3,
metadata={'hello': 'world', 'open': 'stack'},
personality={}))
req = fakes.HTTPRequest.blank('/v2/fake/servers')
Expand All @@ -2408,9 +2409,22 @@ def test_create_instance_above_quota(self):
server = self.controller.create(req, body).obj['server']
self.fail('expected quota to be exceeded')
except webob.exc.HTTPRequestEntityTooLarge as e:
self.assertEquals(e.explanation,
_('Quota exceeded for instances: Requested 1, but'
' already used 0 of 0 instances'))
self.assertEquals(e.explanation, expected_msg)

def test_create_instance_above_quota_instances(self):
msg = _('Quota exceeded for instances: Requested 1, but'
' already used 10 of 10 instances')
self._do_test_create_instance_above_quota('instances', 0, 10, msg)

def test_create_instance_above_quota_ram(self):
msg = _('Quota exceeded for ram: Requested 4096, but'
' already used 8192 of 10240 ram')
self._do_test_create_instance_above_quota('ram', 2048, 10 * 1024, msg)

def test_create_instance_above_quota_cores(self):
msg = _('Quota exceeded for cores: Requested 2, but'
' already used 9 of 10 cores')
self._do_test_create_instance_above_quota('cores', 1, 10, msg)


class TestServerCreateRequestXMLDeserializer(test.TestCase):
Expand Down
25 changes: 13 additions & 12 deletions nova/tests/api/openstack/fakes.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,19 +129,20 @@ def fake_rate_init(self, app):
'__call__', fake_wsgi)


def stub_out_instance_quota(stubs, allowed):
def stub_out_instance_quota(stubs, allowed, quota, resource='instances'):
def fake_reserve(context, **deltas):
instances = deltas.pop('instances', 0)
if instances > allowed:
raise exc.OverQuota(overs=['instances'], quotas=dict(
instances=allowed,
cores=10000,
ram=10000 * 1024,
), usages=dict(
instances=dict(in_use=0, reserved=0),
cores=dict(in_use=0, reserved=0),
ram=dict(in_use=0, reserved=0),
))
requested = deltas.pop(resource, 0)
if requested > allowed:
quotas = dict(instances=1, cores=1, ram=1)
quotas[resource] = quota
usages = dict(instances=dict(in_use=0, reserved=0),
cores=dict(in_use=0, reserved=0),
ram=dict(in_use=0, reserved=0))
usages[resource]['in_use'] = (quotas[resource] * 0.9 -
allowed)
usages[resource]['reserved'] = quotas[resource] * 0.1
raise exc.OverQuota(overs=[resource], quotas=quotas,
usages=usages)
stubs.Set(QUOTAS, 'reserve', fake_reserve)


Expand Down

0 comments on commit 54f4d3b

Please sign in to comment.