diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 0d419f205e00..01787712a65b 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -269,7 +269,7 @@ def get_version_from_href(href): return '2' -def check_img_metadata_quota_limit(context, metadata): +def check_img_metadata_properties_quota(context, metadata): if metadata is None: return num_metadata = len(metadata) @@ -279,6 +279,19 @@ def check_img_metadata_quota_limit(context, metadata): raise webob.exc.HTTPRequestEntityTooLarge(explanation=expl, headers={'Retry-After': 0}) + # check the key length. + if isinstance(metadata, dict): + for key, value in metadata.iteritems(): + if len(key) == 0: + expl = _("Image metadata key cannot be blank") + raise webob.exc.HTTPBadRequest(explanation=expl) + if len(key) > 255: + expl = _("Image metadata key too long") + raise webob.exc.HTTPBadRequest(explanation=expl) + else: + expl = _("Invalid image metadata") + raise webob.exc.HTTPBadRequest(explanation=expl) + def dict_to_query_str(params): # TODO(throughnothing): we should just use urllib.urlencode instead of this diff --git a/nova/api/openstack/compute/contrib/admin_actions.py b/nova/api/openstack/compute/contrib/admin_actions.py index f7908f758e90..f9e661062dfa 100644 --- a/nova/api/openstack/compute/contrib/admin_actions.py +++ b/nova/api/openstack/compute/contrib/admin_actions.py @@ -231,7 +231,7 @@ class AdminActionsController(wsgi.Controller): props = {} metadata = entity.get('metadata', {}) - common.check_img_metadata_quota_limit(context, metadata) + common.check_img_metadata_properties_quota(context, metadata) try: props.update(metadata) except ValueError: diff --git a/nova/api/openstack/compute/image_metadata.py b/nova/api/openstack/compute/image_metadata.py index d79692f2207a..145e0395eb46 100644 --- a/nova/api/openstack/compute/image_metadata.py +++ b/nova/api/openstack/compute/image_metadata.py @@ -64,7 +64,8 @@ class Controller(object): if 'metadata' in body: for key, value in body['metadata'].iteritems(): image['properties'][key] = value - common.check_img_metadata_quota_limit(context, image['properties']) + common.check_img_metadata_properties_quota(context, + image['properties']) self.image_service.update(context, image_id, image, None) return dict(metadata=image['properties']) @@ -88,7 +89,8 @@ class Controller(object): image = self._get_image(context, image_id) image['properties'][id] = meta[id] - common.check_img_metadata_quota_limit(context, image['properties']) + common.check_img_metadata_properties_quota(context, + image['properties']) self.image_service.update(context, image_id, image, None) return dict(meta=meta) @@ -98,7 +100,7 @@ class Controller(object): context = req.environ['nova.context'] image = self._get_image(context, image_id) metadata = body.get('metadata', {}) - common.check_img_metadata_quota_limit(context, metadata) + common.check_img_metadata_properties_quota(context, metadata) image['properties'] = metadata self.image_service.update(context, image_id, image, None) return dict(metadata=metadata) diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 635123fff06e..9aa637cc9825 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -1093,7 +1093,7 @@ class Controller(wsgi.Controller): props = {} metadata = entity.get('metadata', {}) - common.check_img_metadata_quota_limit(context, metadata) + common.check_img_metadata_properties_quota(context, metadata) try: props.update(metadata) except ValueError: diff --git a/nova/tests/api/openstack/test_common.py b/nova/tests/api/openstack/test_common.py index f36a530c1923..5e1e6e0bae75 100644 --- a/nova/tests/api/openstack/test_common.py +++ b/nova/tests/api/openstack/test_common.py @@ -28,6 +28,7 @@ from nova import exception from nova import test from nova.api.openstack import common from nova.api.openstack import xmlutil +from nova.tests import utils as test_utils NS = "{http://docs.openstack.org/compute/api/v1.1}" @@ -328,6 +329,34 @@ class MiscFunctionsTest(test.TestCase): else: self.fail("webob.exc.HTTPConflict was not raised") + def test_check_img_metadata_properties_quota_valid_metadata(self): + ctxt = test_utils.get_test_admin_context() + metadata1 = {"key": "value"} + actual = common.check_img_metadata_properties_quota(ctxt, metadata1) + self.assertEqual(actual, None) + + metadata2 = {"key": "v" * 260} + actual = common.check_img_metadata_properties_quota(ctxt, metadata2) + self.assertEqual(actual, None) + + metadata3 = {"key": ""} + actual = common.check_img_metadata_properties_quota(ctxt, metadata3) + self.assertEqual(actual, None) + + def test_check_img_metadata_properties_quota_inv_metadata(self): + ctxt = test_utils.get_test_admin_context() + metadata1 = {"a" * 260: "value"} + self.assertRaises(webob.exc.HTTPBadRequest, + common.check_img_metadata_properties_quota, ctxt, metadata1) + + metadata2 = {"": "value"} + self.assertRaises(webob.exc.HTTPBadRequest, + common.check_img_metadata_properties_quota, ctxt, metadata2) + + metadata3 = "invalid metadata" + self.assertRaises(webob.exc.HTTPBadRequest, + common.check_img_metadata_properties_quota, ctxt, metadata3) + class MetadataXMLDeserializationTest(test.TestCase):