Tolerate bad environment until validation

Currently if we get a bad environment for a template_resource,
it causes an exception in the resource constructor, which does cause
the stack create to fail, but also all subsequent operations too.

By tolerating the error in the constructor, we can catch it instead at
validation time.

Change-Id: Ia971d8f1c50ca6f265ec36ea564aeba1638de541
Closes-Bug: 1227816
This commit is contained in:
Steven Hardy 2013-09-19 22:31:16 +01:00
parent 6d01a0daa7
commit c6b1c61376
2 changed files with 75 additions and 7 deletions

View File

@ -50,7 +50,14 @@ class TemplateResource(stack_resource.StackResource):
else:
self.allowed_schemes = ('http', 'https', 'file')
tmpl = template.Template(self.parsed_nested)
# parse_nested can fail if the URL in the environment is bad
# or otherwise inaccessible. Suppress the error here so the
# stack can be deleted, and detect it at validate/create time
try:
tmpl = template.Template(self.parsed_nested)
except ValueError:
tmpl = template.Template({})
self.properties_schema = (properties.Properties
.schema_from_params(tmpl.param_schemata()))
self.attributes_schema = (attributes.Attributes
@ -146,6 +153,11 @@ class TemplateResource(stack_resource.StackResource):
raise exception.StackValidationFailed(message=msg)
def validate(self):
try:
td = self.template_data
except ValueError as ex:
msg = _("Failed to retrieve template data: %s") % str(ex)
raise exception.StackValidationFailed(message=msg)
cri = self.stack.env.get_resource_info(
self.type(),
registry_type=environment.ClassResourceInfo)

View File

@ -425,7 +425,7 @@ class ProviderTemplateTest(HeatTestCase):
def test_user_template_not_retrieved_by_file(self):
# make sure that a TemplateResource defined in the user environment
# can NOT be retrieved using the "file:" scheme.
# can NOT be retrieved using the "file:" scheme, validation should fail
env = environment.Environment()
test_templ_name = 'file:///etc/heatr/flippy.yaml'
env.load({'resource_registry':
@ -434,8 +434,64 @@ class ProviderTemplateTest(HeatTestCase):
parser.Template({}), env=env,
stack_id=uuidutils.generate_uuid())
self.assertRaises(ValueError,
template_resource.TemplateResource,
'test_t_res',
{"Type": 'Test::Flippy'},
stack)
temp_res = template_resource.TemplateResource('test_t_res',
{"Type": 'Test::Flippy'},
stack)
self.assertRaises(exception.StackValidationFailed, temp_res.validate)
def test_system_template_retrieve_fail(self):
# make sure that a TemplateResource defined in the global environment
# fails gracefully if the template file specified is inaccessible
# we should be able to create the TemplateResource object, but
# validation should fail, when the second attempt to access it is
# made in validate()
g_env = resources.global_env()
test_templ_name = 'file:///etc/heatr/frodo.yaml'
g_env.load({'resource_registry':
{'Test::Frodo': test_templ_name}})
stack = parser.Stack(utils.dummy_context(), 'test_stack',
parser.Template({}),
stack_id=uuidutils.generate_uuid())
self.m.StubOutWithMock(urlfetch, "get")
urlfetch.get(test_templ_name,
allowed_schemes=('http', 'https',
'file')).AndRaise(IOError)
urlfetch.get(test_templ_name,
allowed_schemes=('http', 'https',
'file')).AndRaise(IOError)
self.m.ReplayAll()
temp_res = template_resource.TemplateResource('test_t_res',
{"Type": 'Test::Frodo'},
stack)
self.assertRaises(exception.StackValidationFailed, temp_res.validate)
self.m.VerifyAll()
def test_user_template_retrieve_fail(self):
# make sure that a TemplateResource defined in the user environment
# fails gracefully if the template file specified is inaccessible
# we should be able to create the TemplateResource object, but
# validation should fail, when the second attempt to access it is
# made in validate()
env = environment.Environment()
test_templ_name = 'http://heatr/noexist.yaml'
env.load({'resource_registry':
{'Test::Flippy': test_templ_name}})
stack = parser.Stack(utils.dummy_context(), 'test_stack',
parser.Template({}), env=env,
stack_id=uuidutils.generate_uuid())
self.m.StubOutWithMock(urlfetch, "get")
urlfetch.get(test_templ_name,
allowed_schemes=('http', 'https')).AndRaise(IOError)
urlfetch.get(test_templ_name,
allowed_schemes=('http', 'https')).AndRaise(IOError)
self.m.ReplayAll()
temp_res = template_resource.TemplateResource('test_t_res',
{"Type": 'Test::Flippy'},
stack)
self.assertRaises(exception.StackValidationFailed, temp_res.validate)
self.m.VerifyAll()