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