Merge "Add required definition in class of Input."
[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, REQUIREMENTS, CAPABILITIES) = \
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
114         # Must provide parameters for required properties of node_type
115         # This checking is internal(inside SubstitutionMappings)
116         for propery in self.node_definition.get_properties_def_objects():
117             # Check property which is 'required' and has no 'default' value
118             if propery.required and propery.default is None and \
119                propery.name not in [input.name for input in self.inputs]:
120                 ExceptionCollector.appendException(
121                     MissingRequiredInputError(
122                         what='SubstitutionMappings with node_type:'
123                         + self.node_type,
124                         input_name=propery.name))
125
126         # Get property names from substituted node tempalte
127         property_names = list(self.sub_mapped_node_template
128                               .get_properties().keys()
129                               if self.sub_mapped_node_template else [])
130         # Sub_mapped_node_template is None(deploy standaolone), will check
131         # according to node_type
132         if 0 == len(property_names):
133             property_names = list(self.node_definition
134                                   .get_properties_def().keys())
135         # Provide default value for parameter which is not property of
136         # node with the type node_type, this may not be mandatory for
137         # current implematation, but the specification express it mandatory.
138         # This checking is external(outside SubstitutionMappings)
139         for input in self.inputs:
140             if input.name not in property_names and input.default is None:
141                 ExceptionCollector.appendException(
142                     MissingRequiredParameterError(
143                         what='SubstitutionMappings with node_type:'
144                         + self.node_type,
145                         input_name=input.name))
146
147     def _validate_capabilities(self):
148         """validate the capabilities of substitution mappings."""
149
150         # The capabilites must be in node template wchich be mapped.
151         tpls_capabilities = self.sub_mapping_def.get(self.CAPABILITIES)
152         node_capabiliteys = self.sub_mapped_node_template.get_capabilities() \
153             if self.sub_mapped_node_template else None
154         for cap in node_capabiliteys.keys() if node_capabiliteys else []:
155             if (tpls_capabilities and
156                     cap not in list(tpls_capabilities.keys())):
157                 pass
158                 # ExceptionCollector.appendException(
159                 #    UnknownFieldError(what='SubstitutionMappings',
160                 #                      field=cap))
161
162     def _validate_requirements(self):
163         """validate the requirements of substitution mappings."""
164
165         # The requirements must be in node template wchich be mapped.
166         tpls_requirements = self.sub_mapping_def.get(self.REQUIREMENTS)
167         node_requirements = self.sub_mapped_node_template.requirements \
168             if self.sub_mapped_node_template else None
169         for req in node_requirements if node_requirements else []:
170             if (tpls_requirements and
171                     req not in list(tpls_requirements.keys())):
172                 pass
173                 # ExceptionCollector.appendException(
174                 #    UnknownFieldError(what='SubstitutionMappings',
175                 #                      field=req))
176
177     def _validate_outputs(self):
178         """validate the outputs of substitution mappings."""
179         pass
180         # The outputs in service template which defines substutition mappings
181         # must be in atrributes of node template wchich be mapped.
182         # outputs_names = self.sub_mapped_node_template.get_properties().
183         #     keys() if self.sub_mapped_node_template else None
184         # for name in outputs_names:
185         #    if name not in [output.name for input in self.outputs]:
186         #        ExceptionCollector.appendException(
187         #            UnknownFieldError(what='SubstitutionMappings',
188         #                              field=name))