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:
parent
d7ed5b28c9
commit
6d8a5cb35c
@ -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(
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user