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 _
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')
37 log = logging.getLogger("tosca.model")
40 class TopologyTemplate(object):
42 '''Load the template data.'''
43 def __init__(self, template, custom_defs,
44 rel_types=None, parsed_params=None,
45 sub_mapped_node_template=None):
47 self.sub_mapped_node_template = sub_mapped_node_template
49 self.custom_defs = custom_defs
50 self.rel_types = rel_types
51 self.parsed_params = parsed_params
52 self._validate_field()
53 self.description = self._tpl_description()
54 self.inputs = self._inputs()
55 self.relationship_templates = self._relationship_templates()
56 self.nodetemplates = self._nodetemplates()
57 self.outputs = self._outputs()
58 if hasattr(self, 'nodetemplates'):
59 self.graph = ToscaGraph(self.nodetemplates)
60 self.groups = self._groups()
61 self.policies = self._policies()
62 self._process_intrinsic_functions()
63 self.substitution_mappings = self._substitution_mappings()
67 for name, attrs in self._tpl_inputs().items():
68 input = Input(name, attrs)
69 if self.parsed_params and name in self.parsed_params:
70 input.validate(self.parsed_params[name])
72 default = input.default
74 input.validate(default)
75 if (self.parsed_params and input.name not in self.parsed_params
76 or self.parsed_params is None) and input.required \
77 and input.default is None:
78 exception.ExceptionCollector.appendException(
79 exception.MissingRequiredParameterError(
81 input_name=input.name))
86 def _nodetemplates(self):
88 tpls = self._tpl_nodetemplates()
91 tpl = NodeTemplate(name, tpls, self.custom_defs,
92 self.relationship_templates,
94 if (tpl.type_definition and
95 (tpl.type in tpl.type_definition.TOSCA_DEF or
96 (tpl.type not in tpl.type_definition.TOSCA_DEF and
97 bool(tpl.custom_def)))):
99 nodetemplates.append(tpl)
102 def _relationship_templates(self):
104 tpls = self._tpl_relationship_templates()
106 tpl = RelationshipTemplate(tpls[name], name, self.custom_defs)
107 rel_templates.append(tpl)
112 for name, attrs in self._tpl_outputs().items():
113 output = Output(name, attrs)
115 outputs.append(output)
118 def _substitution_mappings(self):
119 tpl_substitution_mapping = self._tpl_substitution_mappings()
120 if tpl_substitution_mapping:
121 return SubstitutionMappings(tpl_substitution_mapping,
125 self.sub_mapped_node_template,
130 for policy in self._tpl_policies():
131 for policy_name, policy_tpl in policy.items():
132 target_list = policy_tpl.get('targets')
133 if target_list and len(target_list) >= 1:
135 targets_type = "groups"
136 target_objects = self._get_policy_groups(target_list)
137 if not target_objects:
138 targets_type = "node_templates"
139 target_objects = self._get_group_members(target_list)
140 policyObj = Policy(policy_name, policy_tpl,
141 target_objects, targets_type,
143 policies.append(policyObj)
149 for group_name, group_tpl in self._tpl_groups().items():
150 member_names = group_tpl.get('members')
151 if member_names is not None:
152 DataEntity.validate_datatype('list', member_names)
153 if len(member_names) < 1 or \
154 len(member_names) != len(set(member_names)):
155 exception.ExceptionCollector.appendException(
156 exception.InvalidGroupTargetException(
157 message=_('Member nodes "%s" should be >= 1 '
158 'and not repeated') % member_names))
160 member_nodes = self._get_group_members(member_names)
161 group = Group(group_name, group_tpl,
167 def _get_group_members(self, member_names):
169 self._validate_group_members(member_names)
170 for member in member_names:
171 for node in self.nodetemplates:
172 if node.name == member:
173 member_nodes.append(node)
176 def _get_policy_groups(self, member_names):
178 for member in member_names:
179 for group in self.groups:
180 if group.name == member:
181 member_groups.append(group)
184 def _validate_group_members(self, members):
186 for node in self.nodetemplates:
187 node_names.append(node.name)
188 for member in members:
189 if member not in node_names:
190 exception.ExceptionCollector.appendException(
191 exception.InvalidGroupTargetException(
192 message=_('Target member "%s" is not found in '
193 'node_templates') % member))
195 # topology template can act like node template
196 # it is exposed by substitution_mappings.
198 return (self.substitution_mappings.node_type
199 if self.substitution_mappings else None)
201 def capabilities(self):
202 return (self.substitution_mappings.capabilities
203 if self.substitution_mappings else None)
205 def requirements(self):
206 return (self.substitution_mappings.requirements
207 if self.substitution_mappings else None)
209 def _tpl_description(self):
210 description = self.tpl.get(DESCRIPTION)
212 return description.rstrip()
214 def _tpl_inputs(self):
215 return self.tpl.get(INPUTS) or {}
217 def _tpl_nodetemplates(self):
218 return self.tpl.get(NODE_TEMPLATES)
220 def _tpl_relationship_templates(self):
221 return self.tpl.get(RELATIONSHIP_TEMPLATES) or {}
223 def _tpl_outputs(self):
224 return self.tpl.get(OUTPUTS) or {}
226 def _tpl_substitution_mappings(self):
227 return self.tpl.get(SUBSTITUION_MAPPINGS) or {}
229 def _tpl_groups(self):
230 return self.tpl.get(GROUPS) or {}
232 def _tpl_policies(self):
233 return self.tpl.get(POLICIES) or {}
235 def _validate_field(self):
236 for name in self.tpl:
237 if name not in SECTIONS:
238 exception.ExceptionCollector.appendException(
239 exception.UnknownFieldError(what='Template', field=name))
241 def _process_intrinsic_functions(self):
242 """Process intrinsic functions
244 Current implementation processes functions within node template
245 properties, requirements, interfaces inputs and template outputs.
247 if hasattr(self, 'nodetemplates'):
248 for node_template in self.nodetemplates:
249 for prop in node_template.get_properties_objects():
250 prop.value = functions.get_function(self,
253 for interface in node_template.interfaces:
255 for name, value in interface.inputs.items():
256 interface.inputs[name] = functions.get_function(
260 if node_template.requirements:
261 for req in node_template.requirements:
263 for req_name, req_item in req.items():
264 if isinstance(req_item, dict):
265 rel = req_item.get('relationship')
267 if rel and 'properties' in rel:
268 for key, value in rel['properties'].items():
269 rel['properties'][key] = \
270 functions.get_function(self,
273 if node_template.get_capabilities_objects():
274 for cap in node_template.get_capabilities_objects():
275 if cap.get_properties_objects():
276 for prop in cap.get_properties_objects():
277 propvalue = functions.get_function(
281 if isinstance(propvalue, functions.GetInput):
282 propvalue = propvalue.result()
283 for p, v in cap._properties.items():
285 cap._properties[p] = propvalue
286 for rel, node in node_template.relationships.items():
287 rel_tpls = node.relationship_tpl
289 for rel_tpl in rel_tpls:
290 for interface in rel_tpl.interfaces:
293 interface.inputs.items():
294 interface.inputs[name] = \
295 functions.get_function(self,
298 for output in self.outputs:
299 func = functions.get_function(self, self.outputs, output.value)
300 if isinstance(func, functions.GetAttribute):
301 output.attrs[output.VALUE] = func
304 def get_sub_mapping_node_type(cls, topology_tpl):
305 if topology_tpl and isinstance(topology_tpl, dict):
306 submap_tpl = topology_tpl.get(SUBSTITUION_MAPPINGS)
307 return SubstitutionMappings.get_node_type(submap_tpl)