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