diff options
| author | Dan Prince <dan.prince@rackspace.com> | 2011-08-09 16:33:13 +0000 |
|---|---|---|
| committer | Tarmac <> | 2011-08-09 16:33:13 +0000 |
| commit | 5afb04d2fbeccf31a83681ef6b58cb9a7674993b (patch) | |
| tree | 687aae0af27b6a9c504c8254687bb2d3b476aa43 | |
| parent | 78d086b62cb7f1bf043d368e7d2b9e304d4c764f (diff) | |
| parent | e24e031b453f90bb1d26616ec8d3975048d46220 (diff) | |
Update the OSAPI v1.1 server 'createImage' and 'createBackup' actions to limit the number of image metadata items based on the configured quota.allowed_metadata_items that is set.
| -rw-r--r-- | nova/api/openstack/common.py | 11 | ||||
| -rw-r--r-- | nova/api/openstack/image_metadata.py | 16 | ||||
| -rw-r--r-- | nova/api/openstack/servers.py | 6 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_server_actions.py | 40 |
4 files changed, 58 insertions, 15 deletions
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index ac2104a5f..b916372d6 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -25,6 +25,7 @@ import webob from nova import exception from nova import flags from nova import log as logging +from nova import quota from nova.api.openstack import wsgi @@ -193,6 +194,16 @@ def get_version_from_href(href): return version +def check_img_metadata_quota_limit(context, metadata): + if metadata is None: + return + num_metadata = len(metadata) + quota_metadata = quota.allowed_metadata_items(context, num_metadata) + if quota_metadata < num_metadata: + expl = _("Image metadata limit exceeded") + raise webob.exc.HTTPBadRequest(explanation=expl) + + class MetadataXMLDeserializer(wsgi.XMLDeserializer): def extract_metadata(self, metadata_node): diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index aaf64a123..4d615ea96 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -19,7 +19,6 @@ from webob import exc from nova import flags from nova import image -from nova import quota from nova import utils from nova.api.openstack import common from nova.api.openstack import wsgi @@ -40,15 +39,6 @@ class Controller(object): metadata = image.get('properties', {}) return metadata - def _check_quota_limit(self, context, metadata): - if metadata is None: - return - num_metadata = len(metadata) - quota_metadata = quota.allowed_metadata_items(context, num_metadata) - if quota_metadata < num_metadata: - expl = _("Image metadata limit exceeded") - raise exc.HTTPBadRequest(explanation=expl) - def index(self, req, image_id): """Returns the list of metadata for a given instance""" context = req.environ['nova.context'] @@ -70,7 +60,7 @@ class Controller(object): if 'metadata' in body: for key, value in body['metadata'].iteritems(): metadata[key] = value - self._check_quota_limit(context, metadata) + common.check_img_metadata_quota_limit(context, metadata) img['properties'] = metadata self.image_service.update(context, image_id, img, None) return dict(metadata=metadata) @@ -93,7 +83,7 @@ class Controller(object): img = self.image_service.show(context, image_id) metadata = self._get_metadata(context, image_id, img) metadata[id] = meta[id] - self._check_quota_limit(context, metadata) + common.check_img_metadata_quota_limit(context, metadata) img['properties'] = metadata self.image_service.update(context, image_id, img, None) return dict(meta=meta) @@ -102,7 +92,7 @@ class Controller(object): context = req.environ['nova.context'] img = self.image_service.show(context, image_id) metadata = body.get('metadata', {}) - self._check_quota_limit(context, metadata) + common.check_img_metadata_quota_limit(context, metadata) img['properties'] = metadata self.image_service.update(context, image_id, img, None) return dict(metadata=metadata) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 63e71b3eb..4f34d63c9 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -218,13 +218,14 @@ class Controller(object): props = {'instance_ref': server_ref} metadata = entity.get('metadata', {}) + context = req.environ["nova.context"] + common.check_img_metadata_quota_limit(context, metadata) try: props.update(metadata) except ValueError: msg = _("Invalid metadata") raise webob.exc.HTTPBadRequest(explanation=msg) - context = req.environ["nova.context"] image = self.compute_api.backup(context, instance_id, image_name, @@ -713,13 +714,14 @@ class ControllerV11(Controller): props = {'instance_ref': server_ref} metadata = entity.get('metadata', {}) + context = req.environ['nova.context'] + common.check_img_metadata_quota_limit(context, metadata) try: props.update(metadata) except ValueError: msg = _("Invalid metadata") raise webob.exc.HTTPBadRequest(explanation=msg) - context = req.environ['nova.context'] image = self.compute_api.snapshot(context, instance_id, image_name, diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 311db3f42..717e11c00 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -9,6 +9,7 @@ import webob from nova import context from nova import db from nova import utils +from nova import flags from nova.api.openstack import create_instance_helper from nova.compute import instance_types from nova.compute import power_state @@ -18,6 +19,9 @@ from nova.tests.api.openstack import common from nova.tests.api.openstack import fakes +FLAGS = flags.FLAGS + + def return_server_by_id(context, id): return _get_instance() @@ -370,6 +374,26 @@ class ServerActionsTest(test.TestCase): self.assertEqual(202, response.status_int) self.assertTrue(response.headers['Location']) + def test_create_backup_with_too_much_metadata(self): + self.flags(allow_admin_api=True) + + body = { + 'createBackup': { + 'name': 'Backup 1', + 'backup_type': 'daily', + 'rotation': 1, + 'metadata': {'123': 'asdf'}, + }, + } + for num in range(FLAGS.quota_metadata_items + 1): + body['createBackup']['metadata']['foo%i' % num] = "bar" + req = webob.Request.blank('/v1.0/servers/1/action') + req.method = 'POST' + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + response = req.get_response(fakes.wsgi_app()) + self.assertEqual(400, response.status_int) + def test_create_backup_no_name(self): """Name is required for backups""" self.flags(allow_admin_api=True) @@ -809,6 +833,22 @@ class ServerActionsTestV11(test.TestCase): location = response.headers['Location'] self.assertEqual('http://localhost/v1.1/images/123', location) + def test_create_image_with_too_much_metadata(self): + body = { + 'createImage': { + 'name': 'Snapshot 1', + 'metadata': {}, + }, + } + for num in range(FLAGS.quota_metadata_items + 1): + body['createImage']['metadata']['foo%i' % num] = "bar" + req = webob.Request.blank('/v1.1/servers/1/action') + req.method = 'POST' + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + response = req.get_response(fakes.wsgi_app()) + self.assertEqual(400, response.status_int) + def test_create_image_no_name(self): body = { 'createImage': {}, |
