Generate placeholders for resource proxies before validation

Before validating resources, generate placeholder NodeData for them in the
StackDefinition. Currently, all attributes are given a value of None
(consistent with how the get_attr intrinsic functions substitute them when
the resource state indicates that the attributes are not valid now).
Reference IDs are generated as usual (since the logic for what to return
when the state indicates the data are not valid is contained in the
resource plugins).

In the long term, this should help us to remove the state-checking logic
from the intrinsic functions.

In the short term, this allows us to validate template data that is parsed
against the StackDefinition (rather than the Stack), since it gives us a
list of valid attribute names.

In the medium term, this should give us a place to substitute in more
sophisticated placeholder values to do better validation.

Change-Id: I154ff0cd019d279379886fccbd708cf0d39ce53f
This commit is contained in:
Zane Bitter 2017-02-17 13:33:06 -05:00
parent 666930d195
commit f94d76cb32
3 changed files with 18 additions and 8 deletions

View File

@ -871,10 +871,17 @@ class Resource(status.ResourceStatus):
def get_attrs(attrs):
for attr in attrs:
path = (attr,) if isinstance(attr, six.string_types) else attr
try:
yield attr, self.get_attribute(*path)
except exception.InvalidTemplateAttribute as ita:
LOG.info('%s', ita)
if self.action == self.INIT:
if (type(self).get_attribute != Resource.get_attribute or
type(self).FnGetAtt != Resource.FnGetAtt or
path[0] in self.attributes):
# TODO(ricolin) make better placeholder values here
yield path, None
else:
try:
yield attr, self.get_attribute(*path)
except exception.InvalidTemplateAttribute as ita:
LOG.info('%s', ita)
dep_attrs = set(self.stack.get_dep_attrs(
six.itervalues(self.stack.resources),

View File

@ -839,10 +839,11 @@ class Stack(collections.Mapping):
raise exception.StackValidationFailed(
message=_("Duplicate names %s") % dup_names)
if validate_by_deps:
iter_rsc = self.dependencies
else:
iter_rsc = six.itervalues(resources)
iter_rsc = (self.dependencies if validate_by_deps
else six.itervalues(resources))
for name, res in six.iteritems(resources):
stk_defn.update_resource_data(self.defn, name, res.node_data())
unique_defns = set(res.t for res in six.itervalues(resources))
unique_defn_names = set(defn.name for defn in unique_defns)

View File

@ -604,6 +604,7 @@ class MiscMethodsTest(common.HeatTestCase):
self.resource = self.stack['A']
def test_node_data_ok(self):
self.resource.action = self.resource.CREATE
expected_input_data = {'attrs': {(u'flat_dict', u'key2'): 'val2',
(u'flat_dict', u'key3'): 'val3',
(u'nested_dict', u'dict', u'a'): 1,
@ -618,6 +619,7 @@ class MiscMethodsTest(common.HeatTestCase):
self.assertEqual(expected_input_data, actual_input_data.as_dict())
def test_node_data_exception(self):
self.resource.action = self.resource.CREATE
expected_input_data = {'attrs': {},
'id': mock.ANY,
'reference_id': 'A',