Add resource properties to stack-preview
Certain resource details may influence the final price of the infrastructure being created by a stack (e.g. instance flavors), so this adds resources properties to the output of stack-preview. Implements: blueprint stack-preview-details Change-Id: I6ea892dedfc96aeda8e8a21e67562820fd21c7bb
This commit is contained in:
parent
9f26fc53e7
commit
1d7ba6e4a1
@ -111,7 +111,18 @@ def format_stack(stack):
|
||||
return info
|
||||
|
||||
|
||||
def format_stack_resource(resource, detail=True):
|
||||
def format_resource_properties(resource):
|
||||
def get_property(prop):
|
||||
try:
|
||||
return resource.properties[prop]
|
||||
except (KeyError, ValueError):
|
||||
return None
|
||||
|
||||
return dict((prop, get_property(prop))
|
||||
for prop in resource.properties_schema.keys())
|
||||
|
||||
|
||||
def format_stack_resource(resource, detail=True, with_props=False):
|
||||
'''
|
||||
Return a representation of the given resource that matches the API output
|
||||
expectations.
|
||||
@ -142,6 +153,9 @@ def format_stack_resource(resource, detail=True):
|
||||
res[api.RES_DESCRIPTION] = resource.t.description
|
||||
res[api.RES_METADATA] = resource.metadata_get()
|
||||
|
||||
if with_props:
|
||||
res[api.RES_SCHEMA_PROPERTIES] = format_resource_properties(resource)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
@ -149,7 +163,7 @@ def format_stack_preview(stack):
|
||||
def format_resource(res):
|
||||
if isinstance(res, list):
|
||||
return map(format_resource, res)
|
||||
return format_stack_resource(res)
|
||||
return format_stack_resource(res, with_props=True)
|
||||
|
||||
fmt_stack = format_stack(stack)
|
||||
fmt_resources = map(format_resource, stack.preview_resources())
|
||||
|
@ -108,7 +108,15 @@ class TemplateResource(stack_resource.StackResource):
|
||||
if not pval.implemented():
|
||||
continue
|
||||
|
||||
try:
|
||||
val = self.properties[pname]
|
||||
except ValueError:
|
||||
if self.action == self.INIT:
|
||||
prop = self.properties.props[pname]
|
||||
val = prop.get_value(None)
|
||||
else:
|
||||
raise
|
||||
|
||||
if val is not None:
|
||||
# take a list and create a CommaDelimitedList
|
||||
if pval.type() == properties.Schema.LIST:
|
||||
|
@ -46,6 +46,8 @@ class FormatTest(HeatTestCase):
|
||||
})
|
||||
resource._register_class('GenericResourceType',
|
||||
generic_rsrc.GenericResource)
|
||||
resource._register_class('ResWithComplexPropsAndAttrs',
|
||||
generic_rsrc.ResWithComplexPropsAndAttrs)
|
||||
self.stack = parser.Stack(utils.dummy_context(), 'test_stack',
|
||||
template, stack_id=str(uuid.uuid4()))
|
||||
|
||||
@ -82,6 +84,49 @@ class FormatTest(HeatTestCase):
|
||||
formatted = api.format_stack_resource(res, False)
|
||||
self.assertEqual(resource_keys, set(formatted.keys()))
|
||||
|
||||
@mock.patch.object(api, 'format_resource_properties')
|
||||
def test_format_stack_resource_with_props(self, mock_format_props):
|
||||
mock_format_props.return_value = 'formatted_res_props'
|
||||
res = self.stack['generic1']
|
||||
|
||||
formatted = api.format_stack_resource(res, True, with_props=True)
|
||||
formatted_props = formatted[rpc_api.RES_SCHEMA_PROPERTIES]
|
||||
self.assertEqual('formatted_res_props', formatted_props)
|
||||
|
||||
def _get_formatted_resource_properties(self, res_name):
|
||||
tmpl = parser.Template(template_format.parse('''
|
||||
heat_template_version: 2013-05-23
|
||||
resources:
|
||||
resource1:
|
||||
type: ResWithComplexPropsAndAttrs
|
||||
resource2:
|
||||
type: ResWithComplexPropsAndAttrs
|
||||
properties:
|
||||
a_string: foobar
|
||||
resource3:
|
||||
type: ResWithComplexPropsAndAttrs
|
||||
properties:
|
||||
a_string: { get_attr: [ resource2, string] }
|
||||
'''))
|
||||
stack = parser.Stack(utils.dummy_context(), 'test_stack_for_preview',
|
||||
tmpl, stack_id=str(uuid.uuid4()))
|
||||
res = stack[res_name]
|
||||
return api.format_resource_properties(res)
|
||||
|
||||
def test_format_resource_properties_empty(self):
|
||||
props = self._get_formatted_resource_properties('resource1')
|
||||
self.assertIsNone(props['a_string'])
|
||||
self.assertIsNone(props['a_list'])
|
||||
self.assertIsNone(props['a_map'])
|
||||
|
||||
def test_format_resource_properties_direct_props(self):
|
||||
props = self._get_formatted_resource_properties('resource2')
|
||||
self.assertEqual('foobar', props['a_string'])
|
||||
|
||||
def test_format_resource_properties_get_attr(self):
|
||||
props = self._get_formatted_resource_properties('resource3')
|
||||
self.assertEqual('', props['a_string'])
|
||||
|
||||
def test_format_stack_resource_with_nested_stack(self):
|
||||
res = self.stack['generic1']
|
||||
nested_id = {'foo': 'bar'}
|
||||
@ -157,7 +202,7 @@ class FormatTest(HeatTestCase):
|
||||
|
||||
@mock.patch.object(api, 'format_stack_resource')
|
||||
def test_format_stack_preview(self, mock_fmt_resource):
|
||||
def mock_format_resources(res):
|
||||
def mock_format_resources(res, **kwargs):
|
||||
return 'fmt%s' % res
|
||||
|
||||
mock_fmt_resource.side_effect = mock_format_resources
|
||||
@ -170,6 +215,9 @@ class FormatTest(HeatTestCase):
|
||||
self.assertIn('resources', stack)
|
||||
self.assertEqual(['fmt1', ['fmt2', ['fmt3']]], stack['resources'])
|
||||
|
||||
kwargs = mock_fmt_resource.call_args[1]
|
||||
self.assertTrue(kwargs['with_props'])
|
||||
|
||||
def test_format_stack(self):
|
||||
self.stack.created_time = datetime(1970, 1, 1)
|
||||
info = api.format_stack(self.stack)
|
||||
|
@ -16,6 +16,8 @@ import os
|
||||
import uuid
|
||||
import yaml
|
||||
|
||||
import mock
|
||||
|
||||
from heat.common import exception
|
||||
from heat.common import template_format
|
||||
from heat.common import urlfetch
|
||||
@ -157,6 +159,21 @@ class ProviderTemplateTest(HeatTestCase):
|
||||
# verify Map conversion
|
||||
self.assertEqual(map_prop_val, converted_params.get("AMap"))
|
||||
|
||||
with mock.patch.object(properties.Properties, '__getitem__') as m_get:
|
||||
m_get.side_effect = ValueError('boom')
|
||||
|
||||
# If the property doesn't exist on INIT, return default value
|
||||
temp_res.action = temp_res.INIT
|
||||
converted_params = temp_res.child_params()
|
||||
for key in DummyResource.properties_schema:
|
||||
self.assertIn(key, converted_params)
|
||||
self.assertEqual({}, converted_params['AMap'])
|
||||
self.assertEqual(0, converted_params['ANum'])
|
||||
|
||||
# If the property doesn't exist past INIT, then error out
|
||||
temp_res.action = temp_res.CREATE
|
||||
self.assertRaises(ValueError, temp_res.child_params)
|
||||
|
||||
def test_attributes_extra(self):
|
||||
provider = {
|
||||
'HeatTemplateFormatVersion': '2012-12-12',
|
||||
|
Loading…
Reference in New Issue
Block a user