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