adding custom property api filtering

This commit is contained in:
Brian Waldon
2011-05-15 22:16:49 -04:00
parent 259d853bf2
commit fb501c4599
7 changed files with 115 additions and 42 deletions

View File

@@ -130,8 +130,8 @@ class Controller(wsgi.Controller):
"""
filters = {}
for param in SUPPORTED_FILTERS:
if param in req.str_params:
for param in req.str_params:
if param in SUPPORTED_FILTERS or param.startswith('property-'):
filters[param] = req.str_params.get(param)
return filters

View File

@@ -172,9 +172,28 @@ def image_get_filtered(context, filters):
del filters['size_max']
for (k, v) in filters.items():
query = query.filter(getattr(models.Image, k) == v)
if not k.startswith('property-'):
query = query.filter(getattr(models.Image, k) == v)
return query.all()
images = query.all()
#TODO(bcwaldon): use an actual sqlalchemy query to accomplish this
def prop_filter(key, value):
def func(image):
for prop in image.properties:
if prop.deleted == False and \
prop.name == key and \
prop.value == value:
return True
return False
return func
for (k, v) in filters.items():
if k.startswith('property-'):
_k = k[9:]
images = filter(prop_filter(_k, v), images)
return images
def _drop_protected_attrs(model_class, values):

View File

@@ -102,8 +102,8 @@ class Controller(wsgi.Controller):
"""
filters = {}
for param in SUPPORTED_FILTERS:
if param in req.str_params:
for param in req.str_params:
if param in SUPPORTED_FILTERS or param.startswith('property-'):
filters[param] = req.str_params.get(param)
return filters

View File

@@ -816,6 +816,7 @@ class TestCurlApi(functional.FunctionalTest):
"-H 'X-Image-Meta-Disk-Format: vdi' "
"-H 'X-Image-Meta-Size: 19' "
"-H 'X-Image-Meta-Is-Public: True' "
"-H 'X-Image-Meta-Property-pants: are on' "
"http://0.0.0.0:%d/v1/images") % api_port
exitcode, out, err = execute(cmd)
@@ -834,6 +835,7 @@ class TestCurlApi(functional.FunctionalTest):
"-H 'X-Image-Meta-Disk-Format: vhd' "
"-H 'X-Image-Meta-Size: 20' "
"-H 'X-Image-Meta-Is-Public: True' "
"-H 'X-Image-Meta-Property-pants: are on' "
"http://0.0.0.0:%d/v1/images") % api_port
exitcode, out, err = execute(cmd)
@@ -851,6 +853,7 @@ class TestCurlApi(functional.FunctionalTest):
"-H 'X-Image-Meta-Disk-Format: ami' "
"-H 'X-Image-Meta-Size: 21' "
"-H 'X-Image-Meta-Is-Public: True' "
"-H 'X-Image-Meta-Property-pants: are off' "
"http://0.0.0.0:%d/v1/images") % api_port
exitcode, out, err = execute(cmd)
@@ -964,3 +967,17 @@ class TestCurlApi(functional.FunctionalTest):
self.assertEqual(len(images["images"]), 2)
for image in images["images"]:
self.assertTrue(image["size"] >= 20)
# 9. GET /images with property filter
# Verify correct images returned with property
cmd = ("curl http://0.0.0.0:%d/v1/images/detail?"
"property-pants=are%%20on" % api_port)
exitcode, out, err = execute(cmd)
self.assertEqual(0, exitcode)
images = json.loads(out.strip())
self.assertEqual(len(images["images"]), 2)
for image in images["images"]:
self.assertEqual(image["properties"]["pants"], "are on")

View File

@@ -401,8 +401,20 @@ def stub_out_registry_db_image_api(stubs):
size_max = int(filters.pop('size_max'))
images = [f for f in images if int(f['size']) <= size_max]
def _prop_filter(key, value):
def _func(image):
for prop in image['properties']:
if prop['name'] == key:
return prop['value'] == value
return False
return _func
for k, v in filters.items():
images = [f for f in images if f[k] == v]
if k.startswith('property-'):
_k = k[9:]
images = filter(_prop_filter(_k, v), images)
else:
images = [f for f in images if f[k] == v]
return images

View File

@@ -162,11 +162,6 @@ class TestRegistryAPI(unittest.TestCase):
public images that have a specific name
"""
fixture = {'id': 2,
'name': 'fake image #2',
'size': 19,
'checksum': None}
extra_fixture = {'id': 3,
'status': 'active',
'is_public': True,
@@ -205,11 +200,6 @@ class TestRegistryAPI(unittest.TestCase):
public images that have a specific status
"""
fixture = {'id': 2,
'name': 'fake image #2',
'size': 19,
'checksum': None}
extra_fixture = {'id': 3,
'status': 'saving',
'is_public': True,
@@ -248,11 +238,6 @@ class TestRegistryAPI(unittest.TestCase):
public images that have a specific container_format
"""
fixture = {'id': 2,
'name': 'fake image #2',
'size': 19,
'checksum': None}
extra_fixture = {'id': 3,
'status': 'active',
'is_public': True,
@@ -291,11 +276,6 @@ class TestRegistryAPI(unittest.TestCase):
public images that have a specific disk_format
"""
fixture = {'id': 2,
'name': 'fake image #2',
'size': 19,
'checksum': None}
extra_fixture = {'id': 3,
'status': 'active',
'is_public': True,
@@ -334,11 +314,6 @@ class TestRegistryAPI(unittest.TestCase):
public images that have a size greater than or equal to size_min
"""
fixture = {'id': 2,
'name': 'fake image #2',
'size': 19,
'checksum': None}
extra_fixture = {'id': 3,
'status': 'active',
'is_public': True,
@@ -377,11 +352,6 @@ class TestRegistryAPI(unittest.TestCase):
public images that have a size less than or equal to size_max
"""
fixture = {'id': 2,
'name': 'fake image #2',
'size': 19,
'checksum': None}
extra_fixture = {'id': 3,
'status': 'active',
'is_public': True,
@@ -421,11 +391,6 @@ class TestRegistryAPI(unittest.TestCase):
and greater than or equal to size_min
"""
fixture = {'id': 2,
'name': 'fake image #2',
'size': 19,
'checksum': None}
extra_fixture = {'id': 3,
'status': 'active',
'is_public': True,
@@ -470,6 +435,46 @@ class TestRegistryAPI(unittest.TestCase):
for image in images:
self.assertTrue(image['size'] <= 19 and image['size'] >= 18)
def test_get_details_filter_property(self):
"""Tests that the /images/detail registry API returns list of
public images that have a specific custom property
"""
extra_fixture = {'id': 3,
'status': 'active',
'is_public': True,
'disk_format': 'vhd',
'container_format': 'ovf',
'name': 'fake image #3',
'size': 19,
'checksum': None,
'properties': {'prop_123': 'v a'}}
glance.registry.db.api.image_create(None, extra_fixture)
extra_fixture = {'id': 4,
'status': 'active',
'is_public': True,
'disk_format': 'ami',
'container_format': 'ami',
'name': 'fake image #4',
'size': 19,
'checksum': None,
'properties': {'prop_123': 'v b'}}
glance.registry.db.api.image_create(None, extra_fixture)
req = webob.Request.blank('/images/detail?property-prop_123=v%20a')
res = req.get_response(self.api)
res_dict = json.loads(res.body)
self.assertEquals(res.status_int, 200)
images = res_dict['images']
self.assertEquals(len(images), 1)
for image in images:
self.assertEqual('v a', image['properties']['prop_123'])
def test_create_image(self):
"""Tests that the /images POST registry API creates the image"""
fixture = {'name': 'fake public image',

View File

@@ -222,6 +222,26 @@ class TestRegistryClient(unittest.TestCase):
for image in images:
self.assertTrue(image['size'] >= 20)
def test_get_image_details_by_property(self):
"""Tests that a detailed call can be filtered by a property"""
extra_fixture = {'id': 3,
'status': 'saving',
'is_public': True,
'disk_format': 'vhd',
'container_format': 'ovf',
'name': 'new name! #123',
'size': 19,
'checksum': None,
'properties': {'p a': 'v a'}}
glance.registry.db.api.image_create(None, extra_fixture)
images = self.client.get_images_detailed({'property-p a': 'v a'})
self.assertEquals(len(images), 1)
for image in images:
self.assertEquals('v a', image['properties']['p a'])
def test_get_image(self):
"""Tests that the detailed info about an image returned"""
fixture = {'id': 1,