diff options
20 files changed, 942 insertions, 66 deletions
diff --git a/docs/parser_docs/tosca2heat/examples/Simple_RNC.yaml b/docs/parser_docs/tosca2heat/examples/Simple_RNC.yaml index e22a1c8..76fd002 100644 --- a/docs/parser_docs/tosca2heat/examples/Simple_RNC.yaml +++ b/docs/parser_docs/tosca2heat/examples/Simple_RNC.yaml @@ -1,4 +1,3 @@ -# ## 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 @@ -11,7 +10,6 @@ ## License for the specific language governing permissions and limitations ## under the License. -# Required TOSCA Definitions version string tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 metadata: @@ -22,12 +20,12 @@ metadata: # Optional description of the definitions inside the file. description: > TOSCA simple profile for RNC - 1, Compute Node MM, CM, DM, LB... + 1. Compute Node MM, CM, DM, LB... 1.1 MM: MaintainModule; 1.2 CM: Control Module; 1.3 DM: Data Module; 1.4 LB: LineCard Module - 2, Network Node VL and CP + 2. Network Node VL and CP imports: - Simple_RNC_definition.yaml @@ -79,7 +77,7 @@ topology_template: substitution_mappings: node_type: rnc.nodes.VNF properties: - vnfmtype: TDS-CDMA + vnfmtype: UMTS requirements: virtualLink_VNFM: [ MM_Port_CTRL, virtualLink ] virtualLink_EMS: [ MM_Port_EMS, virtualLink ] @@ -305,7 +303,7 @@ topology_template: order: 0 is_default: true requirements: - - virtualbinding: MM_Active + - virtualBinding: MM_Active - virtualLink: EMS_Net MM_Port_CTRL: @@ -314,7 +312,7 @@ topology_template: order: 1 is_default: false requirements: - - virtualbinding: MM_Active + - virtualBinding: MM_Active - virtualLink: CTRL_Net MM_Port_EXTERMEDIA: @@ -323,7 +321,7 @@ topology_template: order: 2 is_default: false requirements: - - virtualbinding: MM_Active + - virtualBinding: MM_Active - virtualLink: EXTERMEDIA_Net CM_Port_CTRL: @@ -332,7 +330,7 @@ topology_template: order: 0 is_default: true requirements: - - virtualbinding: CM_Active + - virtualBinding: CM_Active - virtualLink: CTRL_Net CM_Port_INTERMEDIA: @@ -341,7 +339,7 @@ topology_template: order: 1 is_default: false requirements: - - virtualbinding: CM_Active + - virtualBinding: CM_Active - virtualLink: INTERMEDIA_Net DM_Port_CTRL: @@ -350,7 +348,7 @@ topology_template: order: 0 is_default: true requirements: - - virtualbinding: DM + - virtualBinding: DM - virtualLink: CTRL_Net DM_Port_INTERMEDIA: @@ -359,7 +357,7 @@ topology_template: order: 1 is_default: false requirements: - - virtualbinding: DM + - virtualBinding: DM - virtualLink: INTERMEDIA_Net LB_Port_CTRL: @@ -368,7 +366,7 @@ topology_template: order: 0 is_default: true requirements: - - virtualbinding: LB + - virtualBinding: LB - virtualLink: CTRL_Net LB_Port_INTERMEDIA: @@ -377,7 +375,7 @@ topology_template: order: 1 is_default: false requirements: - - virtualbinding: LB + - virtualBinding: LB - virtualLink: INTERMEDIA_Net LB_Port_EXTERMEDIA: @@ -386,7 +384,7 @@ topology_template: order: 2 is_default: false requirements: - - virtualbinding: LB + - virtualBinding: LB - virtualLink: EXTERMEDIA_Net # definition of the relationship templates of the topology @@ -400,19 +398,19 @@ topology_template: outputs: private_ip_of_MM: description: The private IP address of the MM. - value: { get_attribute: [ MM_Active, ip_address ] } + value: { get_attribute: [ MM_Active, private_address ] } private_ip_of_CM: description: The private IP address of the CM. - value: { get_attribute: [ CM_Active, ip_address ] } + value: { get_attribute: [ CM_Active, private_address ] } private_ip_of_DM: description: The private IP address of the DM. - value: { get_attribute: [ DM, ip_address ] } + value: { get_attribute: [ DM, private_address ] } private_ip_of_LB: description: The private IP address of the LB. - value: { get_attribute: [ LB, ip_address ] } + value: { get_attribute: [ LB, private_address ] } # definition of logical groups of node templates within the topology # To be continue about this section @@ -423,7 +421,7 @@ topology_template: Logical component grouping for anti affinity placement, MM_Acitve, MM_Passive, CM_Acitve, CM_Passive, LB must host on different host to reduce the impact to each other. - members: [ MM_Acitve, MM_Passive, CM_Acitve, CM_Passive, LB ] + members: [ MM_Active, MM_Passive, CM_Active, CM_Passive, LB ] policies: type: tosca.policy.placement.Antilocate @@ -432,19 +430,19 @@ topology_template: description: > Logical component grouping for affinity placement, CM and DM will be host on the same host to get high performence - members: [ CM, DM ] + members: [ CM_Active, DM ] policies: type: tosca.policy.placement.Antilocate policies: - AnitAffinityPolicy: type: tosca.policies.Placement.Antilocate - description: Apply anti-locate placement policy to group + description: Apply anti-locate placement policy to group targets: [ AnitAffinityServerGroup ] - + - AffinityPolicy: type: tosca.policies.Placement.Colocate - description: Apply anti-locate placement policy to group + description: Apply anti-locate placement policy to group targets: [ AffinityServerGroup ] # ServerGroupScaling_DM: # added future diff --git a/docs/parser_docs/tosca2heat/examples/Simple_RNC_definition.yaml b/docs/parser_docs/tosca2heat/examples/Simple_RNC_definition.yaml index b3dfd55..7478d98 100644 --- a/docs/parser_docs/tosca2heat/examples/Simple_RNC_definition.yaml +++ b/docs/parser_docs/tosca2heat/examples/Simple_RNC_definition.yaml @@ -1,4 +1,3 @@ -# ## 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 @@ -11,25 +10,24 @@ ## License for the specific language governing permissions and limitations ## under the License. -# Required TOSCA Definitions version string tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 -metadata: - template_name: tosca_simple_profile_for_nfv_vRNC - template_author: opnfv_parser_project_from_zte - template_version: tosca_simple_profile_for_nfv_1_0 +#metadata: +# template_name: tosca_simple_profile_for_nfv_vRNC +# template_author: opnfv_parser_project_from_zte +# template_version: tosca_simple_profile_for_nfv_1_0 # Optional description of the definitions inside the file. description: > NFV TOSCA simple profile for RNC types - 1, Compute Node MM, CM, DM, LB... + 1. Compute Node MM, CM, DM, LB... 1.1 MM: MaintainModule; 1.2 CM: Control Module; 1.3 DM: Data Module; 1.4 LB: LineCard Module. - 2, Network Node VL and CP + 2. Network Node VL and CP -# The import section shall be ignored if the value of tosca_definitions_version +# The import section shall be ignored if the value of tosca_definitions_version # is tosca_simple_profile_for_nfv_1_0_0, otherwise will be needed. #imports: # - TOSCA_nfv_definition_1_0.yaml @@ -41,7 +39,7 @@ node_types: properties: vnftype: type: string - description: type of the vnf + description: type of the RNC default: UMTS required: false constraints: @@ -50,15 +48,15 @@ node_types: - virtualLink_VNFM: capability: tosca.capabilities.nfv.VirtualLinkable relationship: tosca.relationships.nfv.VirtualLinksTo - node: tosca.nodes.nfv.VL + node: rnc.nodes.VL - virtualLink_EMS: capability: tosca.capabilities.nfv.VirtualLinkable relationship: tosca.relationships.nfv.VirtualLinksTo - node: tosca.nodes.nfv.VL + node: rnc.nodes.VL - virtualLink_TRAFFIC: capability: tosca.capabilities.nfv.VirtualLinkable relationship: tosca.relationships.nfv.VirtualLinksTo - node: tosca.nodes.nfv.VL + node: rnc.nodes.VL rnc.nodes.compute.MM: derived_from: tosca.nodes.nfv.VDU diff --git a/tosca2heat/tosca-parser/toscaparser/elements/artifacttype.py b/tosca2heat/tosca-parser/toscaparser/elements/artifacttype.py index 3bfd7d0..887e99a 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/artifacttype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/artifacttype.py @@ -20,6 +20,7 @@ class ArtifactTypeDef(StatefulEntityType): super(ArtifactTypeDef, self).__init__(atype, self.ARTIFACT_PREFIX, custom_def) self.type = atype + self.custom_def = custom_def self.properties = None if self.PROPERTIES in self.defs: self.properties = self.defs[self.PROPERTIES] @@ -27,17 +28,24 @@ class ArtifactTypeDef(StatefulEntityType): def _get_parent_artifacts(self): artifacts = {} - parent_artif = self.parent_type + parent_artif = self.parent_type.type if self.parent_type else None if parent_artif: while parent_artif != 'tosca.artifacts.Root': + # only support normative artifact, shall be modified future artifacts[parent_artif] = self.TOSCA_DEF[parent_artif] parent_artif = artifacts[parent_artif]['derived_from'] return artifacts @property def parent_type(self): - '''Return an artifact this artifact is derived from.''' - return self.derived_from(self.defs) + '''Return a artifact entity from which this entity is derived.''' + if not hasattr(self, 'defs'): + return None + partifact_entity = self.derived_from(self.defs) + if partifact_entity: + return ArtifactTypeDef(partifact_entity, self.custom_def) + else: + return None def get_artifact(self, name): '''Return the definition of an artifact field by name.''' diff --git a/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py b/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py index 5d620a5..72e7e3f 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py @@ -106,8 +106,13 @@ class EntityType(object): value[k] = v if isinstance(value, list): for p_value in parent_value: - if p_value not in value: - value.append(p_value) + if isinstance(p_value, dict): + if p_value.keys()[0] not in [ + item.keys()[0] for item in value]: + value.append(p_value) + else: + if p_value not in value: + value.append(p_value) else: value = copy.copy(parent_value) p = p.parent_type diff --git a/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py b/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py index 148d2b6..f5e4eb0 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py @@ -98,6 +98,10 @@ class NodeType(StatefulEntityType): provided capability. ''' + # All types,include normative and custom types, here will + # be substituted because the global moification of TOSCA_DEF + self.TOSCA_DEF.update(self.custom_def) + # Filter the node types node_types = [node_type for node_type in self.TOSCA_DEF.keys() if node_type.startswith(self.NODE_PREFIX) and diff --git a/tosca2heat/tosca-parser/toscaparser/elements/policytype.py b/tosca2heat/tosca-parser/toscaparser/elements/policytype.py index 04cbab5..8fbb0f0 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/policytype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/policytype.py @@ -28,6 +28,7 @@ class PolicyType(StatefulEntityType): super(PolicyType, self).__init__(ptype, self.POLICY_PREFIX, custom_def) self.type = ptype + self.custom_def = custom_def self._validate_keys() self.meta_data = None @@ -55,7 +56,7 @@ class PolicyType(StatefulEntityType): def _get_parent_policies(self): policies = {} - parent_policy = self.parent_type + parent_policy = self.parent_type.type if self.parent_type else None if parent_policy: while parent_policy != 'tosca.policies.Root': policies[parent_policy] = self.TOSCA_DEF[parent_policy] @@ -64,8 +65,12 @@ class PolicyType(StatefulEntityType): @property def parent_type(self): - '''Return a policy this policy is derived from.''' - return self.derived_from(self.defs) + '''Return a policy statefulentity of this node is derived from.''' + if not hasattr(self, 'defs'): + return None + ppolicy_entity = self.derived_from(self.defs) + if ppolicy_entity: + return PolicyType(ppolicy_entity, self.custom_def) def get_policy(self, name): '''Return the definition of a policy field by name.''' diff --git a/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py b/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py index 9462d38..25440ca 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py @@ -26,7 +26,7 @@ class RelationshipType(StatefulEntityType): '''Return a relationship this reletionship is derived from.''' prel = self.derived_from(self.defs) if prel: - return RelationshipType(prel) + return RelationshipType(prel, self.custom_def) @property def valid_target_types(self): diff --git a/tosca2heat/tosca-parser/toscaparser/entity_template.py b/tosca2heat/tosca-parser/toscaparser/entity_template.py index 281012b..f416c99 100644 --- a/tosca2heat/tosca-parser/toscaparser/entity_template.py +++ b/tosca2heat/tosca-parser/toscaparser/entity_template.py @@ -81,6 +81,15 @@ class EntityTemplate(object): def type(self): if self.type_definition: return self.type_definition.type + else: + return None + + @property + def parent_type(self): + if self.type_definition: + return self.type_definition.parent_type + else: + return None @property def requirements(self): diff --git a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/Definitions/rnc_definition.yaml b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/Definitions/rnc_definition.yaml new file mode 100644 index 0000000..8c98fc9 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/Definitions/rnc_definition.yaml @@ -0,0 +1,160 @@ +## 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. + +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 + +#metadata: +# template_name: tosca_simple_profile_for_nfv_vRNC +# template_author: opnfv_parser_project_from_zte +# template_version: tosca_simple_profile_for_nfv_1_0 + +# Optional description of the definitions inside the file. +description: > + NFV TOSCA simple profile for RNC types + 1. Compute Node MM, CM, DM, LB... + 1.1 MM: MaintainModule; + 1.2 CM: Control Module; + 1.3 DM: Data Module; + 1.4 LB: LineCard Module. + 2. Network Node VL and CP + +# The import section shall be ignored if the value of tosca_definitions_version +# is tosca_simple_profile_for_nfv_1_0_0, otherwise will be needed. + +# list of node type definitions +node_types: + rnc.nodes.VNF: + derived_from: tosca.nodes.nfv.VNF + properties: + vnftype: + type: string + description: type of the RNC + default: UMTS + required: false + constraints: + - valid_values: [ TDS-CDMA, UMTS, CDMA ] + requirements: + - virtualLink_VNFM: + capability: tosca.capabilities.nfv.VirtualLinkable + relationship: tosca.relationships.nfv.VirtualLinksTo + node: rnc.nodes.VL + - virtualLink_EMS: + capability: tosca.capabilities.nfv.VirtualLinkable + relationship: tosca.relationships.nfv.VirtualLinksTo + node: rnc.nodes.VL + - virtualLink_TRAFFIC: + capability: tosca.capabilities.nfv.VirtualLinkable + relationship: tosca.relationships.nfv.VirtualLinksTo + node: rnc.nodes.VL + + rnc.nodes.compute.MM: + derived_from: tosca.nodes.nfv.VDU + properties: + activestatus: + type: integer + required: false + description: 1 for active or 0 for passive + constraints: + - valid_values: [ 0, 1 ] + id: + type: string + defaule: MM + required: false + description: > + A identifier of this VDU within the scope of the VNFD, + including version functional description and other + identification information. + + rnc.nodes.compute.CM: + derived_from: tosca.nodes.nfv.VDU + properties: + activestatus: + type: integer + required: false + description: 1 for active or 0 for passive + constraints: + - valid_values: [ 0, 1 ] + + rnc.nodes.compute.DM: + derived_from: tosca.nodes.nfv.VDU + + rnc.nodes.compute.LB: + derived_from: tosca.nodes.nfv.VDU + + rnc.nodes.BlockStorage: + derived_from: tosca.nodes.BlockStorage + + rnc.nodes.VL: + derived_from: tosca.nodes.nfv.VL + + rnc.nodes.CP: + derived_from: tosca.nodes.nfv.CP + + rnc.nodes.CP.MM: + derived_from: tosca.nodes.nfv.CP + # It's ok here because of the weakly validation. + + rnc.nodes.CP.CM: + derived_from: tosca.nodes.nfv.CP + requirements: + - virtualLink: + capability: tosca.capabilities.nfv.VirtualLinkable + relationship: tosca.relationships.nfv.VirtualLinksTo + node: rnc.nodes.VL + - virtualBinding: + capability: tosca.capabilities.nfv.VirtualBindable + relationship: tosca.relationships.nfv.VirtualBindsTo + node: rnc.nodes.compute.CM + + rnc.nodes.CP.DM: + derived_from: tosca.nodes.nfv.CP + requirements: + - virtualLink: + capability: tosca.capabilities.nfv.VirtualLinkable + relationship: tosca.relationships.nfv.VirtualLinksTo + node: rnc.nodes.VL + - virtualBinding: + capability: tosca.capabilities.nfv.VirtualBindable + relationship: tosca.relationships.nfv.VirtualBindsTo + node: rnc.nodes.compute.DM + + rnc.nodes.CP.LB: + derived_from: tosca.nodes.nfv.CP + requirements: + - virtualLink: + capability: tosca.capabilities.nfv.VirtualLinkable + relationship: tosca.relationships.nfv.VirtualLinksTo + node: rnc.nodes.VL + - virtualBinding: + capability: tosca.capabilities.nfv.VirtualBindable + relationship: tosca.relationships.nfv.VirtualBindsTo + node: rnc.nodes.compute.LB + +# list of capability type definitions +capability_types: + rnc.capabilities.Container: + derived_from: tosca.capabilities.Container + properties: + swap: + type: scalar-unit.size + description: swap info + required: false + default: 0 + constraints: + - greater_or_equal: 0 MB + iops: + type: integer + description: IOPS for disk + required: false + default: 0 + constraints: + - greater_than: 0 diff --git a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/Definitions/vRNC.yaml b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/Definitions/vRNC.yaml new file mode 100644 index 0000000..6517c4a --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/Definitions/vRNC.yaml @@ -0,0 +1,551 @@ +## 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. + +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 + +metadata: + template_name: tosca_simple_profile_for_nfv_vRNC + template_author: opnfv_parser_project_from_zte + template_version: tosca_simple_profile_for_nfv_1_0 + +# Optional description of the definitions inside the file. +description: > + TOSCA simple profile for RNC + 1. Compute Node MM, CM, DM, LB... + 1.1 MM: MaintainModule; + 1.2 CM: Control Module; + 1.3 DM: Data Module; + 1.4 LB: LineCard Module + 2. Network Node VL and CP + +imports: + - rnc_definition.yaml + +# list of YAML alias anchors (or macros) +dsl_definitions: + compute_props_os_DEF: &compute_props_os_DEF + architecture: x86_64 + type: Linux + distribution: Cirros + version: 0.3.2 + + compute_props_host_MM: &compute_props_host_MM + disk_size: 1 GB + num_cpus: 2 + mem_size: 64 MB + + compute_props_host_CM: &compute_props_host_CM + disk_size: 0 GB + num_cpus: 2 + mem_size: 64 MB + + compute_props_host_DM: &compute_props_host_DM + disk_size: 0 GB + num_cpus: 2 + mem_size: 64 MB + + compute_props_host_LB: &compute_props_host_LB + disk_size: 0 GB + num_cpus: 2 + mem_size: 64 MB + +# topology template definition of the cloud application or service +topology_template: + # a description of the topology template + description: > + simple RNC template + + inputs: + mm_storage_size: + type: integer + default: 1 + description: mm additional block storage size + constraints: + - in_range: [ 1, 200 ] + + substitution_mappings: + node_type: rnc.nodes.VNF + properties: + vnfmtype: UMTS + requirements: + virtualLink_VNFM: [ MM_Port_CTRL, virtualLink ] + virtualLink_EMS: [ MM_Port_EMS, virtualLink ] + virtualLink_TRAFFIC: [ LB_Port_EXTERMEDIA, virtualLink ] + + # definition of the node templates of the topology + node_templates: + MM_Active: + type: tosca.nodes.SoftwareComponent + properties: + component_version: 1.0 + requirements: + - host: MM_Active_Host + interfaces: + Standard: + create: + implementation: mm_install.sh + configure: + implementation: mm_active_configure.sh + + MM_Active_Host: + type: rnc.nodes.compute.MM + properties: + activestatus: 1 + id: MM_Active + capabilities: + os: + properties: *compute_props_os_DEF + host: + properties: *compute_props_host_MM + requirements: + - local_storage: + node: MM_BlockStorage + relationship: Storage_attachesto + - high_availability: MM_Passive + artifacts: + #the VM image of MM + vm_image: mm.image + + MM_Passive: + type: tosca.nodes.SoftwareComponent + properties: + component_version: 1.0 + requirements: + - host: MM_Passive_Host + interfaces: + Standard: + create: + implementation: mm_install.sh + configure: + implementation: mm_passvie_configure.sh + + MM_Passive_Host: + type: rnc.nodes.compute.MM + properties: + activestatus: 0 + id: MM_Passive + capabilities: + os: + properties: *compute_props_os_DEF + host: + properties: *compute_props_host_MM + requirements: + - local_storage: + node: MM_BlockStorage + relationship: Storage_attachesto + - high_availability: MM_Active + artifacts: + #the VM image of MM + vm_image: mm.image + + CM_Active: + type: tosca.nodes.SoftwareComponent + properties: + component_version: 1.0 + requirements: + - host: CM_Active_Host + interfaces: + Standard: + create: + implementation: cm_install.sh + configure: + implementation: cm_active_configure.sh + + CM_Active_Host: + type: rnc.nodes.compute.CM + properties: + activestatus: 1 + capabilities: + os: + properties: *compute_props_os_DEF + host: + properties: *compute_props_host_CM + scalable: + properties: + min_instances: 1 + max_instances: 12 + default_instances: 1 + requirements: + - high_availability: CM_Passive + artifacts: + #the VM image of CM + vm_image: cm.image + + CM_Passive: + type: tosca.nodes.SoftwareComponent + properties: + component_version: 1.0 + requirements: + - host: CM_Passive_Host + interfaces: + Standard: + create: + implementation: cm_install.sh + configure: + implementation: cm_passvie_configure.sh + + CM_Passive_Host: + type: rnc.nodes.compute.CM + properties: + activestatus: 0 + capabilities: + os: + properties: *compute_props_os_DEF + host: + properties: *compute_props_host_CM + scalable: + properties: + min_instances: 1 + max_instances: 12 + default_instances: 1 + requirements: + - high_availability: CM_Active + artifacts: + #the VM image of CM + vm_image: mm.image + + DM: + type: tosca.nodes.SoftwareComponent + properties: + component_version: 1.0 + requirements: + - host: DM_Host + interfaces: + Standard: + create: + implementation: dm_install.sh + configure: + implementation: dm_configure.sh + + DM_Host: + type: rnc.nodes.compute.DM + capabilities: + os: + properties: *compute_props_os_DEF + host: + properties: *compute_props_host_DM + scalable: + properties: + min_instances: 1 + max_instances: 12 + default_instances: 1 + artifacts: + vm_image: dm.image + + LB: + type: tosca.nodes.SoftwareComponent + properties: + component_version: 1.0 + requirements: + - host: LB_Host + interfaces: + Standard: + create: + implementation: lb_install.sh + configure: + implementation: lb_configure.sh + + LB_Host: + type: rnc.nodes.compute.LB + capabilities: + os: + properties: *compute_props_os_DEF + host: + properties: *compute_props_host_LB + scalable: + properties: + min_instances: 1 + max_instances: 2 + default_instances: 1 + artifacts: + #the VM image of LB + vm_image: lb.image + + MM_BlockStorage: + type: rnc.nodes.BlockStorage + properties: + size: { get_input: mm_storage_size } + interfaces: + Configure: + post_configure_target: + implementation: default_script.sh + + CTRL_Net: + type: rnc.nodes.VL + properties: + vendor: ZTE + cidr: "128.0.0.0/8" + network_name: Ctrl_Net + network_type: vlan + segmentation_id: 110 + dhcp_enabled: false + + INTERMEDIA_Net: + type: rnc.nodes.VL + properties: + vendor: ZTE + cidr: 10.0.0.0/8 + start_ip: 10.1.0.1 + end_ip: 10.1.2.254 + network_name: InterMedia_Net + network_type: vlan + segmentation_id: 111 + dhcp_enabled: false + + EXTERMEDIA_Net: + type: rnc.nodes.VL + properties: + vendor: ZTE + cidr: 172.1.0.0/16 + start_ip: 172.1.0.2 + end_ip: 172.1.2.254 + gateway_ip: 172.1.0.1 + network_name: ExterMdedia_Net + network_type: vlan + segmentation_id: 100 + dhcp_enabled: false + + EMS_Net: + type: rnc.nodes.VL + properties: + vendor: ZTE + cidr: 129.0.0.0/24 + start_ip: 129.0.0.2 + end_ip: 129.0.0.64 + gateway_ip: 129.0.0.1 + network_name: Ems_Net + network_type: vlan + segmentation_id: 101 + dhcp_enabled: false + + MM_Active_Port_EMS: + type: rnc.nodes.CP.MM + properties: + order: 0 + is_default: true + requirements: + - virtualBinding: MM_Active_Host + - virtualLink: EMS_Net + + MM_Active_Port_EXTERMEDIA: + type: rnc.nodes.CP.MM + properties: + order: 1 + is_default: true + requirements: + - virtualBinding: MM_Active_Host + - virtualLink: EMS_Net + + MM_Active_Port_CTRL: + type: rnc.nodes.CP.MM + properties: + order: 2 + is_default: false + requirements: + - virtualBinding: MM_Active_Host + - virtualLink: CTRL_Net + + MM_Active_Port_INTERMEDIA: + type: rnc.nodes.CP.MM + properties: + order: 3 + is_default: false + requirements: + - virtualBinding: MM_Active_Host + - virtualLink: EXTERMEDIA_Net + + MM_Passive_Port_EMS: + type: rnc.nodes.CP.MM + properties: + order: 0 + is_default: true + requirements: + - virtualBinding: MM_Passive_Host + - virtualLink: EMS_Net + + MM_Passive_Port_EXTERMEDIA: + type: rnc.nodes.CP.MM + properties: + order: 1 + is_default: true + requirements: + - virtualBinding: MM_Passive_Host + - virtualLink: EMS_Net + + MM_Passive_Port_CTRL: + type: rnc.nodes.CP.MM + properties: + order: 2 + is_default: false + requirements: + - virtualBinding: MM_Passive_Host + - virtualLink: CTRL_Net + + MM_Passive_Port_INTERMEDIA: + type: rnc.nodes.CP.MM + properties: + order: 3 + is_default: false + requirements: + - virtualBinding: MM_Passive_Host + - virtualLink: EXTERMEDIA_Net + + CM_Active_Port_CTRL: + type: rnc.nodes.CP.CM + properties: + order: 0 + is_default: true + requirements: + - virtualBinding: CM_Active_Host + - virtualLink: CTRL_Net + + CM_Active_Port_INTERMEDIA: + type: rnc.nodes.CP.CM + properties: + order: 1 + is_default: false + requirements: + - virtualBinding: CM_Active_Host + - virtualLink: INTERMEDIA_Net + + CM_Passive_Port_CTRL: + type: rnc.nodes.CP.CM + properties: + order: 0 + is_default: true + requirements: + - virtualBinding: CM_Passive_Host + - virtualLink: CTRL_Net + + CM_Passive_Port_INTERMEDIA: + type: rnc.nodes.CP.CM + properties: + order: 1 + is_default: false + requirements: + - virtualBinding: CM_Passive_Host + - virtualLink: INTERMEDIA_Net + + DM_Port_CTRL: + type: rnc.nodes.CP.DM + properties: + order: 0 + is_default: true + requirements: + - virtualBinding: DM + - virtualLink: CTRL_Net_Host + + DM_Port_INTERMEDIA: + type: rnc.nodes.CP.DM + properties: + order: 1 + is_default: false + requirements: + - virtualBinding: DM_Host + - virtualLink: INTERMEDIA_Net + + LB_Port_CTRL: + type: rnc.nodes.CP.LB + properties: + order: 0 + is_default: true + requirements: + - virtualBinding: LB_Host + - virtualLink: CTRL_Net + + LB_Port_INTERMEDIA: + type: rnc.nodes.CP.LB + properties: + order: 1 + is_default: false + requirements: + - virtualBinding: LB_Host + - virtualLink: INTERMEDIA_Net + + LB_Port_EXTERMEDIA: + type: rnc.nodes.CP.LB + properties: + order: 2 + is_default: false + requirements: + - virtualBinding: LB_Host + - virtualLink: EXTERMEDIA_Net + + # definition of the relationship templates of the topology + relationship_templates: + Storage_attachesto: + type: tosca.relationships.AttachesTo + properties: + location: /data_location + + # definition of output parameters for the topology template + outputs: + private_ip_of_MM: + description: The private IP address of the MM. + value: { get_attribute: [ MM_Active_Host, private_address ] } + + private_ip_of_CM: + description: The private IP address of the CM. + value: { get_attribute: [ CM_Active_Host, private_address ] } + + private_ip_of_DM: + description: The private IP address of the DM. + value: { get_attribute: [ DM_Host, private_address ] } + + private_ip_of_LB: + description: The private IP address of the LB. + value: { get_attribute: [ LB_Host, private_address ] } + + # definition of logical groups of node templates within the topology + # To be continue about this section + groups: + AnitAffinityServerGroup: + type: tosca.groups.Root + description: > + Logical component grouping for anti affinity placement, + MM_Acitve, MM_Passive, CM_Acitve, CM_Passive, LB must host + on different host to reduce the impact to each other. + members: [ MM_Active, MM_Passive, CM_Active, CM_Passive, LB ] + + AffinityServerGroup: + type: tosca.groups.Root + description: > + Logical component grouping for affinity placement, + CM and DM will be host on the same host to get high performence + members: [ CM_Active, DM ] + + policies: + - AnitAffinityPolicy: + type: tosca.policies.Placement.Antilocate + description: Apply anti-locate placement policy to group + targets: [ AnitAffinityServerGroup ] + + - AffinityPolicy: + type: tosca.policies.Placement.Colocate + description: Apply anti-locate placement policy to group + targets: [ AffinityServerGroup ] + + # ServerGroupScaling_DM: # added future + # members: [ DM, ]# only one, will be error + # policies: + # - name: MyScaleUpPolicy + # - type: tosca.policy.scale.up | tosca.policy.scale.down + # - rule: fn.utilizaton [ DM ], greater_than: 80 + # - trigger: script_dm + + # ServerGroupScaling_LB: # added future + # members: [ LB, ] # only one, will be error + # policies: + # - name: MyScaleUpPolicy + # - type: tosca.policy.scale.up | tosca.policy.scale.down + # - rule: fn.utilizaton [ LB ], greater_than: 80 + # - trigger: script_lb diff --git a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/README.txt b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/README.txt new file mode 100644 index 0000000..9ea77a4 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/README.txt @@ -0,0 +1,22 @@ +README: + +This CSAR contains all definitions that are required for deploying a simple +vRNC(virtual Radio Network Controller) on a cloud. + +Entry information for processing through an orchestrator is contained in file +TOSCA-Metadata/TOSCA.meta. This file provides high-level information such as +CSAR version or creator of the CSAR. Furthermore, it provides pointers to the +various TOSCA definitions files that contain the real details. +The entry 'Entry-Definitions' points to the definitions file which holds the +service template for the workload. +'Entry-Definitions' is optional. An orchestrator can also process the contents +like this: +1) Read in and process each definitions file. +2) For each definitions file: + 2.1) Read in all * type definitions (node types, capability types, etc.) and + store them in an internal map +3) Verify and build dependencies (e.g. inheritance) between all type definitions + previously read in. Orchestrator built-in types (e.g. TOSCA base types) are + also considered in this step. +4) Process the actual service template (the file with a node_templates section). + Validate using previously obtained type information.
\ No newline at end of file diff --git a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/TOSCA-Metadata/TOSCA.meta b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/TOSCA-Metadata/TOSCA.meta new file mode 100644 index 0000000..45f9ab2 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/data/vRNC/TOSCA-Metadata/TOSCA.meta @@ -0,0 +1,4 @@ +TOSCA-Meta-File-Version: 1.0 +CSAR-Version: 1.1 +Created-By: shang.xiaodog@zte.com.cn +Entry-Definitions: Definitions/vRNC.yaml
\ No newline at end of file diff --git a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/test_tosca_vRNC.py b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/test_tosca_vRNC.py new file mode 100644 index 0000000..c839626 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tests/test_tosca_vRNC.py @@ -0,0 +1,60 @@ +# 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 os + +from toscaparser.tests.base import TestCase +from toscaparser.tosca_template import ToscaTemplate + + +class ToscaVRNCTemplateTest(TestCase): + + '''NFV TOSCA vRNC template.''' + tosca_tpl = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/vRNC/Definitions/vRNC.yaml") + tosca = ToscaTemplate(tosca_tpl) + + def test_version(self): + self.assertEqual(self.tosca.version, + "tosca_simple_profile_for_nfv_1_0_0") + + def test_input(self): + first_input_name = "mm_storage_size" + self.assertEqual(self.tosca.inputs[0].name, first_input_name) + + def test_nodetemplates(self): + expected_node_list = sorted( + ["MM_Active", "MM_Passive", "MM_BlockStorage", + "MM_Active_Host", "MM_Passive_Host", + "CM_Active", "CM_Passive", "DM", "LB", + "CM_Active_Host", "CM_Passive_Host", "DM_Host", "LB_Host", + "EXTERMEDIA_Net", "INTERMEDIA_Net", "EMS_Net", "CTRL_Net", + "MM_Active_Port_EMS", "MM_Active_Port_CTRL", + "MM_Active_Port_EXTERMEDIA", "MM_Active_Port_INTERMEDIA", + "MM_Passive_Port_EMS", "MM_Passive_Port_CTRL", + "MM_Passive_Port_EXTERMEDIA", "MM_Passive_Port_INTERMEDIA", + "CM_Active_Port_CTRL", "CM_Active_Port_INTERMEDIA", + "CM_Passive_Port_CTRL", "CM_Passive_Port_INTERMEDIA", + "DM_Port_CTRL", "DM_Port_INTERMEDIA", + "LB_Port_INTERMEDIA", "LB_Port_EXTERMEDIA", "LB_Port_CTRL"]) + + node_list = sorted([node.name for node in self.tosca.nodetemplates]) + self.assertEqual(node_list, expected_node_list) + + def test_output(self): + expected_output_name = sorted( + ["private_ip_of_CM", "private_ip_of_DM", + "private_ip_of_LB", "private_ip_of_MM"]) + + output_list = sorted([output.name for output in self.tosca.outputs]) + self.assertEqual(output_list, expected_output_name) diff --git a/tosca2heat/tosca-parser/toscaparser/imports.py b/tosca2heat/tosca-parser/toscaparser/imports.py index 5149382..62748bd 100644 --- a/tosca2heat/tosca-parser/toscaparser/imports.py +++ b/tosca2heat/tosca-parser/toscaparser/imports.py @@ -36,6 +36,7 @@ class ImportsLoader(object): tpl=None): self.importslist = importslist self.custom_defs = {} + self.nested_topo_tpls = [] if not path and not tpl: msg = _('Input tosca template is not provided.') log.warning(msg) @@ -55,6 +56,9 @@ class ImportsLoader(object): def get_custom_defs(self): return self.custom_defs + def get_nested_topo_tpls(self): + return self.nested_topo_tpls + def _validate_and_load_imports(self): imports_names = set() @@ -76,8 +80,8 @@ class ImportsLoader(object): ValidationError(message=msg)) imports_names.add(import_name) - custom_type = self._load_import_template(import_name, - import_uri) + full_file_name, custom_type = self._load_import_template( + import_name, import_uri) namespace_prefix = None if isinstance(import_uri, dict): namespace_prefix = import_uri.get( @@ -86,13 +90,15 @@ class ImportsLoader(object): TypeValidation(custom_type, import_def) self._update_custom_def(custom_type, namespace_prefix) else: # old style of imports - custom_type = self._load_import_template(None, - import_def) + full_file_name, custom_type = self._load_import_template( + None, import_def) if custom_type: TypeValidation( custom_type, import_def) self._update_custom_def(custom_type, None) + self._update_nested_topo_tpls(full_file_name, custom_type) + def _update_custom_def(self, custom_type, namespace_prefix): outer_custom_types = {} for type_def in self.type_definition_list: @@ -112,6 +118,11 @@ class ImportsLoader(object): else: self.custom_defs.update(outer_custom_types) + def _update_nested_topo_tpls(self, full_file_name, custom_tpl): + if full_file_name and custom_tpl: + topo_tpl = {full_file_name: custom_tpl} + self.nested_topo_tpls.append(topo_tpl) + def _validate_import_keys(self, import_name, import_uri_def): if self.FILE not in import_uri_def.keys(): log.warning(_('Missing keyname "file" in import "%(name)s".') @@ -170,7 +181,7 @@ class ImportsLoader(object): return if toscaparser.utils.urlutils.UrlUtils.validate_url(file_name): - return YAML_LOADER(file_name, False) + return file_name, YAML_LOADER(file_name, False) elif not repository: import_template = None if self.path: @@ -234,7 +245,7 @@ class ImportsLoader(object): ImportError(_('Import "%s" is not valid.') % import_uri_def)) return - return YAML_LOADER(import_template, a_file) + return import_template, YAML_LOADER(import_template, a_file) if short_import_notation: log.error(_('Import "%(name)s" is not valid.') % import_uri_def) @@ -261,7 +272,7 @@ class ImportsLoader(object): return if toscaparser.utils.urlutils.UrlUtils.validate_url(full_url): - return YAML_LOADER(full_url, False) + return full_url, YAML_LOADER(full_url, False) else: msg = (_('repository url "%(n_uri)s" is not valid in import ' 'definition "%(tpl)s".') diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/subsystem.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/subsystem.yaml index b27e698..99d645b 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/subsystem.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/subsystem.yaml @@ -12,12 +12,15 @@ topology_template: inputs: mq_server_ip: type: string + required: true description: IP address of the message queuing server to receive messages from. receiver_port: type: string + required: true description: Port to be used for receiving messages. my_cpus: type: integer + default: 2 description: Number of CPUs for the server. constraints: - valid_values: [ 1, 2, 4, 8 ] diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py b/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py index 0f1a33e..cbd4e3b 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py @@ -34,6 +34,11 @@ class TopologyTemplateTest(TestCase): self.topo = TopologyTemplate(self.topo_tpl, self._get_all_custom_def()) + self.tosca_system_tpl_path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/topology_template/system.yaml") + self.system_template = ToscaTemplate(self.tosca_system_tpl_path) + def _get_custom_def(self, type_definition): custom_defs = {} for definition in self.imports: diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py b/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py index 9c2ce35..358bf28 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py @@ -189,8 +189,9 @@ class ToscaDefTest(TestCase): self.assertIn(ifaces.LIFECYCLE_SHORTNAME, root_node.interfaces) def test_artifacts(self): + self.assertEqual(artif_root_type.parent_type, None) self.assertEqual('tosca.artifacts.Root', - artif_file_type.parent_type) + artif_file_type.parent_type.type) self.assertEqual({}, artif_file_type.parent_artifacts) self.assertEqual(sorted(['tosca.artifacts.Root'], key=lambda x: str(x)), @@ -199,7 +200,7 @@ class ToscaDefTest(TestCase): key=lambda x: str(x))) self.assertEqual('tosca.artifacts.Implementation', - artif_bash_type.parent_type) + artif_bash_type.parent_type.type) self.assertEqual({'tosca.artifacts.Implementation': {'derived_from': 'tosca.artifacts.Root', 'description': @@ -213,7 +214,7 @@ class ToscaDefTest(TestCase): key=lambda x: str(x))) self.assertEqual('tosca.artifacts.Implementation', - artif_python_type.parent_type) + artif_python_type.parent_type.type) self.assertEqual({'tosca.artifacts.Implementation': {'derived_from': 'tosca.artifacts.Root', 'description': @@ -228,7 +229,7 @@ class ToscaDefTest(TestCase): key=lambda x: str(x))) self.assertEqual('tosca.artifacts.Deployment.Image', - artif_container_docker_type.parent_type) + artif_container_docker_type.parent_type.type) self.assertEqual({'tosca.artifacts.Deployment': {'derived_from': 'tosca.artifacts.Root', 'description': @@ -245,7 +246,7 @@ class ToscaDefTest(TestCase): key=lambda x: str(x))) self.assertEqual('tosca.artifacts.Deployment.Image', - artif_vm_iso_type.parent_type) + artif_vm_iso_type.parent_type.type) self.assertEqual({'tosca.artifacts.Deployment': {'derived_from': 'tosca.artifacts.Root', 'description': @@ -264,7 +265,7 @@ class ToscaDefTest(TestCase): key=lambda x: str(x))) self.assertEqual('tosca.artifacts.Deployment.Image', - artif_vm_qcow2_type.parent_type) + artif_vm_qcow2_type.parent_type.type) self.assertEqual({'tosca.artifacts.Deployment': {'derived_from': 'tosca.artifacts.Root', 'description': @@ -283,8 +284,9 @@ class ToscaDefTest(TestCase): key=lambda x: str(x))) def test_policies(self): + self.assertEqual(policy_root_type.parent_type, None) self.assertEqual('tosca.policies.Root', - policy_placement_type.parent_type) + policy_placement_type.parent_type.type) self.assertEqual({}, policy_placement_type.parent_policies) self.assertEqual(sorted(['tosca.policies.Root', 'The TOSCA Policy Type definition that is ' @@ -296,7 +298,7 @@ class ToscaDefTest(TestCase): key=lambda x: str(x))) self.assertEqual('tosca.policies.Root', - policy_scaling_type.parent_type) + policy_scaling_type.parent_type.type) self.assertEqual({}, policy_scaling_type.parent_policies) self.assertEqual(sorted(['tosca.policies.Root', 'The TOSCA Policy Type definition that is ' @@ -308,7 +310,7 @@ class ToscaDefTest(TestCase): key=lambda x: str(x))) self.assertEqual('tosca.policies.Root', - policy_update_type.parent_type) + policy_update_type.parent_type.type) self.assertEqual({}, policy_update_type.parent_policies) self.assertEqual(sorted(['tosca.policies.Root', 'The TOSCA Policy Type definition that is ' @@ -320,7 +322,7 @@ class ToscaDefTest(TestCase): key=lambda x: str(x))) self.assertEqual('tosca.policies.Root', - policy_performance_type.parent_type) + policy_performance_type.parent_type.type) self.assertEqual({}, policy_performance_type.parent_policies) self.assertEqual(sorted(['tosca.policies.Root', 'The TOSCA Policy Type definition that is ' diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py index 3fd49bf..ac55059 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py @@ -134,6 +134,19 @@ class ToscaTemplateTest(TestCase): self.assertEqual('Linux', os_props['type'].value) self.assertEqual('Linux', os_type_prop) + def test_node_inheritance_type(self): + wordpress_node = [ + node for node in self.tosca.nodetemplates + if node.name == 'wordpress'][0] + self.assertTrue( + wordpress_node.is_derived_from("tosca.nodes.WebApplication")) + self.assertTrue( + wordpress_node.is_derived_from("tosca.nodes.Root")) + self.assertFalse( + wordpress_node.is_derived_from("tosca.policies.Root")) + self.assertFalse( + wordpress_node.is_derived_from("tosca.groups.Root")) + def test_outputs(self): self.assertEqual( ['website_url'], @@ -211,6 +224,8 @@ class ToscaTemplateTest(TestCase): for key in relation.keys(): rel_tpl = relation.get(key).get_relationship_template() if rel_tpl: + self.assertTrue(rel_tpl[0].is_derived_from( + "tosca.relationships.Root")) interfaces = rel_tpl[0].interfaces for interface in interfaces: self.assertEqual(config_interface, @@ -728,5 +743,7 @@ class ToscaTemplateTest(TestCase): "data/test_tosca_custom_rel_with_script.yaml") tosca = ToscaTemplate(tosca_tpl) rel = tosca.relationship_templates[0] + self.assertEqual(rel.type, "tosca.relationships.HostedOn") + self.assertTrue(rel.is_derived_from("tosca.relationships.Root")) self.assertEqual(len(rel.interfaces), 1) self.assertEqual(rel.interfaces[0].type, "Configure") diff --git a/tosca2heat/tosca-parser/toscaparser/tosca_template.py b/tosca2heat/tosca-parser/toscaparser/tosca_template.py index ba056da..1bad6e9 100644 --- a/tosca2heat/tosca-parser/toscaparser/tosca_template.py +++ b/tosca2heat/tosca-parser/toscaparser/tosca_template.py @@ -69,6 +69,7 @@ class ToscaTemplate(object): self.input_path = None self.path = None self.tpl = None + self.nested_tosca_template = None if path: self.input_path = path self.path = self._get_path(path) @@ -177,9 +178,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_topo_tpls = custom_service.get_nested_topo_tpls() + self._handle_nested_topo_tpls(nested_topo_tpls) + + custom_defs = custom_service.get_custom_defs() if not custom_defs: return @@ -191,6 +197,14 @@ class ToscaTemplate(object): custom_defs.update(inner_custom_types) return custom_defs + def _handle_nested_topo_tpls(self, nested_topo_tpls): + for tpl in nested_topo_tpls: + if tpl.get(TOPOLOGY_TEMPLATE): + nested_tosca_template = ToscaTemplate( + path=self.path, parsed_params=self.parsed_params, + yaml_dict_tpl=nested_topo_tpls) + self.nested_tosca_template.apend(nested_tosca_template) + def _validate_field(self): version = self._tpl_version() if not version: diff --git a/tosca2heat/tosca-parser/tox.ini b/tosca2heat/tosca-parser/tox.ini index 9e5f365..d646b6e 100644 --- a/tosca2heat/tosca-parser/tox.ini +++ b/tosca2heat/tosca-parser/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.6 -envlist = py34,py27,pypy,pep8 +envlist = py34,py27,pep8 skipsdist = True [testenv] |