diff options
-rw-r--r-- | nova/api/openstack/compute/server_metadata.py | 14 | ||||
-rw-r--r-- | nova/api/openstack/compute/servers.py | 5 | ||||
-rw-r--r-- | nova/compute/api.py | 12 | ||||
-rw-r--r-- | nova/tests/api/openstack/compute/test_server_metadata.py | 54 |
4 files changed, 79 insertions, 6 deletions
diff --git a/nova/api/openstack/compute/server_metadata.py b/nova/api/openstack/compute/server_metadata.py index bdef6fbf46..a2fb53e7e4 100644 --- a/nova/api/openstack/compute/server_metadata.py +++ b/nova/api/openstack/compute/server_metadata.py @@ -161,8 +161,18 @@ class Controller(object): def _handle_quota_error(self, error): """Reraise quota errors as api-specific http exceptions.""" - if error.kwargs['code'] == "MetadataLimitExceeded": - raise exc.HTTPRequestEntityTooLarge(explanation=error.message, + 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 diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 2e7b184c48..08b6954770 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -478,6 +478,11 @@ class Controller(wsgi.Controller): _("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 diff --git a/nova/compute/api.py b/nova/compute/api.py index 15946d1167..70f8f69679 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -222,12 +222,16 @@ class API(BaseAPI): # In future, we may support more variable length strings, so we act # as if this is quota-controlled for forwards compatibility for k, v in metadata.iteritems(): + 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: - pid = context.project_id - msg = _("Quota exceeded for %(pid)s, metadata property " - "key or value too long") % locals() + msg = _("Metadata property key or value greater than 255 " + "characters") LOG.warn(msg) - raise exception.QuotaError(code="MetadataLimitExceeded") + raise exception.QuotaError( + code="MetadataKeyValueLimitExceeded") def _check_requested_networks(self, context, requested_networks): """ Check if the networks requested belongs to the project diff --git a/nova/tests/api/openstack/compute/test_server_metadata.py b/nova/tests/api/openstack/compute/test_server_metadata.py index 61bf4fc479..aa4e477068 100644 --- a/nova/tests/api/openstack/compute/test_server_metadata.py +++ b/nova/tests/api/openstack/compute/test_server_metadata.py @@ -346,6 +346,31 @@ class ServerMetaDataTest(test.TestCase): self.assertRaises(webob.exc.HTTPRequestEntityTooLarge, self.controller.create, req, self.uuid, data) + def test_invalid_metadata_items_on_create(self): + self.stubs.Set(nova.db, 'instance_metadata_update', + return_create_instance_metadata) + req = fakes.HTTPRequest.blank(self.url) + req.method = 'POST' + req.headers["content-type"] = "application/json" + + #test for long key + data = {"metadata": {"a" * 260: "value1"}} + req.body = json.dumps(data) + self.assertRaises(webob.exc.HTTPRequestEntityTooLarge, + 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.controller.create, req, self.uuid, data) + + #test for empty key. + data = {"metadata": {"": "value1"}} + req.body = json.dumps(data) + self.assertRaises(webob.exc.HTTPRequestEntityTooLarge, + self.controller.create, req, self.uuid, data) + def test_too_many_metadata_items_on_update_item(self): self.stubs.Set(nova.db, 'instance_metadata_update', return_create_instance_metadata) @@ -359,3 +384,32 @@ class ServerMetaDataTest(test.TestCase): self.assertRaises(webob.exc.HTTPRequestEntityTooLarge, self.controller.update_all, req, self.uuid, data) + + def test_invalid_metadata_items_on_update_item(self): + self.stubs.Set(nova.db, 'instance_metadata_update', + return_create_instance_metadata) + data = {"metadata": {}} + for num in range(FLAGS.quota_metadata_items + 1): + data['metadata']['key%i' % num] = "blah" + req = fakes.HTTPRequest.blank(self.url) + req.method = 'PUT' + req.body = json.dumps(data) + req.headers["content-type"] = "application/json" + + #test for long key + data = {"metadata": {"a" * 260: "value1"}} + req.body = json.dumps(data) + self.assertRaises(webob.exc.HTTPRequestEntityTooLarge, + 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.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.controller.update_all, req, self.uuid, data) |