Fix StatefulEntityType when entitytype is not define
[parser.git] / tosca2heat / tosca-parser / toscaparser / topology_template.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
14 import logging
15
16 from toscaparser.common import exception
17 from toscaparser.dataentity import DataEntity
18 from toscaparser import functions
19 from toscaparser.groups import Group
20 from toscaparser.nodetemplate import NodeTemplate
21 from toscaparser.parameters import Input
22 from toscaparser.parameters import Output
23 from toscaparser.policy import Policy
24 from toscaparser.relationship_template import RelationshipTemplate
25 from toscaparser.substitution_mappings import SubstitutionMappings
26 from toscaparser.tpl_relationship_graph import ToscaGraph
27 from toscaparser.utils.gettextutils import _
28
29
30 # Topology template key names
31 SECTIONS = (DESCRIPTION, INPUTS, NODE_TEMPLATES,
32             RELATIONSHIP_TEMPLATES, OUTPUTS, GROUPS,
33             SUBSTITUION_MAPPINGS, POLICIES) = \
34            ('description', 'inputs', 'node_templates',
35             'relationship_templates', 'outputs', 'groups',
36             'substitution_mappings', 'policies')
37
38 log = logging.getLogger("tosca.model")
39
40
41 class TopologyTemplate(object):
42
43     '''Load the template data.'''
44     def __init__(self, template, custom_defs,
45                  rel_types=None, parsed_params=None,
46                  sub_mapped_node_template=None):
47         self.tpl = template
48         self.sub_mapped_node_template = sub_mapped_node_template
49         if self.tpl:
50             self.custom_defs = custom_defs
51             self.rel_types = rel_types
52             self.parsed_params = parsed_params
53             self._validate_field()
54             self.description = self._tpl_description()
55             self.inputs = self._inputs()
56             self.relationship_templates = self._relationship_templates()
57             self.nodetemplates = self._nodetemplates()
58             self.outputs = self._outputs()
59             if hasattr(self, 'nodetemplates'):
60                 self.graph = ToscaGraph(self.nodetemplates)
61             self.groups = self._groups()
62             self.policies = self._policies()
63             self._process_intrinsic_functions()
64             self.substitution_mappings = self._substitution_mappings()
65
66     def _inputs(self):
67         inputs = []
68         for name, attrs in self._tpl_inputs().items():
69             input = Input(name, attrs, self.custom_defs)
70             if self.parsed_params and name in self.parsed_params:
71                 input.validate(self.parsed_params[name])
72             else:
73                 default = input.default
74                 if default:
75                     input.validate(default)
76             if (self.parsed_params and input.name not in self.parsed_params
77                 or self.parsed_params is None) and input.required \
78                 and input.default is None:
79                 exception.ExceptionCollector.appendException(
80                     exception.MissingRequiredParameterError(
81                         what='Template',
82                         input_name=input.name))
83
84             inputs.append(input)
85         return inputs
86
87     def _nodetemplates(self):
88         nodetemplates = []
89         tpls = self._tpl_nodetemplates()
90         if tpls:
91             for name in tpls:
92                 tpl = NodeTemplate(name, tpls, self.custom_defs,
93                                    self.relationship_templates,
94                                    self.rel_types)
95                 if (tpl.type_definition and
96                     (tpl.type in tpl.type_definition.TOSCA_DEF or
97                      (tpl.type not in tpl.type_definition.TOSCA_DEF and
98                       bool(tpl.custom_def)))):
99                     tpl.validate(self)
100                     nodetemplates.append(tpl)
101         return nodetemplates
102
103     def _relationship_templates(self):
104         rel_templates = []
105         tpls = self._tpl_relationship_templates()
106         for name in tpls:
107             tpl = RelationshipTemplate(tpls[name], name, self.custom_defs)
108             rel_templates.append(tpl)
109         return rel_templates
110
111     def _outputs(self):
112         outputs = []
113         for name, attrs in self._tpl_outputs().items():
114             output = Output(name, attrs)
115             output.validate()
116             outputs.append(output)
117         return outputs
118
119     def _substitution_mappings(self):
120         tpl_substitution_mapping = self._tpl_substitution_mappings()
121         # if tpl_substitution_mapping and self.sub_mapped_node_template:
122         if tpl_substitution_mapping:
123             return SubstitutionMappings(tpl_substitution_mapping,
124                                         self.nodetemplates,
125                                         self.inputs,
126                                         self.outputs,
127                                         self.sub_mapped_node_template,
128                                         self.custom_defs)
129
130     def _policies(self):
131         policies = []
132         for policy in self._tpl_policies():
133             for policy_name, policy_tpl in policy.items():
134                 target_list = policy_tpl.get('targets')
135                 target_objects = []
136                 targets_type = "groups"
137                 if target_list and len(target_list) >= 1:
138                     target_objects = self._get_policy_groups(target_list)
139                     if not target_objects:
140                         targets_type = "node_templates"
141                         target_objects = self._get_group_members(target_list)
142                 policyObj = Policy(policy_name, policy_tpl,
143                                    target_objects, targets_type,
144                                    self.custom_defs)
145                 policies.append(policyObj)
146         return policies
147
148     def _groups(self):
149         groups = []
150         member_nodes = None
151         for group_name, group_tpl in self._tpl_groups().items():
152             member_names = group_tpl.get('members')
153             if member_names is not None:
154                 DataEntity.validate_datatype('list', member_names)
155                 if len(member_names) < 1 or \
156                         len(member_names) != len(set(member_names)):
157                     exception.ExceptionCollector.appendException(
158                         exception.InvalidGroupTargetException(
159                             message=_('Member nodes "%s" should be >= 1 '
160                                       'and not repeated') % member_names))
161                 else:
162                     member_nodes = self._get_group_members(member_names)
163             group = Group(group_name, group_tpl,
164                           member_nodes,
165                           self.custom_defs)
166             groups.append(group)
167         return groups
168
169     def _get_group_members(self, member_names):
170         member_nodes = []
171         self._validate_group_members(member_names)
172         for member in member_names:
173             for node in self.nodetemplates:
174                 if node.name == member:
175                     member_nodes.append(node)
176         return member_nodes
177
178     def _get_policy_groups(self, member_names):
179         member_groups = []
180         for member in member_names:
181             for group in self.groups:
182                 if group.name == member:
183                     member_groups.append(group)
184         return member_groups
185
186     def _validate_group_members(self, members):
187         node_names = []
188         for node in self.nodetemplates:
189             node_names.append(node.name)
190         for member in members:
191             if member not in node_names:
192                 exception.ExceptionCollector.appendException(
193                     exception.InvalidGroupTargetException(
194                         message=_('Target member "%s" is not found in '
195                                   'node_templates') % member))
196
197     # topology template can act like node template
198     # it is exposed by substitution_mappings.
199     def nodetype(self):
200         return self.substitution_mappings.node_type \
201             if self.substitution_mappings else None
202
203     def capabilities(self):
204         return self.substitution_mappings.capabilities \
205             if self.substitution_mappings else None
206
207     def requirements(self):
208         return self.substitution_mappings.requirements \
209             if self.substitution_mappings else None
210
211     def _tpl_description(self):
212         description = self.tpl.get(DESCRIPTION)
213         if description:
214             return description.rstrip()
215
216     def _tpl_inputs(self):
217         return self.tpl.get(INPUTS) or {}
218
219     def _tpl_nodetemplates(self):
220         return self.tpl.get(NODE_TEMPLATES)
221
222     def _tpl_relationship_templates(self):
223         return self.tpl.get(RELATIONSHIP_TEMPLATES) or {}
224
225     def _tpl_outputs(self):
226         return self.tpl.get(OUTPUTS) or {}
227
228     def _tpl_substitution_mappings(self):
229         return self.tpl.get(SUBSTITUION_MAPPINGS) or {}
230
231     def _tpl_groups(self):
232         return self.tpl.get(GROUPS) or {}
233
234     def _tpl_policies(self):
235         return self.tpl.get(POLICIES) or {}
236
237     def _validate_field(self):
238         for name in self.tpl:
239             if name not in SECTIONS:
240                 exception.ExceptionCollector.appendException(
241                     exception.UnknownFieldError(what='Template', field=name))
242
243     def _process_intrinsic_functions(self):
244         """Process intrinsic functions
245
246         Current implementation processes functions within node template
247         properties, requirements, interfaces inputs and template outputs.
248         """
249         if hasattr(self, 'nodetemplates'):
250             for node_template in self.nodetemplates:
251                 for prop in node_template.get_properties_objects():
252                     prop.value = functions.get_function(self,
253                                                         node_template,
254                                                         prop.value)
255                 for interface in node_template.interfaces:
256                     if interface.inputs:
257                         for name, value in interface.inputs.items():
258                             interface.inputs[name] = functions.get_function(
259                                 self,
260                                 node_template,
261                                 value)
262                 if node_template.requirements and \
263                    isinstance(node_template.requirements, list):
264                     for req in node_template.requirements:
265                         rel = req
266                         for req_name, req_item in req.items():
267                             if isinstance(req_item, dict):
268                                 rel = req_item.get('relationship')
269                                 break
270                         if rel and 'properties' in rel:
271                             for key, value in rel['properties'].items():
272                                 rel['properties'][key] = \
273                                     functions.get_function(self,
274                                                            req,
275                                                            value)
276                 if node_template.get_capabilities_objects():
277                     for cap in node_template.get_capabilities_objects():
278                         if cap.get_properties_objects():
279                             for prop in cap.get_properties_objects():
280                                 propvalue = functions.get_function(
281                                     self,
282                                     node_template,
283                                     prop.value)
284                                 if isinstance(propvalue, functions.GetInput):
285                                     propvalue = propvalue.result()
286                                     for p, v in cap._properties.items():
287                                         if p == prop.name:
288                                             cap._properties[p] = propvalue
289                 for rel, node in node_template.relationships.items():
290                     rel_tpls = node.relationship_tpl
291                     if rel_tpls:
292                         for rel_tpl in rel_tpls:
293                             for interface in rel_tpl.interfaces:
294                                 if interface.inputs:
295                                     for name, value in \
296                                             interface.inputs.items():
297                                         interface.inputs[name] = \
298                                             functions.get_function(self,
299                                                                    rel_tpl,
300                                                                    value)
301         for output in self.outputs:
302             func = functions.get_function(self, self.outputs, output.value)
303             if isinstance(func, functions.GetAttribute):
304                 output.attrs[output.VALUE] = func
305
306     @classmethod
307     def get_sub_mapping_node_type(cls, topology_tpl):
308         if topology_tpl and isinstance(topology_tpl, dict):
309             submap_tpl = topology_tpl.get(SUBSTITUION_MAPPINGS)
310             return SubstitutionMappings.get_node_type(submap_tpl)