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