diff --git a/glanceclient/v2/images.py b/glanceclient/v2/images.py index cc19ec88..0b9cf451 100644 --- a/glanceclient/v2/images.py +++ b/glanceclient/v2/images.py @@ -13,6 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. +import urllib + from glanceclient.common import utils DEFAULT_PAGE_SIZE = 20 @@ -23,7 +25,7 @@ class Controller(object): self.http_client = http_client self.model = model - def list(self, page_size=DEFAULT_PAGE_SIZE): + def list(self, **kwargs): """Retrieve a listing of Image objects :param page_size: Number of images to request in each paginated request @@ -41,7 +43,18 @@ class Controller(object): for image in paginate(next_url): yield image - url = '/v2/images?limit=%s' % page_size + filters = kwargs.get('filters', {}) + + if not kwargs.get('page_size'): + filters['limit'] = DEFAULT_PAGE_SIZE + else: + filters['limit'] = kwargs['page_size'] + + for param, value in filters.iteritems(): + if isinstance(value, basestring): + filters[param] = utils.ensure_str(value) + + url = '/v2/images?%s' % urllib.urlencode(filters) for image in paginate(url): #NOTE(bcwaldon): remove 'self' for now until we have an elegant diff --git a/glanceclient/v2/shell.py b/glanceclient/v2/shell.py index 12bef8c0..93e633a9 100644 --- a/glanceclient/v2/shell.py +++ b/glanceclient/v2/shell.py @@ -19,11 +19,22 @@ from glanceclient import exc @utils.arg('--page-size', metavar='', default=None, type=int, help='Number of images to request in each paginated request.') +@utils.arg('--visibility', metavar='', + help='The visibility of the images to display.') +@utils.arg('--member-status', metavar='', + help='The status of images to display.') +@utils.arg('--owner', metavar='', + help='Display images owned by .') def do_image_list(gc, args): """List images you can access.""" - kwargs = {} + filter_keys = ['visibility', 'member_status', 'owner'] + filter_items = [(key, getattr(args, key)) for key in filter_keys] + filters = dict([item for item in filter_items if item[1] is not None]) + + kwargs = {'filters': filters} if args.page_size is not None: kwargs['page_size'] = args.page_size + images = gc.images.list(**kwargs) columns = ['ID', 'Name'] utils.print_list(images, columns) diff --git a/tests/v2/test_images.py b/tests/v2/test_images.py index 766951a0..ea2a63e1 100644 --- a/tests/v2/test_images.py +++ b/tests/v2/test_images.py @@ -1,4 +1,4 @@ -# Copyright 2012 OpenStack LLC. +# Copyright 2012 OpenStack Foundation. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -21,9 +21,17 @@ import warlock from glanceclient.v2 import images from tests import utils +_BOGUS_ID = '63e7f218-29de-4477-abdc-8db7c9533188' +_EVERYTHING_ID = '802cbbb7-0379-4c38-853f-37302b5e3d29' +_OWNED_IMAGE_ID = 'a4963502-acc7-42ba-ad60-5aa0962b7faf' +_OWNER_ID = '6bd473f0-79ae-40ad-a927-e07ec37b642f' +_PRIVATE_ID = 'e33560a7-3964-4de5-8339-5a24559f99ab' +_PUBLIC_ID = '857806e7-05b6-48e0-9d40-cb0e6fb727b9' +_SHARED_ID = '331ac905-2a38-44c5-a83d-653db8f08313' +_STATUS_REJECTED_ID = 'f3ea56ff-d7e4-4451-998c-1e3d33539c8e' fixtures = { - '/v2/images?limit=20': { + '/v2/images?limit=%d' % images.DEFAULT_PAGE_SIZE: { 'GET': ( {}, {'images': [ @@ -107,6 +115,80 @@ fixtures = { 'CCC', ), }, + '/v2/images?limit=%d&visibility=public' % images.DEFAULT_PAGE_SIZE: { + 'GET': ( + {}, + {'images': [ + { + 'id': _PUBLIC_ID, + 'harvey': 'lipshitz', + }, + ]}, + ), + }, + '/v2/images?limit=%d&visibility=private' % images.DEFAULT_PAGE_SIZE: { + 'GET': ( + {}, + {'images': [ + { + 'id': _PRIVATE_ID, + }, + ]}, + ), + }, + '/v2/images?limit=%d&visibility=shared' % images.DEFAULT_PAGE_SIZE: { + 'GET': ( + {}, + {'images': [ + { + 'id': _SHARED_ID, + }, + ]}, + ), + }, + '/v2/images?limit=%d&member_status=rejected' % images.DEFAULT_PAGE_SIZE: { + 'GET': ( + {}, + {'images': [ + { + 'id': _STATUS_REJECTED_ID, + }, + ]}, + ), + }, + '/v2/images?limit=%d&member_status=pending' % images.DEFAULT_PAGE_SIZE: { + 'GET': ( + {}, + {'images': []}, + ), + }, + '/v2/images?owner=%s&limit=%d' % (_OWNER_ID, images.DEFAULT_PAGE_SIZE): { + 'GET': ( + {}, + {'images': [ + { + 'id': _OWNED_IMAGE_ID, + }, + ]}, + ), + }, + '/v2/images?owner=%s&limit=%d' % (_BOGUS_ID, images.DEFAULT_PAGE_SIZE): { + 'GET': ( + {}, + {'images': []}, + ), + }, + '/v2/images?owner=%s&limit=%d&member_status=pending&visibility=shared' + % (_BOGUS_ID, images.DEFAULT_PAGE_SIZE): { + 'GET': ( + {}, + {'images': [ + { + 'id': _EVERYTHING_ID, + }, + ]}, + ), + }, } @@ -136,6 +218,43 @@ class TestController(testtools.TestCase): self.assertEqual(images[1].id, '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810') self.assertEqual(images[1].name, 'image-2') + def test_list_images_visibility_public(self): + filters = {'filters': dict([('visibility', 'public')])} + images = list(self.controller.list(**filters)) + self.assertEqual(images[0].id, _PUBLIC_ID) + + def test_list_images_visibility_private(self): + filters = {'filters': dict([('visibility', 'private')])} + images = list(self.controller.list(**filters)) + self.assertEqual(images[0].id, _PRIVATE_ID) + + def test_list_images_visibility_shared(self): + filters = {'filters': dict([('visibility', 'shared')])} + images = list(self.controller.list(**filters)) + self.assertEqual(images[0].id, _SHARED_ID) + + def test_list_images_member_status_rejected(self): + filters = {'filters': dict([('member_status', 'rejected')])} + images = list(self.controller.list(**filters)) + self.assertEqual(images[0].id, _STATUS_REJECTED_ID) + + def test_list_images_for_owner(self): + filters = {'filters': dict([('owner', _OWNER_ID)])} + images = list(self.controller.list(**filters)) + self.assertEqual(images[0].id, _OWNED_IMAGE_ID) + + def test_list_images_for_bogus_owner(self): + filters = {'filters': dict([('owner', _BOGUS_ID)])} + images = list(self.controller.list(**filters)) + self.assertEqual(images, []) + + def test_list_images_for_bunch_of_filters(self): + filters = {'filters': dict([('owner', _BOGUS_ID), + ('visibility', 'shared'), + ('member_status', 'pending')])} + images = list(self.controller.list(**filters)) + self.assertEqual(images[0].id, _EVERYTHING_ID) + def test_get_image(self): image = self.controller.get('3a4560a1-e585-443e-9b39-553b46ec92d1') self.assertEqual(image.id, '3a4560a1-e585-443e-9b39-553b46ec92d1')