# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from translator.toscalib.common.exception import TypeMismatchError from translator.toscalib.common.exception import UnknownFieldError from translator.toscalib.elements.interfaces import CONFIGURE from translator.toscalib.elements.interfaces import CONFIGURE_SHORTNAME from translator.toscalib.elements.interfaces import InterfacesDef from translator.toscalib.elements.interfaces import LIFECYCLE from translator.toscalib.elements.interfaces import LIFECYCLE_SHORTNAME from translator.toscalib.elements.relationshiptype import RelationshipType from translator.toscalib.entity_template import EntityTemplate from translator.toscalib.relationship_template import RelationshipTemplate from translator.toscalib.utils.gettextutils import _ log = logging.getLogger('tosca') class NodeTemplate(EntityTemplate): '''Node template from a Tosca profile.''' def __init__(self, name, node_templates, custom_def=None, available_rel_tpls=None, available_rel_types=None): super(NodeTemplate, self).__init__(name, node_templates[name], 'node_type', custom_def) self.templates = node_templates self.custom_def = custom_def self.related = {} self.relationship_tpl = [] self.available_rel_tpls = available_rel_tpls self.available_rel_types = available_rel_types self._relationships = {} @property def relationships(self): if not self._relationships: requires = self.requirements if requires: for r in requires: for r1, value in r.items(): if isinstance(value, dict): explicit = self._get_explicit_relationship( r, value) if explicit: for key, value in explicit.items(): self._relationships[key] = value else: # need to check for short notation of requirements keys = self.type_definition.relationship.keys() for rtype in keys: if r1 == rtype.capability_name: related_tpl = NodeTemplate( value, self.templates, self.custom_def) self._relationships[rtype] = related_tpl related_tpl._add_relationship_template( r, rtype.type) return self._relationships def _get_explicit_relationship(self, req, value): """Handle explicit relationship For example, - req: node: DBMS relationship: tosca.relationships.HostedOn """ explicit_relation = {} node = value.get('node') if node: # TODO(spzala) implement look up once Glance meta data is available # to find a matching TOSCA node using the TOSCA types msg = _('Lookup by TOSCA types are not supported. ' 'Requirement for %s can not be full-filled.') % self.name if (node in list(self.type_definition.TOSCA_DEF.keys()) or node in self.custom_def): raise NotImplementedError(msg) related_tpl = NodeTemplate(node, self.templates, self.custom_def) relationship = value.get('relationship') # check if it's type has relationship defined if not relationship: parent_reqs = self.type_definition.get_all_requirements() for key in req.keys(): for req_dict in parent_reqs: if key in req_dict.keys(): relationship = (req_dict.get(key). get('relationship')) break if relationship: found_relationship_tpl = False # apply available relationship templates if found for tpl in self.available_rel_tpls: if tpl.name == relationship: rtype = RelationshipType(tpl.type) explicit_relation[rtype] = related_tpl self.relationship_tpl.append(tpl) found_relationship_tpl = True # create relationship template object. if not found_relationship_tpl: if isinstance(relationship, dict): relationship = relationship.get('type') rel_prfx = self.type_definition.RELATIONSHIP_PREFIX if not relationship.startswith(rel_prfx): relationship = rel_prfx + relationship for rtype in self.type_definition.relationship.keys(): if rtype.type == relationship: explicit_relation[rtype] = related_tpl related_tpl._add_relationship_template(req, rtype.type) elif self.available_rel_types: if relationship in self.available_rel_types.keys(): rel_type_def = self.available_rel_types.\ get(relationship) if 'derived_from' in rel_type_def \ and rtype.type == \ rel_type_def.get('derived_from'): explicit_relation[rtype] = related_tpl related_tpl.\ _add_relationship_template(req, rtype.type) return explicit_relation def _add_relationship_template(self, requirement, rtype): req = requirement.copy() req['type'] = rtype tpl = RelationshipTemplate(req, rtype, None) self.relationship_tpl.append(tpl) def get_relationship_template(self): return self.relationship_tpl def _add_next(self, nodetpl, relationship): self.related[nodetpl] = relationship @property def related_nodes(self): if not self.related: for relation, node in self.type_definition.relationship.items(): for tpl in self.templates: if tpl == node.type: self.related[NodeTemplate(tpl)] = relation return self.related.keys() def validate(self, tosca_tpl=None): self._validate_capabilities() self._validate_requirements() self._validate_properties(self.entity_tpl, self.type_definition) self._validate_interfaces() for prop in self.get_properties_objects(): prop.validate() def _validate_requirements(self): type_requires = self.type_definition.get_all_requirements() allowed_reqs = ["template"] if type_requires: for treq in type_requires: for key, value in treq.items(): allowed_reqs.append(key) if isinstance(value, dict): for key in value: allowed_reqs.append(key) requires = self.type_definition.get_value(self.REQUIREMENTS, self.entity_tpl) if requires: if not isinstance(requires, list): raise TypeMismatchError( what='Requirements of template %s' % self.name, type='list') for req in requires: for r1, value in req.items(): if isinstance(value, dict): allowed_reqs.append(r1) self._common_validate_field(req, allowed_reqs, 'Requirements') def _validate_interfaces(self): ifaces = self.type_definition.get_value(self.INTERFACES, self.entity_tpl) if ifaces: for i in ifaces: for name, value in ifaces.items(): if name in (LIFECYCLE, LIFECYCLE_SHORTNAME): self._common_validate_field( value, InterfacesDef. interfaces_node_lifecycle_operations, 'Interfaces') elif name in (CONFIGURE, CONFIGURE_SHORTNAME): self._common_validate_field( value, InterfacesDef. interfaces_relationship_confiure_operations, 'Interfaces') else: raise UnknownFieldError( what='Interfaces of template %s' % self.name, field=name)