ce2120373576e30cc70fd588b311d06b543260eb
[sdc/sdc-distribution-client.git] /
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 MissingDefaultValueError
18 from toscaparser.common.exception import MissingRequiredFieldError
19 from toscaparser.common.exception import MissingRequiredInputError
20 from toscaparser.common.exception import UnknownFieldError
21 from toscaparser.common.exception import UnknownOutputError
22 from toscaparser.elements.nodetype import NodeType
23 from toscaparser.utils.gettextutils import _
24 from org.openecomp.sdc.toscaparser.jython import JySubstitutionMappings
25
26 log = logging.getLogger('tosca')
27
28
29 class SubstitutionMappings(JySubstitutionMappings):
30     '''SubstitutionMappings class declaration
31
32     SubstitutionMappings exports the topology template as an
33     implementation of a Node type.
34     '''
35
36     SECTIONS = (NODE_TYPE, REQUIREMENTS, CAPABILITIES) = \
37                ('node_type', 'requirements', 'capabilities')
38
39     OPTIONAL_OUTPUTS = ['tosca_id', 'tosca_name', 'state']
40
41     def __init__(self, sub_mapping_def, nodetemplates, inputs, outputs, groups, 
42                  sub_mapped_node_template, custom_defs, metadata):
43         self.nodetemplates = nodetemplates
44         self.sub_mapping_def = sub_mapping_def
45         self.inputs = inputs or []
46         self.outputs = outputs or []
47         self.groups = groups or [] 
48         self.sub_mapped_node_template = sub_mapped_node_template
49         self.custom_defs = custom_defs or {}
50         self._validate()
51         self.metadata = metadata
52         self._capabilities = None
53         self._requirements = None
54         
55     def getJyNodeTemplates(self):
56         return self.nodetemplates
57     
58     def getJyInputs(self):
59         return self.inputs
60     
61     def getJyGroups(self):
62         return self.groups
63     
64     def getJyNodeDefinition(self):
65         return self.node_definition
66
67     def getJyMetadata(self):
68         return self.metadata
69
70     @property
71     def type(self):
72         if self.sub_mapping_def:
73             return self.sub_mapping_def.get(self.NODE_TYPE)
74
75     @classmethod
76     def get_node_type(cls, sub_mapping_def):
77         if isinstance(sub_mapping_def, dict):
78             return sub_mapping_def.get(cls.NODE_TYPE)
79
80     @property
81     def node_type(self):
82         return self.sub_mapping_def.get(self.NODE_TYPE)
83
84     @property
85     def capabilities(self):
86         return self.sub_mapping_def.get(self.CAPABILITIES)
87
88     @property
89     def requirements(self):
90         return self.sub_mapping_def.get(self.REQUIREMENTS)
91
92     @property
93     def node_definition(self):
94         return NodeType(self.node_type, self.custom_defs)
95
96     def _validate(self):
97         # Basic validation
98         self._validate_keys()
99         self._validate_type()
100
101         # SubstitutionMapping class syntax validation
102         self._validate_inputs()
103         self._validate_capabilities()
104         self._validate_requirements()
105         self._validate_outputs()
106
107     def _validate_keys(self):
108         """validate the keys of substitution mappings."""
109         for key in self.sub_mapping_def.keys():
110             if key not in self.SECTIONS:
111                 ExceptionCollector.appendException(
112                     UnknownFieldError(what=_('SubstitutionMappings'),
113                                       field=key))
114
115     def _validate_type(self):
116         """validate the node_type of substitution mappings."""
117         node_type = self.sub_mapping_def.get(self.NODE_TYPE)
118         if not node_type:
119             ExceptionCollector.appendException(
120                 MissingRequiredFieldError(
121                     what=_('SubstitutionMappings used in topology_template'),
122                     required=self.NODE_TYPE))
123
124         node_type_def = self.custom_defs.get(node_type)
125         if not node_type_def:
126             ExceptionCollector.appendException(
127                 InvalidNodeTypeError(what=node_type))
128
129     def _validate_inputs(self):
130         """validate the inputs of substitution mappings.
131
132         The inputs defined by the topology template have to match the
133         properties of the node type or the substituted node. If there are
134         more inputs than the substituted node has properties, default values
135         must be defined for those inputs.
136         """
137
138         all_inputs = set([input.name for input in self.inputs])
139         required_properties = set([p.name for p in
140                                    self.node_definition.
141                                    get_properties_def_objects()
142                                    if p.required and p.default is None])
143         # Must provide inputs for required properties of node type.
144         for property in required_properties:
145             # Check property which is 'required' and has no 'default' value
146             if property not in all_inputs:
147                 ExceptionCollector.appendException(
148                     MissingRequiredInputError(
149                         what=_('SubstitutionMappings with node_type ')
150                         + self.node_type,
151                         input_name=property))
152
153         # If the optional properties of node type need to be customized by
154         # substituted node, it also is necessary to define inputs for them,
155         # otherwise they are not mandatory to be defined.
156         customized_parameters = set(self.sub_mapped_node_template
157                                     .get_properties().keys()
158                                     if self.sub_mapped_node_template else [])
159         all_properties = set(self.node_definition.get_properties_def())
160         for parameter in customized_parameters - all_inputs:
161             if parameter in all_properties:
162                 ExceptionCollector.appendException(
163                     MissingRequiredInputError(
164                         what=_('SubstitutionMappings with node_type ')
165                         + self.node_type,
166                         input_name=parameter))
167
168         # Additional inputs are not in the properties of node type must
169         # provide default values. Currently the scenario may not happen
170         # because of parameters validation in nodetemplate, here is a
171         # guarantee.
172         for input in self.inputs:
173             if input.name in all_inputs - all_properties \
174                and input.default is None:
175                 ExceptionCollector.appendException(
176                     MissingDefaultValueError(
177                         what=_('SubstitutionMappings with node_type ')
178                         + self.node_type,
179                         input_name=input.name))
180
181     def _validate_capabilities(self):
182         """validate the capabilities of substitution mappings."""
183
184         # The capabilites must be in node template wchich be mapped.
185         tpls_capabilities = self.sub_mapping_def.get(self.CAPABILITIES)
186         node_capabiliteys = self.sub_mapped_node_template.get_capabilities() \
187             if self.sub_mapped_node_template else None
188         for cap in node_capabiliteys.keys() if node_capabiliteys else []:
189             if (tpls_capabilities and
190                     cap not in list(tpls_capabilities.keys())):
191                 pass
192                 # ExceptionCollector.appendException(
193                 #    UnknownFieldError(what='SubstitutionMappings',
194                 #                      field=cap))
195
196     def _validate_requirements(self):
197         """validate the requirements of substitution mappings."""
198
199         # The requirements must be in node template wchich be mapped.
200         tpls_requirements = self.sub_mapping_def.get(self.REQUIREMENTS)
201         node_requirements = self.sub_mapped_node_template.requirements \
202             if self.sub_mapped_node_template else None
203         for req in node_requirements if node_requirements else []:
204             if (tpls_requirements and
205                     req not in list(tpls_requirements.keys())):
206                 pass
207                 # ExceptionCollector.appendException(
208                 #    UnknownFieldError(what='SubstitutionMappings',
209                 #                      field=req))
210
211     def _validate_outputs(self):
212         """validate the outputs of substitution mappings.
213
214         The outputs defined by the topology template have to match the
215         attributes of the node type or the substituted node template,
216         and the observable attributes of the substituted node template
217         have to be defined as attributes of the node type or outputs in
218         the topology template.
219         """
220
221         # The outputs defined by the topology template have to match the
222         # attributes of the node type according to the specification, but
223         # it's reasonable that there are more inputs than the node type
224         # has properties, the specification will be amended?
225         for output in self.outputs:
226             if output.name not in self.node_definition.get_attributes_def():
227                 ExceptionCollector.appendException(
228                     UnknownOutputError(
229                         where=_('SubstitutionMappings with node_type ')
230                         + self.node_type,
231                         output_name=output.name))