diff options
| author | Naveed Massjouni <naveedm9@gmail.com> | 2011-03-24 23:46:05 +0000 |
|---|---|---|
| committer | Tarmac <> | 2011-03-24 23:46:05 +0000 |
| commit | 54a3b3d75640d1759a53cae24c8d2d38ad3f9148 (patch) | |
| tree | 44ff422d4d5506aa532b6b19af9a77f9ae0a99c7 | |
| parent | 4e179b4fa9ab35dc50486e7f42e1dc6d06b74c81 (diff) | |
| parent | 5a9b13465822bb214f9e9cc9afff929664cbd1c7 (diff) | |
Support for markers for pagination as defined in the 1.1 spec.
| -rw-r--r-- | nova/api/openstack/common.py | 35 | ||||
| -rw-r--r-- | nova/api/openstack/servers.py | 8 | ||||
| -rw-r--r-- | nova/flags.py | 2 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_servers.py | 30 |
4 files changed, 73 insertions, 2 deletions
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index bff050347..8cad1273a 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -20,9 +20,12 @@ from urlparse import urlparse import webob from nova import exception +from nova import flags +FLAGS = flags.FLAGS -def limited(items, request, max_limit=1000): + +def limited(items, request, max_limit=FLAGS.osapi_max_limit): """ Return a slice of items according to requested offset and limit. @@ -56,6 +59,36 @@ def limited(items, request, max_limit=1000): return items[offset:range_end] +def limited_by_marker(items, request, max_limit=FLAGS.osapi_max_limit): + """Return a slice of items according to the requested marker and limit.""" + + try: + marker = int(request.GET.get('marker', 0)) + except ValueError: + raise webob.exc.HTTPBadRequest(_('marker param must be an integer')) + + try: + limit = int(request.GET.get('limit', max_limit)) + except ValueError: + raise webob.exc.HTTPBadRequest(_('limit param must be an integer')) + + if limit < 0: + raise webob.exc.HTTPBadRequest(_('limit param must be positive')) + + limit = min(max_limit, limit) + start_index = 0 + if marker: + start_index = -1 + for i, item in enumerate(items): + if item['id'] == marker: + start_index = i + 1 + break + if start_index < 0: + raise webob.exc.HTTPBadRequest(_('marker [%s] not found' % marker)) + range_end = start_index + limit + return items[start_index:range_end] + + def get_image_id_from_image_hash(image_service, context, image_hash): """Given an Image ID Hash, return an objectstore Image ID. diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 0dad46268..144d14536 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -82,7 +82,7 @@ class Controller(wsgi.Controller): builder - the response model builder """ instance_list = self.compute_api.get_all(req.environ['nova.context']) - limited_list = common.limited(instance_list, req) + limited_list = self._limit_items(instance_list, req) builder = self._get_view_builder(req) servers = [builder.build(inst, is_detail)['server'] for inst in limited_list] @@ -551,6 +551,9 @@ class ControllerV10(Controller): def _get_addresses_view_builder(self, req): return nova.api.openstack.views.addresses.ViewBuilderV10(req) + def _limit_items(self, items, req): + return common.limited(items, req) + class ControllerV11(Controller): def _image_id_from_req_data(self, data): @@ -574,6 +577,9 @@ class ControllerV11(Controller): def _get_addresses_view_builder(self, req): return nova.api.openstack.views.addresses.ViewBuilderV11(req) + def _limit_items(self, items, req): + return common.limited_by_marker(items, req) + class ServerCreateRequestXMLDeserializer(object): """ diff --git a/nova/flags.py b/nova/flags.py index 00868d9b9..f011ab383 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -304,6 +304,8 @@ DEFINE_string('osapi_host', '$my_ip', 'ip of api server') DEFINE_string('osapi_scheme', 'http', 'prefix for openstack') DEFINE_integer('osapi_port', 8774, 'OpenStack API port') DEFINE_string('osapi_path', '/v1.0/', 'suffix for openstack') +DEFINE_integer('osapi_max_limit', 1000, + 'max number of items returned in a collection response') DEFINE_string('default_project', 'openstack', 'default project for openstack') DEFINE_string('default_image', 'ami-11111', diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 9462bd40b..c48cc5179 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -239,6 +239,36 @@ class ServersTest(test.TestCase): servers = json.loads(res.body)['servers'] self.assertEqual([s['id'] for s in servers], [1, 2]) + def test_get_servers_with_bad_limit(self): + req = webob.Request.blank('/v1.0/servers?limit=asdf&offset=1') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 400) + self.assertTrue(res.body.find('limit param') > -1) + + def test_get_servers_with_bad_offset(self): + req = webob.Request.blank('/v1.0/servers?limit=2&offset=asdf') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 400) + self.assertTrue(res.body.find('offset param') > -1) + + def test_get_servers_with_marker(self): + req = webob.Request.blank('/v1.1/servers?marker=2') + res = req.get_response(fakes.wsgi_app()) + servers = json.loads(res.body)['servers'] + self.assertEqual([s['id'] for s in servers], [3, 4]) + + def test_get_servers_with_limit_and_marker(self): + req = webob.Request.blank('/v1.1/servers?limit=2&marker=1') + res = req.get_response(fakes.wsgi_app()) + servers = json.loads(res.body)['servers'] + self.assertEqual([s['id'] for s in servers], [2, 3]) + + def test_get_servers_with_bad_marker(self): + req = webob.Request.blank('/v1.1/servers?limit=2&marker=asdf') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 400) + self.assertTrue(res.body.find('marker param') > -1) + def _setup_for_create_instance(self): """Shared implementation for tests below that create instance""" def instance_create(context, inst): |
