diff --git a/heat/engine/api.py b/heat/engine/api.py index def6d8956..308186078 100644 --- a/heat/engine/api.py +++ b/heat/engine/api.py @@ -11,8 +11,6 @@ # License for the specific language governing permissions and limitations # under the License. -import collections - from oslo_log import log as logging from oslo_utils import timeutils import six @@ -147,31 +145,32 @@ def format_stack(stack, preview=False): def format_resource_attributes(resource, with_attr=None): + """Format resource attributes in user-friendly way for resource-show. + + Fetch all resource attributes and return it to caller. If with_attr is + not empty request these attributes additionally and try to resolve them. + If some attribute cannot be resolved then return None as attribute value. + + :param resource: resource for which we shows the attributes + :param with_attr: additional attributes that we need to show in output. + This attributes is useful only if a resource have a + dynamic attribute scheme (f.e. resource with nested stack + or software deployment) because we can fetch these + attributes using with_attr only + :type with_attr: list + :returns attributes and attribute values + :rtype dict + """ + def resolve(attr, attr_resolver): + try: + return attr_resolver[attr] + except Exception: + return None + resolver = resource.attributes if not with_attr: with_attr = [] - def resolve(attr, resolver): - try: - return resolver._resolver(attr) - except Exception: - return None - # if 'show' in attribute_schema, will resolve all attributes of resource - # including the ones are not represented in response of show API, such as - # 'console_urls' for nova server, user can view it by taking with_attr - # parameter - if 'show' in six.iterkeys(resolver): - show_attr = resolve('show', resolver) - # check if 'show' resolved to dictionary. so it's not None - if isinstance(show_attr, collections.Mapping): - for a in with_attr: - if a not in show_attr: - show_attr[a] = resolve(a, resolver) - return show_attr - else: - # remove 'show' attribute if it's None or not a mapping - # then resolve all attributes manually - del resolver._attributes['show'] attributes = set(list(six.iterkeys(resolver)) + with_attr) return dict((attr, resolve(attr, resolver)) for attr in attributes) diff --git a/heat/tests/test_engine_api_utils.py b/heat/tests/test_engine_api_utils.py index bcb9ef711..a3be30783 100644 --- a/heat/tests/test_engine_api_utils.py +++ b/heat/tests/test_engine_api_utils.py @@ -113,17 +113,17 @@ class FormatTest(common.HeatTestCase): # the _resolve_attribute method of 'generic1' returns map with all # attributes except 'show' (because it's None in this test) formatted_attributes = api.format_resource_attributes(res) - expected = {'foo': 'generic1', 'Foo': 'generic1'} + expected = {'foo': 'generic1', 'Foo': 'generic1', 'show': None} self.assertEqual(expected, formatted_attributes) def test_format_resource_attributes_show_attribute(self): res = self.stack['generic3'] res.resource_id = 'generic3_id' formatted_attributes = api.format_resource_attributes(res) - self.assertEqual(3, len(formatted_attributes)) - self.assertIn('foo', formatted_attributes) - self.assertIn('Foo', formatted_attributes) - self.assertIn('Another', formatted_attributes) + self.assertEqual(3, len(formatted_attributes['show'])) + self.assertIn('foo', formatted_attributes['show']) + self.assertIn('Foo', formatted_attributes['show']) + self.assertIn('Another', formatted_attributes['show']) def test_format_resource_attributes_show_attribute_with_attr(self): res = self.stack['generic3'] @@ -131,9 +131,10 @@ class FormatTest(common.HeatTestCase): formatted_attributes = api.format_resource_attributes( res, with_attr=['c']) self.assertEqual(4, len(formatted_attributes)) - self.assertIn('foo', formatted_attributes) - self.assertIn('Foo', formatted_attributes) - self.assertIn('Another', formatted_attributes) + self.assertEqual(3, len(formatted_attributes['show'])) + self.assertIn('foo', formatted_attributes['show']) + self.assertIn('Foo', formatted_attributes['show']) + self.assertIn('Another', formatted_attributes['show']) self.assertIn('c', formatted_attributes) def _get_formatted_resource_properties(self, res_name):