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
13 from toscaparser.capabilities import Capability
14 from toscaparser.common.exception import ExceptionCollector
15 from toscaparser.common.exception import MissingRequiredFieldError
16 from toscaparser.common.exception import UnknownFieldError
17 from toscaparser.common.exception import ValidationError
18 from toscaparser.elements.grouptype import GroupType
19 from toscaparser.elements.interfaces import InterfacesDef
20 from toscaparser.elements.nodetype import NodeType
21 from toscaparser.elements.policytype import PolicyType
22 from toscaparser.elements.relationshiptype import RelationshipType
23 from toscaparser.properties import Property
24 from toscaparser.unsupportedtype import UnsupportedType
25 from toscaparser.utils.gettextutils import _
26 from org.openecomp.sdc.toscaparser.jython import JyEntityTemplate
29 class EntityTemplate(JyEntityTemplate):
30 '''Base class for TOSCA templates.'''
32 SECTIONS = (DERIVED_FROM, PROPERTIES, REQUIREMENTS,
33 INTERFACES, CAPABILITIES, TYPE, DESCRIPTION, DIRECTIVES,
34 ATTRIBUTES, ARTIFACTS, NODE_FILTER, COPY) = \
35 ('derived_from', 'properties', 'requirements', 'interfaces',
36 'capabilities', 'type', 'description', 'directives',
37 'attributes', 'artifacts', 'node_filter', 'copy')
38 REQUIREMENTS_SECTION = (NODE, CAPABILITY, RELATIONSHIP, OCCURRENCES, NODE_FILTER) = \
39 ('node', 'capability', 'relationship',
40 'occurrences', 'node_filter')
42 SPECIAL_SECTIONS = (METADATA) = ('metadata')
44 def __init__(self, name, template, entity_name, custom_def=None):
46 self.entity_tpl = template
47 self.custom_def = custom_def
48 self._validate_field(self.entity_tpl)
49 type = self.entity_tpl.get('type')
50 UnsupportedType.validate_type(type)
51 if entity_name == 'node_type':
52 self.type_definition = NodeType(type, custom_def) \
53 if type is not None else None
54 if entity_name == 'relationship_type':
55 relationship = template.get('relationship')
57 if relationship and isinstance(relationship, dict):
58 type = relationship.get('type')
59 elif isinstance(relationship, str):
60 type = self.entity_tpl['relationship']
62 type = self.entity_tpl['type']
63 UnsupportedType.validate_type(type)
64 self.type_definition = RelationshipType(type,
66 if entity_name == 'policy_type':
68 msg = (_('Policy definition of "%(pname)s" must have'
69 ' a "type" ''attribute.') % dict(pname=name))
70 ExceptionCollector.appendException(
73 self.type_definition = PolicyType(type, custom_def)
74 if entity_name == 'group_type':
75 self.type_definition = GroupType(type, custom_def) \
76 if type is not None else None
77 self._properties = None
78 self._interfaces = None
79 self._requirements = None
80 self._capabilities = None
85 def getJyDescription(self):
86 return self.entity_tpl.get('description')
88 def getJyTypeDefinition(self):
89 return self.type_definition
91 def getJyProperties(self):
92 return self.get_properties_objects()
94 def getJyCapabilities(self):
95 return self.get_capabilities_objects()
97 def getJyRequirements(self):
98 return self.requirements
102 if self.type_definition:
103 return self.type_definition.type
106 def parent_type(self):
107 if self.type_definition:
108 return self.type_definition.parent_type
111 def requirements(self):
112 if self._requirements is None:
113 self._requirements = self.type_definition.get_value(
115 self.entity_tpl) or []
116 return self._requirements
118 def get_properties_objects(self):
119 '''Return properties objects for this template.'''
120 if self._properties is None:
121 self._properties = self._create_properties()
122 return self._properties
124 def get_properties(self):
125 '''Return a dictionary of property name-object pairs.'''
126 return {prop.name: prop
127 for prop in self.get_properties_objects()}
129 def get_property_value(self, name):
130 '''Return the value of a given property name.'''
131 props = self.get_properties()
132 if props and name in props.keys():
133 return props[name].value
136 def interfaces(self):
137 if self._interfaces is None:
138 self._interfaces = self._create_interfaces()
139 return self._interfaces
141 def get_capabilities_objects(self):
142 '''Return capabilities objects for this template.'''
143 if not self._capabilities:
144 self._capabilities = self._create_capabilities()
145 return self._capabilities
147 def get_capabilities(self):
148 '''Return a dictionary of capability name-object pairs.'''
149 return {cap.name: cap
150 for cap in self.get_capabilities_objects()}
152 def is_derived_from(self, type_str):
153 '''Check if object inherits from the given type.
155 Returns true if this object is derived from 'type_str'.
160 elif self.type == type_str:
162 elif self.parent_type:
163 return self.parent_type.is_derived_from(type_str)
167 def _create_capabilities(self):
169 caps = self.type_definition.get_value(self.CAPABILITIES,
170 self.entity_tpl, True)
172 for name, props in caps.items():
173 capabilities = self.type_definition.get_capabilities()
174 if name in capabilities.keys():
175 c = capabilities[name]
177 # first use the definition default value
179 for property_name in c.properties.keys():
180 prop_def = c.properties[property_name]
181 if 'default' in prop_def:
182 properties[property_name] = prop_def['default']
183 # then update (if available) with the node properties
184 if 'properties' in props and props['properties']:
185 properties.update(props['properties'])
187 cap = Capability(name, properties, c)
188 capability.append(cap)
191 def _validate_properties(self, template, entitytype):
192 properties = entitytype.get_value(self.PROPERTIES, template)
193 self._common_validate_properties(entitytype, properties)
195 def _validate_capabilities(self):
196 type_capabilities = self.type_definition.get_capabilities()
198 type_capabilities.keys() if type_capabilities else []
199 capabilities = self.type_definition.get_value(self.CAPABILITIES,
202 self._common_validate_field(capabilities, allowed_caps,
204 self._validate_capabilities_properties(capabilities)
206 def _validate_capabilities_properties(self, capabilities):
207 for cap, props in capabilities.items():
208 capability = self.get_capability(cap)
211 capabilitydef = capability.definition
212 self._common_validate_properties(capabilitydef,
213 props[self.PROPERTIES])
215 # validating capability properties values
216 for prop in self.get_capability(cap).get_properties_objects():
219 # TODO(srinivas_tadepalli): temporary work around to validate
220 # default_instances until standardized in specification
221 if cap == "scalable" and prop.name == "default_instances":
222 prop_dict = props[self.PROPERTIES]
223 min_instances = prop_dict.get("min_instances")
224 max_instances = prop_dict.get("max_instances")
225 default_instances = prop_dict.get("default_instances")
226 if not (min_instances <= default_instances
228 err_msg = ('"properties" of template "%s": '
229 '"default_instances" value is not between '
230 '"min_instances" and "max_instances".' %
232 ExceptionCollector.appendException(
233 ValidationError(message=err_msg))
235 def _common_validate_properties(self, entitytype, properties):
238 for p in entitytype.get_properties_def_objects():
239 allowed_props.append(p.name)
240 # If property is 'required' and has no 'default' value then record
241 if p.required and p.default is None:
242 required_props.append(p.name)
243 # validate all required properties have values
245 req_props_no_value_or_default = []
246 self._common_validate_field(properties, allowed_props,
248 # make sure it's not missing any property required by a tosca type
249 for r in required_props:
250 if r not in properties.keys():
251 req_props_no_value_or_default.append(r)
252 # Required properties found without value or a default value
253 if req_props_no_value_or_default:
254 ExceptionCollector.appendException(
255 MissingRequiredFieldError(
256 what='"properties" of template "%s"' % self.name,
257 required=req_props_no_value_or_default))
259 # Required properties in schema, but not in template
261 ExceptionCollector.appendException(
262 MissingRequiredFieldError(
263 what='"properties" of template "%s"' % self.name,
264 required=required_props))
266 def _validate_field(self, template):
267 if not isinstance(template, dict):
268 ExceptionCollector.appendException(
269 MissingRequiredFieldError(
270 what='Template "%s"' % self.name, required=self.TYPE))
272 relationship = template.get('relationship')
273 if relationship and not isinstance(relationship, str):
274 relationship[self.TYPE]
275 elif isinstance(relationship, str):
276 template['relationship']
280 ExceptionCollector.appendException(
281 MissingRequiredFieldError(
282 what='Template "%s"' % self.name, required=self.TYPE))
284 def _common_validate_field(self, schema, allowedlist, section):
286 if name not in allowedlist:
287 ExceptionCollector.appendException(
289 what=('"%(section)s" of template "%(nodename)s"'
290 % {'section': section, 'nodename': self.name}),
293 def _create_properties(self):
295 properties = self.type_definition.get_value(self.PROPERTIES,
296 self.entity_tpl) or {}
297 for name, value in properties.items():
298 props_def = self.type_definition.get_properties_def()
299 if props_def and name in props_def:
300 prop = Property(name, value,
301 props_def[name].schema, self.custom_def)
303 for p in self.type_definition.get_properties_def_objects():
304 if p.default is not None and p.name not in properties.keys():
305 prop = Property(p.name, p.default, p.schema, self.custom_def)
309 def _create_interfaces(self):
311 type_interfaces = None
312 if isinstance(self.type_definition, RelationshipType):
313 if isinstance(self.entity_tpl, dict):
314 if self.INTERFACES in self.entity_tpl:
315 type_interfaces = self.entity_tpl[self.INTERFACES]
317 for rel_def, value in self.entity_tpl.items():
318 if rel_def != 'type':
319 rel_def = self.entity_tpl.get(rel_def)
321 if isinstance(rel_def, dict):
322 rel = rel_def.get('relationship')
324 if self.INTERFACES in rel:
325 type_interfaces = rel[self.INTERFACES]
328 type_interfaces = self.type_definition.get_value(self.INTERFACES,
331 for interface_type, value in type_interfaces.items():
332 for op, op_def in value.items():
333 iface = InterfacesDef(self.type_definition,
334 interfacetype=interface_type,
338 interfaces.append(iface)
341 def get_capability(self, name):
342 """Provide named capability
344 :param name: name of capability
345 :return: capability object if found, None otherwise
347 caps = self.get_capabilities()
348 if caps and name in caps.keys():