diff --git a/heatclient/tests/unit/test_shell.py b/heatclient/tests/unit/test_shell.py index 67a5f201..24953035 100644 --- a/heatclient/tests/unit/test_shell.py +++ b/heatclient/tests/unit/test_shell.py @@ -212,10 +212,20 @@ class ShellParamValidationTest(TestCase): scenarios = [ ('stack-create', dict( command='stack-create ts -P "ab"', + with_tmpl=True, err='Malformed parameter')), ('stack-update', dict( command='stack-update ts -P "a-b"', + with_tmpl=True, err='Malformed parameter')), + ('stack-list-with-sort-dir', dict( + command='stack-list --sort-dir up', + with_tmpl=False, + err='Sorting direction must be one of')), + ('stack-list-with-sort-key', dict( + command='stack-list --sort-keys owner', + with_tmpl=False, + err='Sorting key \'owner\' not one of')), ] def setUp(self): @@ -233,8 +243,12 @@ class ShellParamValidationTest(TestCase): 'OS_AUTH_URL': BASE_URL, } self.set_fake_env(fake_env) - template_file = os.path.join(TEST_VAR_DIR, 'minimal.template') - cmd = '%s --template-file=%s ' % (self.command, template_file) + cmd = self.command + + if self.with_tmpl: + template_file = os.path.join(TEST_VAR_DIR, 'minimal.template') + cmd = '%s --template-file=%s ' % (self.command, template_file) + self.shell_error(cmd, self.err) @@ -4513,7 +4527,10 @@ class MockShellTestUserPass(MockShellBase): ' --not-tags-any=tag7,tag8' ' --global-tenant' ' --show-deleted' - ' --show-hidden') + ' --show-hidden' + ' --sort-keys=stack_name;creation_time' + ' --sort-keys=updated_time' + ' --sort-dir=asc') required = [ 'stack_owner', @@ -4544,7 +4561,10 @@ class MockShellTestUserPass(MockShellBase): 'not_tags_any': ['tag7,tag8'], 'global_tenant': ['True'], 'show_deleted': ['True'], - 'show_hidden': ['True']} + 'show_hidden': ['True'], + 'sort_keys': ['stack_name', 'creation_time', + 'updated_time'], + 'sort_dir': ['asc']} self.assertEqual(expected_query_dict, query_params) diff --git a/heatclient/v1/shell.py b/heatclient/v1/shell.py index 583b4b4c..386a0455 100644 --- a/heatclient/v1/shell.py +++ b/heatclient/v1/shell.py @@ -569,6 +569,16 @@ def do_stack_cancel_update(hc, args): help=_('Limit the number of stacks returned.')) @utils.arg('-m', '--marker', metavar='', help=_('Only return stacks that appear after the given stack ID.')) +@utils.arg('-k', '--sort-keys', metavar='', + help=_('List of keys for sorting the returned stacks. ' + 'This can be specified multiple times or once with keys ' + 'separated by semicolons. Valid sorting keys include ' + '"stack_name", "stack_status", "creation_time" and ' + '"updated_time".'), + action='append') +@utils.arg('-d', '--sort-dir', metavar='[asc|desc]', + help=_('Sorting direction (either "asc" or "desc") for the sorting ' + 'keys.')) @utils.arg('-g', '--global-tenant', action='store_true', default=False, help=_('Display stacks from all tenants. Operation only authorized ' 'for users who match the policy in heat\'s policy.json.')) @@ -578,7 +588,11 @@ def do_stack_cancel_update(hc, args): def do_stack_list(hc, args=None): '''List the user's stacks.''' kwargs = {} - fields = ['id', 'stack_name', 'stack_status', 'creation_time'] + fields = ['id', 'stack_name', 'stack_status', 'creation_time', + 'updated_time'] + sort_keys = ['stack_name', 'stack_status', 'creation_time', + 'updated_time'] + sortby_index = 3 if args: kwargs = {'limit': args.limit, 'marker': args.marker, @@ -594,13 +608,36 @@ def do_stack_list(hc, args=None): fields.append('parent') kwargs['show_nested'] = True + if args.sort_keys: + # flatten key list first + keys = [] + for k in args.sort_keys: + if ';' in k: + keys.extend(k.split(';')) + else: + keys.append(k) + # validate key list + for key in keys: + if key not in sort_keys: + err = _("Sorting key '%(key)s' not one of the supported " + "keys: %(keys)s") % {'key': key, "keys": sort_keys} + raise exc.CommandError(err) + kwargs['sort_keys'] = keys + sortby_index = None + + if args.sort_dir: + if args.sort_dir not in ('asc', 'desc'): + raise exc.CommandError(_("Sorting direction must be one of " + "'asc' and 'desc'")) + kwargs['sort_dir'] = args.sort_dir + if args.global_tenant or args.show_owner: fields.insert(2, 'stack_owner') if args.global_tenant: fields.insert(2, 'project') stacks = hc.stacks.list(**kwargs) - utils.print_list(stacks, fields, sortby_index=3) + utils.print_list(stacks, fields, sortby_index=sortby_index) @utils.arg('id', metavar='',