Define resource/output definition sections with constants

It was unclear what the valid arguments to Template.get_section_name() were
(especially since the function is mis-named for what it actually does in
HOT). Define the arguments as constants and don't pass string literals any
more. Be consistent in how we define paths, standardising on the method in
Resource.validate_template().

Change-Id: Ifd073d9889ff60502f78aaa54532cec2b7814d93
This commit is contained in:
Zane Bitter 2017-11-16 14:18:11 -05:00
parent cb80df4f4a
commit 694dac75ca
6 changed files with 51 additions and 18 deletions

View File

@ -19,6 +19,15 @@ from heat.common import exception
from heat.engine import function from heat.engine import function
# Field names that can be passed to Template.get_section_name() in order to
# determine the appropriate name for a particular template format.
FIELDS = (
VALUE, DESCRIPTION,
) = (
'Value', 'Description',
)
class OutputDefinition(object): class OutputDefinition(object):
"""A definition of a stack output, independent of any template format.""" """A definition of a stack output, independent of any template format."""
@ -30,9 +39,9 @@ class OutputDefinition(object):
self._deps = None self._deps = None
self._all_dep_attrs = None self._all_dep_attrs = None
def validate(self, path=''): def validate(self):
"""Validate the output value without resolving it.""" """Validate the output value without resolving it."""
function.validate(self._value, path) function.validate(self._value, VALUE)
def required_resource_names(self): def required_resource_names(self):
if self._deps is None: if self._deps is None:

View File

@ -18,6 +18,7 @@ from heat.common import exception
from heat.common.i18n import _ from heat.common.i18n import _
from heat.engine import properties from heat.engine import properties
from heat.engine import resource from heat.engine import resource
from heat.engine import rsrc_defn
from heat.engine import support from heat.engine import support
@ -105,8 +106,8 @@ class JobBinary(resource.Resource):
and uuidutils.is_uuid_like(url[len("internal-db://"):]))): and uuidutils.is_uuid_like(url[len("internal-db://"):]))):
msg = _("%s is not a valid job location.") % url msg = _("%s is not a valid job location.") % url
raise exception.StackValidationFailed( raise exception.StackValidationFailed(
path=[self.stack.t.get_section_name('resources'), self.name, path=[self.stack.t.RESOURCES, self.name,
self.stack.t.get_section_name('properties')], self.stack.t.get_section_name(rsrc_defn.PROPERTIES)],
message=msg) message=msg)
def handle_create(self): def handle_create(self):

View File

@ -24,6 +24,7 @@ from heat.common.i18n import _
from heat.engine import constraints from heat.engine import constraints
from heat.engine import properties from heat.engine import properties
from heat.engine import resource from heat.engine import resource
from heat.engine import rsrc_defn
from heat.engine import support from heat.engine import support
from heat.engine import translation from heat.engine import translation
@ -346,9 +347,9 @@ class SaharaNodeGroupTemplate(resource.Resource):
'unsupported': ', '.join(unsupported_processes), 'unsupported': ', '.join(unsupported_processes),
'allowed': ', '.join(allowed_processes)}) 'allowed': ', '.join(allowed_processes)})
raise exception.StackValidationFailed( raise exception.StackValidationFailed(
path=[self.stack.t.get_section_name('resources'), path=[self.stack.t.RESOURCES,
self.name, self.name,
self.stack.t.get_section_name('properties')], self.stack.t.get_section_name(rsrc_defn.PROPERTIES)],
message=msg) message=msg)
def parse_live_resource_data(self, resource_properties, resource_data): def parse_live_resource_data(self, resource_properties, resource_data):

View File

@ -26,6 +26,17 @@ from heat.engine import properties
__all__ = ['ResourceDefinition'] __all__ = ['ResourceDefinition']
# Field names that can be passed to Template.get_section_name() in order to
# determine the appropriate name for a particular template format.
FIELDS = (
TYPE, PROPERTIES, METADATA, DELETION_POLICY, UPDATE_POLICY,
DEPENDS_ON, DESCRIPTION, EXTERNAL_ID,
) = (
'Type', 'Properties', 'Metadata', 'DeletionPolicy', 'UpdatePolicy',
'DependsOn', 'Description', 'external_id',
)
@repr_wrapper @repr_wrapper
class ResourceDefinition(object): class ResourceDefinition(object):
"""A definition of a resource, independent of any template format.""" """A definition of a resource, independent of any template format."""
@ -230,9 +241,9 @@ class ResourceDefinition(object):
return '.'.join([self.name, section]) return '.'.join([self.name, section])
prop_deps = function.dependencies(self._properties, prop_deps = function.dependencies(self._properties,
path('Properties')) path(PROPERTIES))
metadata_deps = function.dependencies(self._metadata, metadata_deps = function.dependencies(self._metadata,
path('Metadata')) path(METADATA))
implicit_depends = six.moves.map(lambda rp: rp.name, implicit_depends = six.moves.map(lambda rp: rp.name,
itertools.chain(prop_deps, itertools.chain(prop_deps,
metadata_deps)) metadata_deps))
@ -282,7 +293,7 @@ class ResourceDefinition(object):
""" """
props = properties.Properties(schema, self._properties or {}, props = properties.Properties(schema, self._properties or {},
function.resolve, context=context, function.resolve, context=context,
section='Properties') section=PROPERTIES)
props.update_translation(self._rules, self._client_resolve) props.update_translation(self._rules, self._client_resolve)
return props return props
@ -301,7 +312,7 @@ class ResourceDefinition(object):
""" """
props = properties.Properties(schema, self._update_policy or {}, props = properties.Properties(schema, self._update_policy or {},
function.resolve, context=context, function.resolve, context=context,
section='UpdatePolicy') section=UPDATE_POLICY)
props.update_translation(self._rules, self._client_resolve) props.update_translation(self._rules, self._client_resolve)
return props return props

View File

@ -904,13 +904,15 @@ class Stack(collections.Mapping):
for op_name, output in six.iteritems(self.outputs): for op_name, output in six.iteritems(self.outputs):
try: try:
path = '.'.join([self.t.OUTPUTS, op_name, output.validate()
self.t.OUTPUT_VALUE]) except exception.StackValidationFailed as ex:
output.validate(path) path = [self.t.OUTPUTS, op_name,
except exception.StackValidationFailed: self.t.get_section_name(ex.path[0])]
raise path.extend(ex.path[1:])
except AssertionError: raise exception.StackValidationFailed(
raise error=ex.error,
path=path,
message=ex.error_message)
def requires_deferred_auth(self): def requires_deferred_auth(self):
"""Determine whether to perform API requests with deferred auth. """Determine whether to perform API requests with deferred auth.

View File

@ -213,7 +213,16 @@ class Template(collections.Mapping):
@abc.abstractmethod @abc.abstractmethod
def get_section_name(self, section): def get_section_name(self, section):
"""Return a correct section name.""" """Get the name of a field within a resource or output definition.
Return the name of the given field (specified by the constants given
in heat.engine.rsrc_defn and heat.engine.output) in the template
format. This is used in error reporting to help users find the
location of errors in the template.
Note that 'section' here does not refer to a top-level section of the
template (like parameters, resources, &c.) as it does everywhere else.
"""
pass pass
@abc.abstractmethod @abc.abstractmethod