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)
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:
122 return SubstitutionMappings(tpl_substitution_mapping,
126 self.sub_mapped_node_template,
131 for policy in self._tpl_policies():
132 for policy_name, policy_tpl in policy.items():
133 target_list = policy_tpl.get('targets')
134 if target_list and len(target_list) >= 1:
136 targets_type = "groups"
137 target_objects = self._get_policy_groups(target_list)
138 if not target_objects:
139 targets_type = "node_templates"
140 target_objects = self._get_group_members(target_list)
141 policyObj = Policy(policy_name, policy_tpl,
142 target_objects, targets_type,
144 policies.append(policyObj)
150 for group_name, group_tpl in self._tpl_groups().items():
151 member_names = group_tpl.get('members')
152 if member_names is not None:
153 DataEntity.validate_datatype('list', member_names)
154 if len(member_names) < 1 or \
155 len(member_names) != len(set(member_names)):
156 exception.ExceptionCollector.appendException(
157 exception.InvalidGroupTargetException(
158 message=_('Member nodes "%s" should be >= 1 '
159 'and not repeated') % member_names))
161 member_nodes = self._get_group_members(member_names)
162 group = Group(group_name, group_tpl,
168 def _get_group_members(self, member_names):
170 self._validate_group_members(member_names)
171 for member in member_names:
172 for node in self.nodetemplates:
173 if node.name == member:
174 member_nodes.append(node)
177 def _get_policy_groups(self, member_names):
179 for member in member_names:
180 for group in self.groups:
181 if group.name == member:
182 member_groups.append(group)
185 def _validate_group_members(self, members):
187 for node in self.nodetemplates:
188 node_names.append(node.name)
189 for member in members:
190 if member not in node_names:
191 exception.ExceptionCollector.appendException(
192 exception.InvalidGroupTargetException(
193 message=_('Target member "%s" is not found in '
194 'node_templates') % member))
196 # topology template can act like node template
197 # it is exposed by substitution_mappings.
199 return (self.substitution_mappings.node_type
200 if self.substitution_mappings else None)
202 def capabilities(self):
203 return (self.substitution_mappings.capabilities
204 if self.substitution_mappings else None)
206 def requirements(self):
207 return (self.substitution_mappings.requirements
208 if self.substitution_mappings else None)
210 def _tpl_description(self):
211 description = self.tpl.get(DESCRIPTION)
213 return description.rstrip()
215 def _tpl_inputs(self):
216 return self.tpl.get(INPUTS) or {}
218 def _tpl_nodetemplates(self):
219 return self.tpl.get(NODE_TEMPLATES)
221 def _tpl_relationship_templates(self):
222 return self.tpl.get(RELATIONSHIP_TEMPLATES) or {}
224 def _tpl_outputs(self):
225 return self.tpl.get(OUTPUTS) or {}
227 def _tpl_substitution_mappings(self):
228 return self.tpl.get(SUBSTITUION_MAPPINGS) or {}
230 def _tpl_groups(self):
231 return self.tpl.get(GROUPS) or {}
233 def _tpl_policies(self):
234 return self.tpl.get(POLICIES) or {}
236 def _validate_field(self):
237 for name in self.tpl:
238 if name not in SECTIONS:
239 exception.ExceptionCollector.appendException(
240 exception.UnknownFieldError(what='Template', field=name))
242 def _process_intrinsic_functions(self):
243 """Process intrinsic functions
245 Current implementation processes functions within node template
246 properties, requirements, interfaces inputs and template outputs.
248 if hasattr(self, 'nodetemplates'):
249 for node_template in self.nodetemplates:
250 for prop in node_template.get_properties_objects():
251 prop.value = functions.get_function(self,
254 for interface in node_template.interfaces:
256 for name, value in interface.inputs.items():
257 interface.inputs[name] = functions.get_function(
261 if node_template.requirements:
262 for req in node_template.requirements:
264 for req_name, req_item in req.items():
265 if isinstance(req_item, dict):
266 rel = req_item.get('relationship')
268 if rel and 'properties' in rel:
269 for key, value in rel['properties'].items():
270 rel['properties'][key] = \
271 functions.get_function(self,
274 if node_template.get_capabilities_objects():
275 for cap in node_template.get_capabilities_objects():
276 if cap.get_properties_objects():
277 for prop in cap.get_properties_objects():
278 propvalue = functions.get_function(
282 if isinstance(propvalue, functions.GetInput):
283 propvalue = propvalue.result()
284 for p, v in cap._properties.items():
286 cap._properties[p] = propvalue
287 for rel, node in node_template.relationships.items():
288 rel_tpls = node.relationship_tpl
290 for rel_tpl in rel_tpls:
291 for interface in rel_tpl.interfaces:
294 interface.inputs.items():
295 interface.inputs[name] = \
296 functions.get_function(self,
299 for output in self.outputs:
300 func = functions.get_function(self, self.outputs, output.value)
301 if isinstance(func, functions.GetAttribute):
302 output.attrs[output.VALUE] = func
305 def get_sub_mapping_node_type(cls, topology_tpl):
306 if topology_tpl and isinstance(topology_tpl, dict):
307 submap_tpl = topology_tpl.get(SUBSTITUION_MAPPINGS)
308 return SubstitutionMappings.get_node_type(submap_tpl)