Merge "Adds the ability to sort images with multiple keys"
This commit is contained in:
		@@ -26,6 +26,10 @@ from glanceclient.v2 import schemas
 | 
			
		||||
 | 
			
		||||
DEFAULT_PAGE_SIZE = 20
 | 
			
		||||
 | 
			
		||||
SORT_DIR_VALUES = ('asc', 'desc')
 | 
			
		||||
SORT_KEY_VALUES = ('name', 'status', 'container_format', 'disk_format',
 | 
			
		||||
                   'size', 'id', 'created_at', 'updated_at')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Controller(object):
 | 
			
		||||
    def __init__(self, http_client, schema_client):
 | 
			
		||||
@@ -94,6 +98,10 @@ class Controller(object):
 | 
			
		||||
        # the page_size as Glance's limit.
 | 
			
		||||
        filters['limit'] = page_size
 | 
			
		||||
 | 
			
		||||
        sort_dir = kwargs.get('sort_dir')
 | 
			
		||||
        if sort_dir is not None:
 | 
			
		||||
            filters['sort_dir'] = sort_dir
 | 
			
		||||
 | 
			
		||||
        tags = filters.pop('tag', [])
 | 
			
		||||
        tags_url_params = []
 | 
			
		||||
 | 
			
		||||
@@ -110,6 +118,13 @@ class Controller(object):
 | 
			
		||||
        for param in tags_url_params:
 | 
			
		||||
            url = '%s&%s' % (url, parse.urlencode(param))
 | 
			
		||||
 | 
			
		||||
        sort_key = kwargs.get('sort_key')
 | 
			
		||||
        if sort_key is not None:
 | 
			
		||||
            if isinstance(sort_key, six.string_types):
 | 
			
		||||
                sort_key = [sort_key]
 | 
			
		||||
            for key in sort_key:
 | 
			
		||||
                url = '%s&sort_key=%s' % (url, key)
 | 
			
		||||
 | 
			
		||||
        for image in paginate(url, page_size, limit):
 | 
			
		||||
            yield image
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@
 | 
			
		||||
from glanceclient.common import progressbar
 | 
			
		||||
from glanceclient.common import utils
 | 
			
		||||
from glanceclient import exc
 | 
			
		||||
from glanceclient.v2 import images
 | 
			
		||||
from glanceclient.v2 import tasks
 | 
			
		||||
import json
 | 
			
		||||
import os
 | 
			
		||||
@@ -124,6 +125,12 @@ def do_image_update(gc, args):
 | 
			
		||||
           help='Displays images that match the checksum.')
 | 
			
		||||
@utils.arg('--tag', metavar='<TAG>', action='append',
 | 
			
		||||
           help="Filter images by a user-defined tag.")
 | 
			
		||||
@utils.arg('--sort-key', default=[], action='append',
 | 
			
		||||
           choices=images.SORT_KEY_VALUES,
 | 
			
		||||
           help='Sort image list by specified fields.')
 | 
			
		||||
@utils.arg('--sort-dir', default='asc',
 | 
			
		||||
           choices=images.SORT_DIR_VALUES,
 | 
			
		||||
           help='Sort image list in specified direction.')
 | 
			
		||||
def do_image_list(gc, args):
 | 
			
		||||
    """List images you can access."""
 | 
			
		||||
    filter_keys = ['visibility', 'member_status', 'owner', 'checksum', 'tag']
 | 
			
		||||
@@ -141,6 +148,11 @@ def do_image_list(gc, args):
 | 
			
		||||
        kwargs['limit'] = args.limit
 | 
			
		||||
    if args.page_size is not None:
 | 
			
		||||
        kwargs['page_size'] = args.page_size
 | 
			
		||||
    if args.sort_key:
 | 
			
		||||
        kwargs['sort_key'] = args.sort_key
 | 
			
		||||
    else:
 | 
			
		||||
        kwargs['sort_key'] = ['name']
 | 
			
		||||
    kwargs['sort_dir'] = args.sort_dir
 | 
			
		||||
 | 
			
		||||
    images = gc.images.list(**kwargs)
 | 
			
		||||
    columns = ['ID', 'Name']
 | 
			
		||||
 
 | 
			
		||||
@@ -394,9 +394,55 @@ data_fixtures = {
 | 
			
		||||
            {'images': []},
 | 
			
		||||
        ),
 | 
			
		||||
    },
 | 
			
		||||
    '/v2/images?limit=%d&sort_key=name' % images.DEFAULT_PAGE_SIZE: {
 | 
			
		||||
        'GET': (
 | 
			
		||||
            {},
 | 
			
		||||
            {'images': [
 | 
			
		||||
                {
 | 
			
		||||
                    'id': '2a4560b2-e585-443e-9b39-553b46ec92d1',
 | 
			
		||||
                    'name': 'image-1',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    'id': '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810',
 | 
			
		||||
                    'name': 'image-2',
 | 
			
		||||
                },
 | 
			
		||||
            ]},
 | 
			
		||||
        ),
 | 
			
		||||
    },
 | 
			
		||||
    '/v2/images?limit=%d&sort_key=name&sort_key=id'
 | 
			
		||||
    % images.DEFAULT_PAGE_SIZE: {
 | 
			
		||||
        'GET': (
 | 
			
		||||
            {},
 | 
			
		||||
            {'images': [
 | 
			
		||||
                {
 | 
			
		||||
                    'id': '2a4560b2-e585-443e-9b39-553b46ec92d1',
 | 
			
		||||
                    'name': 'image',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    'id': '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810',
 | 
			
		||||
                    'name': 'image',
 | 
			
		||||
                },
 | 
			
		||||
            ]},
 | 
			
		||||
        ),
 | 
			
		||||
    },
 | 
			
		||||
    '/v2/images?limit=%d&sort_dir=desc&sort_key=id'
 | 
			
		||||
    % images.DEFAULT_PAGE_SIZE: {
 | 
			
		||||
        'GET': (
 | 
			
		||||
            {},
 | 
			
		||||
            {'images': [
 | 
			
		||||
                {
 | 
			
		||||
                    'id': '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810',
 | 
			
		||||
                    'name': 'image-2',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    'id': '2a4560b2-e585-443e-9b39-553b46ec92d1',
 | 
			
		||||
                    'name': 'image-1',
 | 
			
		||||
                },
 | 
			
		||||
            ]},
 | 
			
		||||
        ),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
schema_fixtures = {
 | 
			
		||||
    'image': {
 | 
			
		||||
        'GET': (
 | 
			
		||||
@@ -560,6 +606,29 @@ class TestController(testtools.TestCase):
 | 
			
		||||
        images = list(self.controller.list(**filters))
 | 
			
		||||
        self.assertEqual(0, len(images))
 | 
			
		||||
 | 
			
		||||
    def test_list_images_with_single_sort_key(self):
 | 
			
		||||
        img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
 | 
			
		||||
        sort_key = 'name'
 | 
			
		||||
        images = list(self.controller.list(sort_key=sort_key))
 | 
			
		||||
        self.assertEqual(2, len(images))
 | 
			
		||||
        self.assertEqual('%s' % img_id1, images[0].id)
 | 
			
		||||
 | 
			
		||||
    def test_list_with_multiple_sort_keys(self):
 | 
			
		||||
        img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
 | 
			
		||||
        sort_key = ['name', 'id']
 | 
			
		||||
        images = list(self.controller.list(sort_key=sort_key))
 | 
			
		||||
        self.assertEqual(2, len(images))
 | 
			
		||||
        self.assertEqual('%s' % img_id1, images[0].id)
 | 
			
		||||
 | 
			
		||||
    def test_list_images_with_desc_sort_dir(self):
 | 
			
		||||
        img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
 | 
			
		||||
        sort_key = 'id'
 | 
			
		||||
        sort_dir = 'desc'
 | 
			
		||||
        images = list(self.controller.list(sort_key=sort_key,
 | 
			
		||||
                                           sort_dir=sort_dir))
 | 
			
		||||
        self.assertEqual(2, len(images))
 | 
			
		||||
        self.assertEqual('%s' % img_id1, images[1].id)
 | 
			
		||||
 | 
			
		||||
    def test_list_images_for_property(self):
 | 
			
		||||
        filters = {'filters': dict([('os_distro', 'NixOS')])}
 | 
			
		||||
        images = list(self.controller.list(**filters))
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,9 @@ class ShellV2Test(testtools.TestCase):
 | 
			
		||||
            'owner': 'test',
 | 
			
		||||
            'checksum': 'fake_checksum',
 | 
			
		||||
            'tag': 'fake tag',
 | 
			
		||||
            'properties': []
 | 
			
		||||
            'properties': [],
 | 
			
		||||
            'sort_key': ['name', 'id'],
 | 
			
		||||
            'sort_dir': 'desc'
 | 
			
		||||
        }
 | 
			
		||||
        args = self._make_args(input)
 | 
			
		||||
        with mock.patch.object(self.gc.images, 'list') as mocked_list:
 | 
			
		||||
@@ -84,6 +86,40 @@ class ShellV2Test(testtools.TestCase):
 | 
			
		||||
                'tag': 'fake tag'
 | 
			
		||||
            }
 | 
			
		||||
            mocked_list.assert_called_once_with(page_size=18,
 | 
			
		||||
                                                sort_key=['name', 'id'],
 | 
			
		||||
                                                sort_dir='desc',
 | 
			
		||||
                                                filters=exp_img_filters)
 | 
			
		||||
            utils.print_list.assert_called_once_with({}, ['ID', 'Name'])
 | 
			
		||||
 | 
			
		||||
    def test_do_image_list_with_single_sort_key(self):
 | 
			
		||||
        input = {
 | 
			
		||||
            'limit': None,
 | 
			
		||||
            'page_size': 18,
 | 
			
		||||
            'visibility': True,
 | 
			
		||||
            'member_status': 'Fake',
 | 
			
		||||
            'owner': 'test',
 | 
			
		||||
            'checksum': 'fake_checksum',
 | 
			
		||||
            'tag': 'fake tag',
 | 
			
		||||
            'properties': [],
 | 
			
		||||
            'sort_key': ['name'],
 | 
			
		||||
            'sort_dir': 'desc'
 | 
			
		||||
        }
 | 
			
		||||
        args = self._make_args(input)
 | 
			
		||||
        with mock.patch.object(self.gc.images, 'list') as mocked_list:
 | 
			
		||||
            mocked_list.return_value = {}
 | 
			
		||||
 | 
			
		||||
            test_shell.do_image_list(self.gc, args)
 | 
			
		||||
 | 
			
		||||
            exp_img_filters = {
 | 
			
		||||
                'owner': 'test',
 | 
			
		||||
                'member_status': 'Fake',
 | 
			
		||||
                'visibility': True,
 | 
			
		||||
                'checksum': 'fake_checksum',
 | 
			
		||||
                'tag': 'fake tag'
 | 
			
		||||
            }
 | 
			
		||||
            mocked_list.assert_called_once_with(page_size=18,
 | 
			
		||||
                                                sort_key=['name'],
 | 
			
		||||
                                                sort_dir='desc',
 | 
			
		||||
                                                filters=exp_img_filters)
 | 
			
		||||
            utils.print_list.assert_called_once_with({}, ['ID', 'Name'])
 | 
			
		||||
 | 
			
		||||
@@ -96,7 +132,9 @@ class ShellV2Test(testtools.TestCase):
 | 
			
		||||
            'owner': 'test',
 | 
			
		||||
            'checksum': 'fake_checksum',
 | 
			
		||||
            'tag': 'fake tag',
 | 
			
		||||
            'properties': ['os_distro=NixOS', 'architecture=x86_64']
 | 
			
		||||
            'properties': ['os_distro=NixOS', 'architecture=x86_64'],
 | 
			
		||||
            'sort_key': ['name'],
 | 
			
		||||
            'sort_dir': 'desc'
 | 
			
		||||
        }
 | 
			
		||||
        args = self._make_args(input)
 | 
			
		||||
        with mock.patch.object(self.gc.images, 'list') as mocked_list:
 | 
			
		||||
@@ -115,6 +153,8 @@ class ShellV2Test(testtools.TestCase):
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            mocked_list.assert_called_once_with(page_size=1,
 | 
			
		||||
                                                sort_key=['name'],
 | 
			
		||||
                                                sort_dir='desc',
 | 
			
		||||
                                                filters=exp_img_filters)
 | 
			
		||||
            utils.print_list.assert_called_once_with({}, ['ID', 'Name'])
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user