Removes redundant validation of template (1)

As part of stack create and preview, template is being
validated twice, first at service._validate_new_stack()
and second at stack.validate() by self.t.validate().
This patch fixes this issue.
It also improves code readability by using
proper indentation.

NOTE: second part, will have dogpile cache backend
integration

Change-Id: I86649752cadcd145760d482d07313881183b02b0
Closes-bug: #1444316
This commit is contained in:
Kanagaraj Manickam 2015-04-17 14:31:50 +05:30
parent 41159da614
commit 81507cc09f
2 changed files with 72 additions and 14 deletions

View File

@ -15,6 +15,7 @@ import abc
import collections
import copy
import functools
import hashlib
from oslo_log import log as logging
import six
@ -115,8 +116,10 @@ class Template(collections.Mapping):
self.files = files or {}
self.maps = self[self.MAPPINGS]
self.env = env or environment.Environment({})
self.version = get_version(self.t,
list(six.iterkeys(_template_classes)))
self.t_digest = None
def __deepcopy__(self, memo):
return Template(copy.deepcopy(self.t, memo), files=self.files,
@ -226,6 +229,18 @@ class Template(collections.Mapping):
sections (e.g. parameters are check by parameters schema class).
'''
t_digest = hashlib.sha256(six.text_type(self.t)).hexdigest()
# TODO(kanagaraj-manickam) currently t_digest is stored in self. which
# is used to check whether already template is validated or not.
# But it needs to be loaded from dogpile cache backend once its
# available in heat (http://specs.openstack.org/openstack/heat-specs/
# specs/liberty/constraint-validation-cache.html). This is required
# as multiple heat-engines may process the same template at least
# in case of instance_group. And it fixes partially bug 1444316
if t_digest == self.t_digest:
return
# check top-level sections
for k in six.iterkeys(self.t):
@ -243,6 +258,7 @@ class Template(collections.Mapping):
message = _('Resources must contain Resource. '
'Found a [%s] instead') % type(res)
raise exception.StackValidationFailed(message=message)
self.t_digest = t_digest
@classmethod
def create_empty_template(cls,

View File

@ -12,6 +12,7 @@
# under the License.
import copy
import hashlib
import json
import fixtures
@ -271,6 +272,27 @@ class ParserTest(common.HeatTestCase):
class TestTemplateValidate(common.HeatTestCase):
def test_template_validate_cfn_check_t_digest(self):
t = {
'AWSTemplateFormatVersion': '2010-09-09',
'Description': 'foo',
'Parameters': {},
'Mappings': {},
'Resources': {
'server': {
'Type': 'OS::Nova::Server'
}
},
'Outputs': {},
}
tmpl = template.Template(t)
self.assertIsNone(tmpl.t_digest)
tmpl.validate()
self.assertEqual(hashlib.sha256(six.text_type(t)).hexdigest(),
tmpl.t_digest,
'invalid template digest')
def test_template_validate_cfn_good(self):
t = {
'AWSTemplateFormatVersion': '2010-09-09',
@ -328,15 +350,35 @@ class TestTemplateValidate(common.HeatTestCase):
def test_template_validate_cfn_empty(self):
t = template_format.parse('''
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Resources:
Outputs:
''')
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Resources:
Outputs:
''')
tmpl = template.Template(t)
err = tmpl.validate()
self.assertIsNone(err)
def test_template_validate_hot_check_t_digest(self):
t = {
'heat_template_version': '2015-04-30',
'description': 'foo',
'parameters': {},
'resources': {
'server': {
'type': 'OS::Nova::Server'
}
},
'outputs': {},
}
tmpl = template.Template(t)
self.assertIsNone(tmpl.t_digest)
tmpl.validate()
self.assertEqual(hashlib.sha256(six.text_type(t)).hexdigest(),
tmpl.t_digest,
'invalid template digest')
def test_template_validate_hot_good(self):
t = {
'heat_template_version': '2013-05-23',
@ -507,16 +549,16 @@ class TemplateTest(common.HeatTestCase):
def test_invalid_template(self):
scanner_error = '''
1
Mappings:
ValidMapping:
TestKey: TestValue
'''
1
Mappings:
ValidMapping:
TestKey: TestValue
'''
parser_error = '''
Mappings:
ValidMapping:
TestKey: {TestKey1: "Value1" TestKey2: "Value2"}
'''
Mappings:
ValidMapping:
TestKey: {TestKey1: "Value1" TestKey2: "Value2"}
'''
self.assertRaises(ValueError, template_format.parse, scanner_error)
self.assertRaises(ValueError, template_format.parse, parser_error)