package org.openecomp.sdc.toscaparser.functions; import java.util.ArrayList; import java.util.LinkedHashMap; import org.openecomp.sdc.toscaparser.Capability; import org.openecomp.sdc.toscaparser.EntityTemplate; import org.openecomp.sdc.toscaparser.NodeTemplate; import org.openecomp.sdc.toscaparser.RelationshipTemplate; import org.openecomp.sdc.toscaparser.TopologyTemplate; import org.openecomp.sdc.toscaparser.common.ExceptionCollector; import org.openecomp.sdc.toscaparser.elements.AttributeDef; import org.openecomp.sdc.toscaparser.elements.CapabilityTypeDef; import org.openecomp.sdc.toscaparser.elements.DataType; import org.openecomp.sdc.toscaparser.elements.EntityType; import org.openecomp.sdc.toscaparser.elements.NodeType; import org.openecomp.sdc.toscaparser.elements.PropertyDef; import org.openecomp.sdc.toscaparser.elements.RelationshipType; import org.openecomp.sdc.toscaparser.elements.StatefulEntityType; import org.openecomp.sdc.toscaparser.elements.constraints.Schema; public class GetAttribute extends Function { // Get an attribute value of an entity defined in the service template // Node template attributes values are set in runtime and therefore its the // responsibility of the Tosca engine to implement the evaluation of // get_attribute functions. // Arguments: // * Node template name | HOST. // * Attribute name. // If the HOST keyword is passed as the node template name argument the // function will search each node template along the HostedOn relationship // chain until a node which contains the attribute is found. // Examples: // * { get_attribute: [ server, private_address ] } // * { get_attribute: [ HOST, private_address ] } // * { get_attribute: [ HOST, private_address, 0 ] } // * { get_attribute: [ HOST, private_address, 0, some_prop] } public GetAttribute(TopologyTemplate ttpl,Object context,String name,ArrayList args) { super(ttpl,context,name,args); } @Override void validate() { if(args.size() < 2) { ExceptionCollector.appendException( "ValueError: Illegal arguments for function \"get_attribute\". Expected arguments: \"node-template-name\", \"req-or-cap\" (optional), \"property name.\""); return; } else if(args.size() == 2) { _findNodeTemplateContainingAttribute(); } else { NodeTemplate nodeTpl = _findNodeTemplate((String)args.get(0)); if(nodeTpl == null) { return; } int index = 2; AttributeDef attr = nodeTpl.getTypeDefinition().getAttributeDefValue((String)args.get(1)); if(attr != null) { // found } else { index = 3; // then check the req or caps attr = _findReqOrCapAttribute((String)args.get(1),(String)args.get(2)); if(attr == null) { return; } } String valueType = (String)attr.getSchema().get("type"); if(args.size() > index) { for(Object elem: args.subList(index,args.size())) { if(valueType.equals("list")) { if(!(elem instanceof Integer)) { ExceptionCollector.appendException(String.format( "ValueError: Illegal arguments for function \"get_attribute\" \"%s\". Expected positive integer argument", elem.toString())); } Object ob = attr.getSchema().get("entry_schema"); valueType = (String) ((LinkedHashMap)ob).get("type"); } else if(valueType.equals("map")) { Object ob = attr.getSchema().get("entry_schema"); valueType = (String) ((LinkedHashMap)ob).get("type"); } else { boolean bFound = false; for(String p: Schema.PROPERTY_TYPES) { if(p.equals(valueType)) { bFound = true; break; } } if(bFound) { ExceptionCollector.appendException(String.format( "ValueError: 'Illegal arguments for function \"get_attribute\". Unexpected attribute/index value \"%d\"", elem)); return; } else { // It is a complex type DataType dataType = new DataType(valueType,null); LinkedHashMap props = dataType.getAllProperties(); PropertyDef prop = props.get((String)elem); if(prop != null) { valueType = (String)prop.getSchema().get("type"); } else { ExceptionCollector.appendException(String.format( "KeyError: Illegal arguments for function \"get_attribute\". Attribute name \"%s\" not found in \"%\"", elem,valueType)); } } } } } } } @Override public Object result() { return this; } private NodeTemplate getReferencedNodeTemplate() { // Gets the NodeTemplate instance the get_attribute function refers to // If HOST keyword was used as the node template argument, the node // template which contains the attribute along the HostedOn relationship // chain will be returned. return _findNodeTemplateContainingAttribute(); } // Attributes can be explicitly created as part of the type definition // or a property name can be implicitly used as an attribute name private NodeTemplate _findNodeTemplateContainingAttribute() { NodeTemplate nodeTpl = _findNodeTemplate((String)args.get(0)); if(nodeTpl != null && !_attributeExistsInType(nodeTpl.getTypeDefinition()) && !nodeTpl.getProperties().keySet().contains(getAttributeName())) { ExceptionCollector.appendException(String.format( "KeyError: Attribute \"%s\" was not found in node template \"%s\"", getAttributeName(),nodeTpl.getName())); } return nodeTpl; } private boolean _attributeExistsInType(StatefulEntityType typeDefinition) { LinkedHashMap attrsDef = typeDefinition.getAttributesDef(); return attrsDef.get(getAttributeName()) != null; } private NodeTemplate _findHostContainingAttribute(String nodeTemplateName) { NodeTemplate nodeTemplate = _findNodeTemplate(nodeTemplateName); if(nodeTemplate != null) { LinkedHashMap hostedOnRel = (LinkedHashMap)EntityType.TOSCA_DEF.get(HOSTED_ON); for(Object ro: nodeTemplate.getRequirements()) { if(ro != null && ro instanceof LinkedHashMap) { LinkedHashMap r = (LinkedHashMap)ro; for(String requirement: r.keySet()) { String targetName = (String)r.get(requirement); NodeTemplate targetNode = _findNodeTemplate(targetName); NodeType targetType = (NodeType)targetNode.getTypeDefinition(); for(CapabilityTypeDef capability: targetType.getCapabilitiesObjects()) { // if(((ArrayList)hostedOnRel.get("valid_target_types")).contains(capability.getType())) { if(capability.inheritsFrom((ArrayList)hostedOnRel.get("valid_target_types"))) { if(_attributeExistsInType(targetType)) { return targetNode; } return _findHostContainingAttribute(targetName); } } } } } } return null; } private NodeTemplate _findNodeTemplate(String nodeTemplateName) { if(nodeTemplateName.equals(HOST)) { // Currently this is the only way to tell whether the function // is used within the outputs section of the TOSCA template. if(context instanceof ArrayList) { ExceptionCollector.appendException( "ValueError: \"get_attribute: [ HOST, ... ]\" is not allowed in \"outputs\" section of the TOSCA template"); return null; } NodeTemplate nodeTpl = _findHostContainingAttribute(SELF); if(nodeTpl == null) { ExceptionCollector.appendException(String.format( "ValueError: \"get_attribute: [ HOST, ... ]\" was used in " + "node template \"%s\" but \"%s\" was not found in " + "the relationship chain",((NodeTemplate)context).getName(),HOSTED_ON)); return null; } return nodeTpl; } if(nodeTemplateName.equals(TARGET)) { if(!(((EntityTemplate)context).getTypeDefinition() instanceof RelationshipType)) { ExceptionCollector.appendException( "KeyError: \"TARGET\" keyword can only be used in context " + " to \"Relationships\" target node"); return null; } return ((RelationshipTemplate)context).getTarget(); } if(nodeTemplateName.equals(SOURCE)) { if(!(((EntityTemplate)context).getTypeDefinition() instanceof RelationshipType)) { ExceptionCollector.appendException( "KeyError: \"SOURCE\" keyword can only be used in context " + " to \"Relationships\" source node"); return null; } return ((RelationshipTemplate)context).getTarget(); } String name; if(nodeTemplateName.equals(SELF) && !(context instanceof ArrayList)) { name = ((NodeTemplate)context).getName(); } else { name = nodeTemplateName; } for(NodeTemplate nt: toscaTpl.getNodeTemplates()) { if(nt.getName().equals(name)) { return nt; } } ExceptionCollector.appendException(String.format( "KeyError: Node template \"%s\" was not found",nodeTemplateName)); return null; } public AttributeDef _findReqOrCapAttribute(String reqOrCap,String attrName) { NodeTemplate nodeTpl = _findNodeTemplate((String)args.get(0)); // Find attribute in node template's requirements for(Object ro: nodeTpl.getRequirements()) { if(ro != null && ro instanceof LinkedHashMap) { LinkedHashMap r = (LinkedHashMap)ro; for(String req: r.keySet()) { String nodeName = (String)r.get(req); if(req.equals(reqOrCap)) { NodeTemplate nodeTemplate = _findNodeTemplate(nodeName); return _getCapabilityAttribute(nodeTemplate,req,attrName); } } } } // If requirement was not found, look in node template's capabilities return _getCapabilityAttribute(nodeTpl,reqOrCap,attrName); } private AttributeDef _getCapabilityAttribute(NodeTemplate nodeTemplate, String capabilityName, String attrName) { // Gets a node template capability attribute LinkedHashMap caps = nodeTemplate.getCapabilities(); if(caps != null && caps.keySet().contains(capabilityName)) { Capability cap = caps.get(capabilityName); AttributeDef attribute = null; LinkedHashMap attrs = cap.getDefinition().getAttributesDef(); if(attrs != null && attrs.keySet().contains(attrName)) { attribute = attrs.get(attrName); } if(attribute == null) { ExceptionCollector.appendException(String.format( "KeyError: Attribute \"%s\" was not found in capability \"%s\" of node template \"%s\" referenced from node template \"%s\"", attrName,capabilityName,nodeTemplate.getName(),((NodeTemplate)context).getName())); } return attribute; } String msg = String.format( "Requirement/Capability \"%s\" referenced from node template \"%s\" was not found in node template \"%s\"", capabilityName,((NodeTemplate)context).getName(),nodeTemplate.getName()); ExceptionCollector.appendException("KeyError: " + msg); return null; } String getNodeTemplateName() { return (String)args.get(0); } String getAttributeName() { return (String)args.get(1); } } /*python class GetAttribute(Function): """Get an attribute value of an entity defined in the service template Node template attributes values are set in runtime and therefore its the responsibility of the Tosca engine to implement the evaluation of get_attribute functions. Arguments: * Node template name | HOST. * Attribute name. If the HOST keyword is passed as the node template name argument the function will search each node template along the HostedOn relationship chain until a node which contains the attribute is found. Examples: * { get_attribute: [ server, private_address ] } * { get_attribute: [ HOST, private_address ] } * { get_attribute: [ HOST, private_address, 0 ] } * { get_attribute: [ HOST, private_address, 0, some_prop] } """ def validate(self): if len(self.args) < 2: ExceptionCollector.appendException( ValueError(_('Illegal arguments for function "{0}". Expected ' 'arguments: "node-template-name", "req-or-cap"' '(optional), "property name"' ).format(GET_ATTRIBUTE))) return elif len(self.args) == 2: self._find_node_template_containing_attribute() else: node_tpl = self._find_node_template(self.args[0]) if node_tpl is None: return index = 2 attrs = node_tpl.type_definition.get_attributes_def() found = [attrs[self.args[1]]] if self.args[1] in attrs else [] if found: attr = found[0] else: index = 3 # then check the req or caps attr = self._find_req_or_cap_attribute(self.args[1], self.args[2]) value_type = attr.schema['type'] if len(self.args) > index: for elem in self.args[index:]: if value_type == "list": if not isinstance(elem, int): ExceptionCollector.appendException( ValueError(_('Illegal arguments for function' ' "{0}". "{1}" Expected positive' ' integer argument' ).format(GET_ATTRIBUTE, elem))) value_type = attr.schema['entry_schema']['type'] elif value_type == "map": value_type = attr.schema['entry_schema']['type'] elif value_type in Schema.PROPERTY_TYPES: ExceptionCollector.appendException( ValueError(_('Illegal arguments for function' ' "{0}". Unexpected attribute/' 'index value "{1}"' ).format(GET_ATTRIBUTE, elem))) return else: # It is a complex type data_type = DataType(value_type) props = data_type.get_all_properties() found = [props[elem]] if elem in props else [] if found: prop = found[0] value_type = prop.schema['type'] else: ExceptionCollector.appendException( KeyError(_('Illegal arguments for function' ' "{0}". Attribute name "{1}" not' ' found in "{2}"' ).format(GET_ATTRIBUTE, elem, value_type))) def result(self): return self def get_referenced_node_template(self): """Gets the NodeTemplate instance the get_attribute function refers to. If HOST keyword was used as the node template argument, the node template which contains the attribute along the HostedOn relationship chain will be returned. """ return self._find_node_template_containing_attribute() # Attributes can be explicitly created as part of the type definition # or a property name can be implicitly used as an attribute name def _find_node_template_containing_attribute(self): node_tpl = self._find_node_template(self.args[0]) if node_tpl and \ not self._attribute_exists_in_type(node_tpl.type_definition) \ and self.attribute_name not in node_tpl.get_properties(): ExceptionCollector.appendException( KeyError(_('Attribute "%(att)s" was not found in node ' 'template "%(ntpl)s".') % {'att': self.attribute_name, 'ntpl': node_tpl.name})) return node_tpl def _attribute_exists_in_type(self, type_definition): attrs_def = type_definition.get_attributes_def() found = [attrs_def[self.attribute_name]] \ if self.attribute_name in attrs_def else [] return len(found) == 1 def _find_host_containing_attribute(self, node_template_name=SELF): node_template = self._find_node_template(node_template_name) if node_template: hosted_on_rel = EntityType.TOSCA_DEF[HOSTED_ON] for r in node_template.requirements: for requirement, target_name in r.items(): target_node = self._find_node_template(target_name) target_type = target_node.type_definition for capability in target_type.get_capabilities_objects(): if capability.type in \ hosted_on_rel['valid_target_types']: if self._attribute_exists_in_type(target_type): return target_node return self._find_host_containing_attribute( target_name) def _find_node_template(self, node_template_name): if node_template_name == HOST: # Currently this is the only way to tell whether the function # is used within the outputs section of the TOSCA template. if isinstance(self.context, list): ExceptionCollector.appendException( ValueError(_( '"get_attribute: [ HOST, ... ]" is not allowed in ' '"outputs" section of the TOSCA template.'))) return node_tpl = self._find_host_containing_attribute() if not node_tpl: ExceptionCollector.appendException( ValueError(_( '"get_attribute: [ HOST, ... ]" was used in node ' 'template "{0}" but "{1}" was not found in ' 'the relationship chain.').format(self.context.name, HOSTED_ON))) return return node_tpl if node_template_name == TARGET: if not isinstance(self.context.type_definition, RelationshipType): ExceptionCollector.appendException( KeyError(_('"TARGET" keyword can only be used in context' ' to "Relationships" target node'))) return return self.context.target if node_template_name == SOURCE: if not isinstance(self.context.type_definition, RelationshipType): ExceptionCollector.appendException( KeyError(_('"SOURCE" keyword can only be used in context' ' to "Relationships" source node'))) return return self.context.source name = self.context.name \ if node_template_name == SELF and \ not isinstance(self.context, list) \ else node_template_name for node_template in self.tosca_tpl.nodetemplates: if node_template.name == name: return node_template ExceptionCollector.appendException( KeyError(_( 'Node template "{0}" was not found.' ).format(node_template_name))) def _find_req_or_cap_attribute(self, req_or_cap, attr_name): node_tpl = self._find_node_template(self.args[0]) # Find attribute in node template's requirements for r in node_tpl.requirements: for req, node_name in r.items(): if req == req_or_cap: node_template = self._find_node_template(node_name) return self._get_capability_attribute( node_template, req, attr_name) # If requirement was not found, look in node template's capabilities return self._get_capability_attribute(node_tpl, req_or_cap, attr_name) def _get_capability_attribute(self, node_template, capability_name, attr_name): """Gets a node template capability attribute.""" caps = node_template.get_capabilities() if caps and capability_name in caps.keys(): cap = caps[capability_name] attribute = None attrs = cap.definition.get_attributes_def() if attrs and attr_name in attrs.keys(): attribute = attrs[attr_name] if not attribute: ExceptionCollector.appendException( KeyError(_('Attribute "%(attr)s" was not found in ' 'capability "%(cap)s" of node template ' '"%(ntpl1)s" referenced from node template ' '"%(ntpl2)s".') % {'attr': attr_name, 'cap': capability_name, 'ntpl1': node_template.name, 'ntpl2': self.context.name})) return attribute msg = _('Requirement/Capability "{0}" referenced from node template ' '"{1}" was not found in node template "{2}".').format( capability_name, self.context.name, node_template.name) ExceptionCollector.appendException(KeyError(msg)) @property def node_template_name(self): return self.args[0] @property def attribute_name(self): return self.args[1] */