summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Meade <alex.meade@rackspace.com>2012-04-30 12:59:21 -0400
committerAlex Meade <alex.meade@rackspace.com>2012-05-02 13:33:24 -0400
commit718a3f057cee0b1163c40fbcbedda29bd2ef9dfe (patch)
tree6d4531db55a152c958ca3e30ff01394de512b190
parent994bba6ae7156a565bd160fc8f0f8e8578c28d1b (diff)
downloadnova-718a3f057cee0b1163c40fbcbedda29bd2ef9dfe.tar.gz
nova-718a3f057cee0b1163c40fbcbedda29bd2ef9dfe.tar.xz
nova-718a3f057cee0b1163c40fbcbedda29bd2ef9dfe.zip
Provide better quota error messages.
Refactor the handling of QuotaErrors. Fixes bug: 990015 Fixes bug: 991994 Change-Id: I722545fad3c0bdff896a8f56f6c53ba47e433b0c
-rw-r--r--nova/api/openstack/compute/contrib/flavorextraspecs.py14
-rw-r--r--nova/api/openstack/compute/contrib/volumetypes.py6
-rw-r--r--nova/api/openstack/compute/server_metadata.py23
-rw-r--r--nova/api/openstack/compute/servers.py33
-rw-r--r--nova/compute/api.py27
-rw-r--r--nova/exception.py29
-rw-r--r--nova/tests/api/openstack/compute/test_server_metadata.py75
-rw-r--r--nova/tests/api/openstack/compute/test_servers.py165
-rw-r--r--nova/volume/api.py2
9 files changed, 283 insertions, 91 deletions
diff --git a/nova/api/openstack/compute/contrib/flavorextraspecs.py b/nova/api/openstack/compute/contrib/flavorextraspecs.py
index e878e2efb..faae7c40b 100644
--- a/nova/api/openstack/compute/contrib/flavorextraspecs.py
+++ b/nova/api/openstack/compute/contrib/flavorextraspecs.py
@@ -66,8 +66,8 @@ class FlavorExtraSpecsController(object):
db.instance_type_extra_specs_update_or_create(context,
flavor_id,
specs)
- except exception.QuotaError as error:
- self._handle_quota_error(error)
+ except exception.MetadataLimitExceeded as error:
+ raise exc.HTTPBadRequest(explanation=unicode(error))
return body
@wsgi.serializers(xml=ExtraSpecsTemplate)
@@ -85,8 +85,8 @@ class FlavorExtraSpecsController(object):
db.instance_type_extra_specs_update_or_create(context,
flavor_id,
body)
- except exception.QuotaError as error:
- self._handle_quota_error(error)
+ except exception.MetadataLimitExceeded as error:
+ raise exc.HTTPBadRequest(explanation=unicode(error))
return body
@@ -107,12 +107,6 @@ class FlavorExtraSpecsController(object):
authorize(context)
db.instance_type_extra_specs_delete(context, flavor_id, id)
- def _handle_quota_error(self, error):
- """Reraise quota errors as api-specific http exceptions."""
- if error.code == "MetadataLimitExceeded":
- raise exc.HTTPBadRequest(explanation=error.message)
- raise error
-
class Flavorextraspecs(extensions.ExtensionDescriptor):
"""Instance type (flavor) extra specs"""
diff --git a/nova/api/openstack/compute/contrib/volumetypes.py b/nova/api/openstack/compute/contrib/volumetypes.py
index 4255ac149..2711c45d7 100644
--- a/nova/api/openstack/compute/contrib/volumetypes.py
+++ b/nova/api/openstack/compute/contrib/volumetypes.py
@@ -114,12 +114,6 @@ class VolumeTypesController(object):
except exception.NotFound:
raise exc.HTTPNotFound()
- def _handle_quota_error(self, error):
- """Reraise quota errors as api-specific http exceptions."""
- if error.code == "MetadataLimitExceeded":
- raise exc.HTTPBadRequest(explanation=error.message)
- raise error
-
class VolumeTypeExtraSpecsTemplate(xmlutil.TemplateBuilder):
def construct(self):
diff --git a/nova/api/openstack/compute/server_metadata.py b/nova/api/openstack/compute/server_metadata.py
index a2fb53e7e..dfb4b55a8 100644
--- a/nova/api/openstack/compute/server_metadata.py
+++ b/nova/api/openstack/compute/server_metadata.py
@@ -126,8 +126,12 @@ class Controller(object):
msg = _("Malformed request body")
raise exc.HTTPBadRequest(explanation=msg)
+ except exception.InvalidMetadata as error:
+ raise exc.HTTPBadRequest(explanation=unicode(error))
+
except exception.QuotaError as error:
- self._handle_quota_error(error)
+ raise exc.HTTPRequestEntityTooLarge(explanation=unicode(error),
+ headers={'Retry-After': 0})
@wsgi.serializers(xml=common.MetaItemTemplate)
def show(self, req, server_id, id):
@@ -159,23 +163,6 @@ class Controller(object):
msg = _('Server does not exist')
raise exc.HTTPNotFound(explanation=msg)
- def _handle_quota_error(self, error):
- """Reraise quota errors as api-specific http exceptions."""
- code_mappings = {
- "MetadataKeyValueLimitExceeded":
- _("Metadata property key or value greater than 255 "
- "characters"),
- "MetadataKeyUnspecified":
- _("Metadata property key blank"),
- "MetadataLimitExceeded":
- error.message % error.kwargs
- }
- expl = code_mappings.get(error.kwargs['code'])
- if expl:
- raise exc.HTTPRequestEntityTooLarge(explanation=expl,
- headers={'Retry-After': 0})
- raise error
-
def create_resource():
return wsgi.Resource(Controller())
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index af6d9c7d6..ff96ded9b 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -471,32 +471,6 @@ class Controller(wsgi.Controller):
except exception.NotFound:
raise exc.HTTPNotFound()
- def _handle_quota_error(self, error):
- """Reraise quota errors as api-specific http exceptions."""
-
- code_mappings = {
- "OnsetFileLimitExceeded":
- _("Personality file limit exceeded"),
- "OnsetFilePathLimitExceeded":
- _("Personality file path too long"),
- "OnsetFileContentLimitExceeded":
- _("Personality file content too long"),
- "MetadataKeyValueLimitExceeded":
- _("Metadata property key or value greater than 255 "
- "characters"),
- "MetadataKeyUnspecified":
- _("Metadata property key blank"),
-
- # NOTE(bcwaldon): expose the message generated below in order
- # to better explain how the quota was exceeded
- "InstanceLimitExceeded": error.message,
- }
-
- code = error.kwargs['code']
- expl = code_mappings.get(code, error.message) % error.kwargs
- raise exc.HTTPRequestEntityTooLarge(explanation=expl,
- headers={'Retry-After': 0})
-
def _validate_server_name(self, value):
if not isinstance(value, basestring):
msg = _("Server name is not a string or unicode")
@@ -726,11 +700,14 @@ class Controller(wsgi.Controller):
auto_disk_config=auto_disk_config,
scheduler_hints=scheduler_hints)
except exception.QuotaError as error:
- self._handle_quota_error(error)
+ raise exc.HTTPRequestEntityTooLarge(explanation=unicode(error),
+ headers={'Retry-After': 0})
except exception.InstanceTypeMemoryTooSmall as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
except exception.InstanceTypeDiskTooSmall as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
+ except exception.InvalidMetadata as error:
+ raise exc.HTTPBadRequest(explanation=unicode(error))
except exception.ImageNotFound as error:
msg = _("Can not find requested image")
raise exc.HTTPBadRequest(explanation=msg)
@@ -1075,6 +1052,8 @@ class Controller(wsgi.Controller):
except exception.InstanceNotFound:
msg = _("Instance could not be found")
raise exc.HTTPNotFound(explanation=msg)
+ except exception.InvalidMetadata as error:
+ raise exc.HTTPBadRequest(explanation=unicode(error))
except exception.ImageNotFound:
msg = _("Cannot find image for rebuild")
raise exc.HTTPBadRequest(explanation=msg)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 542782c8b..ad34dd288 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -176,16 +176,15 @@ class API(BaseAPI):
return
limit = quota.allowed_injected_files(context, len(injected_files))
if len(injected_files) > limit:
- raise exception.QuotaError(code="OnsetFileLimitExceeded")
+ raise exception.OnsetFileLimitExceeded()
path_limit = quota.allowed_injected_file_path_bytes(context)
for path, content in injected_files:
if len(path) > path_limit:
- raise exception.QuotaError(code="OnsetFilePathLimitExceeded")
+ raise exception.OnsetFilePathLimitExceeded()
content_limit = quota.allowed_injected_file_content_bytes(
context, len(content))
if len(content) > content_limit:
- code = "OnsetFileContentLimitExceeded"
- raise exception.QuotaError(code=code)
+ raise exception.OnsetFileContentLimitExceeded()
def _check_num_instances_quota(self, context, instance_type, min_count,
max_count):
@@ -196,12 +195,14 @@ class API(BaseAPI):
pid = context.project_id
if num_instances <= 0:
msg = _("Cannot run any more instances of this type.")
+ used = max_count
else:
msg = (_("Can only run %s more instances of this type.") %
num_instances)
+ used = max_count - num_instances
LOG.warn(_("Quota exceeded for %(pid)s,"
" tried to run %(min_count)s instances. %(msg)s"), locals())
- raise exception.QuotaError(code="InstanceLimitExceeded")
+ raise exception.TooManyInstances(used=used, allowed=max_count)
return num_instances
@@ -216,7 +217,7 @@ class API(BaseAPI):
msg = _("Quota exceeded for %(pid)s, tried to set "
"%(num_metadata)s metadata properties") % locals()
LOG.warn(msg)
- raise exception.QuotaError(code="MetadataLimitExceeded")
+ raise exception.MetadataLimitExceeded(allowed=quota_metadata)
# Because metadata is stored in the DB, we hard-code the size limits
# In future, we may support more variable length strings, so we act
@@ -225,13 +226,15 @@ class API(BaseAPI):
if len(k) == 0:
msg = _("Metadata property key blank")
LOG.warn(msg)
- raise exception.QuotaError(code="MetadataKeyUnspecified")
- if len(k) > 255 or len(v) > 255:
- msg = _("Metadata property key or value greater than 255 "
- "characters")
+ raise exception.InvalidMetadata(reason=msg)
+ if len(k) > 255:
+ msg = _("Metadata property key greater than 255 characters")
LOG.warn(msg)
- raise exception.QuotaError(
- code="MetadataKeyValueLimitExceeded")
+ raise exception.InvalidMetadata(reason=msg)
+ if len(v) > 255:
+ msg = _("Metadata property value greater than 255 characters")
+ LOG.warn(msg)
+ raise exception.InvalidMetadata(reason=msg)
def _check_requested_networks(self, context, requested_networks):
""" Check if the networks requested belongs to the project
diff --git a/nova/exception.py b/nova/exception.py
index 5fa9e0c87..e40fa0ccf 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -265,6 +265,10 @@ class InvalidVolume(Invalid):
message = _("Invalid volume") + ": %(reason)s"
+class InvalidMetadata(Invalid):
+ message = _("Invalid metadata") + ": %(reason)s"
+
+
class InvalidPortRange(Invalid):
message = _("Invalid port range %(from_port)s:%(to_port)s. %(msg)s")
@@ -962,6 +966,31 @@ class QuotaError(NovaException):
message = _("Quota exceeded") + ": code=%(code)s"
+class TooManyInstances(QuotaError):
+ message = _("Quota exceeded: already used %(used)d of %(allowed)d"
+ " instances")
+
+
+class VolumeSizeTooLarge(QuotaError):
+ message = _("Maximum volume size exceeded")
+
+
+class MetadataLimitExceeded(QuotaError):
+ message = _("Maximum number of metadata items exceeds %(allowed)d")
+
+
+class OnsetFileLimitExceeded(QuotaError):
+ message = _("Personality file limit exceeded")
+
+
+class OnsetFilePathLimitExceeded(QuotaError):
+ message = _("Personality file path too long")
+
+
+class OnsetFileContentLimitExceeded(QuotaError):
+ message = _("Personality file content too long")
+
+
class AggregateError(NovaException):
message = _("Aggregate %(aggregate_id)s: action '%(action)s' "
"caused an error: %(reason)s.")
diff --git a/nova/tests/api/openstack/compute/test_server_metadata.py b/nova/tests/api/openstack/compute/test_server_metadata.py
index aa4e47706..87fcec57b 100644
--- a/nova/tests/api/openstack/compute/test_server_metadata.py
+++ b/nova/tests/api/openstack/compute/test_server_metadata.py
@@ -200,6 +200,31 @@ class ServerMetaDataTest(test.TestCase):
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.uuid, None)
+ def test_create_item_empty_key(self):
+ self.stubs.Set(nova.db, 'instance_metadata_update',
+ return_create_instance_metadata)
+ req = fakes.HTTPRequest.blank(self.url + '/key1')
+ req.method = 'PUT'
+ body = {"meta": {"": "value1"}}
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller.create, req, self.uuid, body)
+
+ def test_create_item_key_too_long(self):
+ self.stubs.Set(nova.db, 'instance_metadata_update',
+ return_create_instance_metadata)
+ req = fakes.HTTPRequest.blank(self.url + '/key1')
+ req.method = 'PUT'
+ body = {"meta": {("a" * 260): "value1"}}
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller.create,
+ req, self.uuid, body)
+
def test_create_nonexistant_server(self):
self.stubs.Set(nova.db, 'instance_get', return_server_nonexistant)
req = fakes.HTTPRequest.blank(self.url)
@@ -308,6 +333,44 @@ class ServerMetaDataTest(test.TestCase):
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.uuid, 'key1', None)
+ def test_update_item_empty_key(self):
+ self.stubs.Set(nova.db, 'instance_metadata_update',
+ return_create_instance_metadata)
+ req = fakes.HTTPRequest.blank(self.url + '/key1')
+ req.method = 'PUT'
+ body = {"meta": {"": "value1"}}
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller.update, req, self.uuid, '', body)
+
+ def test_update_item_key_too_long(self):
+ self.stubs.Set(nova.db, 'instance_metadata_update',
+ return_create_instance_metadata)
+ req = fakes.HTTPRequest.blank(self.url + '/key1')
+ req.method = 'PUT'
+ body = {"meta": {("a" * 260): "value1"}}
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller.update,
+ req, self.uuid, ("a" * 260), body)
+
+ def test_update_item_value_too_long(self):
+ self.stubs.Set(nova.db, 'instance_metadata_update',
+ return_create_instance_metadata)
+ req = fakes.HTTPRequest.blank(self.url + '/key1')
+ req.method = 'PUT'
+ body = {"meta": {"key1": ("a" * 260)}}
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller.update,
+ req, self.uuid, "key1", body)
+
def test_update_item_too_many_keys(self):
self.stubs.Set(nova.db, 'instance_metadata_update',
return_create_instance_metadata)
@@ -356,19 +419,19 @@ class ServerMetaDataTest(test.TestCase):
#test for long key
data = {"metadata": {"a" * 260: "value1"}}
req.body = json.dumps(data)
- self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
+ self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.uuid, data)
#test for long value
data = {"metadata": {"key": "v" * 260}}
req.body = json.dumps(data)
- self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
+ self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.uuid, data)
#test for empty key.
data = {"metadata": {"": "value1"}}
req.body = json.dumps(data)
- self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
+ self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.uuid, data)
def test_too_many_metadata_items_on_update_item(self):
@@ -399,17 +462,17 @@ class ServerMetaDataTest(test.TestCase):
#test for long key
data = {"metadata": {"a" * 260: "value1"}}
req.body = json.dumps(data)
- self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
+ self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update_all, req, self.uuid, data)
#test for long value
data = {"metadata": {"key": "v" * 260}}
req.body = json.dumps(data)
- self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
+ self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update_all, req, self.uuid, data)
#test for empty key.
data = {"metadata": {"": "value1"}}
req.body = json.dumps(data)
- self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
+ self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update_all, req, self.uuid, data)
diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py
index 514d7cf84..0004c9fcb 100644
--- a/nova/tests/api/openstack/compute/test_servers.py
+++ b/nova/tests/api/openstack/compute/test_servers.py
@@ -1003,7 +1003,7 @@ class ServersControllerTest(test.TestCase):
req, FAKE_UUID, body)
def test_rebuild_instance_with_access_ipv4_bad_format(self):
- self.stubs.Set(nova.db, 'instance_get',
+ self.stubs.Set(nova.db, 'instance_get_by_uuid',
fakes.fake_instance_get(vm_state=vm_states.ACTIVE))
# proper local hrefs must start with 'http://localhost/v2/'
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
@@ -1036,6 +1036,108 @@ class ServersControllerTest(test.TestCase):
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._action_rebuild, req, FAKE_UUID, body)
+ def test_rebuild_instance_with_blank_metadata_key(self):
+ self.stubs.Set(nova.db, 'instance_get_by_uuid',
+ fakes.fake_instance_get(vm_state=vm_states.ACTIVE))
+ # proper local hrefs must start with 'http://localhost/v2/'
+ image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
+ image_href = 'http://localhost/v2/fake/images/%s' % image_uuid
+ access_ipv4 = '0.0.0.0'
+ access_ipv6 = 'fead::1234'
+ body = {
+ 'rebuild': {
+ 'name': 'new_name',
+ 'imageRef': image_href,
+ 'accessIPv4': access_ipv4,
+ 'accessIPv6': access_ipv6,
+ 'metadata': {
+ '': 'world',
+ 'open': 'stack',
+ },
+ 'personality': [
+ {
+ "path": "/etc/banner.txt",
+ "contents": "MQ==",
+ },
+ ],
+ },
+ }
+
+ req = fakes.HTTPRequest.blank('/v2/fake/servers/a/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller._action_rebuild, req, FAKE_UUID, body)
+
+ def test_rebuild_instance_with_metadata_key_too_long(self):
+ self.stubs.Set(nova.db, 'instance_get_by_uuid',
+ fakes.fake_instance_get(vm_state=vm_states.ACTIVE))
+ # proper local hrefs must start with 'http://localhost/v2/'
+ image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
+ image_href = 'http://localhost/v2/fake/images/%s' % image_uuid
+ access_ipv4 = '0.0.0.0'
+ access_ipv6 = 'fead::1234'
+ body = {
+ 'rebuild': {
+ 'name': 'new_name',
+ 'imageRef': image_href,
+ 'accessIPv4': access_ipv4,
+ 'accessIPv6': access_ipv6,
+ 'metadata': {
+ ('a' * 260): 'world',
+ 'open': 'stack',
+ },
+ 'personality': [
+ {
+ "path": "/etc/banner.txt",
+ "contents": "MQ==",
+ },
+ ],
+ },
+ }
+
+ req = fakes.HTTPRequest.blank('/v2/fake/servers/a/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller._action_rebuild, req, FAKE_UUID, body)
+
+ def test_rebuild_instance_with_metadata_value_too_long(self):
+ self.stubs.Set(nova.db, 'instance_get_by_uuid',
+ fakes.fake_instance_get(vm_state=vm_states.ACTIVE))
+ # proper local hrefs must start with 'http://localhost/v2/'
+ image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
+ image_href = 'http://localhost/v2/fake/images/%s' % image_uuid
+ access_ipv4 = '0.0.0.0'
+ access_ipv6 = 'fead::1234'
+ body = {
+ 'rebuild': {
+ 'name': 'new_name',
+ 'imageRef': image_href,
+ 'accessIPv4': access_ipv4,
+ 'accessIPv6': access_ipv6,
+ 'metadata': {
+ 'key1': ('a' * 260),
+ 'open': 'stack',
+ },
+ 'personality': [
+ {
+ "path": "/etc/banner.txt",
+ "contents": "MQ==",
+ },
+ ],
+ },
+ }
+
+ req = fakes.HTTPRequest.blank('/v2/fake/servers/a/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller._action_rebuild, req, FAKE_UUID, body)
+
def test_rebuild_instance_fails_when_min_ram_too_small(self):
# make min_ram larger than our instance ram size
def fake_get_image(self, context, image_href):
@@ -1845,13 +1947,7 @@ class ServersControllerCreateTest(test.TestCase):
'imageRef': image_href,
'flavorRef': flavor_ref,
'metadata': {
- ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
- 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
- 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
- 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
- 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
- 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
- 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'): '12345',
+ ('a' * 260): '12345',
},
},
}
@@ -1861,7 +1957,55 @@ class ServersControllerCreateTest(test.TestCase):
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
- self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller.create, req, body)
+
+ def test_create_instance_metadata_value_too_long(self):
+ self.flags(quota_metadata_items=1)
+ image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
+ image_href = 'http://localhost/v2/images/%s' % image_uuid
+ flavor_ref = 'http://localhost/123/flavors/3'
+ body = {
+ 'server': {
+ 'name': 'server_test',
+ 'imageRef': image_href,
+ 'flavorRef': flavor_ref,
+ 'metadata': {
+ 'key1': ('a' * 260),
+ },
+ },
+ }
+
+ req = fakes.HTTPRequest.blank('/v2/fake/servers')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller.create, req, body)
+
+ def test_create_instance_metadata_key_blank(self):
+ self.flags(quota_metadata_items=1)
+ image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
+ image_href = 'http://localhost/v2/images/%s' % image_uuid
+ flavor_ref = 'http://localhost/123/flavors/3'
+ body = {
+ 'server': {
+ 'name': 'server_test',
+ 'imageRef': image_href,
+ 'flavorRef': flavor_ref,
+ 'metadata': {
+ '': '12345',
+ },
+ },
+ }
+
+ req = fakes.HTTPRequest.blank('/v2/fake/servers')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, body)
def test_create_instance_invalid_key_name(self):
@@ -2193,9 +2337,8 @@ class ServersControllerCreateTest(test.TestCase):
server = self.controller.create(req, body).obj['server']
fail('excepted quota to be exceeded')
except webob.exc.HTTPRequestEntityTooLarge as e:
- code = {'code': 'InstanceLimitExceeded'}
self.assertEquals(e.explanation,
- _('Quota exceeded: code=%(code)s') % code)
+ _('Quota exceeded: already used 1 of 1 instances'))
class TestServerCreateRequestXMLDeserializer(test.TestCase):
diff --git a/nova/volume/api.py b/nova/volume/api.py
index c40270ac7..f62d41ea6 100644
--- a/nova/volume/api.py
+++ b/nova/volume/api.py
@@ -84,7 +84,7 @@ class API(base.Base):
pid = context.project_id
LOG.warn(_("Quota exceeded for %(pid)s, tried to create"
" %(size)sG volume") % locals())
- raise exception.QuotaError(code="VolumeSizeTooLarge")
+ raise exception.VolumeSizeTooLarge()
if availability_zone is None:
availability_zone = FLAGS.storage_availability_zone