From d098a14d69bf78b7674ec5d75003c21250e640bc Mon Sep 17 00:00:00 2001 From: shangxdy Date: Mon, 5 Dec 2016 14:23:25 +0800 Subject: [PATCH] Add output validation for substitution mappings 1. The outputs defined by the topology template have to match the attributes of the node type or the substituted node template, 2.The observable attributes of the substituted node template have to be defined as attributes of the node type or outputs in the topology template. The patch will be submitted to openstack too. JIRA: PARSER-115 Change-Id: Ifa62be9d5c1be79ceacfa1ae6e3835b2de446f88 Signed-off-by: shangxdy --- .../tosca-parser/toscaparser/common/exception.py | 9 ++++ .../toscaparser/substitution_mappings.py | 58 +++++++++++++++------- .../data/topology_template/databasesubsystem.yaml | 8 +-- .../data/topology_template/queuingsubsystem.yaml | 15 ++++-- .../topology_template/transactionsubsystem.yaml | 6 +++ .../toscaparser/tests/test_topology_template.py | 2 +- 6 files changed, 73 insertions(+), 25 deletions(-) diff --git a/tosca2heat/tosca-parser/toscaparser/common/exception.py b/tosca2heat/tosca-parser/toscaparser/common/exception.py index 724844b..13ccabd 100644 --- a/tosca2heat/tosca-parser/toscaparser/common/exception.py +++ b/tosca2heat/tosca-parser/toscaparser/common/exception.py @@ -114,6 +114,10 @@ class UnknownInputError(TOSCAException): msg_fmt = _('Unknown input "%(input_name)s".') +class UnknownOutputError(TOSCAException): + msg_fmt = _('Unknown output "%(output_name)s" in %(where)s.') + + class MissingRequiredInputError(TOSCAException): msg_fmt = _('%(what)s is missing required input definition ' 'of input "%(input_name)s".') @@ -129,6 +133,11 @@ class MissingDefaultValueError(TOSCAException): 'of input "%(input_name)s".') +class MissingRequiredOutputError(TOSCAException): + msg_fmt = _('%(what)s is missing required output definition ' + 'of output "%(output_name)s".') + + class InvalidPropertyValueError(TOSCAException): msg_fmt = _('Value of property "%(what)s" is invalid.') diff --git a/tosca2heat/tosca-parser/toscaparser/substitution_mappings.py b/tosca2heat/tosca-parser/toscaparser/substitution_mappings.py index d4653c3..dea5de7 100644 --- a/tosca2heat/tosca-parser/toscaparser/substitution_mappings.py +++ b/tosca2heat/tosca-parser/toscaparser/substitution_mappings.py @@ -17,7 +17,9 @@ from toscaparser.common.exception import InvalidNodeTypeError from toscaparser.common.exception import MissingDefaultValueError from toscaparser.common.exception import MissingRequiredFieldError from toscaparser.common.exception import MissingRequiredInputError +from toscaparser.common.exception import MissingRequiredOutputError from toscaparser.common.exception import UnknownFieldError +from toscaparser.common.exception import UnknownOutputError from toscaparser.elements.nodetype import NodeType from toscaparser.utils.gettextutils import _ @@ -34,6 +36,8 @@ class SubstitutionMappings(object): SECTIONS = (NODE_TYPE, REQUIREMENTS, CAPABILITIES) = \ ('node_type', 'requirements', 'capabilities') + OPTIONAL_OUTPUTS = ['tosca_id', 'tosca_name', 'state'] + def __init__(self, sub_mapping_def, nodetemplates, inputs, outputs, sub_mapped_node_template, custom_defs): self.nodetemplates = nodetemplates @@ -110,9 +114,9 @@ class SubstitutionMappings(object): """validate the inputs of substitution mappings. The inputs defined by the topology template have to match the - properties of the node type or the substituted node. If there are - more inputs than the substituted node has properties, default values - must be defined for those inputs. + properties of the node type or the substituted node template. If + there are more inputs than the substituted node has properties, + default values must be defined for those inputs. """ all_inputs = set([input.name for input in self.inputs]) @@ -136,9 +140,7 @@ class SubstitutionMappings(object): customized_parameters = set(self.sub_mapped_node_template .get_properties().keys() if self.sub_mapped_node_template else []) - all_properties = set([p.name for p in - self.node_definition. - get_properties_def_objects()]) + all_properties = set(self.node_definition.get_properties_def()) for parameter in customized_parameters - all_inputs: if parameter in all_properties: ExceptionCollector.appendException( @@ -191,14 +193,36 @@ class SubstitutionMappings(object): # field=req)) def _validate_outputs(self): - """validate the outputs of substitution mappings.""" - pass - # The outputs in service template which defines substutition mappings - # must be in atrributes of node template wchich be mapped. - # outputs_names = self.sub_mapped_node_template.get_properties(). - # keys() if self.sub_mapped_node_template else None - # for name in outputs_names: - # if name not in [output.name for input in self.outputs]: - # ExceptionCollector.appendException( - # UnknownFieldError(what='SubstitutionMappings', - # field=name)) + """validate the outputs of substitution mappings. + + The outputs defined by the topology template have to match the + attributes of the node type or the substituted node template, + and the observable attributes of the substituted node template + have to be defined as attributes of the node type or outputs in + the topology template. + """ + + # The outputs defined by the topology template have to match the + # attributes of the node type according to the specification, but + # it's reasonable that there are more inputs than the node type + # has properties, the specification will be amended? + for output in self.outputs: + if output.name not in self.node_definition.get_attributes_def(): + ExceptionCollector.appendException( + UnknownOutputError( + where=_('SubstitutionMappings with node_type ') + + self.node_type, + output_name=output.name)) + + # The observable attributes of the substituted node template + # have to be defined as attributes of the node type or outputs in + # the topology template, the attributes in tosca.node.root are + # optional. + for attribute in self.node_definition.get_attributes_def(): + if attribute not in [output.name for output in self.outputs] \ + and attribute not in self.OPTIONAL_OUTPUTS: + ExceptionCollector.appendException( + MissingRequiredOutputError( + what=_('SubstitutionMappings with node_type ') + + self.node_type, + output_name=attribute)) diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/databasesubsystem.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/databasesubsystem.yaml index ebf1856..6990679 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/databasesubsystem.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/databasesubsystem.yaml @@ -75,10 +75,10 @@ topology_template: distribution: Ubuntu version: 14.04 - outputs: - receiver_ip: - description: private IP address of the database application - value: { get_attribute: [ server, private_address ] } +# outputs: +# receiver_ip: +# description: private IP address of the database application +# value: { get_attribute: [ server, private_address ] } # It seems current _process_intrisic_function can not handle more than 2 arguments, save it for later # receiver_port: # description: Port of the message receiver endpoint diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/queuingsubsystem.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/queuingsubsystem.yaml index 76fa7e2..8c4cc76 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/queuingsubsystem.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/queuingsubsystem.yaml @@ -61,9 +61,18 @@ topology_template: version: 14.04 outputs: - receiver_ip: - description: private IP address of the message receiver application - value: { get_attribute: [ server, private_address ] } +# receiver_ip: +# description: private IP address of the message receiver application +# value: { get_attribute: [ server, private_address ] } + + server_ip: + description: server_ip of the message receiver application + value: { get_input: server_ip } + + server_port: + description: server_port of the message receiver application + value: { get_input: server_port } + # It seems current _process_intrisic_function can not handle more than 2 arguments, save it for later # receiver_port: # description: Port of the message receiver endpoint diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/transactionsubsystem.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/transactionsubsystem.yaml index 0f145a3..7b839d7 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/transactionsubsystem.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/transactionsubsystem.yaml @@ -77,6 +77,12 @@ topology_template: receiver_ip: description: private IP address of the message receiver application value: { get_attribute: [ server, private_address ] } + + receiver_port: + description: receiver_port of the message receiver application + value: { get_input: receiver_port } + + # It seems current _process_intrisic_function can not handle more than 2 arguments, save it for later # receiver_port: # description: Port of the message receiver endpoint diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py b/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py index 6974d52..eb8d589 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py @@ -154,7 +154,7 @@ class TopologyTemplateTest(TestCase): def test_outputs(self): self.assertEqual( - ['receiver_ip'], + sorted(['receiver_ip', 'receiver_port']), sorted([output.name for output in self.topo.outputs])) def test_groups(self): -- 2.16.6