diff options
Diffstat (limited to 'jtosca/src/main/java/org/onap/sdc/toscaparser/api/functions/GetAttribute.java')
-rw-r--r-- | jtosca/src/main/java/org/onap/sdc/toscaparser/api/functions/GetAttribute.java | 544 |
1 files changed, 544 insertions, 0 deletions
diff --git a/jtosca/src/main/java/org/onap/sdc/toscaparser/api/functions/GetAttribute.java b/jtosca/src/main/java/org/onap/sdc/toscaparser/api/functions/GetAttribute.java new file mode 100644 index 0000000..564d410 --- /dev/null +++ b/jtosca/src/main/java/org/onap/sdc/toscaparser/api/functions/GetAttribute.java @@ -0,0 +1,544 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.toscaparser.api.functions; + +import org.onap.sdc.toscaparser.api.*; +import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue; +import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder; + +import java.util.ArrayList; +import java.util.LinkedHashMap; + +import org.onap.sdc.toscaparser.api.*; +import org.onap.sdc.toscaparser.api.elements.AttributeDef; +import org.onap.sdc.toscaparser.api.elements.CapabilityTypeDef; +import org.onap.sdc.toscaparser.api.elements.DataType; +import org.onap.sdc.toscaparser.api.elements.EntityType; +import org.onap.sdc.toscaparser.api.elements.NodeType; +import org.onap.sdc.toscaparser.api.elements.PropertyDef; +import org.onap.sdc.toscaparser.api.elements.RelationshipType; +import org.onap.sdc.toscaparser.api.elements.StatefulEntityType; +import org.onap.sdc.toscaparser.api.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<Object> args) { + super(ttpl, context, name, args); + } + + @Override + void validate() { + if (args.size() < 2) { + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE146", + "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 + if (!(args.get(1) instanceof String) || !(args.get(2) instanceof String)) { + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE146", "ValueError: Illegal arguments for function \"get_attribute\". Expected a String argument")); + } + + attr = _findReqOrCapAttribute(args.get(1).toString(), args.get(2).toString()); + 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)) { + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE147", 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<String, Object>) ob).get("type"); + } else if (valueType.equals("map")) { + Object ob = attr.getSchema().get("entry_schema"); + valueType = (String) + ((LinkedHashMap<String, Object>) ob).get("type"); + } else { + boolean bFound = false; + for (String p : Schema.PROPERTY_TYPES) { + if (p.equals(valueType)) { + bFound = true; + break; + } + } + if (bFound) { + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE148", String.format( + "ValueError: 'Illegal arguments for function \"get_attribute\". Unexpected attribute/index value \"%s\"", + elem))); + return; + } else { // It is a complex type + DataType dataType = new DataType(valueType, null); + LinkedHashMap<String, PropertyDef> props = + dataType.getAllProperties(); + PropertyDef prop = props.get((String) elem); + if (prop != null) { + valueType = (String) prop.getSchema().get("type"); + } else { + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE149", 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())) { + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE150", String.format( + "KeyError: Attribute \"%s\" was not found in node template \"%s\"", + getAttributeName(), nodeTpl.getName()))); + } + return nodeTpl; + } + + private boolean _attributeExistsInType(StatefulEntityType typeDefinition) { + LinkedHashMap<String, AttributeDef> attrsDef = typeDefinition.getAttributesDef(); + return attrsDef.get(getAttributeName()) != null; + } + + private NodeTemplate _findHostContainingAttribute(String nodeTemplateName) { + NodeTemplate nodeTemplate = _findNodeTemplate(nodeTemplateName); + if (nodeTemplate != null) { + LinkedHashMap<String, Object> hostedOnRel = + (LinkedHashMap<String, Object>) EntityType.TOSCA_DEF.get(HOSTED_ON); + for (RequirementAssignment r : nodeTemplate.getRequirements().getAll()) { + String targetName = r.getNodeTemplateName(); + NodeTemplate targetNode = _findNodeTemplate(targetName); + NodeType targetType = (NodeType) targetNode.getTypeDefinition(); + for (CapabilityTypeDef capability : targetType.getCapabilitiesObjects()) { +// if(((ArrayList<String>)hostedOnRel.get("valid_target_types")).contains(capability.getType())) { + if (capability.inheritsFrom((ArrayList<String>) 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) { + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE151", + "ValueError: \"get_attribute: [ HOST, ... ]\" is not allowed in \"outputs\" section of the TOSCA template")); + return null; + } + NodeTemplate nodeTpl = _findHostContainingAttribute(SELF); + if (nodeTpl == null) { + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE152", 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)) { + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE153", + "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)) { + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE154", + "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; + } + } + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE155", 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 (RequirementAssignment r : nodeTpl.getRequirements().getAll()) { + String nodeName = r.getNodeTemplateName(); + if (r.getName().equals(reqOrCap)) { + NodeTemplate nodeTemplate = _findNodeTemplate(nodeName); + return _getCapabilityAttribute(nodeTemplate, r.getName(), 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 + CapabilityAssignment cap = nodeTemplate.getCapabilities().getCapabilityByName(capabilityName); + + if (cap != null) { + AttributeDef attribute = null; + LinkedHashMap<String, AttributeDef> attrs = + cap.getDefinition().getAttributesDef(); + if (attrs != null && attrs.keySet().contains(attrName)) { + attribute = attrs.get(attrName); + } + if (attribute == null) { + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE156", 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/CapabilityAssignment \"%s\" referenced from node template \"%s\" was not found in node template \"%s\"", + capabilityName, ((NodeTemplate) context).getName(), nodeTemplate.getName()); + ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE157", "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: + ValidationIssueCollector.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): + ValidationIssueCollector.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: + ValidationIssueCollector.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: + ValidationIssueCollector.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(): + ValidationIssueCollector.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): + ValidationIssueCollector.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: + ValidationIssueCollector.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): + ValidationIssueCollector.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): + ValidationIssueCollector.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 + ValidationIssueCollector.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: + ValidationIssueCollector.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/CapabilityAssignment "{0}" referenced from node template ' + '"{1}" was not found in node template "{2}".').format( + capability_name, + self.context.name, + node_template.name) + ValidationIssueCollector.appendException(KeyError(msg)) + +@property +def node_template_name(self): + return self.args[0] + +@property +def attribute_name(self): + return self.args[1] +*/ |