Add filter validation to glance API

Fixes lp: #919250

Change-Id: Ib47d9d107950f14404734b55486996dc0b095f0e
This commit is contained in:
Christopher MacGown 2012-02-02 12:10:18 -08:00
parent 7c2e32511a
commit 3092156ae5
5 changed files with 98 additions and 5 deletions

View File

@ -12,3 +12,4 @@
<soren.hansen@rackspace.com> <soren@openstack.org>
<jeblair@hp.com> <corvus@gnu.org>
<jeblair@hp.com> <james.blair@rackspace.com>
<chris@pistoncloud.com> <chris@slicehost.com>

View File

@ -4,7 +4,7 @@ Andrey Brindeyev <abrindeyev@griddynamics.com>
Brian Lamar <brian.lamar@rackspace.com>
Brian Waldon <brian.waldon@rackspace.com>
Chris Behrens <cbehrens@codestud.com>
Christopher MacGown <chris@slicehost.com>
Christopher MacGown <chris@pistoncloud.com>
Cory Wright <corywright@gmail.com>
Dan Prince <dan.prince@rackspace.com>
Donal Lafferty <donal.lafferty@citrix.com>

42
glance/api/v1/filters.py Normal file
View File

@ -0,0 +1,42 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012, Piston Cloud Computing, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
def validate(filter, value):
return FILTER_FUNCTIONS.get(filter, lambda v: True)(value)
def validate_int_in_range(min=0, max=None):
def _validator(v):
try:
if max is None:
return min <= int(v)
return min <= int(v) <= max
except ValueError:
return False
return _validator
def validate_boolean(v):
return v.lower() in ('none', 'true', 'false', '1', '0')
FILTER_FUNCTIONS = {'size_max': validate_int_in_range(), # build validator
'size_min': validate_int_in_range(), # build validator
'min_ram': validate_int_in_range(), # build validator
'protected': validate_boolean,
'is_public': validate_boolean, }

View File

@ -35,6 +35,7 @@ from webob.exc import (HTTPError,
from glance.api import policy
import glance.api.v1
from glance.api.v1 import controller
from glance.api.v1 import filters
from glance.common import cfg
from glance.common import exception
from glance.common import wsgi
@ -182,6 +183,7 @@ class Controller(controller.BaseController):
:retval dict of parameters that can be used by registry client
"""
params = {'filters': self._get_filters(req)}
for PARAM in SUPPORTED_PARAMS:
if PARAM in req.str_params:
params[PARAM] = req.str_params.get(PARAM)
@ -194,12 +196,15 @@ class Controller(controller.BaseController):
:param req: the Request object coming from the wsgi layer
:retval a dict of key/value filters
"""
filters = {}
query_filters = {}
for param in req.str_params:
if param in SUPPORTED_FILTERS or param.startswith('property-'):
filters[param] = req.str_params.get(param)
return filters
query_filters[param] = req.str_params.get(param)
if not filters.validate(param, query_filters[param]):
raise HTTPBadRequest('Bad value passed to filter %s '
'got %s' % (param,
query_filters[param]))
return query_filters
def meta(self, req, id):
"""

View File

@ -925,6 +925,51 @@ class TestApi(functional.FunctionalTest):
data = json.loads(content)
self.assertEqual(len(data['images']), 0)
# 18. GET /images with size_min filter
# Verify correct images returned with size >= expected
params = "size_min=-1"
path = "http://%s:%d/v1/images?%s" % (
"0.0.0.0", self.api_port, params)
response, content = http.request(path, 'GET')
self.assertEqual(response.status, 400)
self.assertTrue("filter size_min got -1" in content)
# 19. GET /images with size_min filter
# Verify correct images returned with size >= expected
params = "size_max=-1"
path = "http://%s:%d/v1/images?%s" % (
"0.0.0.0", self.api_port, params)
response, content = http.request(path, 'GET')
self.assertEqual(response.status, 400)
self.assertTrue("filter size_max got -1" in content)
# 20. GET /images with size_min filter
# Verify correct images returned with size >= expected
params = "min_ram=-1"
path = "http://%s:%d/v1/images?%s" % (
"0.0.0.0", self.api_port, params)
response, content = http.request(path, 'GET')
self.assertEqual(response.status, 400)
self.assertTrue("Bad value passed to filter min_ram got -1" in content)
# 21. GET /images with size_min filter
# Verify correct images returned with size >= expected
params = "protected=imalittleteapot"
path = "http://%s:%d/v1/images?%s" % (
"0.0.0.0", self.api_port, params)
response, content = http.request(path, 'GET')
self.assertEqual(response.status, 400)
self.assertTrue("protected got imalittleteapot" in content)
# 22. GET /images with size_min filter
# Verify correct images returned with size >= expected
params = "is_public=imalittleteapot"
path = "http://%s:%d/v1/images?%s" % (
"0.0.0.0", self.api_port, params)
response, content = http.request(path, 'GET')
self.assertEqual(response.status, 400)
self.assertTrue("is_public got imalittleteapot" in content)
self.stop_servers()
@skip_if_disabled