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