diff options
Diffstat (limited to 'tosca2heat/heat-translator-0.3.0/translator/hot/translate_node_templates.py')
-rw-r--r-- | tosca2heat/heat-translator-0.3.0/translator/hot/translate_node_templates.py | 408 |
1 files changed, 0 insertions, 408 deletions
diff --git a/tosca2heat/heat-translator-0.3.0/translator/hot/translate_node_templates.py b/tosca2heat/heat-translator-0.3.0/translator/hot/translate_node_templates.py deleted file mode 100644 index 152603d..0000000 --- a/tosca2heat/heat-translator-0.3.0/translator/hot/translate_node_templates.py +++ /dev/null @@ -1,408 +0,0 @@ -# -# 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 importlib -import logging -import os -import six - -from toscaparser.functions import GetAttribute -from toscaparser.functions import GetInput -from toscaparser.functions import GetProperty -from toscaparser.relationship_template import RelationshipTemplate -from translator.common.exception import ToscaClassAttributeError -from translator.common.exception import ToscaClassImportError -from translator.common.exception import ToscaModImportError -from translator.conf.config import ConfigProvider as translatorConfig -from translator.hot.syntax.hot_resource import HotResource -from translator.hot.tosca.tosca_block_storage_attachment import ( - ToscaBlockStorageAttachment - ) - -########################### -# Module utility Functions -# for dynamic class loading -########################### - - -def _generate_type_map(): - '''Generate TOSCA translation types map. - - Load user defined classes from location path specified in conf file. - Base classes are located within the tosca directory. - - ''' - - # Base types directory - BASE_PATH = 'translator/hot/tosca' - - # Custom types directory defined in conf file - custom_path = translatorConfig.get_value('DEFAULT', - 'custom_types_location') - - # First need to load the parent module, for example 'contrib.hot', - # for all of the dynamically loaded classes. - classes = [] - _load_classes((BASE_PATH, custom_path), classes) - try: - types_map = {clazz.toscatype: clazz for clazz in classes} - except AttributeError as e: - raise ToscaClassAttributeError(message=e.message) - - return types_map - - -def _load_classes(locations, classes): - '''Dynamically load all the classes from the given locations.''' - - for cls_path in locations: - # Use the absolute path of the class path - abs_path = os.path.dirname(os.path.abspath(__file__)) - abs_path = abs_path.replace('translator/hot', cls_path) - - # Grab all the tosca type module files in the given path - mod_files = [f for f in os.listdir(abs_path) if f.endswith('.py') - and not f.startswith('__init__') - and f.startswith('tosca_')] - - # For each module, pick out the target translation class - for f in mod_files: - # NOTE: For some reason the existing code does not use the map to - # instantiate ToscaBlockStorageAttachment. Don't add it to the map - # here until the dependent code is fixed to use the map. - if f == 'tosca_block_storage_attachment.py': - continue - - mod_name = cls_path + '/' + f.strip('.py') - mod_name = mod_name.replace('/', '.') - try: - mod = importlib.import_module(mod_name) - target_name = getattr(mod, 'TARGET_CLASS_NAME') - clazz = getattr(mod, target_name) - classes.append(clazz) - except ImportError: - raise ToscaModImportError(mod_name=mod_name) - except AttributeError: - if target_name: - raise ToscaClassImportError(name=target_name, - mod_name=mod_name) - else: - # TARGET_CLASS_NAME is not defined in module. - # Re-raise the exception - raise - -################## -# Module constants -################## - -SECTIONS = (TYPE, PROPERTIES, REQUIREMENTS, INTERFACES, LIFECYCLE, INPUT) = \ - ('type', 'properties', 'requirements', - 'interfaces', 'lifecycle', 'input') - -# TODO(anyone): the following requirement names should not be hard-coded -# in the translator. Since they are basically arbitrary names, we have to get -# them from TOSCA type definitions. -# To be fixed with the blueprint: -# https://blueprints.launchpad.net/heat-translator/+spec/tosca-custom-types -REQUIRES = (CONTAINER, DEPENDENCY, DATABASE_ENDPOINT, CONNECTION, HOST) = \ - ('container', 'dependency', 'database_endpoint', - 'connection', 'host') - -INTERFACES_STATE = (CREATE, START, CONFIGURE, START, DELETE) = \ - ('create', 'stop', 'configure', 'start', 'delete') - - -TOSCA_TO_HOT_REQUIRES = {'container': 'server', 'host': 'server', - 'dependency': 'depends_on', "connects": 'depends_on'} - -TOSCA_TO_HOT_PROPERTIES = {'properties': 'input'} -log = logging.getLogger('heat-translator') - -TOSCA_TO_HOT_TYPE = _generate_type_map() - - -class TranslateNodeTemplates(object): - '''Translate TOSCA NodeTemplates to Heat Resources.''' - - def __init__(self, tosca, hot_template): - self.tosca = tosca - self.nodetemplates = self.tosca.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 _recursive_handle_properties(self, resource): - '''Recursively handle the properties of the depends_on_nodes nodes.''' - # Use of hashtable (dict) here should be faster? - if resource in self.processed_resources: - return - self.processed_resources.append(resource) - for depend_on in resource.depends_on_nodes: - self._recursive_handle_properties(depend_on) - - resource.handle_properties() - - def _translate_nodetemplates(self): - - suffix = 0 - # Copy the TOSCA graph: nodetemplate - for node in self.nodetemplates: - hot_node = TOSCA_TO_HOT_TYPE[node.type](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. - if node.type == "tosca.nodes.Compute": - volume_name = None - requirements = node.requirements - if requirements: - # Find the name of associated BlockStorage node - for requires in requirements: - for value in requires.values(): - if isinstance(value, dict): - for node_name in value.values(): - for n in self.nodetemplates: - if n.name == node_name: - volume_name = node_name - break - else: # unreachable code ! - for n in self.nodetemplates: - if n.name == node_name: - volume_name = node_name - break - - suffix = suffix + 1 - attachment_node = self._get_attachment_node(node, - suffix, - volume_name) - if 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 self.hot_resources: - expanded = resource.handle_life_cycle() - if expanded: - lifecycle_resources += expanded - self.hot_resources += lifecycle_resources - - # Handle configuration from ConnectsTo relationship in the TOSCA node: - # this will generate multiple HOT resources, set of 2 for each - # configuration - connectsto_resources = [] - for node in self.nodetemplates: - for requirement in node.requirements: - for endpoint, details in six.iteritems(requirement): - relation = None - if isinstance(details, dict): - target = details.get('node') - relation = details.get('relationship') - else: - target = details - if (target and relation and - not isinstance(relation, six.string_types)): - interfaces = relation.get('interfaces') - connectsto_resources += \ - self._create_connect_configs(node, - target, - interfaces) - self.hot_resources += connectsto_resources - - # Copy the initial dependencies based on the relationship in - # the TOSCA template - for node in self.nodetemplates: - for node_depend in node.related_nodes: - # if the source of dependency is a server and the - # relationship type is 'tosca.relationships.HostedOn', - # add dependency as properties.server - if node_depend.type == 'tosca.nodes.Compute' and \ - node.related[node_depend].type == \ - node.type_definition.HOSTEDON: - self.hot_lookup[node].properties['server'] = \ - {'get_resource': self.hot_lookup[node_depend].name} - # for all others, add dependency as depends_on - else: - self.hot_lookup[node].depends_on.append( - self.hot_lookup[node_depend].top_of_chain()) - - self.hot_lookup[node].depends_on_nodes.append( - self.hot_lookup[node_depend].top_of_chain()) - - # handle hosting relationship - for resource in self.hot_resources: - resource.handle_hosting() - - # handle built-in properties of HOT resources - # if a resource depends on other resources, - # their properties need to be handled first. - # Use recursion to handle the properties of the - # dependent nodes in correct order - self.processed_resources = [] - for resource in self.hot_resources: - self._recursive_handle_properties(resource) - - # handle resources that need to expand to more than one HOT resource - expansion_resources = [] - for resource in self.hot_resources: - expanded = resource.handle_expansion() - if expanded: - expansion_resources += expanded - self.hot_resources += expansion_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 - ntpl = self.nodetemplates - for key, value in node.relationships.items(): - if key.is_derived_from('tosca.relationships.AttachesTo'): - if value.is_derived_from('tosca.nodes.BlockStorage'): - attach = True - if attach: - relationship_tpl = None - for req in node.requirements: - for key, val in req.items(): - attach = val - relship = val.get('relationship') - for rkey, rval in val.items(): - if relship and isinstance(relship, dict): - for rkey, rval in relship.items(): - if rkey == 'type': - relationship_tpl = val - attach = rval - elif rkey == 'template': - rel_tpl_list = \ - (self.tosca.topology_template. - _tpl_relationship_templates()) - relationship_tpl = rel_tpl_list[rval] - attach = rval - else: - continue - elif isinstance(relship, str): - attach = relship - relationship_tpl = val - relationship_templates = \ - self.tosca._tpl_relationship_templates() - if 'relationship' in relationship_tpl and \ - attach not in \ - self.tosca._tpl_relationship_types() and \ - attach in relationship_templates: - relationship_tpl['relationship'] = \ - relationship_templates[attach] - break - if relationship_tpl: - rval_new = attach + "_" + str(suffix) - att = RelationshipTemplate( - relationship_tpl, rval_new, - self.tosca._tpl_relationship_types()) - hot_node = ToscaBlockStorageAttachment(att, ntpl, - node.name, - volume_name - ) - return hot_node - - def find_hot_resource(self, name): - for resource in self.hot_resources: - if resource.name == name: - return resource - - def _find_tosca_node(self, tosca_name): - for node in self.nodetemplates: - if node.name == tosca_name: - return node - - def _find_hot_resource_for_tosca(self, tosca_name): - for node in self.nodetemplates: - if node.name == tosca_name: - return self.hot_lookup[node] - - def _create_connect_configs(self, source_node, target_name, - connect_interfaces): - connectsto_resources = [] - if connect_interfaces: - for iname, interface in six.iteritems(connect_interfaces): - connectsto_resources += \ - self._create_connect_config(source_node, target_name, - interface) - return connectsto_resources - - def _create_connect_config(self, source_node, target_name, - connect_interface): - connectsto_resources = [] - target_node = self._find_tosca_node(target_name) - # the configuration can occur on the source or the target - connect_config = connect_interface.get('pre_configure_target') - if connect_config is not None: - config_location = 'target' - else: - connect_config = connect_interface.get('pre_configure_source') - if connect_config is not None: - config_location = 'source' - else: - msg = _("Template error: " - "no configuration found for ConnectsTo " - "in {1}").format(self.nodetemplate.name) - log.warning(msg) - raise Exception(msg) - config_name = source_node.name + '_' + target_name + '_connect_config' - implement = connect_config.get('implementation') - if config_location == 'target': - hot_config = HotResource(target_node, - config_name, - 'OS::Heat::SoftwareConfig', - {'config': {'get_file': implement}}) - elif config_location == 'source': - hot_config = HotResource(source_node, - config_name, - 'OS::Heat::SoftwareConfig', - {'config': {'get_file': implement}}) - connectsto_resources.append(hot_config) - hot_target = self._find_hot_resource_for_tosca(target_name) - hot_source = self._find_hot_resource_for_tosca(source_node.name) - connectsto_resources.append(hot_config. - handle_connectsto(source_node, - target_node, - hot_source, - hot_target, - config_location, - connect_interface)) - return connectsto_resources |