From a004819e30856127f19fed138a89a7f3975b27c4 Mon Sep 17 00:00:00 2001 From: Oleksii Chuprykov Date: Tue, 15 Dec 2015 17:34:45 +0200 Subject: [PATCH] Resolve outputs from stack object There are use cases where user have new heatclient and old version of rpc api ( < 1.19) so heatclient call new api methods that doesn't exist. In this case get stack outputs from stack object. Change-Id: I6c1fdbe13ecb8ae61690e0e7d8bac31405c148c6 Closes-Bug: #1526392 --- heatclient/tests/unit/test_shell.py | 114 ++++++++++++++++++++++++++++ heatclient/v1/shell.py | 92 +++++++++++++--------- 2 files changed, 172 insertions(+), 34 deletions(-) diff --git a/heatclient/tests/unit/test_shell.py b/heatclient/tests/unit/test_shell.py index 2a7c1f4e..908f4b7a 100644 --- a/heatclient/tests/unit/test_shell.py +++ b/heatclient/tests/unit/test_shell.py @@ -2619,6 +2619,64 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(list_text, r) + def test_output_list_api_400_error(self): + self.register_keystone_auth_fixture() + outputs = [{ + "output_key": "key", + "description": "description" + }, + { + "output_key": "key1", + "description": "description1" + }] + stack_dict = {"stack": { + "id": "1", + "stack_name": "teststack", + "stack_status": 'CREATE_COMPLETE', + "creation_time": "2012-10-25T01:58:47Z", + "outputs": outputs + }} + + stack_resp = fakes.FakeHTTPResponse( + 200, + 'OK', + {'content-type': 'application/json'}, + jsonutils.dumps(stack_dict)) + resp = fakes.FakeHTTPResponse( + 404, + 'Not Found', + {'content-type': 'application/json'}, + jsonutils.dumps({})) + if self.client == http.SessionClient: + self.client.request( + '/stacks/teststack/1/outputs', + 'GET').AndRaise(exc.from_response(resp)) + self.client.request( + '/stacks/teststack/1', + 'GET').AndReturn(stack_resp) + else: + http.HTTPClient.json_request( + 'GET', + '/stacks/teststack/1/outputs').AndRaise( + exc.from_response(resp)) + http.HTTPClient.json_request( + 'GET', '/stacks/teststack/1').AndReturn((stack_resp, + stack_dict)) + + self.m.ReplayAll() + list_text = self.shell('output-list teststack/1') + + required = [ + 'output_key', + 'description', + 'key', + 'description', + 'key1', + 'description1' + ] + for r in required: + self.assertRegexpMatches(list_text, r) + def test_output_show_all(self): self.register_keystone_auth_fixture() @@ -2712,6 +2770,62 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(resp, r) + def test_output_show_api_400_error(self): + self.register_keystone_auth_fixture() + output = { + "output_key": "key", + "output_value": "value", + 'description': 'description' + } + stack_dict = {"stack": { + "id": "1", + "stack_name": "teststack", + "stack_status": 'CREATE_COMPLETE', + "creation_time": "2012-10-25T01:58:47Z", + 'outputs': [output] + }} + + resp = fakes.FakeHTTPResponse( + 404, + 'Internal Error', + {'content-type': 'application/json'}, + jsonutils.dumps({})) + if self.client == http.SessionClient: + self.client.request( + '/stacks/teststack/1/outputs/key', + 'GET').AndRaise(exc.from_response(resp)) + self.client.request('/stacks/teststack/1', 'GET').AndReturn( + fakes.FakeHTTPResponse( + 200, + 'OK', + {'content-type': 'application/json'}, + jsonutils.dumps(stack_dict))) + else: + http.HTTPClient.json_request( + 'GET', + '/stacks/teststack/1/outputs/key').AndRaise( + exc.from_response(resp)) + http.HTTPClient.json_request( + 'GET', '/stacks/teststack/1').AndReturn(( + fakes.FakeHTTPResponse( + 200, + 'OK', + {'content-type': 'application/json'}, + jsonutils.dumps(stack_dict)), stack_dict)) + + self.m.ReplayAll() + resp = self.shell('output-show teststack/1 key') + required = [ + 'output_key', + 'output_value', + 'description', + 'key', + 'value', + 'description', + ] + for r in required: + self.assertRegexpMatches(resp, r) + def test_output_show_output1(self): self.register_keystone_auth_fixture() diff --git a/heatclient/v1/shell.py b/heatclient/v1/shell.py index 307ef7e4..1e8a69af 100644 --- a/heatclient/v1/shell.py +++ b/heatclient/v1/shell.py @@ -651,15 +651,18 @@ def do_output_list(hc, args): try: outputs = hc.stacks.output_list(args.id) except exc.HTTPNotFound: - raise exc.CommandError(_('Stack not found: %s') % args.id) - else: - fields = ['output_key', 'description'] - formatters = { - 'output_key': lambda x: x['output_key'], - 'description': lambda x: x['description'], - } + try: + outputs = hc.stacks.get(args.id).to_dict() + except exc.HTTPNotFound: + raise exc.CommandError(_('Stack not found: %s') % args.id) - utils.print_list(outputs['outputs'], fields, formatters=formatters) + fields = ['output_key', 'description'] + formatters = { + 'output_key': lambda x: x['output_key'], + 'description': lambda x: x['description'], + } + + utils.print_list(outputs['outputs'], fields, formatters=formatters) @utils.arg('id', metavar='', @@ -675,43 +678,64 @@ def do_output_list(hc, args): help=_('Returns only output value in specified format.')) def do_output_show(hc, args): """Show a specific stack output.""" - def show_output_by_key(output_key): + def resolve_output(output_key): try: output = hc.stacks.output_show(args.id, output_key) except exc.HTTPNotFound: - raise exc.CommandError(_('Stack %(id)s or ' - 'output %(key)s not found.') % { - 'id': args.id, - 'key': args.output}) - else: - if 'output_error' in output['output']: - msg = _("Output error: %s") % output['output']['output_error'] - raise exc.CommandError(msg) - if args.only_value: - if (args.format == 'json' - or isinstance(output['output']['output_value'], dict) - or isinstance(output['output']['output_value'], list)): - print( - utils.json_formatter(output['output']['output_value'])) - else: - print(output['output']['output_value']) + try: + output = None + stack = hc.stacks.get(args.id).to_dict() + for o in stack.get('outputs', []): + if o['output_key'] == output_key: + output = {'output': o} + break + if output is None: + raise exc.CommandError(_('Output %(key)s not found.') % { + 'key': args.output}) + except exc.HTTPNotFound: + raise exc.CommandError( + _('Stack %(id)s or output %(key)s not found.') % { + 'id': args.id, + 'key': args.output}) + return output + + def show_output(output): + if 'output_error' in output['output']: + msg = _("Output error: %s") % output['output']['output_error'] + raise exc.CommandError(msg) + if args.only_value: + if (args.format == 'json' + or isinstance(output['output']['output_value'], dict) + or isinstance(output['output']['output_value'], list)): + print( + utils.json_formatter(output['output']['output_value'])) else: - formatters = { - 'output_value': (lambda x: utils.json_formatter(x) - if args.format == 'json' - else x) - } - utils.print_dict(output['output'], formatters=formatters) + print(output['output']['output_value']) + else: + formatters = { + 'output_value': (lambda x: utils.json_formatter(x) + if args.format == 'json' + else x) + } + utils.print_dict(output['output'], formatters=formatters) if args.all: try: outputs = hc.stacks.output_list(args.id) + resolved = False except exc.HTTPNotFound: - raise exc.CommandError(_('Stack not found: %s') % args.id) + try: + outputs = hc.stacks.get(args.id).to_dict() + resolved = True + except exc.HTTPNotFound: + raise exc.CommandError(_('Stack not found: %s') % args.id) for output in outputs['outputs']: - show_output_by_key(output['output_key']) + if resolved: + show_output({'output': output}) + else: + show_output(resolve_output(output['output_key'])) else: - show_output_by_key(args.output) + show_output(resolve_output(args.output)) @utils.arg('-f', '--filters', metavar='',