From b480a1167858eea7c0212800fdaa38090463b522 Mon Sep 17 00:00:00 2001 From: Miguel Caballer <micafer1@upv.es> Date: Wed, 9 Mar 2016 12:53:23 +0100 Subject: [PATCH] Add support for SOURCE and TARGET in get_property and get_attribute functions Change-Id: I17181c8adb23f7e55c49c780d6bfaba9c26fc985 Related-Bug: 1554507 --- toscaparser/functions.py | 33 +++++++++++++- toscaparser/nodetemplate.py | 11 +++-- toscaparser/relationship_template.py | 5 ++- ..._get_attribute_source_target_keywords.yaml | 30 +++++++++++++ ...t_get_property_source_target_keywords.yaml | 35 +++++++++++++++ toscaparser/tests/test_functions.py | 43 +++++++++++++++++++ 6 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 toscaparser/tests/data/functions/test_get_attribute_source_target_keywords.yaml create mode 100644 toscaparser/tests/data/functions/test_get_property_source_target_keywords.yaml diff --git a/toscaparser/functions.py b/toscaparser/functions.py index 8261b213..62b2fc9f 100644 --- a/toscaparser/functions.py +++ b/toscaparser/functions.py @@ -19,6 +19,7 @@ from toscaparser.common.exception import ExceptionCollector from toscaparser.common.exception import UnknownInputError from toscaparser.dataentity import DataEntity from toscaparser.elements.entity_type import EntityType +from toscaparser.elements.relationshiptype import RelationshipType from toscaparser.utils.gettextutils import _ @@ -28,6 +29,8 @@ GET_INPUT = 'get_input' SELF = 'SELF' HOST = 'HOST' +TARGET = 'TARGET' +SOURCE = 'SOURCE' HOSTED_ON = 'tosca.relationships.HostedOn' @@ -210,6 +213,20 @@ class GetAttribute(Function): target_name) def _find_node_template(self, node_template_name): + 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) \ @@ -236,7 +253,7 @@ class GetProperty(Function): Arguments: - * Node template name. + * Node template name | SELF | HOST | SOURCE | TARGET. * Requirement or capability name (optional). * Property name. @@ -364,6 +381,20 @@ class GetProperty(Function): # enable the HOST value in the function if node_template_name == HOST: return self._find_host_containing_property() + 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 if not hasattr(self.tosca_tpl, 'nodetemplates'): return for node_template in self.tosca_tpl.nodetemplates: diff --git a/toscaparser/nodetemplate.py b/toscaparser/nodetemplate.py index 3bb93155..d969d51b 100644 --- a/toscaparser/nodetemplate.py +++ b/toscaparser/nodetemplate.py @@ -114,6 +114,8 @@ class NodeTemplate(EntityTemplate): 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. @@ -137,7 +139,8 @@ class NodeTemplate(EntityTemplate): if rtype.type == relationship: explicit_relation[rtype] = related_tpl related_tpl._add_relationship_template(req, - rtype.type) + rtype.type, + self) elif self.available_rel_types: if relationship in self.available_rel_types.keys(): rel_type_def = self.available_rel_types.\ @@ -151,13 +154,13 @@ class NodeTemplate(EntityTemplate): explicit_relation[rtype] = related_tpl related_tpl.\ _add_relationship_template( - req, rtype.type) + req, rtype.type, self) return explicit_relation - def _add_relationship_template(self, requirement, rtype): + def _add_relationship_template(self, requirement, rtype, source): req = requirement.copy() req['type'] = rtype - tpl = RelationshipTemplate(req, rtype, self.custom_def) + tpl = RelationshipTemplate(req, rtype, self.custom_def, self, source) self.relationship_tpl.append(tpl) def get_relationship_template(self): diff --git a/toscaparser/relationship_template.py b/toscaparser/relationship_template.py index d405b9c7..b9656d41 100644 --- a/toscaparser/relationship_template.py +++ b/toscaparser/relationship_template.py @@ -26,12 +26,15 @@ log = logging.getLogger('tosca') class RelationshipTemplate(EntityTemplate): '''Relationship template.''' - def __init__(self, relationship_template, name, custom_def=None): + def __init__(self, relationship_template, name, custom_def=None, + target=None, source=None): super(RelationshipTemplate, self).__init__(name, relationship_template, 'relationship_type', custom_def) self.name = name.lower() + self.target = target + self.source = source def get_properties_objects(self): '''Return properties objects for this template.''' diff --git a/toscaparser/tests/data/functions/test_get_attribute_source_target_keywords.yaml b/toscaparser/tests/data/functions/test_get_attribute_source_target_keywords.yaml new file mode 100644 index 00000000..047387fe --- /dev/null +++ b/toscaparser/tests/data/functions/test_get_attribute_source_target_keywords.yaml @@ -0,0 +1,30 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + TOSCA template for testing get_attribute with TARGET ans SOURCE keywords. + +topology_template: + + node_templates: + + mysql: + type: tosca.nodes.DBMS + properties: + root_password: rootpw + port: 3306 + requirements: + - host: + node: db_server + relationship: + type: tosca.relationships.HostedOn + interfaces: + Configure: + pre_configure_source: + implementation: some_script.sh + inputs: + target_test: { get_attribute: [ TARGET, public_address ] } + source_port: { get_attribute: [ SOURCE, tosca_name ] } + + db_server: + type: tosca.nodes.Compute + diff --git a/toscaparser/tests/data/functions/test_get_property_source_target_keywords.yaml b/toscaparser/tests/data/functions/test_get_property_source_target_keywords.yaml new file mode 100644 index 00000000..c4602577 --- /dev/null +++ b/toscaparser/tests/data/functions/test_get_property_source_target_keywords.yaml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + TOSCA template for testing get_property with TARGET ans SOURCE keywords. + +imports: + - ../custom_types/compute_with_prop.yaml + +topology_template: + + node_templates: + + mysql: + type: tosca.nodes.DBMS + properties: + root_password: rootpw + port: 3306 + requirements: + - host: + node: db_server + relationship: + type: tosca.relationships.HostedOn + interfaces: + Configure: + pre_configure_source: + implementation: some_script.sh + inputs: + target_test: { get_property: [ TARGET, test ] } + source_port: { get_property: [ SOURCE, port ] } + + db_server: + type: tosca.nodes.ComputeWithProp + properties: + test: 1 + diff --git a/toscaparser/tests/test_functions.py b/toscaparser/tests/test_functions.py index d5671c0d..7062df4a 100644 --- a/toscaparser/tests/test_functions.py +++ b/toscaparser/tests/test_functions.py @@ -157,6 +157,26 @@ class IntrinsicFunctionsTest(TestCase): self.assertTrue(isinstance(some_input, functions.GetProperty)) self.assertEqual('someval', some_input.result()) + def test_get_property_source_target_keywords(self): + tosca_tpl = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/functions/test_get_property_source_target_keywords.yaml") + tosca = ToscaTemplate(tosca_tpl) + + for node in tosca.nodetemplates: + for relationship, trgt in node.relationships.items(): + rel_template = trgt.get_relationship_template()[0] + break + + operation = self._get_operation(rel_template.interfaces, + 'pre_configure_source') + target_test = operation.inputs['target_test'] + self.assertTrue(isinstance(target_test, functions.GetProperty)) + self.assertEqual(1, target_test.result()) + source_port = operation.inputs['source_port'] + self.assertTrue(isinstance(source_port, functions.GetProperty)) + self.assertEqual(3306, source_port.result()) + class GetAttributeTest(TestCase): @@ -166,6 +186,11 @@ class GetAttributeTest(TestCase): 'data', filename)) + def _get_operation(self, interfaces, operation): + return [ + interface for interface in interfaces + if interface.name == operation][0] + def test_get_attribute_in_outputs(self): tpl = self._load_template('tosca_single_instance_wordpress.yaml') website_url_output = [ @@ -256,3 +281,21 @@ class GetAttributeTest(TestCase): ValueError, _('Illegal arguments for function "get_attribute". ' 'Expected arguments: "node-template-name", "attribute-name"')) + + def test_get_attribute_source_target_keywords(self): + tosca_tpl = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/functions/test_get_attribute_source_target_keywords.yaml") + tosca = ToscaTemplate(tosca_tpl) + + for node in tosca.nodetemplates: + for relationship, trgt in node.relationships.items(): + rel_template = trgt.get_relationship_template()[0] + break + + operation = self._get_operation(rel_template.interfaces, + 'pre_configure_source') + target_test = operation.inputs['target_test'] + self.assertTrue(isinstance(target_test, functions.GetAttribute)) + source_port = operation.inputs['source_port'] + self.assertTrue(isinstance(source_port, functions.GetAttribute))