def __init__(self, name, template, entity_name, custom_def=None): self.name = name self.entity_tpl = template self.custom_def = custom_def self._validate_field(self.entity_tpl) type = self.entity_tpl.get('type') UnsupportedType.validate_type(type) if entity_name == 'node_type': self.type_definition = NodeType(type, custom_def) \ if type is not None else None if entity_name == 'relationship_type': relationship = template.get('relationship') type = None if relationship and isinstance(relationship, dict): type = relationship.get('type') elif isinstance(relationship, str): type = self.entity_tpl['relationship'] else: type = self.entity_tpl['type'] UnsupportedType.validate_type(type) self.type_definition = RelationshipType(type, None, custom_def) if entity_name == 'policy_type': if not type: msg = (_('Policy definition of "%(pname)s" must have' ' a "type" ' 'attribute.') % dict(pname=name)) ExceptionCollector.appendException(ValidationError(msg)) self.type_definition = PolicyType(type, custom_def) if entity_name == 'group_type': self.type_definition = GroupType(type, custom_def) \ if type is not None else None self._properties = None self._interfaces = None self._requirements = None self._capabilities = None
def relationship(self): '''Return a dictionary of relationships to other node types. This method returns a dictionary of named relationships that nodes of the current node type (self) can have to other nodes (of specific types) in a TOSCA template. ''' relationship = {} requires = self.get_all_requirements() if requires: # NOTE(sdmonov): Check if requires is a dict. # If it is a dict convert it to a list of dicts. # This is needed because currently the code below supports only # lists as requirements definition. The following check will # make sure if a map (dict) was provided it will be converted to # a list before proceeding to the parsing. if isinstance(requires, dict): requires = [{key: value} for key, value in requires.items()] keyword = None node_type = None for require in requires: log.debug("{}: Relation require: {}".format(self.ntype, require)) for key, req in require.items(): log.debug("{}: Req {}".format(self.ntype, req)) if 'relationship' in req: relation = req.get('relationship') log.debug("{}: Relation {}".format(self.ntype, relation)) if 'type' in relation: relation = relation.get('type') node_type = req.get('node') value = req if node_type: keyword = 'node' else: # If value is a dict and has a type key # we need to lookup the node type using # the capability type value = req if isinstance(value, dict): captype = value['capability'] value = (self._get_node_type_by_cap(captype)) keyword = key node_type = value log.debug("{}: RelationshipType: {}, {}, {}". format(self.ntype, relation or None, keyword, self.custom_def)) rtype = RelationshipType(relation, keyword, self.custom_def) relatednode = NodeType(node_type, self.custom_def) relationship[rtype] = relatednode return relationship
def __init__(self, name, template, entity_name, custom_def=None): self.name = name self.entity_tpl = template self.custom_def = custom_def self._validate_field(self.entity_tpl) if entity_name == 'node_type': type = self.entity_tpl.get('type') self.type_definition = NodeType(type, custom_def) \ if type is not None else None if entity_name == 'relationship_type': relationship = template.get('relationship') type = None if relationship and isinstance(relationship, dict): type = relationship.get('type') elif isinstance(relationship, str): type = self.entity_tpl['relationship'] else: type = self.entity_tpl['type'] self.type_definition = RelationshipType(type, None, custom_def) self._properties = None self._interfaces = None self._requirements = None self._capabilities = None
def __init__(self, name, template, entity_name, custom_def=None): self.name = name self.entity_tpl = template self.custom_def = custom_def self._validate_field(self.entity_tpl) if entity_name == 'node_type': self.type_definition = NodeType(self.entity_tpl['type'], custom_def) if entity_name == 'relationship_type': relationship = template.get('relationship') type = None if relationship and isinstance(relationship, dict): type = relationship.get('type') elif isinstance(relationship, str): type = self.entity_tpl['relationship'] else: type = self.entity_tpl['type'] self.type_definition = RelationshipType(type, None, custom_def) self._properties = None self._interfaces = None self._requirements = None self._capabilities = None
def __init__(self, name, template, entity_name, custom_def=None): self.name = name self.entity_tpl = template self.custom_def = custom_def self._validate_field(self.entity_tpl) type = self.entity_tpl.get('type') UnsupportedType.validate_type(type) if '__typename' not in template: self._validate_fields(template) if entity_name == 'node_type': self.type_definition = NodeType(type, custom_def) \ if type is not None else None self._validate_directives(self.entity_tpl) if entity_name == 'relationship_type': self.type_definition = RelationshipType(type, custom_def) if entity_name == 'policy_type': if not type: msg = (_('Policy definition of "%(pname)s" must have' ' a "type" ' 'attribute.') % dict(pname=name)) ExceptionCollector.appendException( ValidationError(message=msg)) self.type_definition = PolicyType(type, custom_def) if entity_name == 'group_type': self.type_definition = GroupType(type, custom_def) \ if type is not None else None if entity_name == 'artifact_type': self.type_definition = ArtifactTypeDef(type, custom_def) \ if type is not None else None self._properties = None self._interfaces = None self._requirements = None self._capabilities = None if not self.type_definition: msg = "no type found %s for %s" % (entity_name, template) ExceptionCollector.appendException(ValidationError(message=msg)) return metadata = self.type_definition.get_definition('metadata') if metadata and 'additionalProperties' in metadata: self.additionalProperties = metadata['additionalProperties'] self._properties_tpl = self._validate_properties() for prop in self.get_properties_objects(): prop.validate() self._validate_interfaces()
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 isinstance(value, dict) else value 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 is 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): ExceptionCollector.appendException(NotImplementedError(msg)) return if node not in self.templates: ExceptionCollector.appendException( KeyError(_('Node template "%s" was not found.') % node)) return related_tpl = NodeTemplate(node, self.templates, self.custom_def) relationship = value.get('relationship') \ if isinstance(value, dict) else None # check if it's type has relationship defined if not relationship: parent_reqs = self.type_definition.get_all_requirements() if parent_reqs is None: ExceptionCollector.appendException( ValidationError(message='parent_req is ' + str(parent_reqs))) else: 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 if self.available_rel_tpls: for tpl in self.available_rel_tpls: if tpl.name == relationship: rtype = RelationshipType(tpl.type, None, self.custom_def) explicit_relation[rtype] = related_tpl tpl.target = related_tpl tpl.source = self self.relationship_tpl.append(tpl) found_relationship_tpl = True # create relationship template object. rel_prfx = self.type_definition.RELATIONSHIP_PREFIX if not found_relationship_tpl: if isinstance(relationship, dict): relationship = relationship.get('type') if relationship: if self.available_rel_types and \ relationship in self.available_rel_types.keys(): pass elif not relationship.startswith(rel_prfx): relationship = rel_prfx + relationship else: ExceptionCollector.appendException( MissingRequiredFieldError( what=_('"relationship" used in template ' '"%s"') % related_tpl.name, required=self.TYPE)) 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, self) 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: super_type = \ rel_type_def.get('derived_from') if not super_type.startswith(rel_prfx): super_type = rel_prfx + super_type if rtype.type == super_type: explicit_relation[rtype] = related_tpl related_tpl.\ _add_relationship_template( req, rtype.type, self) return explicit_relation
class EntityTemplate(object): '''Base class for TOSCA templates.''' SECTIONS = (DERIVED_FROM, PROPERTIES, REQUIREMENTS, INTERFACES, CAPABILITIES, TYPE, DESCRIPTION, DIRECTIVES, ATTRIBUTES, ARTIFACTS, NODE_FILTER, COPY) = \ ('derived_from', 'properties', 'requirements', 'interfaces', 'capabilities', 'type', 'description', 'directives', 'attributes', 'artifacts', 'node_filter', 'copy') REQUIREMENTS_SECTION = (NODE, CAPABILITY, RELATIONSHIP, OCCURRENCES) = \ ('node', 'capability', 'relationship', 'occurrences') # Special key names SPECIAL_SECTIONS = (METADATA) = ('metadata') def __init__(self, name, template, entity_name, custom_def=None): self.name = name self.entity_tpl = template self.custom_def = custom_def self._validate_field(self.entity_tpl) if entity_name == 'node_type': type = self.entity_tpl.get('type') self.type_definition = NodeType(type, custom_def) \ if type is not None else None if entity_name == 'relationship_type': relationship = template.get('relationship') type = None if relationship and isinstance(relationship, dict): type = relationship.get('type') elif isinstance(relationship, str): type = self.entity_tpl['relationship'] else: type = self.entity_tpl['type'] self.type_definition = RelationshipType(type, None, custom_def) self._properties = None self._interfaces = None self._requirements = None self._capabilities = None @property def type(self): if self.type_definition: return self.type_definition.type @property def requirements(self): if self._requirements is None: self._requirements = self.type_definition.get_value( self.REQUIREMENTS, self.entity_tpl) or [] return self._requirements def get_properties_objects(self): '''Return properties objects for this template.''' if self._properties is None: self._properties = self._create_properties() return self._properties def get_properties(self): '''Return a dictionary of property name-object pairs.''' return {prop.name: prop for prop in self.get_properties_objects()} def get_property_value(self, name): '''Return the value of a given property name.''' props = self.get_properties() if props and name in props.keys(): return props[name].value @property def interfaces(self): if self._interfaces is None: self._interfaces = self._create_interfaces() return self._interfaces def get_capabilities_objects(self): '''Return capabilities objects for this template.''' if not self._capabilities: self._capabilities = self._create_capabilities() return self._capabilities def get_capabilities(self): '''Return a dictionary of capability name-object pairs.''' return {cap.name: cap for cap in self.get_capabilities_objects()} def is_derived_from(self, type_str): '''Check if object inherits from the given type. Returns true if this object is derived from 'type_str'. False otherwise. ''' if not self.type: return False elif self.type == type_str: return True elif self.parent_type: return self.parent_type.is_derived_from(type_str) else: return False def _create_capabilities(self): capability = [] caps = self.type_definition.get_value(self.CAPABILITIES, self.entity_tpl) if caps: for name, props in caps.items(): capabilities = self.type_definition.get_capabilities() if name in capabilities.keys(): c = capabilities[name] cap = Capability(name, props['properties'], c, self.custom_def) capability.append(cap) return capability def _validate_properties(self, template, entitytype): properties = entitytype.get_value(self.PROPERTIES, template) self._common_validate_properties(entitytype, properties) def _validate_capabilities(self): type_capabilities = self.type_definition.get_capabilities() allowed_caps = \ type_capabilities.keys() if type_capabilities else [] capabilities = self.type_definition.get_value(self.CAPABILITIES, self.entity_tpl) if capabilities: self._common_validate_field(capabilities, allowed_caps, 'capabilities') self._validate_capabilities_properties(capabilities) def _validate_capabilities_properties(self, capabilities): for cap, props in capabilities.items(): capabilitydef = self.get_capability(cap).definition self._common_validate_properties(capabilitydef, props[self.PROPERTIES]) # validating capability properties values for prop in self.get_capability(cap).get_properties_objects(): prop.validate() # TODO(srinivas_tadepalli): temporary work around to validate # default_instances until standardized in specification if cap == "scalable" and prop.name == "default_instances": prop_dict = props[self.PROPERTIES] min_instances = prop_dict.get("min_instances") max_instances = prop_dict.get("max_instances") default_instances = prop_dict.get("default_instances") if not (min_instances <= default_instances <= max_instances): err_msg = ('"properties" of template "%s": ' '"default_instances" value is not between ' '"min_instances" and "max_instances".' % self.name) ExceptionCollector.appendException( ValidationError(message=err_msg)) def _common_validate_properties(self, entitytype, properties): allowed_props = [] required_props = [] for p in entitytype.get_properties_def_objects(): allowed_props.append(p.name) if p.required: required_props.append(p.name) if properties: self._common_validate_field(properties, allowed_props, 'properties') # make sure it's not missing any property required by a tosca type missingprop = [] for r in required_props: if r not in properties.keys(): missingprop.append(r) if missingprop: ExceptionCollector.appendException( MissingRequiredFieldError( what='"properties" of template "%s"' % self.name, required=missingprop)) else: if required_props: ExceptionCollector.appendException( MissingRequiredFieldError( what='"properties" of template "%s"' % self.name, required=missingprop)) def _validate_field(self, template): if not isinstance(template, dict): ExceptionCollector.appendException( MissingRequiredFieldError(what='Template "%s"' % self.name, required=self.TYPE)) try: relationship = template.get('relationship') if relationship and not isinstance(relationship, str): relationship[self.TYPE] elif isinstance(relationship, str): template['relationship'] else: template[self.TYPE] except KeyError: ExceptionCollector.appendException( MissingRequiredFieldError(what='Template "%s"' % self.name, required=self.TYPE)) def _common_validate_field(self, schema, allowedlist, section): for name in schema: if name not in allowedlist: ExceptionCollector.appendException( UnknownFieldError( what=('"%(section)s" of template "%(nodename)s"' % { 'section': section, 'nodename': self.name }), field=name)) def _create_properties(self): props = [] properties = self.type_definition.get_value(self.PROPERTIES, self.entity_tpl) or {} for name, value in properties.items(): props_def = self.type_definition.get_properties_def() if props_def and name in props_def: prop = Property(name, value, props_def[name].schema, self.custom_def) props.append(prop) for p in self.type_definition.get_properties_def_objects(): if p.default is not None and p.name not in properties.keys(): prop = Property(p.name, p.default, p.schema, self.custom_def) props.append(prop) return props def _create_interfaces(self): interfaces = [] type_interfaces = None if isinstance(self.type_definition, RelationshipType): if isinstance(self.entity_tpl, dict): for rel_def, value in self.entity_tpl.items(): if rel_def != 'type': rel_def = self.entity_tpl.get(rel_def) rel = None if isinstance(rel_def, dict): rel = rel_def.get('relationship') if rel: if self.INTERFACES in rel: type_interfaces = rel[self.INTERFACES] break else: type_interfaces = self.type_definition.get_value( self.INTERFACES, self.entity_tpl) if type_interfaces: for interface_type, value in type_interfaces.items(): for op, op_def in value.items(): iface = InterfacesDef(self.type_definition, interfacetype=interface_type, node_template=self, name=op, value=op_def) interfaces.append(iface) return interfaces def get_capability(self, name): """Provide named capability :param name: name of capability :return: capability object if found, None otherwise """ caps = self.get_capabilities() if caps and name in caps.keys(): return caps[name]
class EntityTemplate(object): '''Base class for TOSCA templates.''' SECTIONS = (DERIVED_FROM, PROPERTIES, REQUIREMENTS, INTERFACES, CAPABILITIES, TYPE, DESCRIPTION, DIRECTIVES, ATTRIBUTES, ARTIFACTS, NODE_FILTER, COPY) = \ ('derived_from', 'properties', 'requirements', 'interfaces', 'capabilities', 'type', 'description', 'directives', 'attributes', 'artifacts', 'node_filter', 'copy') REQUIREMENTS_SECTION = (NODE, CAPABILITY, RELATIONSHIP, OCCURRENCES) = \ ('node', 'capability', 'relationship', 'occurrences') # Special key names SPECIAL_SECTIONS = (METADATA) = ('metadata') def __init__(self, name, template, entity_name, custom_def=None): self.name = name self.entity_tpl = template self.custom_def = custom_def self._validate_field(self.entity_tpl) if entity_name == 'node_type': type = self.entity_tpl.get('type') self.type_definition = NodeType(type, custom_def) \ if type is not None else None if entity_name == 'relationship_type': relationship = template.get('relationship') type = None if relationship and isinstance(relationship, dict): type = relationship.get('type') elif isinstance(relationship, str): type = self.entity_tpl['relationship'] else: type = self.entity_tpl['type'] self.type_definition = RelationshipType(type, None, custom_def) self._properties = None self._interfaces = None self._requirements = None self._capabilities = None @property def type(self): if self.type_definition: return self.type_definition.type @property def requirements(self): if self._requirements is None: self._requirements = self.type_definition.get_value( self.REQUIREMENTS, self.entity_tpl) or [] return self._requirements def get_properties_objects(self): '''Return properties objects for this template.''' if self._properties is None: self._properties = self._create_properties() return self._properties def get_properties(self): '''Return a dictionary of property name-object pairs.''' return {prop.name: prop for prop in self.get_properties_objects()} def get_property_value(self, name): '''Return the value of a given property name.''' props = self.get_properties() if props and name in props.keys(): return props[name].value @property def interfaces(self): if self._interfaces is None: self._interfaces = self._create_interfaces() return self._interfaces def get_capabilities_objects(self): '''Return capabilities objects for this template.''' if not self._capabilities: self._capabilities = self._create_capabilities() return self._capabilities def get_capabilities(self): '''Return a dictionary of capability name-object pairs.''' return {cap.name: cap for cap in self.get_capabilities_objects()} def is_derived_from(self, type_str): '''Check if object inherits from the given type. Returns true if this object is derived from 'type_str'. False otherwise. ''' if not self.type: return False elif self.type == type_str: return True elif self.parent_type: return self.parent_type.is_derived_from(type_str) else: return False def _create_capabilities(self): capability = [] caps = self.type_definition.get_value(self.CAPABILITIES, self.entity_tpl) if caps: for name, props in caps.items(): capabilities = self.type_definition.get_capabilities() if name in capabilities.keys(): c = capabilities[name] cap = Capability(name, props['properties'], c, self.custom_def) capability.append(cap) return capability def _validate_properties(self, template, entitytype): properties = entitytype.get_value(self.PROPERTIES, template) self._common_validate_properties(entitytype, properties) def _validate_capabilities(self): type_capabilities = self.type_definition.get_capabilities() allowed_caps = \ type_capabilities.keys() if type_capabilities else [] capabilities = self.type_definition.get_value(self.CAPABILITIES, self.entity_tpl) if capabilities: self._common_validate_field(capabilities, allowed_caps, 'capabilities') self._validate_capabilities_properties(capabilities) def _validate_capabilities_properties(self, capabilities): for cap, props in capabilities.items(): capabilitydef = self.get_capability(cap).definition self._common_validate_properties(capabilitydef, props[self.PROPERTIES]) # validating capability properties values for prop in self.get_capability(cap).get_properties_objects(): prop.validate() # TODO(srinivas_tadepalli): temporary work around to validate # default_instances until standardized in specification if cap == "scalable" and prop.name == "default_instances": prop_dict = props[self.PROPERTIES] min_instances = prop_dict.get("min_instances") max_instances = prop_dict.get("max_instances") default_instances = prop_dict.get("default_instances") if not (min_instances <= default_instances <= max_instances): err_msg = ('"properties" of template "%s": ' '"default_instances" value is not between ' '"min_instances" and "max_instances".' % self.name) ExceptionCollector.appendException( ValidationError(message=err_msg)) def _common_validate_properties(self, entitytype, properties): allowed_props = [] required_props = [] for p in entitytype.get_properties_def_objects(): allowed_props.append(p.name) if p.required: required_props.append(p.name) if properties: self._common_validate_field(properties, allowed_props, 'properties') # make sure it's not missing any property required by a tosca type missingprop = [] for r in required_props: if r not in properties.keys(): missingprop.append(r) if missingprop: ExceptionCollector.appendException( MissingRequiredFieldError( what='"properties" of template "%s"' % self.name, required=missingprop)) else: if required_props: ExceptionCollector.appendException( MissingRequiredFieldError( what='"properties" of template "%s"' % self.name, required=missingprop)) def _validate_field(self, template): if not isinstance(template, dict): ExceptionCollector.appendException( MissingRequiredFieldError( what='Template "%s"' % self.name, required=self.TYPE)) try: relationship = template.get('relationship') if relationship and not isinstance(relationship, str): relationship[self.TYPE] elif isinstance(relationship, str): template['relationship'] else: template[self.TYPE] except KeyError: ExceptionCollector.appendException( MissingRequiredFieldError( what='Template "%s"' % self.name, required=self.TYPE)) def _common_validate_field(self, schema, allowedlist, section): for name in schema: if name not in allowedlist: ExceptionCollector.appendException( UnknownFieldError( what=('"%(section)s" of template "%(nodename)s"' % {'section': section, 'nodename': self.name}), field=name)) def _create_properties(self): props = [] properties = self.type_definition.get_value(self.PROPERTIES, self.entity_tpl) or {} for name, value in properties.items(): props_def = self.type_definition.get_properties_def() if props_def and name in props_def: prop = Property(name, value, props_def[name].schema, self.custom_def) props.append(prop) for p in self.type_definition.get_properties_def_objects(): if p.default is not None and p.name not in properties.keys(): prop = Property(p.name, p.default, p.schema, self.custom_def) props.append(prop) return props def _create_interfaces(self): interfaces = [] type_interfaces = None if isinstance(self.type_definition, RelationshipType): if isinstance(self.entity_tpl, dict): for rel_def, value in self.entity_tpl.items(): if rel_def != 'type': rel_def = self.entity_tpl.get(rel_def) rel = None if isinstance(rel_def, dict): rel = rel_def.get('relationship') if rel: if self.INTERFACES in rel: type_interfaces = rel[self.INTERFACES] break else: type_interfaces = self.type_definition.get_value(self.INTERFACES, self.entity_tpl) if type_interfaces: for interface_type, value in type_interfaces.items(): for op, op_def in value.items(): iface = InterfacesDef(self.type_definition, interfacetype=interface_type, node_template=self, name=op, value=op_def) interfaces.append(iface) return interfaces def get_capability(self, name): """Provide named capability :param name: name of capability :return: capability object if found, None otherwise """ caps = self.get_capabilities() if caps and name in caps.keys(): return caps[name]