From 6f94614c71659aec9e8fa6826ba2b06131081913 Mon Sep 17 00:00:00 2001 From: Hiroo Kitamura Date: Tue, 26 Nov 2019 15:29:55 +0900 Subject: [PATCH] ETSI-NFV SOL 001 translation: CP,VL Currently heat-translator supports translation of TOSCA Simple Profile for YAML[1] and TOSCA Simple Profile for NFV[2] only. This commit enables to translation of the follwoing type defined in ETSI NFV-SOL 001[3]. - tosca.nodes.nfv.VduCp - tosca.nodes.nfv.VnfVirtualLink [1] http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/tosca-nfv-v1.0.html [2] http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/TOSCA-Simple-Profile-YAML-v1.0.html [3] https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/001/02.06.01_60/gs_NFV-SOL001v020601p.pdf Change-Id: I28b4ff67b74e7d5ad4264acb93cd8c292b91a0d4 Story: 2006372 Task: 37620 --- .../hot/tosca/etsi_nfv/tosca_nfv_vducp.py | 117 ++++++++++++ .../etsi_nfv/tosca_nfv_vnfvirtuallink.py | 167 ++++++++++++++++++ translator/hot/translate_node_templates.py | 15 +- .../etsi_nfv/tosca_nfv_check_cp_order.yaml | 82 +++++++++ .../tests/data/etsi_nfv/tosca_nfv_cp.yaml | 17 ++ .../tosca_nfv_cp_with_extended_vnic_type.yaml | 50 ++++++ .../etsi_nfv/tosca_nfv_non_leaf_in_vl.yaml | 24 +++ .../tests/data/etsi_nfv/tosca_nfv_vl.yaml | 30 ++++ ...osca_nfv_vl_with_unsupported_protocol.yaml | 95 ++++++++++ .../etsi_nfv/hot_nfv_check_cp_order.yaml | 45 +++++ .../data/hot_output/etsi_nfv/hot_nfv_cp.yaml | 11 ++ .../hot_nfv_cp_with_extended_vnic_type.yaml | 32 ++++ .../etsi_nfv/hot_nfv_non_leaf_in_vl.yaml | 15 ++ .../data/hot_output/etsi_nfv/hot_nfv_vl.yaml | 23 +++ .../hot_nfv_vl_with_unsupported_protocol.yaml | 38 ++++ .../tests/test_etsi_tosca_hot_translation.py | 79 +++++++++ .../tests/test_translate_node_template.py | 4 +- 17 files changed, 840 insertions(+), 4 deletions(-) create mode 100644 translator/hot/tosca/etsi_nfv/tosca_nfv_vducp.py create mode 100644 translator/hot/tosca/etsi_nfv/tosca_nfv_vnfvirtuallink.py create mode 100644 translator/tests/data/etsi_nfv/tosca_nfv_check_cp_order.yaml create mode 100644 translator/tests/data/etsi_nfv/tosca_nfv_cp.yaml create mode 100644 translator/tests/data/etsi_nfv/tosca_nfv_cp_with_extended_vnic_type.yaml create mode 100644 translator/tests/data/etsi_nfv/tosca_nfv_non_leaf_in_vl.yaml create mode 100644 translator/tests/data/etsi_nfv/tosca_nfv_vl.yaml create mode 100644 translator/tests/data/etsi_nfv/tosca_nfv_vl_with_unsupported_protocol.yaml create mode 100644 translator/tests/data/hot_output/etsi_nfv/hot_nfv_check_cp_order.yaml create mode 100644 translator/tests/data/hot_output/etsi_nfv/hot_nfv_cp.yaml create mode 100644 translator/tests/data/hot_output/etsi_nfv/hot_nfv_cp_with_extended_vnic_type.yaml create mode 100644 translator/tests/data/hot_output/etsi_nfv/hot_nfv_non_leaf_in_vl.yaml create mode 100644 translator/tests/data/hot_output/etsi_nfv/hot_nfv_vl.yaml create mode 100644 translator/tests/data/hot_output/etsi_nfv/hot_nfv_vl_with_unsupported_protocol.yaml diff --git a/translator/hot/tosca/etsi_nfv/tosca_nfv_vducp.py b/translator/hot/tosca/etsi_nfv/tosca_nfv_vducp.py new file mode 100644 index 00000000..62f4f348 --- /dev/null +++ b/translator/hot/tosca/etsi_nfv/tosca_nfv_vducp.py @@ -0,0 +1,117 @@ +# +# 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 logging + +from translator.hot.syntax.hot_resource import HotResource +log = logging.getLogger('heat-translator') + + +# Name used to dynamically load appropriate map class. +TARGET_CLASS_NAME = 'ToscaNfvVducp' +TOSCA_LINKS_TO = 'tosca.relationships.nfv.VirtualLinksTo' +TOSCA_BINDS_TO = 'tosca.relationships.nfv.VirtualBindsTo' +depends_on_set = ( + TOSCA_LINKS_TO, + TOSCA_BINDS_TO, +) + + +class ToscaNfvVducp(HotResource): + """Translate TOSCA node type tosca.nodes.nfv.VduCp.""" + + toscatype = 'tosca.nodes.nfv.VduCp' + EXTERNAL_VL = '#ADD_YOUR_NETWORK_HERE' + + def __init__(self, nodetemplate, csar_dir=None): + super(ToscaNfvVducp, self).__init__( + nodetemplate, + type='OS::Neutron::Port', + csar_dir=csar_dir) + + # Default order + self.order = 0 + + # Extract virtual_link and virtual_binding + self.virtual_link = None + self.virtual_binding = None + requirements = self.nodetemplate.requirements + for req in requirements: + if 'virtual_link' in req: + vl_val = req.get('virtual_link') + if isinstance(vl_val, dict): + self.virtual_link = vl_val.get('node') + else: + self.virtual_link = vl_val + elif 'virtual_binding' in req: + self.virtual_binding = req.get('virtual_binding') + + def _generate_networks_for_compute(self, port_resources): + '''Generate compute networks property list from the port resources.''' + networks = [] + for resource in port_resources: + networks.append({'port': '{ get_resource: %s }' % (resource.name)}) + return networks + + def _insert_sorted_resource(self, resources, resource): + '''Insert a resource in the list of resources and keep the order.''' + lo = 0 + hi = len(resources) + while lo < hi: + mid = (lo + hi) // 2 + if resource.order < resources[mid].order: + hi = mid + else: + lo = mid + 1 + resources.insert(lo, resource) + + def handle_properties(self): + tosca_props = self.get_tosca_props() + own_props = {} + + if self.virtual_link: + own_props['network'] = '{ get_resource: %s }' % ( + self.virtual_link + ) + else: + # If no virtual_binding is specified in VNFD, users + # have to input external VL given in instantiation VNF request. + own_props['network'] = '%s' % ( + self.EXTERNAL_VL + ) + + for key, value in tosca_props.items(): + if key == 'order': + self.order = value + elif key == 'vnic_type': + own_props['binding:vnic_type'] = value + + # Remove depends_on + self.remove_depends_on(depends_on_set) + + binds_to = None + for rel, node in self.nodetemplate.relationships.items(): + # Check for BindsTo relationship. If found add network to the + # network property of the corresponding compute resource + if not binds_to and rel.is_derived_from(TOSCA_BINDS_TO): + binds_to = node + for hot_resource in self.depends_on_nodes: + if binds_to.name == hot_resource.name: + port_rsrcs = hot_resource.assoc_port_resources + self._insert_sorted_resource(port_rsrcs, self) + networks = \ + self._generate_networks_for_compute(port_rsrcs) + hot_resource.properties['networks'] = networks + break + + self.properties = own_props diff --git a/translator/hot/tosca/etsi_nfv/tosca_nfv_vnfvirtuallink.py b/translator/hot/tosca/etsi_nfv/tosca_nfv_vnfvirtuallink.py new file mode 100644 index 00000000..3a4b8449 --- /dev/null +++ b/translator/hot/tosca/etsi_nfv/tosca_nfv_vnfvirtuallink.py @@ -0,0 +1,167 @@ +# +# 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 logging + +from translator.common.utils import MemoryUnit +from translator.hot.syntax.hot_resource import HotResource + +log = logging.getLogger('heat-translator') + + +# Name used to dynamically load appropriate map class. +TARGET_CLASS_NAME = 'ToscaNfvVnfVirtualLink' + + +class ToscaNfvVnfVirtualLink(HotResource): + """Translate TOSCA node type tosca.nodes.nfv.VnfVirtualLink.""" + + toscatype = 'tosca.nodes.nfv.VnfVirtualLink' + SUBNET_SUFFIX = '_subnet' + QOSPOLICY_SUFFIX = '_qospolicy' + BANDWIDTH_SUFFIX = '_bandwidth' + ip_map = { + 'ipv4': '4', + 'ipv6': '6', + } + + def __init__(self, nodetemplate, csar_dir=None): + + # Check if it is an IP network + tosca_props = {} + for prop in nodetemplate.get_properties_objects(): + tosca_props[prop.name] = prop.value + + lp = tosca_props.get('connectivity_type').get('layer_protocols') + self.ip_protocol = list(set(self.ip_map.keys()) & set(lp)) + + # Branch by IP or not + if self.ip_protocol: + super(ToscaNfvVnfVirtualLink, self).__init__( + nodetemplate, + type='OS::Neutron::Net', + csar_dir=csar_dir + ) + else: + super(ToscaNfvVnfVirtualLink, self).__init__( + nodetemplate, + csar_dir=csar_dir + ) + log.warning(('Unsupported layer_protocols, ' + 'virtual_link_name:%s, protocol_name:%s') + % (self.name, lp)) + + def handle_properties(self): + + # Branch by IP or not + if self.ip_protocol: + tosca_props = self.get_tosca_props() + own_props = {} + + self.is_leaf = False + for key, value in tosca_props.items(): + if key == 'vl_profile': + mbr = value['max_bitrate_requirements'] + if 'leaf' in mbr: + max_bps = mbr['leaf'] + # Convert to KiB + self.max_kbps = \ + max_bps / MemoryUnit.UNIT_SIZE_DICT['KiB'] + self.is_leaf = True + else: + log.warning('Can not set the required properties ' + 'max_kbps on HOT.' + 'virtual_link_name:%s' % self.name) + + if self.is_leaf: + own_props['qos_policy'] = '{ get_resource: %s%s }' % ( + self.name, + self.QOSPOLICY_SUFFIX, + ) + + self.properties = own_props + + else: + pass + + def handle_expansion(self): + hot_resources = [] + + # Branch by IP or not + if self.ip_protocol: + tosca_props = self.get_tosca_props() + + # subnet props + subnet_props = {} + subnet_props['ip_version'] = self.ip_map.get(self.ip_protocol[0]) + subnet_props['network'] = '{ get_resource: %s }' % (self.name) + + for key, value in tosca_props.items(): + if key == 'vl_profile': + if 'virtual_link_protocol_data' in value: + vlpd = value['virtual_link_protocol_data'] + if 'l3_protocol_data' in vlpd[0]: + l3pd = vlpd[0]['l3_protocol_data'] + subnet_props['cidr'] = l3pd['cidr'] + + subnet_resource_name = self.name + self.SUBNET_SUFFIX + + hot_resources.append( + HotResource( + self.nodetemplate, + type='OS::Neutron::Subnet', + name=subnet_resource_name, + properties=subnet_props, + ) + ) + + # qospolicy_props props + qospolicy_props = {} + + qospolicy_resource_name = self.name + self.QOSPOLICY_SUFFIX + + # bandwidth props + bandwidth_props = {} + bandwidth_props['policy'] = '{ get_resource: %s%s }' % ( + self.name, + self.QOSPOLICY_SUFFIX, + ) + + bandwidth_resource_name = self.name + self.BANDWIDTH_SUFFIX + + # Create QoSPolicy and QoSBandwidthLimitRule resources + # only when max_bitrate_requirements has leaf property. + if self.is_leaf: + hot_resources.append( + HotResource( + self.nodetemplate, + type='OS::Neutron::QoSPolicy', + name=qospolicy_resource_name, + properties=qospolicy_props, + ) + ) + + bandwidth_props['max_kbps'] = self.max_kbps + hot_resources.append( + HotResource( + self.nodetemplate, + type='OS::Neutron::QoSBandwidthLimitRule', + name=bandwidth_resource_name, + properties=bandwidth_props, + ) + ) + + else: + pass + + return hot_resources diff --git a/translator/hot/translate_node_templates.py b/translator/hot/translate_node_templates.py index cc13d67a..49080752 100644 --- a/translator/hot/translate_node_templates.py +++ b/translator/hot/translate_node_templates.py @@ -218,9 +218,7 @@ class TranslateNodeTemplates(object): suffix = 0 # Copy the TOSCA graph: nodetemplate for node in self.nodetemplates: - base_type = HotResource.get_base_type_str(node.type_definition) - if base_type not in TOSCA_TO_HOT_TYPE: - raise UnsupportedTypeError(type=_('%s') % base_type) + base_type = self._get_supported_type(node) hot_node = TOSCA_TO_HOT_TYPE[base_type](node, csar_dir=self.csar_dir) self.hot_resources.append(hot_node) @@ -408,6 +406,17 @@ class TranslateNodeTemplates(object): return self.hot_resources + def _get_supported_type(self, original_node): + # trace parent types until finding a supported type + node = original_node + node_type = original_node.type + while node_type not in TOSCA_TO_HOT_TYPE: + node = node.parent_type + if node is None: + raise UnsupportedTypeError(type=_('%s') % original_node.type) + node_type = node.type + return node_type + def translate_param_value(self, param_value, resource): tosca_template = None if resource: diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_check_cp_order.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_check_cp_order.yaml new file mode 100644 index 00000000..04dbcfca --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_check_cp_order.yaml @@ -0,0 +1,82 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for deploying one VDU and four CP, + and check CP's order. + CP3 -> CP2 -> CP4 -> CP1 + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +topology_template: + node_templates: + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU1 + description: VDU1 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + sw_image_data: + name: Software of VDU1 + version: '0.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + container_format: bare + disk_format: qcow2 + min_disk: 1 GiB + size: 1 GiB + + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: Files/images/cirros-0.4.0-x86_64-disk.img + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MiB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GiB + + CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 3 + vnic_type: direct-physical + requirements: + - virtual_binding: VDU1 + + CP2: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 1 + vnic_type: direct-physical + requirements: + - virtual_binding: VDU1 + + CP3: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + vnic_type: direct-physical + requirements: + - virtual_binding: VDU1 + + CP4: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 2 + vnic_type: direct-physical + requirements: + - virtual_binding: VDU1 diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_cp.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_cp.yaml new file mode 100644 index 00000000..0ebabd2a --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_cp.yaml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for deploying one CP. + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +topology_template: + node_templates: + CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + vnic_type: direct-physical diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_cp_with_extended_vnic_type.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_cp_with_extended_vnic_type.yaml new file mode 100644 index 00000000..6e177481 --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_cp_with_extended_vnic_type.yaml @@ -0,0 +1,50 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for deploying CPs, + with several vnic_types. + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +node_types: + custom.VduCp: + derived_from: tosca.nodes.nfv.VduCp + properties: + vnic_type: + type: string + constraints: + - valid_values: [ normal, virtio, direct-physical, direct, macvtap, baremetal ] + +topology_template: + node_templates: + CP1: + type: custom.VduCp + properties: + layer_protocols: [ ipv4 ] + vnic_type: direct-physical + + CP2: + type: custom.VduCp + properties: + layer_protocols: [ ipv4 ] + vnic_type: normal + + CP3: + type: custom.VduCp + properties: + layer_protocols: [ ipv4 ] + vnic_type: direct + + CP4: + type: custom.VduCp + properties: + layer_protocols: [ ipv4 ] + vnic_type: macvtap + + CP5: + type: custom.VduCp + properties: + layer_protocols: [ ipv4 ] + vnic_type: baremetal diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_non_leaf_in_vl.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_non_leaf_in_vl.yaml new file mode 100644 index 00000000..217352b9 --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_non_leaf_in_vl.yaml @@ -0,0 +1,24 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for deploying one VirtualLink, + and omit non required properties + which are required in HOT. + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +node_types: +topology_template: + node_templates: + VL1: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv4 ] + vl_profile: + max_bitrate_requirements: + root: 1048576 + min_bitrate_requirements: + root: 1048576 diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_vl.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_vl.yaml new file mode 100644 index 00000000..fedfcdb8 --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_vl.yaml @@ -0,0 +1,30 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for deploying one VirtualLink. + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +node_types: +topology_template: + node_templates: + VL1: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv4 ] + description: Internal Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + virtual_link_protocol_data: + - associated_layer_protocol: ipv4 + l3_protocol_data: + ip_version: ipv4 + cidr: 11.11.0.0/24 diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_vl_with_unsupported_protocol.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_vl_with_unsupported_protocol.yaml new file mode 100644 index 00000000..128349fd --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_vl_with_unsupported_protocol.yaml @@ -0,0 +1,95 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for VirtualLink with unsupported layer_protocols. + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +node_types: +topology_template: + node_templates: + VL1: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv4 ] + description: Internal Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + + VL2: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv6 ] + description: Internal Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + + VL3: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ethernet ] + description: Internal Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + + VL4: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ mpls ] + description: Internal Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + + VL5: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ odu2 ] + description: Internal Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + + VL6: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ pseudo-wire ] + description: Internal Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 diff --git a/translator/tests/data/hot_output/etsi_nfv/hot_nfv_check_cp_order.yaml b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_check_cp_order.yaml new file mode 100644 index 00000000..fba10f81 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_check_cp_order.yaml @@ -0,0 +1,45 @@ +heat_template_version: 2013-05-23 +description: > + Template for deploying one VDU and four CP, + and check CP's order. + CP3 -> CP2 -> CP4 -> CP1 +parameters: {} +resources: + CP1: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct-physical + CP2: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct-physical + CP3: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct-physical + CP4: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct-physical + VDU1: + type: OS::Nova::Server + properties: + flavor: { get_resource: VDU1_flavor } + name: VDU1 + image: #ADD_YOUR_IMAGE_HERE + networks: + - port: { get_resource: CP3 } + - port: { get_resource: CP2 } + - port: { get_resource: CP4 } + - port: { get_resource: CP1 } + VDU1_flavor: + type: OS::Nova::Flavor + properties: + ram: 512 + vcpus: 1 + disk: 1 +outputs: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/hot_nfv_cp.yaml b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_cp.yaml new file mode 100644 index 00000000..abb99600 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_cp.yaml @@ -0,0 +1,11 @@ +heat_template_version: 2013-05-23 +description: > + Template for deploying one CP. +parameters: {} +resources: + CP1: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct-physical +outputs: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/hot_nfv_cp_with_extended_vnic_type.yaml b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_cp_with_extended_vnic_type.yaml new file mode 100644 index 00000000..de39338f --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_cp_with_extended_vnic_type.yaml @@ -0,0 +1,32 @@ +heat_template_version: 2013-05-23 +description: > + Template for deploying CPs, + with several vnic_types. +parameters: {} +resources: + CP1: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct-physical + CP2: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: normal + CP3: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct + CP4: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: macvtap + CP5: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: baremetal +outputs: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/hot_nfv_non_leaf_in_vl.yaml b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_non_leaf_in_vl.yaml new file mode 100644 index 00000000..8b93b543 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_non_leaf_in_vl.yaml @@ -0,0 +1,15 @@ +heat_template_version: 2013-05-23 +description: > + Template for deploying one VirtualLink, + and omit non required properties + which are required in HOT. +parameters: {} +resources: + VL1: + type: OS::Neutron::Net + VL1_subnet: + type: OS::Neutron::Subnet + properties: + network: { get_resource: VL1 } + ip_version: 4 +outputs: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/hot_nfv_vl.yaml b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_vl.yaml new file mode 100644 index 00000000..6e84d108 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_vl.yaml @@ -0,0 +1,23 @@ +heat_template_version: 2013-05-23 +description: > + Template for deploying one VirtualLink. +parameters: {} +resources: + VL1: + type: OS::Neutron::Net + properties: + qos_policy: { get_resource: VL1_qospolicy } + VL1_subnet: + type: OS::Neutron::Subnet + properties: + network: { get_resource: VL1 } + ip_version: 4 + cidr: 11.11.0.0/24 + VL1_bandwidth: + type: OS::Neutron::QoSBandwidthLimitRule + properties: + max_kbps: 1024 + policy: { get_resource: VL1_qospolicy } + VL1_qospolicy: + type: OS::Neutron::QoSPolicy +outputs: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/hot_nfv_vl_with_unsupported_protocol.yaml b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_vl_with_unsupported_protocol.yaml new file mode 100644 index 00000000..8f7fbd52 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/hot_nfv_vl_with_unsupported_protocol.yaml @@ -0,0 +1,38 @@ +heat_template_version: 2013-05-23 +description: > + Template for VirtualLink with unsupported layer_protocols. +parameters: {} +resources: + VL1: + type: OS::Neutron::Net + properties: + qos_policy: { get_resource: VL1_qospolicy } + VL1_subnet: + type: OS::Neutron::Subnet + properties: + network: { get_resource: VL1 } + ip_version: 4 + VL1_bandwidth: + type: OS::Neutron::QoSBandwidthLimitRule + properties: + max_kbps: 1024 + policy: { get_resource: VL1_qospolicy } + VL1_qospolicy: + type: OS::Neutron::QoSPolicy + VL2: + type: OS::Neutron::Net + properties: + qos_policy: { get_resource: VL2_qospolicy } + VL2_subnet: + type: OS::Neutron::Subnet + properties: + network: { get_resource: VL2 } + ip_version: 6 + VL2_bandwidth: + type: OS::Neutron::QoSBandwidthLimitRule + properties: + max_kbps: 1024 + policy: { get_resource: VL2_qospolicy } + VL2_qospolicy: + type: OS::Neutron::QoSPolicy +outputs: {} diff --git a/translator/tests/test_etsi_tosca_hot_translation.py b/translator/tests/test_etsi_tosca_hot_translation.py index 2baf0f68..81134613 100644 --- a/translator/tests/test_etsi_tosca_hot_translation.py +++ b/translator/tests/test_etsi_tosca_hot_translation.py @@ -112,3 +112,82 @@ class EtsiToscaHotTranslationTest(TestCase): expected_msg, self.log_fixture.output ) + + def test_hot_translate_etsi_nfv_cp(self): + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_cp.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'hot_nfv_cp.yaml', + ] + self._test_successful_translation(tosca_file, hot_files, params={}) + + def test_hot_translate_etsi_nfv_cp_with_extended_vnic_type(self): + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_cp_with_extended_vnic_type.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'hot_nfv_cp_with_extended_vnic_type.yaml', + ] + self._test_successful_translation(tosca_file, hot_files, params={}) + + def test_hot_translate_etsi_nfv_check_cp_order(self): + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_check_cp_order.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'hot_nfv_check_cp_order.yaml', + ] + self._test_successful_translation(tosca_file, hot_files, params={}) + + def test_hot_translate_etsi_nfv_vl(self): + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_vl.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'hot_nfv_vl.yaml', + ] + self._test_successful_translation(tosca_file, hot_files, params={}) + + def test_hot_translate_etsi_nfv_vl_with_unsupported_protocol(self): + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_vl_with_unsupported_protocol.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'hot_nfv_vl_with_unsupported_protocol.yaml', + ] + expected_msgs = ( + 'Unsupported layer_protocols, virtual_link_name:VL3, ' + 'protocol_name:[\'ethernet\']', + 'Unsupported layer_protocols, virtual_link_name:VL4, ' + 'protocol_name:[\'mpls\']', + 'Unsupported layer_protocols, virtual_link_name:VL5, ' + 'protocol_name:[\'odu2\']', + 'Unsupported layer_protocols, virtual_link_name:VL6, ' + 'protocol_name:[\'pseudo-wire\']' + ) + self._test_successful_translation(tosca_file, hot_files, params={}) + for expected_msg in expected_msgs: + self.assertIn( + expected_msg, + self.log_fixture.output + ) + + def test_hot_translate_etsi_nfv_non_leaf_in_vl(self): + vl_name = 'VL1' + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_non_leaf_in_vl.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'hot_nfv_non_leaf_in_vl.yaml', + ] + expected_msgs = ( + 'Can not set the required properties ' + 'max_kbps on HOT.' + 'virtual_link_name:%s' % vl_name,) + self._test_successful_translation(tosca_file, hot_files, params={}) + for expected_msg in expected_msgs: + self.assertIn( + expected_msg, + self.log_fixture.output + ) diff --git a/translator/tests/test_translate_node_template.py b/translator/tests/test_translate_node_template.py index 08df1771..42f68ea7 100644 --- a/translator/tests/test_translate_node_template.py +++ b/translator/tests/test_translate_node_template.py @@ -36,7 +36,9 @@ class TranslateNodeTemplatesTest(TestCase): 'tosca.policies.Scaling', 'tosca.policies.Scaling.Cluster', 'tosca.nodes.nfv.VNF', - 'tosca.nodes.nfv.Vdu.Compute' + 'tosca.nodes.nfv.Vdu.Compute', + 'tosca.nodes.nfv.VduCp', + 'tosca.nodes.nfv.VnfVirtualLink' ] actual_type_list = list(_generate_type_map())