Expose resource attributes in the engine

This changes the engine to allow the user to be able to view resource
attributes after creating a stack, even if such attributes were not
included in the template outputs.

Implements: blueprint detailed-resource-show
Change-Id: I842eb89ac42de8d525d2092ff9d02e70daa8a981
This commit is contained in:
Anderson Mesquita 2014-11-17 17:54:32 -05:00
parent d7ed5b28c9
commit 6d8a5cb35c
4 changed files with 72 additions and 8 deletions

View File

@ -120,6 +120,25 @@ def format_stack(stack, preview=False):
return info
def format_resource_attributes(resource, with_attr=None):
def resolve(attr, resolver):
try:
return resolver[attr]
except Exception:
return None
resolver = resource.attributes
if 'show' in resolver.keys():
resolver = resolver['show']
if not with_attr:
with_attr = []
attributes = set(resolver.keys() + with_attr)
return dict((attr, resolve(attr, resolver))
for attr in attributes)
def format_resource_properties(resource):
def get_property(prop):
try:
@ -131,7 +150,8 @@ def format_resource_properties(resource):
for prop in resource.properties_schema.keys())
def format_stack_resource(resource, detail=True, with_props=False):
def format_stack_resource(resource, detail=True, with_props=False,
with_attr=None):
'''
Return a representation of the given resource that matches the API output
expectations.
@ -161,6 +181,8 @@ def format_stack_resource(resource, detail=True, with_props=False):
if detail:
res[rpc_api.RES_DESCRIPTION] = resource.t.description
res[rpc_api.RES_METADATA] = resource.metadata_get()
res[rpc_api.RES_SCHEMA_ATTRIBUTES] = format_resource_attributes(
resource, with_attr)
if with_props:
res[rpc_api.RES_SCHEMA_PROPERTIES] = format_resource_properties(

View File

@ -349,7 +349,7 @@ class EngineService(service.Service):
by the RPC caller.
"""
RPC_API_VERSION = '1.1'
RPC_API_VERSION = '1.2'
def __init__(self, host, topic, manager=None):
super(EngineService, self).__init__()
@ -1085,7 +1085,8 @@ class EngineService(service.Service):
raise exception.ResourceNotAvailable(resource_name=resource_name)
@request_context
def describe_stack_resource(self, cnxt, stack_identity, resource_name):
def describe_stack_resource(self, cnxt, stack_identity, resource_name,
with_attr=None):
s = self._get_stack(cnxt, stack_identity)
stack = parser.Stack.load(cnxt, stack=s)
@ -1096,7 +1097,8 @@ class EngineService(service.Service):
self._verify_stack_resource(stack, resource_name)
return api.format_stack_resource(stack[resource_name])
return api.format_stack_resource(stack[resource_name],
with_attr=with_attr)
@request_context
def resource_signal(self, cnxt, stack_identity, resource_name, details):

View File

@ -76,10 +76,14 @@ class FormatTest(common.HeatTestCase):
rpc_api.RES_ID,
rpc_api.RES_STACK_ID,
rpc_api.RES_STACK_NAME,
rpc_api.RES_REQUIRED_BY))
rpc_api.RES_REQUIRED_BY,
))
resource_details_keys = resource_keys.union(set(
(rpc_api.RES_DESCRIPTION, rpc_api.RES_METADATA)))
resource_details_keys = resource_keys.union(set((
rpc_api.RES_DESCRIPTION,
rpc_api.RES_METADATA,
rpc_api.RES_SCHEMA_ATTRIBUTES,
)))
formatted = api.format_stack_resource(res, True)
self.assertEqual(resource_details_keys, set(formatted.keys()))
@ -96,6 +100,41 @@ class FormatTest(common.HeatTestCase):
formatted_props = formatted[rpc_api.RES_SCHEMA_PROPERTIES]
self.assertEqual('formatted_res_props', formatted_props)
@mock.patch.object(api, 'format_resource_attributes')
def test_format_stack_resource_with_attributes(self, mock_format_attrs):
mock_format_attrs.return_value = 'formatted_resource_attrs'
res = self.stack['generic1']
formatted = api.format_stack_resource(res, True, with_attr=['a', 'b'])
formatted_attrs = formatted[rpc_api.RES_SCHEMA_ATTRIBUTES]
self.assertEqual('formatted_resource_attrs', formatted_attrs)
def test_format_resource_attributes(self):
res = self.stack['generic1']
formatted_attributes = api.format_resource_attributes(res)
self.assertEqual(2, len(formatted_attributes))
self.assertIn('foo', formatted_attributes)
self.assertIn('Foo', formatted_attributes)
def test_format_resource_attributes_show_attribute(self):
res = mock.Mock()
res.attributes = {'a': 'a_value', 'show': {'b': 'b_value'}}
formatted_attributes = api.format_resource_attributes(res)
self.assertIn('b', formatted_attributes)
self.assertNotIn('a', formatted_attributes)
def test_format_resource_attributes_force_attributes(self):
res = self.stack['generic1']
force_attrs = ['a1', 'a2']
formatted_attributes = api.format_resource_attributes(res, force_attrs)
self.assertEqual(4, len(formatted_attributes))
self.assertIn('foo', formatted_attributes)
self.assertIn('Foo', formatted_attributes)
self.assertIn('a1', formatted_attributes)
self.assertIn('a2', formatted_attributes)
def _get_formatted_resource_properties(self, res_name):
tmpl = parser.Template(template_format.parse('''
heat_template_version: 2013-05-23

View File

@ -2281,7 +2281,7 @@ class StackServiceTest(common.HeatTestCase):
self.m.ReplayAll()
r = self.eng.describe_stack_resource(self.ctx, self.stack.identifier(),
'WebServer')
'WebServer', with_attr=None)
self.assertIn('resource_identity', r)
self.assertIn('description', r)
@ -2296,6 +2296,7 @@ class StackServiceTest(common.HeatTestCase):
self.assertIn('resource_type', r)
self.assertIn('physical_resource_id', r)
self.assertIn('resource_name', r)
self.assertIn('attributes', r)
self.assertEqual('WebServer', r['resource_name'])
self.m.VerifyAll()