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:
parent
37851cabfc
commit
2f2e84123a
4
.gitignore
vendored
4
.gitignore
vendored
@ -48,4 +48,6 @@ ChangeLog
|
|||||||
|
|
||||||
# Editors
|
# Editors
|
||||||
*~
|
*~
|
||||||
.*.swp
|
.*.swp
|
||||||
|
.idea
|
||||||
|
*.iml
|
@ -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:
|
||||||
|
111
translator/toscalib/functions.py
Normal file
111
translator/toscalib/functions.py
Normal 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
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
Loading…
Reference in New Issue
Block a user