Merge "Main translation code to handle parameters"
This commit is contained in:
30
translator/hot/tosca/tosca_nodejs.py
Executable file
30
translator/hot/tosca/tosca_nodejs.py
Executable file
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# 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.
|
||||
|
||||
from translator.hot.syntax.hot_resource import HotResource
|
||||
|
||||
|
||||
class ToscaNodejs(HotResource):
|
||||
'''Translate TOSCA node type tosca.nodes.SoftwareComponent.Nodejs.'''
|
||||
# TODO(anyone): this is a custom TOSCA type so it should be kept separate
|
||||
# from the TOSCA base types; need to come up with a scheme so new custom
|
||||
# types can be added by users.
|
||||
|
||||
toscatype = 'tosca.nodes.SoftwareComponent.Nodejs'
|
||||
|
||||
def __init__(self, nodetemplate):
|
||||
super(ToscaNodejs, self).__init__(nodetemplate)
|
||||
pass
|
||||
|
||||
def handle_properties(self):
|
||||
pass
|
||||
@@ -25,12 +25,15 @@ class TOSCATranslator(object):
|
||||
self.tosca = tosca
|
||||
self.hot_template = HotTemplate()
|
||||
self.parsed_params = parsed_params
|
||||
self.node_translator = None
|
||||
|
||||
def translate(self):
|
||||
self._resolve_input()
|
||||
self.hot_template.description = self.tosca.description
|
||||
self.hot_template.parameters = self._translate_inputs()
|
||||
self.hot_template.resources = self._translate_node_templates()
|
||||
self.node_translator = TranslateNodeTemplates(self.tosca.nodetemplates,
|
||||
self.hot_template)
|
||||
self.hot_template.resources = self.node_translator.translate()
|
||||
self.hot_template.outputs = self._translate_outputs()
|
||||
return self.hot_template.output_to_yaml()
|
||||
|
||||
@@ -38,13 +41,8 @@ class TOSCATranslator(object):
|
||||
translator = TranslateInputs(self.tosca.inputs, self.parsed_params)
|
||||
return translator.translate()
|
||||
|
||||
def _translate_node_templates(self):
|
||||
translator = TranslateNodeTemplates(self.tosca.nodetemplates,
|
||||
self.hot_template)
|
||||
return translator.translate()
|
||||
|
||||
def _translate_outputs(self):
|
||||
translator = TranslateOutputs(self.tosca.outputs)
|
||||
translator = TranslateOutputs(self.tosca.outputs, self.node_translator)
|
||||
return translator.translate()
|
||||
|
||||
# check all properties for all node and ensure they are resolved
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
# under the License.
|
||||
|
||||
from translator.hot.syntax.hot_parameter import HotParameter
|
||||
from translator.toscalib.utils.gettextutils import _
|
||||
|
||||
|
||||
INPUT_CONSTRAINTS = (CONSTRAINTS, DESCRIPTION, LENGTH, RANGE,
|
||||
@@ -68,11 +69,17 @@ class TranslateInputs():
|
||||
hc, hvalue = self._translate_constraints(
|
||||
constraint.constraint_key, constraint.constraint_value)
|
||||
hot_constraints.append({hc: hvalue})
|
||||
cli_value = self.parsed_params[input.name]
|
||||
if input.name in self.parsed_params:
|
||||
hot_default = self.parsed_params[input.name]
|
||||
elif input.default is not None:
|
||||
hot_default = input.default
|
||||
else:
|
||||
raise Exception(_("Need to specify a value "
|
||||
"for input {0}").format(input.name))
|
||||
hot_inputs.append(HotParameter(name=input.name,
|
||||
type=hot_input_type,
|
||||
description=input.description,
|
||||
default=cli_value,
|
||||
default=hot_default,
|
||||
constraints=hot_constraints))
|
||||
return hot_inputs
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import six
|
||||
from translator.hot.tosca.tosca_block_storage import ToscaBlockStorage
|
||||
from translator.hot.tosca.tosca_block_storage_attachment import (
|
||||
ToscaBlockStorageAttachment
|
||||
@@ -18,8 +19,12 @@ from translator.hot.tosca.tosca_block_storage_attachment import (
|
||||
from translator.hot.tosca.tosca_compute import ToscaCompute
|
||||
from translator.hot.tosca.tosca_database import ToscaDatabase
|
||||
from translator.hot.tosca.tosca_dbms import ToscaDbms
|
||||
from translator.hot.tosca.tosca_nodejs import ToscaNodejs
|
||||
from translator.hot.tosca.tosca_webserver import ToscaWebserver
|
||||
from translator.hot.tosca.tosca_wordpress import ToscaWordpress
|
||||
from translator.toscalib.functions import GetAttribute
|
||||
from translator.toscalib.functions import GetInput
|
||||
from translator.toscalib.functions import GetProperty
|
||||
from translator.toscalib.relationship_template import RelationshipTemplate
|
||||
|
||||
SECTIONS = (TYPE, PROPERTIES, REQUIREMENTS, INTERFACES, LIFECYCLE, INPUT) = \
|
||||
@@ -45,7 +50,8 @@ TOSCA_TO_HOT_TYPE = {'tosca.nodes.Compute': ToscaCompute,
|
||||
'tosca.nodes.DBMS': ToscaDbms,
|
||||
'tosca.nodes.Database': ToscaDatabase,
|
||||
'tosca.nodes.WebApplication.WordPress': ToscaWordpress,
|
||||
'tosca.nodes.BlockStorage': ToscaBlockStorage}
|
||||
'tosca.nodes.BlockStorage': ToscaBlockStorage,
|
||||
'tosca.nodes.SoftwareComponent.Nodejs': ToscaNodejs}
|
||||
|
||||
TOSCA_TO_HOT_REQUIRES = {'container': 'server', 'host': 'server',
|
||||
'dependency': 'depends_on', "connects": 'depends_on'}
|
||||
@@ -59,20 +65,22 @@ class TranslateNodeTemplates():
|
||||
def __init__(self, nodetemplates, hot_template):
|
||||
self.nodetemplates = nodetemplates
|
||||
self.hot_template = hot_template
|
||||
# list of all HOT resources generated
|
||||
self.hot_resources = []
|
||||
# mapping between TOSCA nodetemplate and HOT resource
|
||||
self.hot_lookup = {}
|
||||
|
||||
def translate(self):
|
||||
return self._translate_nodetemplates()
|
||||
|
||||
def _translate_nodetemplates(self):
|
||||
hot_resources = []
|
||||
hot_lookup = {}
|
||||
|
||||
suffix = 0
|
||||
# Copy the TOSCA graph: nodetemplate
|
||||
for node in self.nodetemplates:
|
||||
hot_node = TOSCA_TO_HOT_TYPE[node.type](node)
|
||||
hot_resources.append(hot_node)
|
||||
hot_lookup[node] = hot_node
|
||||
self.hot_resources.append(hot_node)
|
||||
self.hot_lookup[node] = hot_node
|
||||
|
||||
# BlockStorage Attachment is a special case,
|
||||
# which doesn't match to Heat Resources 1 to 1.
|
||||
@@ -80,7 +88,7 @@ class TranslateNodeTemplates():
|
||||
volume_name = None
|
||||
requirements = node.requirements
|
||||
if requirements:
|
||||
# Find the name of associated BlockStorage node
|
||||
# Find the name of associated BlockStorage node
|
||||
for requires in requirements:
|
||||
for value in requires.values():
|
||||
for n in self.nodetemplates:
|
||||
@@ -92,16 +100,16 @@ class TranslateNodeTemplates():
|
||||
suffix,
|
||||
volume_name)
|
||||
if attachment_node:
|
||||
hot_resources.append(attachment_node)
|
||||
self.hot_resources.append(attachment_node)
|
||||
|
||||
# Handle life cycle operations: this may expand each node
|
||||
# into multiple HOT resources and may change their name
|
||||
lifecycle_resources = []
|
||||
for resource in hot_resources:
|
||||
for resource in self.hot_resources:
|
||||
expanded = resource.handle_life_cycle()
|
||||
if expanded:
|
||||
lifecycle_resources += expanded
|
||||
hot_resources += lifecycle_resources
|
||||
self.hot_resources += lifecycle_resources
|
||||
|
||||
# Copy the initial dependencies based on the relationship in
|
||||
# the TOSCA template
|
||||
@@ -110,22 +118,44 @@ class TranslateNodeTemplates():
|
||||
# if the source of dependency is a server, add dependency
|
||||
# as properties.get_resource
|
||||
if node_depend.type == 'tosca.nodes.Compute':
|
||||
hot_lookup[node].properties['server'] = \
|
||||
{'get_resource': hot_lookup[node_depend].name}
|
||||
self.hot_lookup[node].properties['server'] = \
|
||||
{'get_resource': self.hot_lookup[node_depend].name}
|
||||
# for all others, add dependency as depends_on
|
||||
else:
|
||||
hot_lookup[node].depends_on.append(hot_lookup[node_depend].
|
||||
top_of_chain())
|
||||
self.hot_lookup[node].depends_on.append(
|
||||
self.hot_lookup[node_depend].top_of_chain())
|
||||
|
||||
# handle hosting relationship
|
||||
for resource in hot_resources:
|
||||
for resource in self.hot_resources:
|
||||
resource.handle_hosting()
|
||||
|
||||
# Handle properties
|
||||
for resource in hot_resources:
|
||||
# handle built-in properties of HOT resources
|
||||
for resource in self.hot_resources:
|
||||
resource.handle_properties()
|
||||
|
||||
return hot_resources
|
||||
# Resolve function calls: GetProperty, GetAttribute, GetInput
|
||||
# at this point, all the HOT resources should have been created
|
||||
# in the graph.
|
||||
for resource in self.hot_resources:
|
||||
# traverse the reference chain to get the actual value
|
||||
inputs = resource.properties.get('input_values')
|
||||
if inputs:
|
||||
for name, value in six.iteritems(inputs):
|
||||
if isinstance(value, GetAttribute):
|
||||
# for the attribute
|
||||
# get the proper target type to perform the translation
|
||||
args = value.result()
|
||||
target = args[0]
|
||||
hot_target = self.find_hot_resource(target)
|
||||
|
||||
inputs[name] = hot_target.get_hot_attribute(args[1],
|
||||
args)
|
||||
else:
|
||||
if isinstance(value, GetProperty) or \
|
||||
isinstance(value, GetInput):
|
||||
inputs[name] = value.result()
|
||||
|
||||
return self.hot_resources
|
||||
|
||||
def _get_attachment_node(self, node, suffix, volume_name):
|
||||
attach = False
|
||||
@@ -145,3 +175,8 @@ class TranslateNodeTemplates():
|
||||
volume_name
|
||||
)
|
||||
return hot_node
|
||||
|
||||
def find_hot_resource(self, name):
|
||||
for resource in self.hot_resources:
|
||||
if resource.name == name:
|
||||
return resource
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
# under the License.
|
||||
|
||||
from translator.hot.syntax.hot_output import HotOutput
|
||||
from translator.toscalib import functions
|
||||
from translator.toscalib.utils.gettextutils import _
|
||||
|
||||
TOSCA_TO_HOT_GET_ATTRS = {'ip_address': 'first_address'}
|
||||
|
||||
@@ -21,8 +19,9 @@ TOSCA_TO_HOT_GET_ATTRS = {'ip_address': 'first_address'}
|
||||
class TranslateOutputs():
|
||||
'''Translate TOSCA Outputs to Heat Outputs.'''
|
||||
|
||||
def __init__(self, outputs):
|
||||
def __init__(self, outputs, node_translator):
|
||||
self.outputs = outputs
|
||||
self.nodes = node_translator
|
||||
|
||||
def translate(self):
|
||||
return self._translate_outputs()
|
||||
@@ -30,29 +29,16 @@ class TranslateOutputs():
|
||||
def _translate_outputs(self):
|
||||
hot_outputs = []
|
||||
for output in self.outputs:
|
||||
hot_value = {}
|
||||
if isinstance(output.value, functions.GetAttribute):
|
||||
func = output.value
|
||||
get_parameters = [
|
||||
func.get_referenced_node_template().name,
|
||||
self._translate_attribute_name(func.attribute_name)]
|
||||
hot_value['get_attr'] = get_parameters
|
||||
elif isinstance(output.value, functions.GetProperty):
|
||||
func = output.value
|
||||
if func.req_or_cap:
|
||||
raise NotImplementedError(_(
|
||||
'get_property with requirement/capability in outputs '
|
||||
'translation is not supported'))
|
||||
get_parameters = [
|
||||
func.node_template_name,
|
||||
self._translate_attribute_name(func.property_name)]
|
||||
hot_value['get_attr'] = get_parameters
|
||||
if output.value.name == 'get_attribute':
|
||||
get_parameters = output.value.args
|
||||
hot_target = self.nodes.find_hot_resource(get_parameters[0])
|
||||
hot_value = hot_target.get_hot_attribute(get_parameters[1],
|
||||
get_parameters)
|
||||
hot_outputs.append(HotOutput(output.name,
|
||||
hot_value,
|
||||
output.description))
|
||||
else:
|
||||
hot_value['get_attr'] = output.value
|
||||
hot_outputs.append(HotOutput(output.name,
|
||||
hot_value,
|
||||
output.description))
|
||||
hot_outputs.append(HotOutput(output.name,
|
||||
output.value,
|
||||
output.description))
|
||||
return hot_outputs
|
||||
|
||||
def _translate_attribute_name(self, attribute_name):
|
||||
return TOSCA_TO_HOT_GET_ATTRS.get(attribute_name, attribute_name)
|
||||
|
||||
@@ -51,12 +51,12 @@ class ToscaBlockStorageTest(TestCase):
|
||||
self.assertEqual(
|
||||
'Public IP address of the newly created compute instance.',
|
||||
outputs['public_ip']['description'])
|
||||
self.assertEqual({'get_attr': ['my_server', 'first_address']},
|
||||
self.assertEqual({'get_attr': ['my_server', 'networks', 'private', 0]},
|
||||
outputs['public_ip']['value'])
|
||||
self.assertIn('volume_id', outputs)
|
||||
self.assertEqual('The volume id of the block storage instance.',
|
||||
outputs['volume_id']['description'])
|
||||
self.assertEqual({'get_attr': ['my_storage', 'volume_id']},
|
||||
self.assertEqual({'get_resource': 'my_storage'},
|
||||
outputs['volume_id']['value'])
|
||||
|
||||
def test_translate_multi_storage(self):
|
||||
|
||||
Reference in New Issue
Block a user