OpenstackClient plugin for template show
This change implements the 'openstack stack template show' command. Blueprint: heat-support-python-openstackclient Change-Id: I4a832435e692fb92a169d01a9e95c5c083c49531
This commit is contained in:
parent
270d0178f8
commit
f6373978e5
|
@ -807,3 +807,31 @@ class OutputListStack(lister.Lister):
|
||||||
columns,
|
columns,
|
||||||
(utils.get_dict_properties(s, columns) for s in outputs)
|
(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='<NAME or ID>',
|
||||||
|
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)
|
||||||
|
|
|
@ -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
|
||||||
|
'''
|
|
@ -16,12 +16,15 @@ import io
|
||||||
import mock
|
import mock
|
||||||
import six
|
import six
|
||||||
import testscenarios
|
import testscenarios
|
||||||
|
import yaml
|
||||||
|
|
||||||
from openstackclient.common import exceptions as exc
|
from openstackclient.common import exceptions as exc
|
||||||
from openstackclient.common import utils
|
from openstackclient.common import utils
|
||||||
|
|
||||||
|
from heatclient.common import template_format
|
||||||
from heatclient import exc as heat_exc
|
from heatclient import exc as heat_exc
|
||||||
from heatclient.osc.v1 import stack
|
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.tests.unit.osc.v1 import fakes as orchestration_fakes
|
||||||
from heatclient.v1 import stacks
|
from heatclient.v1 import stacks
|
||||||
|
|
||||||
|
@ -757,3 +760,45 @@ class TestStackOutputList(TestStack):
|
||||||
error = self.assertRaises(exc.CommandError,
|
error = self.assertRaises(exc.CommandError,
|
||||||
self.cmd.take_action, parsed_args)
|
self.cmd.take_action, parsed_args)
|
||||||
self.assertEqual('Stack not found: my_stack', str(error))
|
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)
|
||||||
|
|
|
@ -45,6 +45,7 @@ openstack.orchestration.v1 =
|
||||||
stack_resource_metadata = heatclient.osc.v1.resources:ResourceMetadata
|
stack_resource_metadata = heatclient.osc.v1.resources:ResourceMetadata
|
||||||
stack_show = heatclient.osc.v1.stack:ShowStack
|
stack_show = heatclient.osc.v1.stack:ShowStack
|
||||||
stack_snapshot_list = heatclient.osc.v1.snapshot:ListSnapshot
|
stack_snapshot_list = heatclient.osc.v1.snapshot:ListSnapshot
|
||||||
|
stack_template_show = heatclient.osc.v1.stack:TemplateShowStack
|
||||||
stack_update = heatclient.osc.v1.stack:UpdateStack
|
stack_update = heatclient.osc.v1.stack:UpdateStack
|
||||||
|
|
||||||
[global]
|
[global]
|
||||||
|
|
Loading…
Reference in New Issue