diff --git a/bin/glance b/bin/glance index db2e63b3bd..3246326343 100755 --- a/bin/glance +++ b/bin/glance @@ -426,7 +426,6 @@ def _images_index(client, filters, limit, print_header=False, **kwargs): if kwarg in kwargs: parameters[kwarg] = kwargs[kwarg] - images = client.get_images(**parameters) if not images: @@ -454,7 +453,6 @@ def _images_index(client, filters, limit, print_header=False, **kwargs): return SUCCESS parameters['marker'] = images[-1]['id'] - print parameters return _images_index(client, **parameters) @@ -485,17 +483,19 @@ fields are treated as image metadata properties""" print_header=True) -def _images_details(client, filters, limit, marker=None, print_header=False): +def _images_details(client, filters, limit, print_header=False, **kwargs): """Driver function for images_details""" - kwargs = { + parameters = { "filters": filters, "limit": limit, } - if marker is not None: - kwargs["marker"] = marker + optional_kwargs = ['marker', 'sort_key', 'sort_dir'] + for kwarg in optional_kwargs: + if kwarg in kwargs: + parameters[kwarg] = kwargs[kwarg] - images = client.get_images_detailed(**kwargs) + images = client.get_images_detailed(**parameters) if len(images) == 0: return SUCCESS @@ -511,8 +511,8 @@ def _images_details(client, filters, limit, marker=None, print_header=False): not user_confirm("Fetch next page?", True): return SUCCESS - next_marker = images[-1]['id'] - return _images_details(client, filters, limit, marker=next_marker) + parameters["marker"] = images[-1]['id'] + return _images_details(client, **parameters) @catch_error('show details') @@ -530,11 +530,15 @@ fields are treated as image metadata properties""" filters = get_image_filters_from_args(args) limit = options.limit marker = options.marker + sort_key = options.sort_key + sort_dir = options.sort_dir return _images_details(client, filters, limit, marker=marker, + sort_key=sort_key, + sort_dir=sort_dir, print_header=True) diff --git a/doc/source/glance.rst b/doc/source/glance.rst index d67d451ef6..5136835fd8 100644 --- a/doc/source/glance.rst +++ b/doc/source/glance.rst @@ -98,6 +98,9 @@ a brief help message, like so:: -p PORT, --port=PORT Port the Glance API host listens on. Default: 9292 --limit=LIMIT Page size to use while requesting image metadata --marker=MARKER Image index after which to begin pagination + --sort_key=KEY Sort results by this image attribute. + --sort_dir=[desc|asc] + Sort results in this direction. -f, --force Prevent select actions from requesting user confirmation --dry-run Don't actually execute the command, just print output @@ -326,6 +329,11 @@ restricted to returning a maximum number of results. Without the 'force' option, the user will be prompted before each page of results is fetched from the API. +Results from index and details commands may be ordered using the 'sort_key' +and 'sort_dir' options. Any image attribute may be used for 'sort_key', +while only 'asc' or 'desc' are allowed for 'sort_dir'. + + The ``details`` command ----------------------- diff --git a/tests/functional/test_bin_glance.py b/tests/functional/test_bin_glance.py index bef8edf90b..8db6fb34d2 100644 --- a/tests/functional/test_bin_glance.py +++ b/tests/functional/test_bin_glance.py @@ -477,9 +477,9 @@ class TestBinGlance(functional.FunctionalTest): _add_cmd = "bin/glance --port=%d add is_public=True" % self.api_port _add_args = [ "name=Name1 disk_format=ami container_format=ami", - "name=Name2 disk_format=vhd container_format=ovf", + "name=Name4 disk_format=vhd container_format=ovf", "name=Name3 disk_format=ami container_format=ami", - "name=Name4 disk_format=ami container_format=ami", + "name=Name2 disk_format=ami container_format=ami", "name=Name5 disk_format=vhd container_format=ovf", ] @@ -496,10 +496,44 @@ class TestBinGlance(functional.FunctionalTest): self.assertEqual(0, exitcode) image_lines = out.split("\n")[2:-1] - print out self.assertEqual(5, len(image_lines)) self.assertTrue(image_lines[0].startswith('1')) - self.assertTrue(image_lines[1].startswith('2')) + self.assertTrue(image_lines[1].startswith('4')) self.assertTrue(image_lines[2].startswith('3')) - self.assertTrue(image_lines[3].startswith('4')) + self.assertTrue(image_lines[3].startswith('2')) self.assertTrue(image_lines[4].startswith('5')) + + # 3. Sort by name asc with a marker + cmd = "--sort_key=name --sort_dir=asc --marker=4" + exitcode, out, err = execute("%s %s" % (index_cmd, cmd)) + + self.assertEqual(0, exitcode) + image_lines = out.split("\n")[2:-1] + self.assertEqual(3, len(image_lines)) + self.assertTrue(image_lines[0].startswith('3')) + self.assertTrue(image_lines[1].startswith('2')) + self.assertTrue(image_lines[2].startswith('5')) + + # 4. Sort by container_format desc + cmd = "--sort_key=container_format --sort_dir=desc" + exitcode, out, err = execute("%s %s" % (index_cmd, cmd)) + + self.assertEqual(0, exitcode) + image_lines = out.split("\n")[2:-1] + self.assertEqual(5, len(image_lines)) + self.assertTrue(image_lines[0].startswith('5')) + self.assertTrue(image_lines[1].startswith('2')) + self.assertTrue(image_lines[2].startswith('4')) + self.assertTrue(image_lines[3].startswith('3')) + self.assertTrue(image_lines[4].startswith('1')) + + # 5. Sort by name asc with a marker (details) + cmd = "--sort_key=name --sort_dir=asc --marker=4" + exitcode, out, err = execute("%s %s" % (details_cmd, cmd)) + + self.assertEqual(0, exitcode) + image_lines = out.split("\n")[1:-1] + self.assertEqual(30, len(image_lines)) + self.assertTrue(image_lines[1].startswith('Id: 3')) + self.assertTrue(image_lines[11].startswith('Id: 2')) + self.assertTrue(image_lines[21].startswith('Id: 5'))