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
5 # http://www.apache.org/licenses/LICENSE-2.0
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
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 _
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')
38 log = logging.getLogger("tosca.model")
41 class TopologyTemplate(object):
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):
48 self.sub_mapped_node_template = sub_mapped_node_template
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()
68 for name, attrs in self._tpl_inputs().items():
69 input = Input(name, attrs, self.custom_defs)
70 if self.parsed_params and name in self.parsed_params:
71 input.validate(self.parsed_params[name])
73 default = input.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(
82 input_name=input.name))
87 def _nodetemplates(self):
89 tpls = self._tpl_nodetemplates()
92 tpl = NodeTemplate(name, tpls, self.custom_defs,
93 self.relationship_templates,
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)))):
100 nodetemplates.append(tpl)
103 def _relationship_templates(self):
105 tpls = self._tpl_relationship_templates()
107 tpl = RelationshipTemplate(tpls[name], name, self.custom_defs)
108 rel_templates.append(tpl)
113 for name, attrs in self._tpl_outputs().items():
114 output = Output(name, attrs)
116 outputs.append(output)
119 def _substitution_mappings(self):
120 tpl_substitution_mapping = self._tpl_substitution_mappings()
121 # if tpl_substitution_mapping and self.sub_mapped_node_template:
122 if tpl_substitution_mapping:
123 return SubstitutionMappings(tpl_substitution_mapping,
127 self.sub_mapped_node_template,
132 for policy in self._tpl_policies():
133 for policy_name, policy_tpl in policy.items():
134 target_list = policy_tpl.get('targets')
136 targets_type = "groups"
137 if target_list and len(target_list) >= 1:
138 target_objects = self._get_policy_groups(target_list)
139 if not target_objects:
140 targets_type = "node_templates"
141 target_objects = self._get_group_members(target_list)
142 policyObj = Policy(policy_name, policy_tpl,
143 target_objects, targets_type,
145 policies.append(policyObj)
151 for group_name, group_tpl in self._tpl_groups().items():
152 member_names = group_tpl.get('members')
153 if member_names is not None:
154 DataEntity.validate_datatype('list', member_names)
155 if len(member_names) < 1 or \
156 len(member_names) != len(set(member_names)):
157 exception.ExceptionCollector.appendException(
158 exception.InvalidGroupTargetException(
159 message=_('Member nodes "%s" should be >= 1 '
160 'and not repeated') % member_names))
162 member_nodes = self._get_group_members(member_names)
163 group = Group(group_name, group_tpl,
169 def _get_group_members(self, member_names):
171 self._validate_group_members(member_names)
172 for member in member_names:
173 for node in self.nodetemplates:
174 if node.name == member:
175 member_nodes.append(node)
178 def _get_policy_groups(self, member_names):
180 for member in member_names:
181 for group in self.groups:
182 if group.name == member:
183 member_groups.append(group)
186 def _validate_group_members(self, members):
188 for node in self.nodetemplates:
189 node_names.append(node.name)
190 for member in members:
191 if member not in node_names:
192 exception.ExceptionCollector.appendException(
193 exception.InvalidGroupTargetException(
194 message=_('Target member "%s" is not found in '
195 'node_templates') % member))
197 # topology template can act like node template
198 # it is exposed by substitution_mappings.
200 return self.substitution_mappings.node_type \
201 if self.substitution_mappings else None
203 def capabilities(self):
204 return self.substitution_mappings.capabilities \
205 if self.substitution_mappings else None
207 def requirements(self):
208 return self.substitution_mappings.requirements \
209 if self.substitution_mappings else None
211 def _tpl_description(self):
212 description = self.tpl.get(DESCRIPTION)
214 return description.rstrip()
216 def _tpl_inputs(self):
217 return self.tpl.get(INPUTS) or {}
219 def _tpl_nodetemplates(self):
220 return self.tpl.get(NODE_TEMPLATES)
222 def _tpl_relationship_templates(self):
223 return self.tpl.get(RELATIONSHIP_TEMPLATES) or {}
225 def _tpl_outputs(self):
226 return self.tpl.get(OUTPUTS) or {}
228 def _tpl_substitution_mappings(self):
229 return self.tpl.get(SUBSTITUION_MAPPINGS) or {}
231 def _tpl_groups(self):
232 return self.tpl.get(GROUPS) or {}
234 def _tpl_policies(self):
235 return self.tpl.get(POLICIES) or {}
237 def _validate_field(self):
238 for name in self.tpl:
239 if name not in SECTIONS:
240 exception.ExceptionCollector.appendException(
241 exception.UnknownFieldError(what='Template', field=name))
243 def _process_intrinsic_functions(self):
244 """Process intrinsic functions
246 Current implementation processes functions within node template
247 properties, requirements, interfaces inputs and template outputs.
249 if hasattr(self, 'nodetemplates'):
250 for node_template in self.nodetemplates:
251 for prop in node_template.get_properties_objects():
252 prop.value = functions.get_function(self,
255 for interface in node_template.interfaces:
257 for name, value in interface.inputs.items():
258 interface.inputs[name] = functions.get_function(
262 if node_template.requirements and \
263 isinstance(node_template.requirements, list):
264 for req in node_template.requirements:
266 for req_name, req_item in req.items():
267 if isinstance(req_item, dict):
268 rel = req_item.get('relationship')
270 if rel and 'properties' in rel:
271 for key, value in rel['properties'].items():
272 rel['properties'][key] = \
273 functions.get_function(self,
276 if node_template.get_capabilities_objects():
277 for cap in node_template.get_capabilities_objects():
278 if cap.get_properties_objects():
279 for prop in cap.get_properties_objects():
280 propvalue = functions.get_function(
284 if isinstance(propvalue, functions.GetInput):
285 propvalue = propvalue.result()
286 for p, v in cap._properties.items():
288 cap._properties[p] = propvalue
289 for rel, node in node_template.relationships.items():
290 rel_tpls = node.relationship_tpl
292 for rel_tpl in rel_tpls:
293 for interface in rel_tpl.interfaces:
296 interface.inputs.items():
297 interface.inputs[name] = \
298 functions.get_function(self,
301 for output in self.outputs:
302 func = functions.get_function(self, self.outputs, output.value)
303 if isinstance(func, functions.GetAttribute):
304 output.attrs[output.VALUE] = func
307 def get_sub_mapping_node_type(cls, topology_tpl):
308 if topology_tpl and isinstance(topology_tpl, dict):
309 submap_tpl = topology_tpl.get(SUBSTITUION_MAPPINGS)
310 return SubstitutionMappings.get_node_type(submap_tpl)