Add input validation in substitution_mapping class
[parser.git] / tosca2heat / tosca-parser / toscaparser / substitution_mappings.py
1 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
2 #    not use this file except in compliance with the License. You may obtain
3 #    a copy of the License at
4 #
5 #         http://www.apache.org/licenses/LICENSE-2.0
6 #
7 #    Unless required by applicable law or agreed to in writing, software
8 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 #    License for the specific language governing permissions and limitations
11 #    under the License.
12
13 import logging
14
15 from toscaparser.common.exception import ExceptionCollector
16 from toscaparser.common.exception import InvalidNodeTypeError
17 from toscaparser.common.exception import MissingRequiredFieldError
18 from toscaparser.common.exception import MissingRequiredInputError
19 from toscaparser.common.exception import MissingRequiredParameterError
20 from toscaparser.common.exception import UnknownFieldError
21 from toscaparser.elements.nodetype import NodeType
22
23
24 log = logging.getLogger('tosca')
25
26
27 class SubstitutionMappings(object):
28     '''SubstitutionMappings class declaration
29
30     Substitution_mappings exports the topology template as an
31     implementation of a Node type.
32     '''
33
34     SECTIONS = (NODE_TYPE, CAPABILITIES, REQUIREMENTS) = \
35                ('node_type', 'requirements', 'capabilities')
36
37     def __init__(self, sub_mapping_def, nodetemplates, inputs, outputs,
38                  sub_mapped_node_template, custom_defs):
39         self.nodetemplates = nodetemplates
40         self.sub_mapping_def = sub_mapping_def
41         self.inputs = inputs or []
42         self.outputs = outputs or []
43         self.sub_mapped_node_template = sub_mapped_node_template
44         self.custom_defs = custom_defs or {}
45         self._validate()
46
47         self._capabilities = None
48         self._requirements = None
49
50     @classmethod
51     def get_node_type(cls, sub_mapping_def):
52         if isinstance(sub_mapping_def, dict):
53             return sub_mapping_def.get(cls.NODE_TYPE)
54
55     @property
56     def node_type(self):
57         return self.sub_mapping_def.get(self.NODE_TYPE)
58
59     @property
60     def capabilities(self):
61         return self.sub_mapping_def.get(self.CAPABILITIES)
62
63     @property
64     def requirements(self):
65         return self.sub_mapping_def.get(self.REQUIREMENTS)
66
67     @property
68     def node_definition(self):
69         return NodeType(self.node_type, self.custom_defs)
70
71     def _validate(self):
72         # basic valiation
73         self._validate_keys()
74         self._validate_type()
75
76         # SubstitutionMapping class syntax validation
77         self._validate_inputs()
78         self._validate_capabilities()
79         self._validate_requirements()
80         self._validate_outputs()
81
82     def _validate_keys(self):
83         """validate the keys of substitution mappings."""
84         for key in self.sub_mapping_def.keys():
85             if key not in self.SECTIONS:
86                 ExceptionCollector.appendException(
87                     UnknownFieldError(what='SubstitutionMappings',
88                                       field=key))
89
90     def _validate_type(self):
91         """validate the node_type of substitution mappings."""
92         node_type = self.sub_mapping_def.get(self.NODE_TYPE)
93         if not node_type:
94             ExceptionCollector.appendException(
95                 MissingRequiredFieldError(
96                     what=_('SubstitutionMappings used in topology_template'),
97                     required=self.NODE_TYPE))
98
99         node_type_def = self.custom_defs.get(node_type)
100         if not node_type_def:
101             ExceptionCollector.appendException(
102                 InvalidNodeTypeError(what=node_type_def))
103
104     def _validate_inputs(self):
105         """validate the inputs of substitution mappings."""
106
107         # The inputs in service template which provides substutition mappings
108         # must be in properties of node template which is mapped or provide
109         # defualt value. Currently the input.name is not restrict to be the
110         # same as property name in specification, but they should be equal
111         # for current implementation.
112
113         # Must provide parameters for required properties of node_type
114         # This checking is internal(inside SubstitutionMappings)
115         for propery in self.node_definition.get_properties_def_objects():
116             # Check property which is 'required' and has no 'default' value
117             if propery.required and propery.default is None and \
118                propery.name not in [input.name for input in self.inputs]:
119                 ExceptionCollector.appendException(
120                     MissingRequiredInputError(
121                         what='SubstitutionMappings with node_type:'
122                         + self.node_type,
123                         input_name=propery.name))
124
125         # Get property names from substituted node tempalte
126         property_names = list(self.sub_mapped_node_template
127                               .get_properties().keys()
128                               if self.sub_mapped_node_template else [])
129         # Sub_mapped_node_template is None(deploy standaolone), will check
130         # according to node_type
131         if 0 == len(property_names):
132             property_names = list(self.node_definition
133                                   .get_properties_def().keys())
134         # Provide default value for parameter which is not property of
135         # node with the type node_type, this may not be mandatory for
136         # current implematation, but the specification express it mandatory.
137         # This checking is external(outside SubstitutionMappings)
138         for input in self.inputs:
139             if input.name not in property_names and input.default is None:
140                 ExceptionCollector.appendException(
141                     MissingRequiredParameterError(
142                         what='SubstitutionMappings with node_type:'
143                         + self.node_type,
144                         input_name=input.name))
145
146     def _validate_capabilities(self):
147         """validate the capabilities of substitution mappings."""
148
149         # The capabilites must be in node template wchich be mapped.
150         tpls_capabilities = self.sub_mapping_def.get(self.CAPABILITIES)
151         node_capabiliteys = self.sub_mapped_node_template.get_capabilities() \
152             if self.sub_mapped_node_template else None
153         for cap in node_capabiliteys.keys() if node_capabiliteys else []:
154             if (tpls_capabilities and
155                     cap not in list(tpls_capabilities.keys())):
156                 pass
157                 # ExceptionCollector.appendException(
158                 #    UnknownFieldError(what='SubstitutionMappings',
159                 #                      field=cap))
160
161     def _validate_requirements(self):
162         """validate the requirements of substitution mappings."""
163
164         # The requirements must be in node template wchich be mapped.
165         tpls_requirements = self.sub_mapping_def.get(self.REQUIREMENTS)
166         node_requirements = self.sub_mapped_node_template.requirements \
167             if self.sub_mapped_node_template else None
168         for req in node_requirements if node_requirements else []:
169             if (tpls_requirements and
170                     req not in list(tpls_requirements.keys())):
171                 pass
172                 # ExceptionCollector.appendException(
173                 #    UnknownFieldError(what='SubstitutionMappings',
174                 #                      field=req))
175
176     def _validate_outputs(self):
177         """validate the outputs of substitution mappings."""
178         pass
179         # The outputs in service template which defines substutition mappings
180         # must be in atrributes of node template wchich be mapped.
181         # outputs_names = self.sub_mapped_node_template.get_properties().
182         #     keys() if self.sub_mapped_node_template else None
183         # for name in outputs_names:
184         #    if name not in [output.name for input in self.outputs]:
185         #        ExceptionCollector.appendException(
186         #            UnknownFieldError(what='SubstitutionMappings',
187         #                              field=name))