diff options
author | Jenkins <jenkins@review.openstack.org> | 2013-07-30 17:31:06 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2013-07-30 17:31:06 +0000 |
commit | e34dc38a703334edb88e18a0b838df159a79c10a (patch) | |
tree | 2ea37b45e6ad5a7c5df76e4dfe68c68b30fccb03 | |
parent | fd0e1175795ac3a5497dcf72ed250077abaf2ed1 (diff) | |
parent | 12feedb2cfe087f7126f250850f35ebb1cf3de7a (diff) | |
download | python-glanceclient-e34dc38a703334edb88e18a0b838df159a79c10a.tar.gz |
Merge "Add v1 client side owner based filtering"
-rw-r--r-- | glanceclient/v1/images.py | 33 | ||||
-rw-r--r-- | glanceclient/v1/shell.py | 8 | ||||
-rw-r--r-- | tests/v1/test_images.py | 122 |
3 files changed, 157 insertions, 6 deletions
diff --git a/glanceclient/v1/images.py b/glanceclient/v1/images.py index c96d5fa..abde32f 100644 --- a/glanceclient/v1/images.py +++ b/glanceclient/v1/images.py @@ -142,24 +142,42 @@ class ImageManager(base.Manager): list than that represented by this image id :param filters: dict of direct comparison filters that mimics the structure of an image object + :param owner: If provided, only images with this owner (tenant id) + will be listed. An empty string ('') matches ownerless + images. :rtype: list of :class:`Image` """ absolute_limit = kwargs.get('limit') def paginate(qp, seen=0): - # Note(flaper87) Url encoding should - # be moved inside http utils, at least - # shouldn't be here. - # - # Making sure all params are str before - # trying to encode them + def filter_owner(owner, image): + # If client side owner 'filter' is specified + # only return images that match 'owner'. + if owner is None: + # Do not filter based on owner + return False + if (not hasattr(image, 'owner')) or image.owner is None: + # ownerless image + return not (owner == '') + else: + return not (image.owner == owner) + + owner = qp.pop('owner', None) for param, value in qp.iteritems(): if isinstance(value, basestring): + # Note(flaper87) Url encoding should + # be moved inside http utils, at least + # shouldn't be here. + # + # Making sure all params are str before + # trying to encode them qp[param] = strutils.safe_encode(value) url = '/v1/images/detail?%s' % urllib.urlencode(qp) images = self._list(url, "images") for image in images: + if filter_owner(owner, image): + continue seen += 1 if absolute_limit is not None and seen > absolute_limit: return @@ -198,6 +216,9 @@ class ImageManager(base.Manager): for key, value in properties.items(): params['property-%s' % key] = value params.update(filters) + if kwargs.get('owner') is not None: + params['owner'] = kwargs['owner'] + params['is_public'] = None return paginate(params) diff --git a/glanceclient/v1/shell.py b/glanceclient/v1/shell.py index 71882aa..946bb80 100644 --- a/glanceclient/v1/shell.py +++ b/glanceclient/v1/shell.py @@ -66,6 +66,13 @@ DISK_FORMATS = ('Acceptable formats: ami, ari, aki, vhd, vmdk, raw, ' @utils.arg('--is-public', type=utils.string_to_bool, metavar='{True|False}', help=('Allows the user to select a listing of public or non ' 'public images.')) +@utils.arg('--owner', default=None, metavar='<TENANT_ID>', + help='Display only images owned by this tenant id. Filtering ' + 'occurs on the client side so may be inefficient. This option ' + 'is mainly intended for admin use. Use an empty string (\'\') ' + 'to list images with no owner. Note: This option overrides ' + 'the --is-public argument if present. Note: the v2 API ' + 'supports more efficient server-side owner based filtering.') def do_image_list(gc, args): """List images you can access.""" filter_keys = ['name', 'status', 'container_format', 'disk_format', @@ -83,6 +90,7 @@ def do_image_list(gc, args): kwargs['sort_key'] = args.sort_key kwargs['sort_dir'] = args.sort_dir + kwargs['owner'] = args.owner images = gc.images.list(**kwargs) diff --git a/tests/v1/test_images.py b/tests/v1/test_images.py index 9b93639..7758f13 100644 --- a/tests/v1/test_images.py +++ b/tests/v1/test_images.py @@ -68,6 +68,90 @@ fixtures = { ]}, ), }, + '/v1/images/detail?is_public=None&limit=20': { + 'GET': ( + {}, + {'images': [ + { + 'id': 'a', + 'owner': 'A', + 'name': 'image-1', + 'properties': {'arch': 'x86_64'}, + }, + { + 'id': 'b', + 'owner': 'B', + 'name': 'image-2', + 'properties': {'arch': 'x86_64'}, + }, + { + 'id': 'c', + 'name': 'image-3', + 'properties': {'arch': 'x86_64'}, + }, + ]}, + ), + }, + '/v1/images/detail?is_public=None&limit=5': { + 'GET': ( + {}, + {'images': [ + { + 'id': 'a', + 'owner': 'A', + 'name': 'image-1', + 'properties': {'arch': 'x86_64'}, + }, + { + 'id': 'b', + 'owner': 'B', + 'name': 'image-2', + 'properties': {'arch': 'x86_64'}, + }, + { + 'id': 'b2', + 'owner': 'B', + 'name': 'image-3', + 'properties': {'arch': 'x86_64'}, + }, + { + 'id': 'c', + 'name': 'image-3', + 'properties': {'arch': 'x86_64'}, + }, + ]}, + ), + }, + '/v1/images/detail?limit=5': { + 'GET': ( + {}, + {'images': [ + { + 'id': 'a', + 'owner': 'A', + 'name': 'image-1', + 'properties': {'arch': 'x86_64'}, + }, + { + 'id': 'b', + 'owner': 'B', + 'name': 'image-2', + 'properties': {'arch': 'x86_64'}, + }, + { + 'id': 'b2', + 'owner': 'B', + 'name': 'image-3', + 'properties': {'arch': 'x86_64'}, + }, + { + 'id': 'c', + 'name': 'image-3', + 'properties': {'arch': 'x86_64'}, + }, + ]}, + ), + }, '/v1/images/detail?marker=a&limit=%d' % images.DEFAULT_PAGE_SIZE: { 'GET': ( {}, @@ -501,6 +585,44 @@ class ImageManagerTest(testtools.TestCase): headers = self.mgr._image_meta_from_headers(fields) self.assertEqual(headers["name"], u"ni\xf1o") + def test_image_list_with_owner(self): + images = self.mgr.list(owner='A', page_size=20) + image_list = list(images) + self.assertEqual(image_list[0].owner, 'A') + self.assertEqual(image_list[0].id, 'a') + self.assertEqual(len(image_list), 1) + + def test_image_list_with_notfound_owner(self): + images = self.mgr.list(owner='X', page_size=20) + self.assertEqual(len(list(images)), 0) + + def test_image_list_with_empty_string_owner(self): + images = self.mgr.list(owner='', page_size=20) + image_list = list(images) + self.assertRaises(AttributeError, lambda: image_list[0].owner) + self.assertEqual(image_list[0].id, 'c') + self.assertEqual(len(image_list), 1) + + def test_image_list_with_unspecified_owner(self): + images = self.mgr.list(owner=None, page_size=5) + image_list = list(images) + self.assertEqual(image_list[0].owner, 'A') + self.assertEqual(image_list[0].id, 'a') + self.assertEqual(image_list[1].owner, 'B') + self.assertEqual(image_list[1].id, 'b') + self.assertEqual(image_list[2].owner, 'B') + self.assertEqual(image_list[2].id, 'b2') + self.assertRaises(AttributeError, lambda: image_list[3].owner) + self.assertEqual(image_list[3].id, 'c') + self.assertEqual(len(image_list), 4) + + def test_image_list_with_owner_and_limit(self): + images = self.mgr.list(owner='B', page_size=5, limit=1) + image_list = list(images) + self.assertEqual(image_list[0].owner, 'B') + self.assertEqual(image_list[0].id, 'b') + self.assertEqual(len(image_list), 1) + class ImageTest(testtools.TestCase): def setUp(self): |