Merge "Provide file list about the difference between parser and upstreams."
[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)
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:
122             return SubstitutionMappings(tpl_substitution_mapping,
123                                         self.nodetemplates,
124                                         self.inputs,
125                                         self.outputs,
126                                         self.sub_mapped_node_template,
127                                         self.custom_defs)
128
129     def _policies(self):
130         policies = []
131         for policy in self._tpl_policies():
132             for policy_name, policy_tpl in policy.items():
133                 target_list = policy_tpl.get('targets')
134                 if target_list and len(target_list) >= 1:
135                     target_objects = []
136                     targets_type = "groups"
137                     target_objects = self._get_policy_groups(target_list)
138                     if not target_objects:
139                         targets_type = "node_templates"
140                         target_objects = self._get_group_members(target_list)
141                     policyObj = Policy(policy_name, policy_tpl,
142                                        target_objects, targets_type,
143                                        self.custom_defs)
144                     policies.append(policyObj)
145         return policies
146
147     def _groups(self):
148         groups = []
149         member_nodes = None
150         for group_name, group_tpl in self._tpl_groups().items():
151             member_names = group_tpl.get('members')
152             if member_names is not None:
153                 DataEntity.validate_datatype('list', member_names)
154                 if len(member_names) < 1 or \
155                     len(member_names) != len(set(member_names)):
156                     exception.ExceptionCollector.appendException(
157                         exception.InvalidGroupTargetException(
158                             message=_('Member nodes "%s" should be >= 1 '
159                                       'and not repeated') % member_names))
160                 else:
161                     member_nodes = self._get_group_members(member_names)
162             group = Group(group_name, group_tpl,
163                           member_nodes,
164                           self.custom_defs)
165             groups.append(group)
166         return groups
167
168     def _get_group_members(self, member_names):
169         member_nodes = []
170         self._validate_group_members(member_names)
171         for member in member_names:
172             for node in self.nodetemplates:
173                 if node.name == member:
174                     member_nodes.append(node)
175         return member_nodes
176
177     def _get_policy_groups(self, member_names):
178         member_groups = []
179         for member in member_names:
180             for group in self.groups:
181                 if group.name == member:
182                     member_groups.append(group)
183         return member_groups
184
185     def _validate_group_members(self, members):
186         node_names = []
187         for node in self.nodetemplates:
188             node_names.append(node.name)
189         for member in members:
190             if member not in node_names:
191                 exception.ExceptionCollector.appendException(
192                     exception.InvalidGroupTargetException(
193                         message=_('Target member "%s" is not found in '
194                                   'node_templates') % member))
195
196     # topology template can act like node template
197     # it is exposed by substitution_mappings.
198     def nodetype(self):
199         return (self.substitution_mappings.node_type
200                 if self.substitution_mappings else None)
201
202     def capabilities(self):
203         return (self.substitution_mappings.capabilities
204                 if self.substitution_mappings else None)
205
206     def requirements(self):
207         return (self.substitution_mappings.requirements
208                 if self.substitution_mappings else None)
209
210     def _tpl_description(self):
211         description = self.tpl.get(DESCRIPTION)
212         if description:
213             return description.rstrip()
214
215     def _tpl_inputs(self):
216         return self.tpl.get(INPUTS) or {}
217
218     def _tpl_nodetemplates(self):
219         return self.tpl.get(NODE_TEMPLATES)
220
221     def _tpl_relationship_templates(self):
222         return self.tpl.get(RELATIONSHIP_TEMPLATES) or {}
223
224     def _tpl_outputs(self):
225         return self.tpl.get(OUTPUTS) or {}
226
227     def _tpl_substitution_mappings(self):
228         return self.tpl.get(SUBSTITUION_MAPPINGS) or {}
229
230     def _tpl_groups(self):
231         return self.tpl.get(GROUPS) or {}
232
233     def _tpl_policies(self):
234         return self.tpl.get(POLICIES) or {}
235
236     def _validate_field(self):
237         for name in self.tpl:
238             if name not in SECTIONS:
239                 exception.ExceptionCollector.appendException(
240                     exception.UnknownFieldError(what='Template', field=name))
241
242     def _process_intrinsic_functions(self):
243         """Process intrinsic functions
244
245         Current implementation processes functions within node template
246         properties, requirements, interfaces inputs and template outputs.
247         """
248         if hasattr(self, 'nodetemplates'):
249             for node_template in self.nodetemplates:
250                 for prop in node_template.get_properties_objects():
251                     prop.value = functions.get_function(self,
252                                                         node_template,
253                                                         prop.value)
254                 for interface in node_template.interfaces:
255                     if interface.inputs:
256                         for name, value in interface.inputs.items():
257                             interface.inputs[name] = functions.get_function(
258                                 self,
259                                 node_template,
260                                 value)
261                 if node_template.requirements:
262                     for req in node_template.requirements:
263                         rel = req
264                         for req_name, req_item in req.items():
265                             if isinstance(req_item, dict):
266                                 rel = req_item.get('relationship')
267                                 break
268                         if rel and 'properties' in rel:
269                             for key, value in rel['properties'].items():
270                                 rel['properties'][key] = \
271                                     functions.get_function(self,
272                                                            req,
273                                                            value)
274                 if node_template.get_capabilities_objects():
275                     for cap in node_template.get_capabilities_objects():
276                         if cap.get_properties_objects():
277                             for prop in cap.get_properties_objects():
278                                 propvalue = functions.get_function(
279                                     self,
280                                     node_template,
281                                     prop.value)
282                                 if isinstance(propvalue, functions.GetInput):
283                                     propvalue = propvalue.result()
284                                     for p, v in cap._properties.items():
285                                         if p == prop.name:
286                                             cap._properties[p] = propvalue
287                 for rel, node in node_template.relationships.items():
288                     rel_tpls = node.relationship_tpl
289                     if rel_tpls:
290                         for rel_tpl in rel_tpls:
291                             for interface in rel_tpl.interfaces:
292                                 if interface.inputs:
293                                     for name, value in \
294                                         interface.inputs.items():
295                                         interface.inputs[name] = \
296                                             functions.get_function(self,
297                                                                    rel_tpl,
298                                                                    value)
299         for output in self.outputs:
300             func = functions.get_function(self, self.outputs, output.value)
301             if isinstance(func, functions.GetAttribute):
302                 output.attrs[output.VALUE] = func
303
304     @classmethod
305     def get_sub_mapping_node_type(cls, topology_tpl):
306         if topology_tpl and isinstance(topology_tpl, dict):
307             submap_tpl = topology_tpl.get(SUBSTITUION_MAPPINGS)
308             return SubstitutionMappings.get_node_type(submap_tpl)