Added a module for intrinsic function.

Curenntly only handles get_ref_property specified in interface operation
input.

Renamed ntype to node_type.

Change-Id: I4d95b28faba9b55a5d16b9f16dbe36bd3bcd5b4d
Implements: blueprint tosca-ref-property
This commit is contained in:
Idan Moyal 2014-06-24 15:53:30 +03:00
parent 37851cabfc
commit 2f2e84123a
5 changed files with 175 additions and 15 deletions

4
.gitignore vendored
View File

@ -48,4 +48,6 @@ ChangeLog
# Editors # Editors
*~ *~
.*.swp .*.swp
.idea
*.iml

View File

@ -14,6 +14,7 @@
# under the License. # under the License.
from translator.toscalib.elements.statefulentitytype import StatefulEntityType from translator.toscalib.elements.statefulentitytype import StatefulEntityType
from translator.toscalib.functions import get_function
SECTIONS = (LIFECYCLE, CONFIGURE) = \ SECTIONS = (LIFECYCLE, CONFIGURE) = \
('tosca.interfaces.node.Lifecycle', ('tosca.interfaces.node.Lifecycle',
@ -23,17 +24,17 @@ SECTIONS = (LIFECYCLE, CONFIGURE) = \
class InterfacesDef(StatefulEntityType): class InterfacesDef(StatefulEntityType):
'''TOSCA built-in interfaces type.''' '''TOSCA built-in interfaces type.'''
def __init__(self, ntype, interfacetype, def __init__(self, node_type, interfacetype,
tpl_name=None, name=None, value=None): node_template=None, name=None, value=None):
self.nodetype = ntype self.ntype = node_type
self.tpl_name = tpl_name self.node_template = node_template
self.type = interfacetype self.type = interfacetype
self.name = name self.name = name
self.value = value self.value = value
self.implementation = None self.implementation = None
self.input = None self.input = None
self.defs = {} self.defs = {}
if ntype: if node_type:
self.defs = self.TOSCA_DEF[interfacetype] self.defs = self.TOSCA_DEF[interfacetype]
if value: if value:
if isinstance(self.value, dict): if isinstance(self.value, dict):
@ -41,10 +42,19 @@ class InterfacesDef(StatefulEntityType):
if i == 'implementation': if i == 'implementation':
self.implementation = j self.implementation = j
if i == 'input': if i == 'input':
self.input = j self.input = self._create_input_functions(j)
else: else:
self.implementation = value self.implementation = value
def _create_input_functions(self, raw_input):
"""Creates input functions if necessary.
:param raw_input: Raw input as dict.
:return: Modified input dict containing template functions.
:rtype: dict
"""
return dict((k, get_function(self.node_template, v))
for (k, v) in raw_input.items())
@property @property
def lifecycle_ops(self): def lifecycle_ops(self):
if self.defs: if self.defs:

View File

@ -0,0 +1,111 @@
#
# 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.
import abc
GET_PROPERTY = 'get_property'
GET_REF_PROPERTY = 'get_ref_property'
class Function(object):
"""An abstract type for representing a Tosca template function."""
__metaclass__ = abc.ABCMeta
def __init__(self, node_template, func_name, args):
self.node_template = node_template
self.name = func_name
self.args = args
self.validate()
@abc.abstractmethod
def result(self):
"""Invokes the function and returns its result
Some methods invocation may only be relevant on runtime (for example,
getting runtime properties) and therefore its the responsibility of
the orchestrator/translator to take care of such functions invocation.
:return: Function invocation result.
"""
return {self.name: self.args}
def validate(self):
"""Validates function arguments."""
class GetRefProperty(Function):
"""Get a property via a reference expressed in the requirements section.
Arguments:
- Requirement name.
- Capability name.
- Property to get.
Example:
get_ref_property: [ database_endpoint, database_endpoint, port ]
"""
def validate(self):
if len(self.args) != 3:
raise ValueError(
'Expected arguments: requirement, capability, property')
def result(self):
requires = self.node_template.requirements
name = None
if requires:
requirement = self.args[0]
for r in requires:
for cap, node in r.items():
if cap == requirement:
name = node
break
if name:
from translator.toscalib.nodetemplate import NodeTemplate
tpl = NodeTemplate(
name, self.node_template.node_templates)
caps = tpl.capabilities
required_cap = self.args[1]
required_property = self.args[2]
for c in caps:
if c.name == required_cap:
return c.properties.get(required_property)
function_mappings = {
GET_REF_PROPERTY: GetRefProperty
}
def get_function(node_template, raw_function):
"""Gets a Function instance representing the provided template function.
If the format provided raw_function format is not relevant for template
functions or if the function name doesn't exist in function mapping the
method returns the provided raw_function.
:param node_template: The node template the function is specified for.
:param raw_function: The raw function as dict.
:return: Template function as Function instance or the raw_function if
parsing was unsuccessful.
"""
if isinstance(raw_function, dict) and len(raw_function) == 1:
func_name = list(raw_function.keys())[0]
if func_name in function_mappings:
func = function_mappings[func_name]
func_args = list(raw_function.values())[0]
return func(node_template, func_name, func_args)
return raw_function

View File

@ -78,14 +78,17 @@ class NodeTemplate(object):
@property @property
def interfaces(self): def interfaces(self):
interfaces = [] interfaces = []
ifaces = self.node_type.get_value(INTERFACES, self.node_template) type_interfaces = self.node_type.get_value(INTERFACES,
if ifaces: self.node_template)
for i in ifaces: if type_interfaces:
for name, value in ifaces.items(): for interface_type, value in type_interfaces.items():
for ops, val in value.items(): for op, op_def in value.items():
iface = InterfacesDef(None, name, self.name, iface = InterfacesDef(self.node_type,
ops, val) interfacetype=interface_type,
interfaces.append(iface) node_template=self,
name=op,
value=op_def)
interfaces.append(iface)
return interfaces return interfaces
@property @property

View File

@ -14,6 +14,7 @@
# under the License. # under the License.
import os import os
from translator.toscalib.functions import GetRefProperty
from translator.toscalib.tests.base import TestCase from translator.toscalib.tests.base import TestCase
from translator.toscalib.tosca_template import ToscaTemplate from translator.toscalib.tosca_template import ToscaTemplate
@ -104,3 +105,36 @@ class ToscaTemplateTest(TestCase):
self.assertEqual( self.assertEqual(
['website_url'], ['website_url'],
sorted([output.name for output in self.tosca.outputs])) sorted([output.name for output in self.tosca.outputs]))
def test_interfaces(self):
wordpress_node = [
node for node in self.tosca.nodetemplates
if node.name == 'wordpress'][0]
interfaces = wordpress_node.interfaces
self.assertEqual(2, len(interfaces))
for interface in interfaces:
if interface.name == 'create':
self.assertEqual('tosca.interfaces.node.Lifecycle',
interface.type)
self.assertEqual('wordpress_install.sh',
interface.implementation)
self.assertIsNone(interface.input)
elif interface.name == 'configure':
self.assertEqual('tosca.interfaces.node.Lifecycle',
interface.type)
self.assertEqual('wordpress_configure.sh',
interface.implementation)
self.assertEqual(4, len(interface.input))
wp_db_port = interface.input['wp_db_port']
self.assertTrue(isinstance(wp_db_port, GetRefProperty))
self.assertEqual('get_ref_property', wp_db_port.name)
self.assertEqual(['database_endpoint',
'database_endpoint',
'port'],
wp_db_port.args)
result = wp_db_port.result()
self.assertEqual(1, len(result))
self.assertEqual('db_port', result['get_input'])
else:
raise AssertionError(
'Unexpected interface: {0}'.format(interface.name))