diff --git a/senlinclient/tests/unit/v1/test_shell.py b/senlinclient/tests/unit/v1/test_shell.py index dd682b7..a2325a7 100644 --- a/senlinclient/tests/unit/v1/test_shell.py +++ b/senlinclient/tests/unit/v1/test_shell.py @@ -112,6 +112,8 @@ class ShellTest(testtools.TestCase): args = { 'limit': 20, 'marker': 'mark_id', + 'sort': 'key:dir', + 'global_project': True, } queries = copy.deepcopy(args) formatters = {} @@ -119,6 +121,11 @@ class ShellTest(testtools.TestCase): args.full_id = True sh.do_profile_list(service, args) service.profiles.assert_called_once_with(**queries) + mock_print.assert_called_with(profiles, fields, formatters=formatters, + sortby_index=None) + + args.sort = None + sh.do_profile_list(service, args) mock_print.assert_called_with(profiles, fields, formatters=formatters, sortby_index=1) @@ -333,8 +340,7 @@ class ShellTest(testtools.TestCase): params = { 'limit': 10, 'marker': 'fake_id', - 'sort_keys': 'name', - 'sort_dir': 'asc', + 'sort': 'key:dir', 'filters': ['filter_key=filter_value'], 'global_project': False, 'full_id': False, @@ -365,7 +371,7 @@ class ShellTest(testtools.TestCase): sortby_index=None) # default sorting - args.sort_keys = None + args.sort = None sh.do_receiver_list(service, args) mock_print.assert_called_with(receivers, fields, formatters={}, @@ -461,19 +467,28 @@ class ShellTest(testtools.TestCase): args = { 'limit': 20, 'marker': 'fake_id', + 'sort': 'name', + 'global_project': False, 'full_id': True } args = self._make_args(args) queries = { 'limit': 20, - 'marker': - 'fake_id', + 'marker': 'fake_id', + 'sort': 'name', + 'global_project': False, } policies = mock.Mock() service.policies.return_value = policies formatters = {} sh.do_policy_list(service, args) service.policies.assert_called_once_with(**queries) + mock_print.assert_called_once_with( + policies, fields, formatters=formatters, sortby_index=None) + mock_print.reset_mock() + + args.sort = None + sh.do_policy_list(service, args) mock_print.assert_called_once_with( policies, fields, formatters=formatters, sortby_index=1) @@ -589,8 +604,7 @@ class ShellTest(testtools.TestCase): args = { 'limit': 20, 'marker': 'fake_id', - 'sort_keys': 'name', - 'sort_dir': 'asc', + 'sort': 'key:dir', 'show_nested': True, 'global_project': False, 'filters': ['status=ACTIVE'], @@ -608,12 +622,10 @@ class ShellTest(testtools.TestCase): mock_print.assert_called_once_with(clusters, fields, formatters=formatters, sortby_index=None) - - # invalid sort key - args.sort_keys = 'id' - ex = exc.CommandError - ex = self.assertRaises(ex, sh.do_cluster_list, service, args) - self.assertEqual(_('Invalid sorting key: id'), six.text_type(ex)) + args.sort = None + sh.do_cluster_list(service, args) + mock_print.assert_called_with(clusters, fields, + formatters={}, sortby_index=3) @mock.patch.object(utils, 'print_dict') def test_show_cluster(self, mock_print): @@ -950,14 +962,12 @@ class ShellTest(testtools.TestCase): args = { 'id': 'C1', 'filters': ['enabled=True'], - 'sort_keys': 'level', - 'sort_dir': 'asc', + 'sort': 'level:asc', 'full_id': True, } args = self._make_args(args) queries = { - 'sort_keys': 'level', - 'sort_dir': 'asc', + 'sort': 'level:asc', 'enabled': 'True', } cluster = mock.Mock() @@ -972,13 +982,6 @@ class ShellTest(testtools.TestCase): mock_print.assert_called_once_with(policies, fields, formatters=formatters, sortby_index=None) - # wrong sort_key - args.sort_keys = 'level;BADKEY' - ex = self.assertRaises(exc.CommandError, - sh.do_cluster_policy_list, - service, args) - msg = _('Invalid sorting key: BADKEY') - self.assertEqual(msg, six.text_type(ex)) @mock.patch.object(utils, 'print_dict') def test_do_cluster_policy_show(self, mock_print): @@ -1087,8 +1090,7 @@ class ShellTest(testtools.TestCase): 'profile_name', 'created_at', 'updated_at'] args = { 'cluster': 'cluster1', - 'sort_keys': 'name', - 'sort_dir': 'asc', + 'sort': 'name:asc', 'limit': 20, 'marker': 'marker_id', 'global_project': True, @@ -1097,8 +1099,7 @@ class ShellTest(testtools.TestCase): } queries = { 'cluster_id': 'cluster1', - 'sort_keys': 'name', - 'sort_dir': 'asc', + 'sort': 'name:asc', 'limit': 20, 'marker': 'marker_id', 'global_project': True, @@ -1114,13 +1115,6 @@ class ShellTest(testtools.TestCase): sortby_index=None) service.nodes.assert_called_once_with(**queries) - # wrong sort key - args.sort_keys = 'name;BADKEY' - ex = exc.CommandError - ex = self.assertRaises(ex, sh.do_node_list, service, args) - msg = _('Invalid sorting key: BADKEY') - self.assertEqual(msg, six.text_type(ex)) - @mock.patch.object(utils, 'print_dict') @mock.patch.object(utils, 'nested_dict_formatter') def test_show_node(self, mock_nested, mock_print): @@ -1254,8 +1248,7 @@ class ShellTest(testtools.TestCase): fields = ['id', 'timestamp', 'obj_type', 'obj_id', 'obj_name', 'action', 'status', 'status_reason', 'level'] args = { - 'sort_keys': 'timestamp', - 'sort_dir': 'asc', + 'sort': 'timestamp:asc', 'limit': 20, 'marker': 'marker_id', 'global_project': True, @@ -1278,13 +1271,6 @@ class ShellTest(testtools.TestCase): mock_print.assert_called_once_with(events, fields, formatters=formatters, sortby_index=sortby_index) - # invalid sorting key - args.sort_keys = 'wrong_key' - ex = self.assertRaises(exc.CommandError, - sh.do_event_list, - service, args) - msg = _('Invalid sorting key: wrong_key') - self.assertEqual(msg, six.text_type(ex)) @mock.patch.object(utils, 'print_dict') def test_do_event_show(self, mock_print): @@ -1320,8 +1306,7 @@ class ShellTest(testtools.TestCase): fields = ['id', 'name', 'action', 'status', 'target', 'depends_on', 'depended_by', 'created_at'] args = { - 'sort_keys': 'status', - 'sort_dir': 'asc', + 'sort': 'status', 'limit': 20, 'marker': 'marker_id', } @@ -1343,22 +1328,6 @@ class ShellTest(testtools.TestCase): formatters=formatters, sortby_index=sortby_index) - def test_do_action_list_invalid_sorting_key(self): - service = mock.Mock() - args = { - 'sort_keys': 'BOGUS', - 'sort_dir': 'asc', - 'limit': 20, - 'marker': 'marker_id', - 'filters': ['status=ACTIVE'] - } - args = self._make_args(args) - - ex = self.assertRaises(exc.CommandError, sh.do_action_list, - service, args) - msg = _('Invalid sorting key: BOGUS') - self.assertEqual(msg, six.text_type(ex)) - @mock.patch.object(utils, 'print_dict') def test_do_action_show(self, mock_print): class FakeAction(object): diff --git a/senlinclient/v1/shell.py b/senlinclient/v1/shell.py index ad46413..dd654c4 100644 --- a/senlinclient/v1/shell.py +++ b/senlinclient/v1/shell.py @@ -76,6 +76,14 @@ def do_profile_type_show(service, args): help=_('Limit the number of profiles returned.')) @utils.arg('-m', '--marker', metavar='', help=_('Only return profiles that appear after the given ID.')) +@utils.arg('-o', '--sort', metavar='', + help=_('Sorting option which is a string containing a list of keys ' + 'separated by commas. Each key can be optionally appened by ' + 'a sort direction (:asc or :desc)')) +@utils.arg('-g', '--global-project', default=False, action="store_true", + help=_('Indicate that the list should include profiles from' + ' all projects. This option is subject to access policy ' + 'checking. Default is False.')) @utils.arg('-F', '--full-id', default=False, action="store_true", help=_('Print full IDs in list.')) def do_profile_list(service, args=None): @@ -84,15 +92,20 @@ def do_profile_list(service, args=None): queries = { 'limit': args.limit, 'marker': args.marker, + 'sort': args.sort, + 'global_project': args.global_project, } + sortby_index = None if args.sort else 1 + profiles = service.profiles(**queries) formatters = {} if not args.full_id: formatters = { 'id': lambda x: x.id[:8], } - utils.print_list(profiles, fields, formatters=formatters, sortby_index=1) + utils.print_list(profiles, fields, formatters=formatters, + sortby_index=sortby_index) def _show_profile(service, profile_id): @@ -243,6 +256,14 @@ def do_policy_type_show(service, args): help=_('Limit the number of policies returned.')) @utils.arg('-m', '--marker', metavar='', help=_('Only return policies that appear after the given ID.')) +@utils.arg('-o', '--sort', metavar='', + help=_('Sorting option which is a string containing a list of keys ' + 'separated by commas. Each key can be optionally appened by ' + 'a sort direction (:asc or :desc)')) +@utils.arg('-g', '--global-project', default=False, action="store_true", + help=_('Indicate that the list should include policies from' + ' all projects. This option is subject to access policy ' + 'checking. Default is False.')) @utils.arg('-F', '--full-id', default=False, action="store_true", help=_('Print full IDs in list.')) def do_policy_list(service, args=None): @@ -251,15 +272,19 @@ def do_policy_list(service, args=None): queries = { 'limit': args.limit, 'marker': args.marker, + 'sort': args.sort, + 'global_project': args.global_project, } + sortby_index = None if args.sort else 1 policies = service.policies(**queries) formatters = {} if not args.full_id: formatters = { 'id': lambda x: x.id[:8] } - utils.print_list(policies, fields, formatters=formatters, sortby_index=1) + utils.print_list(policies, fields, formatters=formatters, + sortby_index=sortby_index) def _show_policy(service, policy_id): @@ -359,10 +384,10 @@ def do_policy_delete(service, args): 'This can be specified multiple times, or once with ' 'parameters separated by a semicolon.'), action='append') -@utils.arg('-k', '--sort-keys', metavar='', - help=_('Name of keys used for sorting the returned clusters.')) -@utils.arg('-s', '--sort-dir', metavar='', - help=_('Direction for sorting, where DIR can be "asc" or "desc".')) +@utils.arg('-o', '--sort', metavar='', + help=_('Sorting option which is a string containing a list of keys ' + 'separated by commas. Each key can be optionally appened by ' + 'a sort direction (:asc or :desc)')) @utils.arg('-l', '--limit', metavar='', help=_('Limit the number of clusters returned.')) @utils.arg('-m', '--marker', metavar='', @@ -377,12 +402,10 @@ def do_policy_delete(service, args): def do_cluster_list(service, args=None): """List the user's clusters.""" fields = ['id', 'name', 'status', 'created_at', 'updated_at'] - sort_keys = ['name', 'status', 'created_at', 'updated_at'] queries = { 'limit': args.limit, 'marker': args.marker, - 'sort_keys': args.sort_keys, - 'sort_dir': args.sort_dir, + 'sort': args.sort, 'show_nested': args.show_nested, 'global_project': args.global_project, } @@ -392,17 +415,7 @@ def do_cluster_list(service, args=None): if args.show_nested: fields.append('parent') - # we only validate the sort keys - # - if all keys are valid, we won't enforce sorting in the resulting list - # - if any keys are invalid, we abort the command execution; - # - if no sort key is specified, we use created_at column for sorting - if args.sort_keys: - for key in args.sort_keys.split(';'): - if len(key) > 0 and key not in sort_keys: - raise exc.CommandError(_('Invalid sorting key: %s') % key) - sortby_index = None - else: - sortby_index = 3 + sortby_index = None if args.sort else 3 clusters = service.clusters(**queries) formatters = {} @@ -707,10 +720,10 @@ def do_cluster_scale_in(service, args): 'This can be specified multiple times, or once with ' 'parameters separated by a semicolon.'), action='append') -@utils.arg('-k', '--sort-keys', metavar='', - help=_('Name of keys used for sorting the returned policies.')) -@utils.arg('-s', '--sort-dir', metavar='', - help=_('Direction for sorting, where DIR can be "asc" or "desc".')) +@utils.arg('-o', '--sort', metavar='', + help=_('Sorting option which is a string containing a list of keys ' + 'separated by commas. Each key can be optionally appened by ' + 'a sort direction (:asc or :desc)')) @utils.arg('-F', '--full-id', default=False, action="store_true", help=_('Print full IDs in list.')) @utils.arg('id', metavar='', @@ -719,25 +732,15 @@ def do_cluster_policy_list(service, args): """List policies from cluster.""" fields = ['policy_id', 'policy_name', 'policy_type', 'priority', 'level', 'cooldown', 'enabled'] - sort_keys = ['priority', 'level', 'cooldown', 'enabled'] - cluster = service.get_cluster(args.id) queries = { - 'sort_keys': args.sort_keys, - 'sort_dir': args.sort_dir, + 'sort': args.sort, } if args.filters: queries.update(utils.format_parameters(args.filters)) - sortby_index = None - if args.sort_keys: - for key in args.sort_keys.split(';'): - if len(key) > 0 and key not in sort_keys: - raise exc.CommandError(_('Invalid sorting key: %s') % key) - else: - sortby_index = 3 - + sortby_index = None if args.sort else 3 policies = service.cluster_policies(cluster.id, **queries) formatters = {} if not args.full_id: @@ -857,10 +860,10 @@ def do_cluster_policy_disable(service, args): 'This can be specified multiple times, or once with ' 'parameters separated by a semicolon.'), action='append') -@utils.arg('-k', '--sort-keys', metavar='', - help=_('Name of keys used for sorting the returned nodes.')) -@utils.arg('-s', '--sort-dir', metavar='', - help=_('Direction for sorting, where DIR can be "asc" or "desc".')) +@utils.arg('-o', '--sort', metavar='', + help=_('Sorting option which is a string containing a list of keys ' + 'separated by commas. Each key can be optionally appened by ' + 'a sort direction (:asc or :desc)')) @utils.arg('-l', '--limit', metavar='', help=_('Limit the number of nodes returned.')) @utils.arg('-m', '--marker', metavar='', @@ -876,12 +879,9 @@ def do_node_list(service, args): fields = ['id', 'name', 'index', 'status', 'cluster_id', 'physical_id', 'profile_name', 'created_at', 'updated_at'] - sort_keys = ['index', 'name', 'created_at', 'updated_at', 'status'] - queries = { 'cluster_id': args.cluster, - 'sort_keys': args.sort_keys, - 'sort_dir': args.sort_dir, + 'sort': args.sort, 'limit': args.limit, 'marker': args.marker, 'global_project': args.global_project, @@ -890,13 +890,7 @@ def do_node_list(service, args): if args.filters: queries.update(utils.format_parameters(args.filters)) - sortby_index = None - if args.sort_keys: - for key in args.sort_keys.split(';'): - if len(key) > 0 and key not in sort_keys: - raise exc.CommandError(_('Invalid sorting key: %s') % key) - else: - sortby_index = 6 + sortby_index = None if args.sort else 6 nodes = service.nodes(**queries) @@ -1053,10 +1047,10 @@ def do_node_leave(service, args): help=_('Limit the number of receivers returned.')) @utils.arg('-m', '--marker', metavar='', help=_('Only return receivers that appear after the given ID.')) -@utils.arg('-k', '--sort-keys', metavar='', - help=_('Name of keys used for sorting the returned receivers.')) -@utils.arg('-s', '--sort-dir', metavar='', - help=_('Direction for sorting, where DIR can be "asc" or "desc".')) +@utils.arg('-o', '--sort', metavar='', + help=_('Sorting option which is a string containing a list of keys ' + 'separated by commas. Each key can be optionally appened by ' + 'a sort direction (:asc or :desc)')) @utils.arg('-g', '--global-project', default=False, action="store_true", help=_('Indicate that the list should include receivers from' ' all projects. This option is subject to access policy ' @@ -1066,25 +1060,17 @@ def do_node_leave(service, args): def do_receiver_list(service, args=None): """List receivers that meet the criteria.""" fields = ['id', 'name', 'type', 'cluster_id', 'action', 'created_at'] - sort_keys = ['name', 'type', 'cluster_id', 'created_at'] queries = { 'limit': args.limit, 'marker': args.marker, - 'sort_keys': args.sort_keys, - 'sort_dir': args.sort_dir, + 'sort': args.sort, 'global_project': args.global_project, } if args.filters: queries.update(utils.format_parameters(args.filters)) - if args.sort_keys: - for key in args.sort_keys.split(';'): - if len(key) > 0 and key not in sort_keys: - raise exc.CommandError(_('Invalid sorting key: %s') % key) - sortby_index = None - else: - sortby_index = 0 + sortby_index = None if args.sort else 0 receivers = service.receivers(**queries) formatters = {} @@ -1176,10 +1162,10 @@ def do_receiver_delete(service, args): help=_('Limit the number of events returned.')) @utils.arg('-m', '--marker', metavar='', help=_('Only return events that appear after the given event ID.')) -@utils.arg('-k', '--sort-keys', metavar='', - help=_('Name of keys used for sorting the returned events.')) -@utils.arg('-s', '--sort-dir', metavar='', - help=_('Direction for sorting, where DIR can be "asc" or "desc".')) +@utils.arg('-o', '--sort', metavar='', + help=_('Sorting option which is a string containing a list of keys ' + 'separated by commas. Each key can be optionally appened by ' + 'a sort direction (:asc or :desc)')) @utils.arg('-g', '--global-project', default=False, action="store_true", help=_('Whether events from all projects should be listed. ' ' Default to False. Setting this to True may demand ' @@ -1191,11 +1177,8 @@ def do_event_list(service, args): fields = ['id', 'timestamp', 'obj_type', 'obj_id', 'obj_name', 'action', 'status', 'status_reason', 'level'] - sort_keys = ['timestamp', 'obj_type', 'obj_name', 'level', 'action'] - queries = { - 'sort_keys': args.sort_keys, - 'sort_dir': args.sort_dir, + 'sort': args.sort, 'limit': args.limit, 'marker': args.marker, 'global_project': args.global_project, @@ -1204,14 +1187,7 @@ def do_event_list(service, args): if args.filters: queries.update(utils.format_parameters(args.filters)) - sortby_index = None - if args.sort_keys: - for key in args.sort_keys.split(';'): - if len(key) > 0 and key not in sort_keys: - raise exc.CommandError(_('Invalid sorting key: %s') % key) - else: - sortby_index = 0 - + sortby_index = None if args.sort else 0 formatters = {} if not args.full_id: formatters['id'] = lambda x: x.id[:8] @@ -1242,10 +1218,10 @@ def do_event_show(service, args): 'This can be specified multiple times, or once with ' 'parameters separated by a semicolon.'), action='append') -@utils.arg('-k', '--sort-keys', metavar='', - help=_('Name of keys used for sorting the returned actions.')) -@utils.arg('-s', '--sort-dir', metavar='', - help=_('Direction for sorting, where DIR can be "asc" or "desc".')) +@utils.arg('-o', '--sort', metavar='', + help=_('Sorting option which is a string containing a list of keys ' + 'separated by commas. Each key can be optionally appened by ' + 'a sort direction (:asc or :desc)')) @utils.arg('-l', '--limit', metavar='', help=_('Limit the number of actions returned.')) @utils.arg('-m', '--marker', metavar='', @@ -1257,11 +1233,9 @@ def do_action_list(service, args): fields = ['id', 'name', 'action', 'status', 'target', 'depends_on', 'depended_by', 'created_at'] - sort_keys = ['name', 'target', 'action', 'created_at', 'status'] queries = { - 'sort_keys': args.sort_keys, - 'sort_dir': args.sort_dir, + 'sort': args.sort, 'limit': args.limit, 'marker': args.marker, } @@ -1269,13 +1243,7 @@ def do_action_list(service, args): if args.filters: queries.update(utils.format_parameters(args.filters)) - sortby_index = None - if args.sort_keys: - for key in args.sort_keys.split(';'): - if len(key) > 0 and key not in sort_keys: - raise exc.CommandError(_('Invalid sorting key: %s') % key) - else: - sortby_index = 0 + sortby_index = None if args.sort else 0 actions = service.actions(**queries)