From 97e976f6d2a8baf7a73bdf7f71bfe2362b1ab9f0 Mon Sep 17 00:00:00 2001 From: cooldharma06 Date: Wed, 4 Oct 2017 16:59:47 +0530 Subject: [PATCH] Add image-search support Change-Id: I7555c05ae7cf2298648d1488efc9e539066a7297 Closes-Bug: #1658365 --- setup.cfg | 1 + zunclient/common/base.py | 11 ++++++++++ zunclient/osc/v1/images.py | 29 ++++++++++++++++++++++++++ zunclient/tests/unit/v1/test_images.py | 25 ++++++++++++++++++++++ zunclient/v1/images.py | 18 ++++++++++++++++ zunclient/v1/images_shell.py | 19 +++++++++++++++++ 6 files changed, 103 insertions(+) diff --git a/setup.cfg b/setup.cfg index 32d7faa4..89357731 100644 --- a/setup.cfg +++ b/setup.cfg @@ -62,6 +62,7 @@ openstack.container.v1 = appcontainer_host_show = zunclient.osc.v1.hosts:ShowHost appcontainer_network_detach = zunclient.osc.v1.containers:NetworkDetach appcontainer_network_attach = zunclient.osc.v1.containers:NetworkAttach + appcontainer_image_search = zunclient.osc.v1.images:SearchImage [build_sphinx] source-dir = doc/source diff --git a/zunclient/common/base.py b/zunclient/common/base.py index 27afa68f..7a0343ff 100644 --- a/zunclient/common/base.py +++ b/zunclient/common/base.py @@ -144,6 +144,17 @@ class Manager(object): url = "%s?%s" % (url, urlparse.urlencode(qparams)) self.api.raw_request('DELETE', url) + def _search(self, url, body=None, response_key=None, obj_class=None, + qparams=None): + if qparams: + url = "%s?%s" % (url, urlparse.urlencode(qparams)) + + resp, body = self.api.json_request('SEARCH', url, body=body) + data = self._format_body_data(body, response_key) + if obj_class is None: + obj_class = self.resource_class + return [obj_class(self, res, loaded=True) for res in data if res] + class Resource(base.Resource): """Represents a particular instance of an object (tenant, user, etc). diff --git a/zunclient/osc/v1/images.py b/zunclient/osc/v1/images.py index bedae204..4acd147e 100644 --- a/zunclient/osc/v1/images.py +++ b/zunclient/osc/v1/images.py @@ -90,3 +90,32 @@ class PullImage(command.ShowOne): image = client.images.create(**opts) columns = _image_columns(image) return columns, utils.get_item_properties(image, columns) + + +class SearchImage(command.Lister): + """Search specified image""" + + log = logging.getLogger(__name__ + ".SearchImage") + + def get_parser(self, prog_name): + parser = super(SearchImage, self).get_parser(prog_name) + parser.add_argument( + '--image-driver', + metavar='', + help='Name of the image driver') + parser.add_argument( + 'image_name', + metavar='', + help='Name of the image') + return parser + + def take_action(self, parsed_args): + client = _get_client(self, parsed_args) + opts = {} + opts['image_driver'] = parsed_args.image_driver + opts['image'] = parsed_args.image_name + opts = zun_utils.remove_null_parms(**opts) + images = client.images.search_image(**opts) + columns = ('ID', 'Name', 'Tags', 'Status', 'Size', 'Metadata') + return (columns, (utils.get_item_properties(image, columns) + for image in images)) diff --git a/zunclient/tests/unit/v1/test_images.py b/zunclient/tests/unit/v1/test_images.py index dfac8082..ca2c09e5 100644 --- a/zunclient/tests/unit/v1/test_images.py +++ b/zunclient/tests/unit/v1/test_images.py @@ -29,6 +29,17 @@ IMAGE2 = {'uuid': '1996ba70-b074-454b-a8fc-0895ae26c7c6', 'tag': 'latest', 'size': '1024', } +IMAGE3 = {'uuid': '1267gf34-34e4-tf4b-b84c-1345avf6c7c6', + 'image_id': '24r5tt6y87c6', + 'image': 'fake-name3', + 'tag': 'latest', + 'size': '1024', + 'image_driver': 'fake-driver', + } +SEARCH_IMAGE = {'image': 'fake-name3', + 'image_driver': 'fake-driver', + } + fake_responses = { '/v1/images/': @@ -37,6 +48,10 @@ fake_responses = { {}, {'images': [IMAGE1, IMAGE2]}, ), + 'SEARCH': ( + {}, + {'images': [IMAGE3]}, + ), }, '/v1/images/?limit=2': { @@ -161,3 +176,13 @@ class ImageManagerTest(testtools.TestCase): self._test_image_list_with_filters( sort_key='image_id', sort_dir='desc', expect=expect) + + def test_image_search(self): + images = self.mgr.search_image(**SEARCH_IMAGE) + expect = [ + ('SEARCH', '/v1/images/', {}, + {'image': IMAGE3['image'], + 'image_driver': IMAGE3['image_driver']}), + ] + self.assertEqual(expect, self.api.calls) + self.assertThat(images, matchers.HasLength(1)) diff --git a/zunclient/v1/images.py b/zunclient/v1/images.py index 4f92613d..9dd19959 100644 --- a/zunclient/v1/images.py +++ b/zunclient/v1/images.py @@ -16,6 +16,7 @@ from zunclient import exceptions PULL_ATTRIBUTES = ['repo'] +IMAGE_SEARCH_ATTRIBUTES = ['image', 'image_driver'] class Image(base.Resource): @@ -94,3 +95,20 @@ class ImageManager(base.Manager): raise exceptions.InvalidAttribute( "Key must be in %s" % ','.join(PULL_ATTRIBUTES)) return self._create(self._path(), new) + + def search_image(self, **kwargs): + """Retrieves list of images based on image name and image_driver name + + :returns: A list of images based on the search query + i.e., image_name & image_driver + + """ + image_query = {} + for (key, value) in kwargs.items(): + if key in IMAGE_SEARCH_ATTRIBUTES: + image_query[key] = value + else: + raise exceptions.InvalidAttribute( + "Key must be in %s" % ','.join(IMAGE_SEARCH_ATTRIBUTES)) + path = '' + return self._search(self._path(path), image_query) diff --git a/zunclient/v1/images_shell.py b/zunclient/v1/images_shell.py index c9619dcd..0ce70298 100644 --- a/zunclient/v1/images_shell.py +++ b/zunclient/v1/images_shell.py @@ -57,3 +57,22 @@ def do_image_list(cs, args): utils.print_list(images, columns, {'versions': zun_utils.print_list_field('versions')}, sortby_index=None) + + +@utils.arg('image', + metavar='', + help='Name of the image') +@utils.arg('image_driver', + metavar='', + choices=['glance', 'docker'], + help='Name of the image driver (glance, docker)') +def do_image_search(cs, args): + """Print list of available images from repository based on user query.""" + opts = {} + opts['image'] = args.image + opts['image_driver'] = args.image_driver + images = cs.images.search_image(**opts) + columns = ('ID', 'Name', 'Tags', 'Status', 'Size', 'Metadata') + utils.print_list(images, columns, + {'versions': zun_utils.print_list_field('versions')}, + sortby_index=None)