X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=tosca2heat%2Ftosca-parser%2Ftoscaparser%2Ftosca_template.py;h=ac534dc0787606f6d9bc30e7f0fa6ffa4ee9fd39;hb=f416d7ba961edddfd956b556ed6566bf48824bf5;hp=ba056da23ffda65b0bb754d39eef2d4062dd59d3;hpb=c8201c119ec686e79797721156767685fe848aca;p=parser.git diff --git a/tosca2heat/tosca-parser/toscaparser/tosca_template.py b/tosca2heat/tosca-parser/toscaparser/tosca_template.py index ba056da..ac534dc 100644 --- a/tosca2heat/tosca-parser/toscaparser/tosca_template.py +++ b/tosca2heat/tosca-parser/toscaparser/tosca_template.py @@ -14,15 +14,18 @@ import logging import os +from copy import deepcopy from toscaparser.common.exception import ExceptionCollector from toscaparser.common.exception import InvalidTemplateVersion from toscaparser.common.exception import MissingRequiredFieldError +from toscaparser.common.exception import MissingRequiredParameterError from toscaparser.common.exception import UnknownFieldError from toscaparser.common.exception import ValidationError from toscaparser.elements.entity_type import update_definitions from toscaparser.extensions.exttools import ExtTools import toscaparser.imports from toscaparser.prereq.csar import CSAR +from toscaparser.repositories import Repository from toscaparser.topology_template import TopologyTemplate from toscaparser.tpl_relationship_graph import ToscaGraph from toscaparser.utils.gettextutils import _ @@ -34,14 +37,14 @@ SECTIONS = (DEFINITION_VERSION, DEFAULT_NAMESPACE, TEMPLATE_NAME, TOPOLOGY_TEMPLATE, TEMPLATE_AUTHOR, TEMPLATE_VERSION, DESCRIPTION, IMPORTS, DSL_DEFINITIONS, NODE_TYPES, RELATIONSHIP_TYPES, RELATIONSHIP_TEMPLATES, - CAPABILITY_TYPES, ARTIFACT_TYPES, DATA_TYPES, + CAPABILITY_TYPES, ARTIFACT_TYPES, DATA_TYPES, INTERFACE_TYPES, POLICY_TYPES, GROUP_TYPES, REPOSITORIES) = \ ('tosca_definitions_version', 'tosca_default_namespace', 'template_name', 'topology_template', 'template_author', 'template_version', 'description', 'imports', 'dsl_definitions', 'node_types', 'relationship_types', 'relationship_templates', 'capability_types', 'artifact_types', 'data_types', - 'policy_types', 'group_types', 'repositories') + 'interface_types', 'policy_types', 'group_types', 'repositories') # Sections that are specific to individual template definitions SPECIAL_SECTIONS = (METADATA) = ('metadata') @@ -53,22 +56,30 @@ YAML_LOADER = toscaparser.utils.yamlparser.load_yaml class ToscaTemplate(object): exttools = ExtTools() - VALID_TEMPLATE_VERSIONS = ['tosca_simple_yaml_1_0'] + VALID_TEMPLATE_VERSIONS = ['tosca_simple_yaml_1_0', + 'tosca_simple_yaml_1_1'] VALID_TEMPLATE_VERSIONS.extend(exttools.get_versions()) - ADDITIONAL_SECTIONS = {'tosca_simple_yaml_1_0': SPECIAL_SECTIONS} + ADDITIONAL_SECTIONS = {'tosca_simple_yaml_1_0': SPECIAL_SECTIONS, + 'tosca_simple_yaml_1_1': SPECIAL_SECTIONS} ADDITIONAL_SECTIONS.update(exttools.get_sections()) '''Load the template data.''' def __init__(self, path=None, parsed_params=None, a_file=True, - yaml_dict_tpl=None): - ExceptionCollector.start() + yaml_dict_tpl=None, sub_mapped_node_template=None, + no_required_paras_valid=False): + if sub_mapped_node_template is None: + ExceptionCollector.start() self.a_file = a_file self.input_path = None self.path = None self.tpl = None + self.sub_mapped_node_template = sub_mapped_node_template + self.nested_tosca_tpls_with_topology = {} + self.nested_tosca_templates_with_topology = [] + self.no_required_paras_valid = no_required_paras_valid if path: self.input_path = path self.path = self._get_path(path) @@ -94,21 +105,26 @@ class ToscaTemplate(object): self.relationship_types = self._tpl_relationship_types() self.description = self._tpl_description() self.topology_template = self._topology_template() + self.repositories = self._tpl_repositories() if self.topology_template.tpl: self.inputs = self._inputs() self.relationship_templates = self._relationship_templates() self.nodetemplates = self._nodetemplates() self.outputs = self._outputs() + self.policies = self._policies() + self._handle_nested_tosca_templates_with_topology() self.graph = ToscaGraph(self.nodetemplates) - ExceptionCollector.stop() + if sub_mapped_node_template is None: + ExceptionCollector.stop() self.verify_template() def _topology_template(self): return TopologyTemplate(self._tpl_topology_template(), self._get_all_custom_defs(), self.relationship_types, - self.parsed_params) + self.parsed_params, + self.sub_mapped_node_template) def _inputs(self): return self.topology_template.inputs @@ -133,6 +149,15 @@ class ToscaTemplate(object): def _tpl_imports(self): return self.tpl.get(IMPORTS) + def _tpl_repositories(self): + repositories = self.tpl.get(REPOSITORIES) + reposit = [] + if repositories: + for name, val in repositories.items(): + reposits = Repository(name, val) + reposit.append(reposits) + return reposit + def _tpl_relationship_types(self): return self._get_custom_types(RELATIONSHIP_TYPES) @@ -143,9 +168,12 @@ class ToscaTemplate(object): def _tpl_topology_template(self): return self.tpl.get(TOPOLOGY_TEMPLATE) + def _policies(self): + return self.topology_template.policies + def _get_all_custom_defs(self, imports=None): types = [IMPORTS, NODE_TYPES, CAPABILITY_TYPES, RELATIONSHIP_TYPES, - DATA_TYPES, POLICY_TYPES, GROUP_TYPES] + DATA_TYPES, INTERFACE_TYPES, POLICY_TYPES, GROUP_TYPES] custom_defs_final = {} custom_defs = self._get_custom_types(types, imports) if custom_defs: @@ -177,9 +205,14 @@ class ToscaTemplate(object): imports = self._tpl_imports() if imports: - custom_defs = toscaparser.imports.\ + custom_service = toscaparser.imports.\ ImportsLoader(imports, self.path, - type_defs, self.tpl).get_custom_defs() + type_defs, self.tpl) + + nested_tosca_tpls = custom_service.get_nested_tosca_tpls() + self._update_nested_tosca_tpls_with_topology(nested_tosca_tpls) + + custom_defs = custom_service.get_custom_defs() if not custom_defs: return @@ -191,6 +224,33 @@ class ToscaTemplate(object): custom_defs.update(inner_custom_types) return custom_defs + def _update_nested_tosca_tpls_with_topology(self, nested_tosca_tpls): + for tpl in nested_tosca_tpls: + filename, tosca_tpl = list(tpl.items())[0] + if (tosca_tpl.get(TOPOLOGY_TEMPLATE) and + filename not in list( + self.nested_tosca_tpls_with_topology.keys())): + self.nested_tosca_tpls_with_topology.update(tpl) + + def _handle_nested_tosca_templates_with_topology(self): + for fname, tosca_tpl in self.nested_tosca_tpls_with_topology.items(): + for nodetemplate in self.nodetemplates: + if self._is_sub_mapped_node(nodetemplate, tosca_tpl): + parsed_params = self._get_params_for_nested_template( + nodetemplate) + nested_template = ToscaTemplate( + path=fname, parsed_params=parsed_params, + yaml_dict_tpl=tosca_tpl, + sub_mapped_node_template=nodetemplate, + no_required_paras_valid=self.no_required_paras_valid) + if nested_template._has_substitution_mappings(): + # Record the nested templates in top level template + self.nested_tosca_templates_with_topology.\ + append(nested_template) + # Set the substitution toscatemplate for mapped node + nodetemplate.sub_mapping_tosca_template = \ + nested_template + def _validate_field(self): version = self._tpl_version() if not version: @@ -214,11 +274,12 @@ class ToscaTemplate(object): what=version, valid_versions=', '. join(self.VALID_TEMPLATE_VERSIONS))) else: - if version != 'tosca_simple_yaml_1_0': + if (version != 'tosca_simple_yaml_1_0' and + version != 'tosca_simple_yaml_1_1'): update_definitions(version) def _get_path(self, path): - if path.lower().endswith('.yaml'): + if path.lower().endswith('.yaml') or path.lower().endswith('.yml'): return path elif path.lower().endswith(('.zip', '.csar')): # a CSAR archive @@ -234,6 +295,10 @@ class ToscaTemplate(object): def verify_template(self): if ExceptionCollector.exceptionsCaught(): + if self.no_required_paras_valid: + ExceptionCollector.removeException( + MissingRequiredParameterError) + if self.input_path: raise ValidationError( message=(_('\nThe input "%(path)s" failed validation with ' @@ -253,3 +318,38 @@ class ToscaTemplate(object): msg = _('The pre-parsed input successfully passed validation.') log.info(msg) + + def _is_sub_mapped_node(self, nodetemplate, tosca_tpl): + """Return True if the nodetemple is substituted.""" + if (nodetemplate and not nodetemplate.substitution_mapped and + self.get_sub_mapping_node_type(tosca_tpl) == nodetemplate.type + and len(nodetemplate.interfaces) < 1): + return True + else: + return False + + def _get_params_for_nested_template(self, nodetemplate): + """Return total params for nested_template.""" + parsed_params = deepcopy(self.parsed_params) \ + if self.parsed_params else {} + if nodetemplate: + for pname in nodetemplate.get_properties(): + parsed_params.update({pname: + nodetemplate.get_property_value(pname)}) + return parsed_params + + def get_sub_mapping_node_type(self, tosca_tpl): + """Return substitution mappings node type.""" + if tosca_tpl: + return TopologyTemplate.get_sub_mapping_node_type( + tosca_tpl.get(TOPOLOGY_TEMPLATE)) + + def _has_substitution_mappings(self): + """Return True if the template has valid substitution mappings.""" + return self.topology_template is not None and \ + self.topology_template.substitution_mappings is not None + + def has_nested_templates(self): + """Return True if the tosca template has nested templates.""" + return self.nested_tosca_templates_with_topology is not None and \ + len(self.nested_tosca_templates_with_topology) >= 1