Support of nested properties and indexes in get_property function

Change-Id: Ib2f53047cc32a7a0913ee364f1405b8559b11f6c
Related-Bug: 1527206
This commit is contained in:
Miguel Caballer 2016-01-11 09:35:45 +01:00
parent 2330571e72
commit 5014b33690
4 changed files with 166 additions and 13 deletions

View File

@ -239,10 +239,11 @@ class GetProperty(Function):
* { get_property: [ mysql_server, port ] } * { get_property: [ mysql_server, port ] }
* { get_property: [ SELF, db_port ] } * { get_property: [ SELF, db_port ] }
* { get_property: [ SELF, database_endpoint, port ] } * { get_property: [ SELF, database_endpoint, port ] }
* { get_property: [ SELF, database_endpoint, port, 1 ] }
""" """
def validate(self): def validate(self):
if len(self.args) < 2 or len(self.args) > 3: if len(self.args) < 2:
ExceptionCollector.appendException( ExceptionCollector.appendException(
ValueError(_( ValueError(_(
'Expected arguments: "node-template-name", "req-or-cap" ' 'Expected arguments: "node-template-name", "req-or-cap" '
@ -255,15 +256,31 @@ class GetProperty(Function):
prop = found_prop.value prop = found_prop.value
if not isinstance(prop, Function): if not isinstance(prop, Function):
get_function(self.tosca_tpl, self.context, prop) get_function(self.tosca_tpl, self.context, prop)
elif len(self.args) == 3: elif len(self.args) >= 3:
get_function(self.tosca_tpl, # do not use _find_property to avoid raise KeyError
self.context, # if the prop is not found
self._find_req_or_cap_property(self.args[1], # First check if there is property with this name
self.args[2])) node_tpl = self._find_node_template(self.args[0])
else: props = node_tpl.get_properties() if node_tpl else []
ExceptionCollector.appendException( index = 2
NotImplementedError(_( found = [props[self.args[1]]] if self.args[1] in props else []
'Nested properties are not supported.'))) if found:
property_value = found[0].value
else:
index = 3
# then check the req or caps
property_value = self._find_req_or_cap_property(self.args[1],
self.args[2])
if len(self.args) > index:
for elem in self.args[index:]:
if isinstance(property_value, list):
int_elem = int(elem)
property_value = self._get_index_value(property_value,
int_elem)
else:
property_value = self._get_attribute_value(
property_value,
elem)
def _find_req_or_cap_property(self, req_or_cap, property_name): def _find_req_or_cap_property(self, req_or_cap, property_name):
node_tpl = self._find_node_template(self.args[0]) node_tpl = self._find_node_template(self.args[0])
@ -341,6 +358,52 @@ class GetProperty(Function):
'Node template "{0}" was not found.' 'Node template "{0}" was not found.'
).format(node_template_name))) ).format(node_template_name)))
def _get_index_value(self, value, index):
if isinstance(value, list):
if index < len(value):
return value[index]
else:
ExceptionCollector.appendException(
KeyError(_(
"Property '{0}' found in capability '{1}'"
" referenced from node template {2}"
" must have an element with index {3}.").
format(self.args[2],
self.args[1],
self.context.name,
index)))
else:
ExceptionCollector.appendException(
KeyError(_(
"Property '{0}' found in capability '{1}'"
" referenced from node template {2}"
" must be a list.").format(self.args[2],
self.args[1],
self.context.name)))
def _get_attribute_value(self, value, attibute):
if isinstance(value, dict):
if attibute in value:
return value[attibute]
else:
ExceptionCollector.appendException(
KeyError(_(
"Property '{0}' found in capability '{1}'"
" referenced from node template {2}"
" must have an attribute named {3}.").
format(self.args[2],
self.args[1],
self.context.name,
attibute)))
else:
ExceptionCollector.appendException(
KeyError(_(
"Property '{0}' found in capability '{1}'"
" referenced from node template {2}"
" must be a dict.").format(self.args[2],
self.args[1],
self.context.name)))
# Add this functions similar to get_attribute case # Add this functions similar to get_attribute case
def _find_host_containing_property(self, node_template_name=SELF): def _find_host_containing_property(self, node_template_name=SELF):
node_template = self._find_node_template(node_template_name) node_template = self._find_node_template(node_template_name)
@ -364,9 +427,29 @@ class GetProperty(Function):
return len(found) == 1 return len(found) == 1
def result(self): def result(self):
if len(self.args) == 3: if len(self.args) >= 3:
property_value = self._find_req_or_cap_property(self.args[1], # First check if there is property with this name
self.args[2]) node_tpl = self._find_node_template(self.args[0])
props = node_tpl.get_properties() if node_tpl else []
index = 2
found = [props[self.args[1]]] if self.args[1] in props else []
if found:
property_value = found[0].value
else:
index = 3
# then check the req or caps
property_value = self._find_req_or_cap_property(self.args[1],
self.args[2])
if len(self.args) > index:
for elem in self.args[index:]:
if isinstance(property_value, list):
int_elem = int(elem)
property_value = self._get_index_value(property_value,
int_elem)
else:
property_value = self._get_attribute_value(
property_value,
elem)
else: else:
property_value = self._find_property(self.args[1]).value property_value = self._find_property(self.args[1]).value
if isinstance(property_value, Function): if isinstance(property_value, Function):

View File

@ -0,0 +1,10 @@
tosca_definitions_version: tosca_simple_yaml_1_0
node_types:
tosca.nodes.DatabaseWithListParam:
derived_from: tosca.nodes.Database
properties:
list_prop:
type: list
entry_schema:
type: integer

View File

@ -0,0 +1,47 @@
tosca_definitions_version: tosca_simple_yaml_1_0
description: TOSCA simple profile with nested property names or indexes.
imports:
- ../custom_types/wordpress.yaml
- ../custom_types/db_with_list_param.yaml
topology_template:
node_templates:
wordpress:
type: tosca.nodes.WebApplication.WordPress
requirements:
- host: server
- database_endpoint: mysql_database
interfaces:
Standard:
configure:
implementation: wordpress/wordpress_configure.sh
inputs:
wp_endpoint_protocol: { get_property: [ SELF, database_endpoint, ports, user_port, protocol ] }
wp_list_prop: { get_property: [ mysql_database, list_prop, 2 ] }
mysql_database:
type: tosca.nodes.DatabaseWithListParam
properties:
list_prop: [1,2,3]
capabilities:
database_endpoint:
properties:
ports:
user_port:
protocol: tcp
target: 50000
source: 9000
requirements:
- host: mysql_dbms
mysql_dbms:
type: tosca.nodes.DBMS
requirements:
- host: server
server:
type: tosca.nodes.Compute

View File

@ -134,6 +134,19 @@ class IntrinsicFunctionsTest(TestCase):
result = test.result() result = test.result()
self.assertEqual(1, result) self.assertEqual(1, result)
def test_get_property_with_nested_params(self):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/functions/tosca_nested_property_names_indexes.yaml")
webserver = self._get_node('wordpress', ToscaTemplate(tosca_tpl))
operation = self._get_operation(webserver.interfaces, 'configure')
wp_endpoint_prot = operation.inputs['wp_endpoint_protocol']
self.assertTrue(isinstance(wp_endpoint_prot, functions.GetProperty))
self.assertEqual('tcp', wp_endpoint_prot.result())
wp_list_prop = operation.inputs['wp_list_prop']
self.assertTrue(isinstance(wp_list_prop, functions.GetProperty))
self.assertEqual(3, wp_list_prop.result())
class GetAttributeTest(TestCase): class GetAttributeTest(TestCase):