summaryrefslogtreecommitdiffstats
path: root/tosca2heat/tosca-parser/toscaparser
diff options
context:
space:
mode:
authorshangxdy <shang.xiaodong@zte.com.cn>2016-08-14 02:16:28 +0800
committershangxdy <shang.xiaodong@zte.com.cn>2016-08-14 23:30:24 +0800
commit5559b0c06930deb1c7831efe599a1036574f50b3 (patch)
treeeae0c84222cec4a15b1b5ae46656aeb157c01bbe /tosca2heat/tosca-parser/toscaparser
parentbfdb0cd484dbabda2488d16536612dfe6d818a18 (diff)
Add input validation in substitution_mapping class
Add input validation in class of substitution_mapping according to specification of http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/ TOSCA-Simple-Profile-YAML-v1.0.html: 1) The properties of substituted node template which be mapped must be in the inputs of nested service template which defines substutition mappings; 2) The inputs of nested service template which are not in properties of the substituted node template must have default values. 3) If the properties of node_type is required and no default value, must provide inputs for them; 4) Property names and the input names must be the same. JIRA:PARSER-79 Change-Id: Ie4664fe17c8279ad531ac9acec057f98d4e9281a Signed-off-by: shangxdy <shang.xiaodong@zte.com.cn>
Diffstat (limited to 'tosca2heat/tosca-parser/toscaparser')
-rw-r--r--tosca2heat/tosca-parser/toscaparser/common/exception.py10
-rw-r--r--tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/Definitions/vRNC.yaml12
-rw-r--r--tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/test_tosca_vRNC.py6
-rw-r--r--tosca2heat/tosca-parser/toscaparser/substitution_mappings.py67
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/databasesubsystem.yaml12
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tosca_template.py15
6 files changed, 99 insertions, 23 deletions
diff --git a/tosca2heat/tosca-parser/toscaparser/common/exception.py b/tosca2heat/tosca-parser/toscaparser/common/exception.py
index bd0ed9c..34abe77 100644
--- a/tosca2heat/tosca-parser/toscaparser/common/exception.py
+++ b/tosca2heat/tosca-parser/toscaparser/common/exception.py
@@ -109,6 +109,16 @@ class UnknownInputError(TOSCAException):
msg_fmt = _('Unknown input "%(input_name)s".')
+class MissingRequiredInputError(TOSCAException):
+ msg_fmt = _('%(what)s is missing required input definition '
+ ' with name: "%(input_name)s".')
+
+
+class MissingRequiredParameterError(TOSCAException):
+ msg_fmt = _('%(what)s is missing required parameter for input: '
+ '"%(input_name)s".')
+
+
class InvalidPropertyValueError(TOSCAException):
msg_fmt = _('Value of property "%(what)s" is invalid.')
diff --git a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/Definitions/vRNC.yaml b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/Definitions/vRNC.yaml
index 21f79e2..7068c7a 100644
--- a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/Definitions/vRNC.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/Definitions/vRNC.yaml
@@ -71,6 +71,18 @@ topology_template:
description: mm additional block storage size
constraints:
- in_range: [ 1, 200 ]
+ id:
+ type: string
+ description: ID of this VNF
+ default: UMTS
+ vendor:
+ type: string
+ description: name of the vendor who generate this VNF
+ default: ZTE
+ version:
+ type: version
+ description: version of the software for this VNF
+ default: 1.0
substitution_mappings:
node_type: rnc.nodes.VNF
diff --git a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/test_tosca_vRNC.py b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/test_tosca_vRNC.py
index c839626..a0ffc21 100644
--- a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/test_tosca_vRNC.py
+++ b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/test_tosca_vRNC.py
@@ -29,8 +29,10 @@ class ToscaVRNCTemplateTest(TestCase):
"tosca_simple_profile_for_nfv_1_0_0")
def test_input(self):
- first_input_name = "mm_storage_size"
- self.assertEqual(self.tosca.inputs[0].name, first_input_name)
+ input_names = sorted(["mm_storage_size", "id",
+ "vendor", "version"])
+ self.assertEqual(sorted([i.name for i in self.tosca.inputs]),
+ input_names)
def test_nodetemplates(self):
expected_node_list = sorted(
diff --git a/tosca2heat/tosca-parser/toscaparser/substitution_mappings.py b/tosca2heat/tosca-parser/toscaparser/substitution_mappings.py
index 83ff590..f644808 100644
--- a/tosca2heat/tosca-parser/toscaparser/substitution_mappings.py
+++ b/tosca2heat/tosca-parser/toscaparser/substitution_mappings.py
@@ -15,7 +15,11 @@ import logging
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import InvalidNodeTypeError
from toscaparser.common.exception import MissingRequiredFieldError
+from toscaparser.common.exception import MissingRequiredInputError
+from toscaparser.common.exception import MissingRequiredParameterError
from toscaparser.common.exception import UnknownFieldError
+from toscaparser.elements.nodetype import NodeType
+
log = logging.getLogger('tosca')
@@ -60,9 +64,16 @@ class SubstitutionMappings(object):
def requirements(self):
return self.sub_mapping_def.get(self.REQUIREMENTS)
+ @property
+ def node_definition(self):
+ return NodeType(self.node_type, self.custom_defs)
+
def _validate(self):
+ # basic valiation
self._validate_keys()
self._validate_type()
+
+ # SubstitutionMapping class syntax validation
self._validate_inputs()
self._validate_capabilities()
self._validate_requirements()
@@ -73,7 +84,7 @@ class SubstitutionMappings(object):
for key in self.sub_mapping_def.keys():
if key not in self.SECTIONS:
ExceptionCollector.appendException(
- UnknownFieldError(what='Substitution_mappings',
+ UnknownFieldError(what='SubstitutionMappings',
field=key))
def _validate_type(self):
@@ -82,7 +93,7 @@ class SubstitutionMappings(object):
if not node_type:
ExceptionCollector.appendException(
MissingRequiredFieldError(
- what=_('Substitution_mappings used in topology_template'),
+ what=_('SubstitutionMappings used in topology_template'),
required=self.NODE_TYPE))
node_type_def = self.custom_defs.get(node_type)
@@ -93,16 +104,44 @@ class SubstitutionMappings(object):
def _validate_inputs(self):
"""validate the inputs of substitution mappings."""
- # The inputs in service template which defines substutition mappings
- # must be in properties of node template wchich be mapped.
- inputs_names = list(self.sub_mapped_node_template
- .get_properties().keys()
- if self.sub_mapped_node_template else [])
- for name in inputs_names:
- if name not in [input.name for input in self.inputs]:
+ # The inputs in service template which provides substutition mappings
+ # must be in properties of node template which is mapped or provide
+ # defualt value. Currently the input.name is not restrict to be the
+ # same as property name in specification, but they should be equal
+ # for current implementation.
+
+ # Must provide parameters for required properties of node_type
+ # This checking is internal(inside SubstitutionMappings)
+ for propery in self.node_definition.get_properties_def_objects():
+ # Check property which is 'required' and has no 'default' value
+ if propery.required and propery.default is None and \
+ propery.name not in [input.name for input in self.inputs]:
ExceptionCollector.appendException(
- UnknownFieldError(what='SubstitutionMappings',
- field=name))
+ MissingRequiredInputError(
+ what='SubstitutionMappings with node_type:'
+ + self.node_type,
+ input_name=propery.name))
+
+ # Get property names from substituted node tempalte
+ property_names = list(self.sub_mapped_node_template
+ .get_properties().keys()
+ if self.sub_mapped_node_template else [])
+ # Sub_mapped_node_template is None(deploy standaolone), will check
+ # according to node_type
+ if 0 == len(property_names):
+ property_names = list(self.node_definition
+ .get_properties_def().keys())
+ # Provide default value for parameter which is not property of
+ # node with the type node_type, this may not be mandatory for
+ # current implematation, but the specification express it mandatory.
+ # This checking is external(outside SubstitutionMappings)
+ for input in self.inputs:
+ if input.name not in property_names and input.default is None:
+ ExceptionCollector.appendException(
+ MissingRequiredParameterError(
+ what='SubstitutionMappings with node_type:'
+ + self.node_type,
+ input_name=input.name))
def _validate_capabilities(self):
"""validate the capabilities of substitution mappings."""
@@ -116,7 +155,7 @@ class SubstitutionMappings(object):
cap not in list(tpls_capabilities.keys())):
pass
# ExceptionCollector.appendException(
- # UnknownFieldError(what='Substitution_mappings',
+ # UnknownFieldError(what='SubstitutionMappings',
# field=cap))
def _validate_requirements(self):
@@ -131,7 +170,7 @@ class SubstitutionMappings(object):
req not in list(tpls_requirements.keys())):
pass
# ExceptionCollector.appendException(
- # UnknownFieldError(what='Substitution_mappings',
+ # UnknownFieldError(what='SubstitutionMappings',
# field=req))
def _validate_outputs(self):
@@ -144,5 +183,5 @@ class SubstitutionMappings(object):
# for name in outputs_names:
# if name not in [output.name for input in self.outputs]:
# ExceptionCollector.appendException(
- # UnknownFieldError(what='Substitution_mappings',
+ # UnknownFieldError(what='SubstitutionMappings',
# field=name))
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 22eb259..ebf1856 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/databasesubsystem.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/databasesubsystem.yaml
@@ -12,15 +12,15 @@ topology_template:
description: Template of a database including its hosting stack.
inputs:
- db_user:
+ user:
type: string
description: the user name of database.
default: test
- db_port:
+ port:
type: integer
description: the port of database.
default: 3306
- db_name:
+ name:
type: string
description: the name of database.
default: test
@@ -40,9 +40,9 @@ topology_template:
db_app:
type: tosca.nodes.Database
properties:
- user: { get_input: db_user }
- port: { get_input: db_port }
- name: { get_input: db_name }
+ user: { get_input: user }
+ port: { get_input: port }
+ name: { get_input: name }
capabilities:
database_endpoint:
properties:
diff --git a/tosca2heat/tosca-parser/toscaparser/tosca_template.py b/tosca2heat/tosca-parser/toscaparser/tosca_template.py
index 80cb1cb..2e815fd 100644
--- a/tosca2heat/tosca-parser/toscaparser/tosca_template.py
+++ b/tosca2heat/tosca-parser/toscaparser/tosca_template.py
@@ -14,6 +14,7 @@
import logging
import os
+from copy import deepcopy
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import InvalidTemplateVersion
from toscaparser.common.exception import MissingRequiredFieldError
@@ -226,8 +227,10 @@ class ToscaTemplate(object):
for fname, tosca_tpl in self.nested_tosca_tpls_with_topology.items():
for nodetemplate in self.nodetemplates:
if self._is_sub_mapped_node(nodetemplate, tosca_tpl):
+ parsed_params = self._get_params_for_nested_template(
+ nodetemplate)
nested_template = ToscaTemplate(
- path=fname, parsed_params=self.parsed_params,
+ path=fname, parsed_params=parsed_params,
yaml_dict_tpl=tosca_tpl,
sub_mapped_node_template=nodetemplate)
if nested_template.has_substitution_mappings():
@@ -310,6 +313,16 @@ class ToscaTemplate(object):
else:
return False
+ def _get_params_for_nested_template(self, nodetemplate):
+ """Return total params for nested_template."""
+ parsed_params = deepcopy(self.parsed_params) \
+ if self.parsed_params else {}
+ if nodetemplate:
+ for pname in nodetemplate.get_properties():
+ parsed_params.update({pname:
+ nodetemplate.get_property_value(pname)})
+ return parsed_params
+
def get_sub_mapping_node_type(self, tosca_tpl):
"""Return substitution mappings node type."""
if tosca_tpl: