Raise EntityNotFound in get_resource_info()

Rather than return None when doing get_resource_info() on resource types
that don't exist, raise an EntityNotFound exception. We can then catch that
and turn it into StackValidationFailed where appropriate, but we don't make
assumptions about where the code is being called from at the point where we
raise the exception.

Change-Id: Idf6f837befea8ccb10fdaf9196490da3dd5be1fb
Related-Bug: #1447194
Related-Bug: #1518458
This commit is contained in:
Zane Bitter 2015-11-30 18:08:56 -05:00
parent a6813f9175
commit 9935c38e5c
6 changed files with 56 additions and 33 deletions

View File

@ -400,8 +400,12 @@ class ResourceRegistry(object):
giter)
for info in sorted(matches):
match = info.get_resource_info(resource_type,
resource_name)
try:
match = info.get_resource_info(resource_type,
resource_name)
except exception.EntityNotFound:
continue
if registry_type is None or isinstance(match, registry_type):
if ignore is not None and match == ignore:
continue
@ -416,6 +420,9 @@ class ResourceRegistry(object):
self._register_info([resource_type], info)
return match
raise exception.EntityNotFound(entity='Resource Type',
name=resource_type)
def get_class(self, resource_type, resource_name=None, files=None):
if resource_type == "":
msg = _('Resource "%s" has no type') % resource_name
@ -428,11 +435,12 @@ class ResourceRegistry(object):
msg = _('Resource "%s" type is not a string') % resource_name
raise exception.StackValidationFailed(message=msg)
info = self.get_resource_info(resource_type,
resource_name=resource_name)
if info is None:
msg = _("Unknown resource Type : %s") % resource_type
raise exception.StackValidationFailed(message=msg)
try:
info = self.get_resource_info(resource_type,
resource_name=resource_name)
except exception.EntityNotFound as exc:
raise exception.StackValidationFailed(message=six.text_type(exc))
return info.get_class(files=files)
def as_dict(self):

View File

@ -429,9 +429,14 @@ class Resource(object):
"""
if self.type() == resource_type:
return True
ri = self.stack.env.get_resource_info(self.type(),
self.name)
return ri is not None and ri.name == resource_type
try:
ri = self.stack.env.get_resource_info(self.type(),
self.name)
except exception.EntityNotFound:
return False
else:
return ri.name == resource_type
def implementation_signature(self):
"""Return a tuple defining the implementation.

View File

@ -71,11 +71,12 @@ class TemplateResource(stack_resource.StackResource):
return TemplateResource
def _get_resource_info(self, rsrc_defn):
tri = self.stack.env.get_resource_info(
rsrc_defn.resource_type,
resource_name=rsrc_defn.name,
registry_type=environment.TemplateResourceInfo)
if tri is None:
try:
tri = self.stack.env.get_resource_info(
rsrc_defn.resource_type,
resource_name=rsrc_defn.name,
registry_type=environment.TemplateResourceInfo)
except exception.EntityNotFound:
self.validation_exception = ValueError(_(
'Only Templates with an extension of .yaml or '
'.template are supported'))
@ -88,7 +89,7 @@ class TemplateResource(stack_resource.StackResource):
else:
self.allowed_schemes = ('http', 'https', 'file')
return tri
return tri
@staticmethod
def get_template_file(template_name, allowed_schemes):
@ -266,14 +267,17 @@ class TemplateResource(stack_resource.StackResource):
except ValueError as ex:
msg = _("Failed to retrieve template data: %s") % ex
raise exception.StackValidationFailed(message=msg)
fri = self.stack.env.get_resource_info(
self.type(),
resource_name=self.name,
ignore=self.resource_info)
# If we're using an existing resource type as a facade for this
# template, check for compatibility between the interfaces.
if fri is not None:
try:
fri = self.stack.env.get_resource_info(
self.type(),
resource_name=self.name,
ignore=self.resource_info)
except exception.EntityNotFound:
pass
else:
facade_cls = fri.get_class(files=self.stack.t.files)
self._validate_against_facade(facade_cls)

View File

@ -419,7 +419,8 @@ class ResourceGroupTest(common.HeatTestCase):
resg = resource_group.ResourceGroup('test', snip, stack)
exc = self.assertRaises(exception.StackValidationFailed,
resg.validate)
self.assertIn('Unknown resource Type', six.text_type(exc))
exp_msg = 'The Resource Type (idontexist) could not be found.'
self.assertIn(exp_msg, six.text_type(exc))
def test_reference_attr(self):
stack = utils.parse_stack(template2)

View File

@ -105,8 +105,9 @@ class EnvironmentTest(common.HeatTestCase):
u'OS::Networking::FloatingIP': 'ip.yaml'}}}}
env = environment.Environment()
self.assertIsNone(env.get_resource_info('OS::Networking::FloatingIP',
'my_fip'))
self.assertRaises(exception.EntityNotFound,
env.get_resource_info,
'OS::Networking::FloatingIP', 'my_fip')
env.load(new_env)
self.assertEqual('ip.yaml',
@ -203,7 +204,7 @@ class EnvironmentDuplicateTest(common.HeatTestCase):
expected_equal=True)),
('diff_temp', dict(resource_type='not.yaml',
expected_equal=False)),
('diff_map', dict(resource_type='OS::SomethingElse',
('diff_map', dict(resource_type='OS::Nova::Server',
expected_equal=False)),
('diff_path', dict(resource_type='a/test.yaml',
expected_equal=False)),
@ -385,7 +386,8 @@ class GlobalEnvLoadingTest(common.HeatTestCase):
resources._load_global_environment(g_env)
# 3. assert our resource is in now gone.
self.assertIsNone(g_env.get_resource_info('OS::Nova::Server'))
self.assertRaises(exception.EntityNotFound,
g_env.get_resource_info, 'OS::Nova::Server')
# 4. make sure we haven't removed something we shouldn't have
self.assertEqual(instance.Instance,
@ -410,7 +412,8 @@ class GlobalEnvLoadingTest(common.HeatTestCase):
resources._load_global_environment(g_env)
# 3. assert our resources are now gone.
self.assertIsNone(g_env.get_resource_info('AWS::EC2::Instance'))
self.assertRaises(exception.EntityNotFound,
g_env.get_resource_info, 'AWS::EC2::Instance')
# 4. make sure we haven't removed something we shouldn't have
self.assertEqual(server.Server,
@ -521,11 +524,12 @@ class ChildEnvTest(common.HeatTestCase):
self.assertIsNotNone(victim)
cenv = environment.get_child_environment(penv, None,
item_to_remove=victim)
res = cenv.get_resource_info('OS::Food', resource_name='abc')
self.assertIsNone(res)
self.assertRaises(exception.EntityNotFound,
cenv.get_resource_info,
'OS::Food', resource_name='abc')
self.assertNotIn('OS::Food',
cenv.user_env_as_dict()['resource_registry'])
# make sure the parent env is uneffected
# make sure the parent env is unaffected
innocent = penv.get_resource_info('OS::Food', resource_name='abc')
self.assertIsNotNone(innocent)
@ -586,8 +590,9 @@ class ChildEnvTest(common.HeatTestCase):
self.assertIn('hooks', resources['nested_res'])
self.assertIsNotNone(
cenv.get_resource_info('OS::Food', resource_name='abc'))
self.assertIsNone(
cenv.get_resource_info('OS::Fruit', resource_name='a'))
self.assertRaises(exception.EntityNotFound,
cenv.get_resource_info,
'OS::Fruit', resource_name='a')
res = cenv.get_resource_info('OS::Fruit', resource_name='b')
self.assertIsNotNone(res)
self.assertEqual(u'carrots.yaml', res.value)

View File

@ -388,7 +388,7 @@ class StackResourceTest(StackResourceBaseTest):
def _test_validate_unknown_resource_type(self, stack_name, tmpl,
resource_name):
raise_exc_msg = ('Unknown resource Type : idontexist')
raise_exc_msg = 'The Resource Type (idontexist) could not be found.'
stack = parser.Stack(utils.dummy_context(), stack_name, tmpl)
rsrc = stack[resource_name]