From 8477f95d59037b00a8197f8d443c1f5b28d26560 Mon Sep 17 00:00:00 2001 From: wanghao Date: Fri, 20 Jan 2017 11:25:04 +0800 Subject: [PATCH] Add validation of limit value in querying flavors and poolss Now queues and subscriptions have a constraint that limit arg in API must be bigger than 0. But flavor and pool have missed it, so added this validation. Change-Id: I9cc5146b7149adb0f7592eea15ff21e7fb3549f2 Closes-Bug: #1590182 --- .../unit/transport/wsgi/v2_0/test_flavors.py | 8 +++++ .../unit/transport/wsgi/v2_0/test_pools.py | 8 +++++ zaqar/transport/validation.py | 32 +++++++++++++++++++ zaqar/transport/wsgi/v2_0/__init__.py | 6 ++-- zaqar/transport/wsgi/v2_0/flavors.py | 10 +++++- zaqar/transport/wsgi/v2_0/pools.py | 10 +++++- 6 files changed, 70 insertions(+), 4 deletions(-) diff --git a/zaqar/tests/unit/transport/wsgi/v2_0/test_flavors.py b/zaqar/tests/unit/transport/wsgi/v2_0/test_flavors.py index efef8acf5..d1b57c840 100644 --- a/zaqar/tests/unit/transport/wsgi/v2_0/test_flavors.py +++ b/zaqar/tests/unit/transport/wsgi/v2_0/test_flavors.py @@ -325,6 +325,14 @@ class TestFlavorsMongoDB(base.V2Base): path, capabilities = expected[4][:2] self._flavor_expect(flavor_list[0], path, self.doc['pool_group']) + def test_listing_error_with_invalid_limit(self): + self.simulate_delete(self.flavor_path) + query = 'limit={0}&detailed={1}'.format(0, True) + + with flavors(self, 10, self.doc['pool_group']): + self.simulate_get(self.url_prefix + '/flavors', query_string=query) + self.assertEqual(falcon.HTTP_400, self.srmock.status) + def test_queue_create_works(self): metadata = {'_flavor': self.flavor} self.simulate_put(self.queue_path, body=jsonutils.dumps(metadata)) diff --git a/zaqar/tests/unit/transport/wsgi/v2_0/test_pools.py b/zaqar/tests/unit/transport/wsgi/v2_0/test_pools.py index 194bda67b..80a7414c9 100644 --- a/zaqar/tests/unit/transport/wsgi/v2_0/test_pools.py +++ b/zaqar/tests/unit/transport/wsgi/v2_0/test_pools.py @@ -361,3 +361,11 @@ class TestPoolsMongoDB(base.V2Base): self.assertEqual(6, len(pool_list)) path, weight = expected[4][:2] self._pool_expect(pool_list[0], path, weight, self.doc['uri']) + + def test_listing_error_with_invalid_limit(self): + self.simulate_delete(self.pool) + query = 'limit={0}&detailed={1}'.format(0, True) + + with pools(self, 10, self.doc['uri'], 'my-group'): + self.simulate_get(self.url_prefix + '/pools', query_string=query) + self.assertEqual(falcon.HTTP_400, self.srmock.status) diff --git a/zaqar/transport/validation.py b/zaqar/transport/validation.py index db7d01697..cbb002a42 100644 --- a/zaqar/transport/validation.py +++ b/zaqar/transport/validation.py @@ -79,6 +79,12 @@ _TRANSPORT_LIMITS_OPTIONS = ( cfg.ListOpt('subscriber_types', default=['http', 'https', 'mailto', 'trust+http', 'trust+https'], help='Defines supported subscriber types.'), + + cfg.IntOpt('max_flavors_per_page', default=20, + help='Defines the maximum number of flavors per page.'), + + cfg.IntOpt('max_pools_per_page', default=20, + help='Defines the maximum number of pools per page.'), ) _TRANSPORT_LIMITS_GROUP = 'transport' @@ -585,3 +591,29 @@ class Validator(object): :param limit_conf_name: configuration name """ return self._limits_conf[limit_conf_name] + + def flavor_listing(self, limit=None, **kwargs): + """Restrictions involving a list of pools. + + :param limit: The expected number of flavors in the list + :param kwargs: Ignored arguments passed to storage API + :raises: ValidationFailed if the limit is exceeded + """ + + uplimit = self._limits_conf.max_flavors_per_page + if limit is not None and not (0 < limit <= uplimit): + msg = _(u'Limit must be at least 1 and no greater than {0}.') + raise ValidationFailed(msg, self._limits_conf.max_flavors_per_page) + + def pool_listing(self, limit=None, **kwargs): + """Restrictions involving a list of pools. + + :param limit: The expected number of flavors in the list + :param kwargs: Ignored arguments passed to storage API + :raises: ValidationFailed if the limit is exceeded + """ + + uplimit = self._limits_conf.max_pools_per_page + if limit is not None and not (0 < limit <= uplimit): + msg = _(u'Limit must be at least 1 and no greater than {0}.') + raise ValidationFailed(msg, self._limits_conf.max_pools_per_page) diff --git a/zaqar/transport/wsgi/v2_0/__init__.py b/zaqar/transport/wsgi/v2_0/__init__.py index c621ff453..a1604fe41 100644 --- a/zaqar/transport/wsgi/v2_0/__init__.py +++ b/zaqar/transport/wsgi/v2_0/__init__.py @@ -133,14 +133,16 @@ def private_endpoints(driver, conf): if conf.pooling: pools_controller = driver._control.pools_controller flavors_controller = driver._control.flavors_controller + validate = driver._validate catalogue.extend([ ('/pools', - pools.Listing(pools_controller)), + pools.Listing(pools_controller, validate)), ('/pools/{pool}', pools.Resource(pools_controller)), ('/flavors', - flavors.Listing(flavors_controller, pools_controller)), + flavors.Listing(flavors_controller, pools_controller, + validate)), ('/flavors/{flavor}', flavors.Resource(flavors_controller, pools_controller)), ]) diff --git a/zaqar/transport/wsgi/v2_0/flavors.py b/zaqar/transport/wsgi/v2_0/flavors.py index 2da9be119..ffbb3b377 100644 --- a/zaqar/transport/wsgi/v2_0/flavors.py +++ b/zaqar/transport/wsgi/v2_0/flavors.py @@ -25,6 +25,7 @@ from zaqar.i18n import _ from zaqar.storage import errors from zaqar.transport import acl from zaqar.transport import utils as transport_utils +from zaqar.transport import validation from zaqar.transport.wsgi import errors as wsgi_errors from zaqar.transport.wsgi import utils as wsgi_utils @@ -37,9 +38,10 @@ class Listing(object): :param flavors_controller: means to interact with storage """ - def __init__(self, flavors_controller, pools_controller): + def __init__(self, flavors_controller, pools_controller, validate): self._ctrl = flavors_controller self._pools_ctrl = pools_controller + self._validate = validate @decorators.TransportLog("Flavors collection") @acl.enforce("flavors:get_all") @@ -69,6 +71,12 @@ class Listing(object): request.get_param_as_int('limit', store=store) detailed = request.get_param_as_bool('detailed') + try: + self._validate.flavor_listing(**store) + except validation.ValidationFailed as ex: + LOG.debug(ex) + raise wsgi_errors.HTTPBadRequestAPI(six.text_type(ex)) + cursor = self._ctrl.list(project=project_id, **store) flavors = list(next(cursor)) diff --git a/zaqar/transport/wsgi/v2_0/pools.py b/zaqar/transport/wsgi/v2_0/pools.py index 453e30f6e..4799d6c95 100644 --- a/zaqar/transport/wsgi/v2_0/pools.py +++ b/zaqar/transport/wsgi/v2_0/pools.py @@ -49,6 +49,7 @@ from zaqar.storage import errors from zaqar.storage import utils as storage_utils from zaqar.transport import acl from zaqar.transport import utils as transport_utils +from zaqar.transport import validation from zaqar.transport.wsgi import errors as wsgi_errors from zaqar.transport.wsgi import utils as wsgi_utils @@ -61,8 +62,9 @@ class Listing(object): :param pools_controller: means to interact with storage """ - def __init__(self, pools_controller): + def __init__(self, pools_controller, validate): self._ctrl = pools_controller + self._validate = validate @decorators.TransportLog("Pools collection") @acl.enforce("pools:get_all") @@ -91,6 +93,12 @@ class Listing(object): request.get_param_as_int('limit', store=store) request.get_param_as_bool('detailed', store=store) + try: + self._validate.pool_listing(**store) + except validation.ValidationFailed as ex: + LOG.debug(ex) + raise wsgi_errors.HTTPBadRequestAPI(six.text_type(ex)) + cursor = self._ctrl.list(**store) pools = list(next(cursor))