From f6373978e5858a19ecf35cf3b73a506601bfe6a2 Mon Sep 17 00:00:00 2001 From: Bryan Jones Date: Thu, 14 Jan 2016 16:43:58 +0000 Subject: [PATCH] OpenstackClient plugin for template show This change implements the 'openstack stack template show' command. Blueprint: heat-support-python-openstackclient Change-Id: I4a832435e692fb92a169d01a9e95c5c083c49531 --- heatclient/osc/v1/stack.py | 28 ++++++++ heatclient/tests/inline_templates.py | 78 ++++++++++++++++++++++ heatclient/tests/unit/osc/v1/test_stack.py | 45 +++++++++++++ setup.cfg | 1 + 4 files changed, 152 insertions(+) create mode 100644 heatclient/tests/inline_templates.py diff --git a/heatclient/osc/v1/stack.py b/heatclient/osc/v1/stack.py index dc1c9d35..c0b988cf 100644 --- a/heatclient/osc/v1/stack.py +++ b/heatclient/osc/v1/stack.py @@ -807,3 +807,31 @@ class OutputListStack(lister.Lister): columns, (utils.get_dict_properties(s, columns) for s in outputs) ) + + +class TemplateShowStack(format_utils.YamlFormat): + """Display stack template.""" + + log = logging.getLogger(__name__ + '.TemplateShowStack') + + def get_parser(self, prog_name): + parser = super(TemplateShowStack, self).get_parser(prog_name) + parser.add_argument( + 'stack', + metavar='', + help=_('Name or ID of stack to query') + ) + return parser + + def take_action(self, parsed_args): + self.log.debug('take_action(%s)', parsed_args) + + client = self.app.client_manager.orchestration + + try: + template = client.stacks.template(stack_id=parsed_args.stack) + except heat_exc.HTTPNotFound: + msg = _('Stack not found: %s') % parsed_args.stack + raise exc.CommandError(msg) + + return self.dict2columns(template) diff --git a/heatclient/tests/inline_templates.py b/heatclient/tests/inline_templates.py new file mode 100644 index 00000000..56667ac0 --- /dev/null +++ b/heatclient/tests/inline_templates.py @@ -0,0 +1,78 @@ +# +# Copyright 2016 IBM Corp. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +FULL_TEMPLATE = ''' +heat_template_version: 2016-04-08 + +description: a template + +parameter_groups: + - label: param_group_1 + description: parameter group 1 + parameters: + - param1 + - param2 + - label: param_group_2 + description: parameter group 2 + parameters: + - param3 + +parameters: + param1: + type: string + label: parameter 5 + description: parameter 5 + default: foo + hidden: false + constraints: + - allowed_values: ['foo', 'bar', 'bax'] + param2: + type: number + default: 0 + constraints: + - range: {min: 0, max: 10} + description: must be betwen 0 and 10 + param3: + type: boolean + +resources: + resource1: + type: OS::Heat::None + properties: + prop1: { get_param: param1 } + prop2: { get_param: param2 } + prop3: value + resource2: + type: OS::Heat::None + properties: + prop1: { get_param: param3 } + depends_on: resource1 + +outputs: + output1: + description: resource 1 prop 3 + value: { get_attr: [resource1, prop3] } + output2: + description: resource 2 prop 1 + value: { get_attr: [resource2, prop1] } +''' + +SHORT_TEMPLATE = ''' +heat_template_version: 2016-04-08 + +resources: + res1: + type: OS::Heat::None +''' diff --git a/heatclient/tests/unit/osc/v1/test_stack.py b/heatclient/tests/unit/osc/v1/test_stack.py index 8dd30cbc..f74b800d 100644 --- a/heatclient/tests/unit/osc/v1/test_stack.py +++ b/heatclient/tests/unit/osc/v1/test_stack.py @@ -16,12 +16,15 @@ import io import mock import six import testscenarios +import yaml from openstackclient.common import exceptions as exc from openstackclient.common import utils +from heatclient.common import template_format from heatclient import exc as heat_exc from heatclient.osc.v1 import stack +from heatclient.tests import inline_templates from heatclient.tests.unit.osc.v1 import fakes as orchestration_fakes from heatclient.v1 import stacks @@ -757,3 +760,45 @@ class TestStackOutputList(TestStack): error = self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args) self.assertEqual('Stack not found: my_stack', str(error)) + + +class TestStackTemplateShow(TestStack): + + fields = ['heat_template_version', 'description', 'parameter_groups', + 'parameters', 'resources', 'outputs'] + + def setUp(self): + super(TestStackTemplateShow, self).setUp() + self.cmd = stack.TemplateShowStack(self.app, None) + + def test_stack_template_show_full_template(self): + arglist = ['my_stack'] + self.stack_client.template = mock.MagicMock( + return_value=yaml.load(inline_templates.FULL_TEMPLATE, + Loader=template_format.yaml_loader)) + parsed_args = self.check_parser(self.cmd, arglist, []) + + columns, outputs = self.cmd.take_action(parsed_args) + + for f in self.fields: + self.assertIn(f, columns) + + def test_stack_template_show_short_template(self): + arglist = ['my_stack'] + self.stack_client.template = mock.MagicMock( + return_value=yaml.load(inline_templates.SHORT_TEMPLATE, + Loader=template_format.yaml_loader)) + parsed_args = self.check_parser(self.cmd, arglist, []) + + columns, outputs = self.cmd.take_action(parsed_args) + + for f in ['heat_template_version', 'resources']: + self.assertIn(f, columns) + + def test_stack_template_show_not_found(self): + arglist = ['my_stack'] + self.stack_client.template = mock.MagicMock( + side_effect=heat_exc.HTTPNotFound) + parsed_args = self.check_parser(self.cmd, arglist, []) + + self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args) diff --git a/setup.cfg b/setup.cfg index 1f6fbb00..bdb82d2b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -45,6 +45,7 @@ openstack.orchestration.v1 = stack_resource_metadata = heatclient.osc.v1.resources:ResourceMetadata stack_show = heatclient.osc.v1.stack:ShowStack stack_snapshot_list = heatclient.osc.v1.snapshot:ListSnapshot + stack_template_show = heatclient.osc.v1.stack:TemplateShowStack stack_update = heatclient.osc.v1.stack:UpdateStack [global]