summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFei Long Wang <flwang@cn.ibm.com>2013-08-11 11:02:32 +0800
committerFei Long Wang <flwang@cn.ibm.com>2013-08-28 14:13:27 +0800
commit897ae3d795423a0f1d92f0738ad4dff99c28c6de (patch)
treef10072da8d30024e3794e76b0b04a3509ef3a659
parentb6e117f151e6d3ed8dc4849c4138d7fb28652e75 (diff)
downloadpython-glanceclient-897ae3d795423a0f1d92f0738ad4dff99c28c6de.tar.gz
Enable query image by tag
This patch will enable Glance client to query images by user defined tags. Implement bp image-query-by-tag Implement bp glance-client-v2 Change-Id: I6f54630c5b7c9c567d85485ad4289284e5486814
-rw-r--r--glanceclient/v2/images.py10
-rw-r--r--glanceclient/v2/shell.py4
-rw-r--r--tests/v2/test_images.py77
-rw-r--r--tests/v2/test_shell_v2.py2
4 files changed, 92 insertions, 1 deletions
diff --git a/glanceclient/v2/images.py b/glanceclient/v2/images.py
index 2f59db9..76c185d 100644
--- a/glanceclient/v2/images.py
+++ b/glanceclient/v2/images.py
@@ -52,12 +52,22 @@ class Controller(object):
else:
filters['limit'] = kwargs['page_size']
+ tags = filters.pop('tag', [])
+ tags_url_params = []
+
+ for tag in tags:
+ if isinstance(tag, basestring):
+ tags_url_params.append({'tag': strutils.safe_encode(tag)})
+
for param, value in filters.iteritems():
if isinstance(value, basestring):
filters[param] = strutils.safe_encode(value)
url = '/v2/images?%s' % urllib.urlencode(filters)
+ for param in tags_url_params:
+ url = '%s&%s' % (url, urllib.urlencode(param))
+
for image in paginate(url):
#NOTE(bcwaldon): remove 'self' for now until we have an elegant
# way to pass it into the model constructor without conflict
diff --git a/glanceclient/v2/shell.py b/glanceclient/v2/shell.py
index 87705ba..f601f38 100644
--- a/glanceclient/v2/shell.py
+++ b/glanceclient/v2/shell.py
@@ -28,9 +28,11 @@ from glanceclient import exc
help='Display images owned by <OWNER>.')
@utils.arg('--checksum', metavar='<CHECKSUM>',
help='Display images matching the checksum')
+@utils.arg('--tag', metavar='<TAG>', action='append',
+ help="Filter images by an user-defined tag.")
def do_image_list(gc, args):
"""List images you can access."""
- filter_keys = ['visibility', 'member_status', 'owner', 'checksum']
+ filter_keys = ['visibility', 'member_status', 'owner', 'checksum', 'tag']
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])
diff --git a/tests/v2/test_images.py b/tests/v2/test_images.py
index cd1eb6c..c19c95f 100644
--- a/tests/v2/test_images.py
+++ b/tests/v2/test_images.py
@@ -24,6 +24,9 @@ from tests import utils
_CHKSUM = '93264c3edf5972c9f1cb309543d38a5c'
_CHKSUM1 = '54264c3edf5972c9f1cb309453d38a46'
+_TAG1 = 'power'
+_TAG2 = '64bit'
+
_BOGUS_ID = '63e7f218-29de-4477-abdc-8db7c9533188'
_EVERYTHING_ID = '802cbbb7-0379-4c38-853f-37302b5e3d29'
_OWNED_IMAGE_ID = 'a4963502-acc7-42ba-ad60-5aa0962b7faf'
@@ -254,6 +257,51 @@ fixtures = {
{'images': []},
),
},
+ '/v2/images?limit=%d&tag=%s' % (images.DEFAULT_PAGE_SIZE, _TAG1): {
+ 'GET': (
+ {},
+ {'images': [
+ {
+ 'id': '3a4560a1-e585-443e-9b39-553b46ec92d1',
+ 'name': 'image-1',
+ }
+ ]},
+ ),
+ },
+ '/v2/images?limit=%d&tag=%s' % (images.DEFAULT_PAGE_SIZE, _TAG2): {
+ 'GET': (
+ {},
+ {'images': [
+ {
+ 'id': '2a4560b2-e585-443e-9b39-553b46ec92d1',
+ 'name': 'image-1',
+ },
+ {
+ 'id': '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810',
+ 'name': 'image-2',
+ },
+ ]},
+ ),
+ },
+ '/v2/images?limit=%d&tag=%s&tag=%s' % (images.DEFAULT_PAGE_SIZE,
+ _TAG1, _TAG2):
+ {
+ 'GET': (
+ {},
+ {'images': [
+ {
+ 'id': '2a4560b2-e585-443e-9b39-553b46ec92d1',
+ 'name': 'image-1',
+ }
+ ]},
+ ),
+ },
+ '/v2/images?limit=%d&tag=fake' % images.DEFAULT_PAGE_SIZE: {
+ 'GET': (
+ {},
+ {'images': []},
+ ),
+ },
}
@@ -358,6 +406,35 @@ class TestController(testtools.TestCase):
self.assertEqual(filters["owner"], "ni\xc3\xb1o")
+ def test_list_images_for_tag_single_image(self):
+ img_id = '3a4560a1-e585-443e-9b39-553b46ec92d1'
+ filters = {'filters': dict([('tag', [_TAG1])])}
+ images = list(self.controller.list(**filters))
+ self.assertEquals(1, len(images))
+ self.assertEqual(images[0].id, '%s' % img_id)
+ pass
+
+ def test_list_images_for_tag_multiple_images(self):
+ img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
+ img_id2 = '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810'
+ filters = {'filters': dict([('tag', [_TAG2])])}
+ images = list(self.controller.list(**filters))
+ self.assertEquals(2, len(images))
+ self.assertEqual(images[0].id, '%s' % img_id1)
+ self.assertEqual(images[1].id, '%s' % img_id2)
+
+ def test_list_images_for_multi_tags(self):
+ img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
+ filters = {'filters': dict([('tag', [_TAG1, _TAG2])])}
+ images = list(self.controller.list(**filters))
+ self.assertEquals(1, len(images))
+ self.assertEqual(images[0].id, '%s' % img_id1)
+
+ def test_list_images_for_non_existent_tag(self):
+ filters = {'filters': dict([('tag', ['fake'])])}
+ images = list(self.controller.list(**filters))
+ self.assertEquals(0, len(images))
+
def test_get_image(self):
image = self.controller.get('3a4560a1-e585-443e-9b39-553b46ec92d1')
self.assertEqual(image.id, '3a4560a1-e585-443e-9b39-553b46ec92d1')
diff --git a/tests/v2/test_shell_v2.py b/tests/v2/test_shell_v2.py
index d4ef1a2..2f8ae91 100644
--- a/tests/v2/test_shell_v2.py
+++ b/tests/v2/test_shell_v2.py
@@ -70,6 +70,7 @@ class ShellV2Test(testtools.TestCase):
'member_status': 'Fake',
'owner': 'test',
'checksum': 'fake_checksum',
+ 'tag': 'fake tag'
}
args = self._make_args(input)
with mock.patch.object(self.gc.images, 'list') as mocked_list:
@@ -82,6 +83,7 @@ class ShellV2Test(testtools.TestCase):
'member_status': 'Fake',
'visibility': True,
'checksum': 'fake_checksum',
+ 'tag': 'fake tag'
}
mocked_list.assert_called_once_with(page_size=18,
filters=exp_img_filters)