From 2e4a6e237cf226eb61cf905a72cfb5eb3d5177f0 Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Tue, 19 Dec 2017 16:36:43 -0500 Subject: [PATCH] Use appropriate exception in StackResource.get_output() Don't raise InvalidTemplateAttribute in StackResource.get_output() when an output does not exist - it's not the case that get_output() is only used for fetching attributes. Instead, raise NotFound from get_output(), and translate that to InvalidTemplateAttribute in the caller when we are actually fetching an attribute. Change-Id: I4f883e4b583a965785d0a595c8c33b47dc94118c Related-Bug: #1719333 --- heat/engine/resources/aws/cfn/stack.py | 6 +++++- heat/engine/resources/aws/lb/loadbalancer.py | 6 +++++- heat/engine/resources/stack_resource.py | 15 ++++++++------- heat/engine/resources/template_resource.py | 9 +++++++-- heat/tests/test_stack_resource.py | 4 ++-- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/heat/engine/resources/aws/cfn/stack.py b/heat/engine/resources/aws/cfn/stack.py index 8f348e7390..4ecb1b6d31 100644 --- a/heat/engine/resources/aws/cfn/stack.py +++ b/heat/engine/resources/aws/cfn/stack.py @@ -85,7 +85,11 @@ class NestedStack(stack_resource.StackResource): if key and not key.startswith('Outputs.'): raise exception.InvalidTemplateAttribute(resource=self.name, key=key) - attribute = self.get_output(key.partition('.')[-1]) + try: + attribute = self.get_output(key.partition('.')[-1]) + except exception.NotFound: + raise exception.InvalidTemplateAttribute(resource=self.name, + key=key) return attributes.select_from_attribute(attribute, path) def get_reference_id(self): diff --git a/heat/engine/resources/aws/lb/loadbalancer.py b/heat/engine/resources/aws/lb/loadbalancer.py index 8ee4bbf078..439de06431 100644 --- a/heat/engine/resources/aws/lb/loadbalancer.py +++ b/heat/engine/resources/aws/lb/loadbalancer.py @@ -628,7 +628,11 @@ backend servers def _resolve_attribute(self, name): """We don't really support any of these yet.""" if name == self.DNS_NAME: - return self.get_output('PublicIp') + try: + return self.get_output('PublicIp') + except exception.NotFound: + raise exception.InvalidTemplateAttribute(resource=self.name, + key=name) elif name in self.attributes_schema: # Not sure if we should return anything for the other attribs # since they aren't really supported in any meaningful way diff --git a/heat/engine/resources/stack_resource.py b/heat/engine/resources/stack_resource.py index a3566c9062..892e9fcc62 100644 --- a/heat/engine/resources/stack_resource.py +++ b/heat/engine/resources/stack_resource.py @@ -606,10 +606,7 @@ class StackResource(resource.Resource): def get_output(self, op): """Return the specified Output value from the nested stack. - If the output key does not exist, raise an InvalidTemplateAttribute - exception. (Note that TemplateResource.get_attribute() relies on this - particular exception, not KeyError, being raised if the key does not - exist.) + If the output key does not exist, raise a NotFound exception. """ if (self._outputs is None or (op in self._outputs and @@ -626,8 +623,8 @@ class StackResource(resource.Resource): self._outputs = {o[rpc_api.OUTPUT_KEY]: o for o in outputs} if op not in self._outputs: - raise exception.InvalidTemplateAttribute(resource=self.name, - key=op) + raise exception.NotFound(_('Specified output key %s not ' + 'found.') % op) output_data = self._outputs[op] if rpc_api.OUTPUT_ERROR in output_data: @@ -639,4 +636,8 @@ class StackResource(resource.Resource): return output_data[rpc_api.OUTPUT_VALUE] def _resolve_attribute(self, name): - return self.get_output(name) + try: + return self.get_output(name) + except exception.NotFound: + raise exception.InvalidTemplateAttribute(resource=self.name, + key=name) diff --git a/heat/engine/resources/template_resource.py b/heat/engine/resources/template_resource.py index a0bdefc0b4..fcd3737483 100644 --- a/heat/engine/resources/template_resource.py +++ b/heat/engine/resources/template_resource.py @@ -330,7 +330,7 @@ class TemplateResource(stack_resource.StackResource): message=output[rpc_api.OUTPUT_ERROR]) except exception.TemplateOutputError as err: LOG.info('%s', err) - except (exception.InvalidTemplateAttribute, exception.NotFound): + except exception.NotFound: pass else: self._reference_id = output[rpc_api.OUTPUT_VALUE] @@ -347,4 +347,9 @@ class TemplateResource(stack_resource.StackResource): return grouputils.get_nested_attrs(self, key, False, *path) # then look for normal outputs - return attributes.select_from_attribute(self.get_output(key), path) + try: + return attributes.select_from_attribute(self.get_output(key), + path) + except exception.NotFound: + raise exception.InvalidTemplateAttribute(resource=self.name, + key=key) diff --git a/heat/tests/test_stack_resource.py b/heat/tests/test_stack_resource.py index 64ece0c0d8..cbb6a95389 100644 --- a/heat/tests/test_stack_resource.py +++ b/heat/tests/test_stack_resource.py @@ -689,7 +689,7 @@ class StackResourceAttrTest(StackResourceBaseTest): output = {'outputs': []} self.parent_resource._rpc_client.show_stack.return_value = [output] - self.assertRaises(exception.InvalidTemplateAttribute, + self.assertRaises(exception.NotFound, self.parent_resource.get_output, "key") @@ -701,7 +701,7 @@ class StackResourceAttrTest(StackResourceBaseTest): output = {} self.parent_resource._rpc_client.show_stack.return_value = [output] - self.assertRaises(exception.InvalidTemplateAttribute, + self.assertRaises(exception.NotFound, self.parent_resource.get_output, "key")