From ccb79934ec436fc5ccc12438841e6a561fa3bff7 Mon Sep 17 00:00:00 2001 From: Bharath Thiruveedula Date: Sun, 21 Aug 2016 14:34:38 +0530 Subject: [PATCH] Implement VNFC support Change-Id: Ib3be5c8c19b17bac4add76c0210c1ec7af3d99ac implements-blueprint: vnf-components-support Co-Authored-By: Manikantha Srinivas Tadi --- .../devref/vnf_component_usage_guide.rst | 57 +++++++++ doc/source/index.rst | 1 + ...rt-to-tosca-template-f8e34334ba823f34.yaml | 8 ++ .../tosca-templates/vnfd/test_tosca_vnfc.yaml | 40 +++++++ .../test_tosca_vnfc_multiple_servers.yaml | 63 ++++++++++ tacker/tests/constants.py | 1 + tacker/tests/etc/samples/install_vnfc.sh | 2 + .../tests/etc/samples/sample_tosca_vnfc.yaml | 42 +++++++ .../tests/functional/vnfm/test_tosca_vnfc.py | 110 ++++++++++++++++++ .../openstack/data/hot_tosca_vnfc.yaml | 36 ++++++ .../openstack/data/test_tosca_vnfc.yaml | 39 +++++++ .../vnfm/infra_drivers/openstack/openstack.py | 2 +- tacker/vnfm/tosca/lib/tacker_nfv_defs.yaml | 6 + tacker/vnfm/tosca/utils.py | 8 ++ 14 files changed, 414 insertions(+), 1 deletion(-) create mode 100644 doc/source/devref/vnf_component_usage_guide.rst create mode 100644 releasenotes/notes/add-vnfc-support-to-tosca-template-f8e34334ba823f34.yaml create mode 100644 samples/tosca-templates/vnfd/test_tosca_vnfc.yaml create mode 100644 samples/tosca-templates/vnfd/test_tosca_vnfc_multiple_servers.yaml create mode 100644 tacker/tests/etc/samples/install_vnfc.sh create mode 100644 tacker/tests/etc/samples/sample_tosca_vnfc.yaml create mode 100644 tacker/tests/functional/vnfm/test_tosca_vnfc.py create mode 100644 tacker/tests/unit/vm/infra_drivers/openstack/data/hot_tosca_vnfc.yaml create mode 100644 tacker/tests/unit/vm/infra_drivers/openstack/data/test_tosca_vnfc.yaml diff --git a/doc/source/devref/vnf_component_usage_guide.rst b/doc/source/devref/vnf_component_usage_guide.rst new file mode 100644 index 000000000..34627c419 --- /dev/null +++ b/doc/source/devref/vnf_component_usage_guide.rst @@ -0,0 +1,57 @@ +======================== +VNF Component in Tacker +======================== + +This section will cover how to deploy `vnf component` in Tacker with the +examples of how to write VNF descriptors. + + +Sample TOSCA with vnfc +======================= + +The following example shows vnfc resource using TOSCA template. +The target (VDU1) of the 'firewall_vnfc' in this example need to be +described firstly like other TOSCA templates in Tacker. + +.. code-block:: yaml + + topology_template: + node_templates: + firewall_vnfc: + type: tosca.nodes.nfv.VNFC.Tacker + requirements: + - host: VDU1 + interfaces: + Standard: + create: install_vnfc.sh + +Every vnfc node must be of type 'tosca.nodes.nfv.VNFC.Tacker'. It takes +two parameters: + +1) requirements: This node will accept list of hosts on which VNFC has to be + installed. +2) interfaces: This node will accept the absolute path of shell script to be run + on the VDUs. This shell script should reside in the machine where tacker + server is running. + + +How to setup environment +~~~~~~~~~~~~~~~~~~~~~~~~~ +To make use of VNFC in Tacker, we have to upload the image to the glance in +which heat-config and heat-config agents are installed. The installation steps +can be referred `here `_. + +Currently VNFC feature works by using `heat software config `_ which +makes use of heat API. + +So the glance images which has heat-config agents installed are only to be +passed to VDU. + +Known Limitations +~~~~~~~~~~~~~~~~~ +1) Only one VNFC is supported for one VDU. Multiple VNFC per VDU will + be introduced in future. +2) The shell script for vnfc has to be placed in the machine where tacker + server is running. diff --git a/doc/source/index.rst b/doc/source/index.rst index a60a38b68..5c1341a4e 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -61,6 +61,7 @@ Feature Documentation devref/vnffgd_template_description.rst devref/vnffg_usage_guide.rst devref/nsd_usage_guide.rst + devref/vnf_component_usage_guide.rst API Documentation ================= diff --git a/releasenotes/notes/add-vnfc-support-to-tosca-template-f8e34334ba823f34.yaml b/releasenotes/notes/add-vnfc-support-to-tosca-template-f8e34334ba823f34.yaml new file mode 100644 index 000000000..ab3c23097 --- /dev/null +++ b/releasenotes/notes/add-vnfc-support-to-tosca-template-f8e34334ba823f34.yaml @@ -0,0 +1,8 @@ +--- +features: + - Add support to pass shell script to install VNF + components in the tosca template +other: + - Only one VNFC is supported for one VDU. Multiple VNFC per VDU will + be introduced in future. + - The shell script for vnfc has to be placed in the machine where tacker server is running diff --git a/samples/tosca-templates/vnfd/test_tosca_vnfc.yaml b/samples/tosca-templates/vnfd/test_tosca_vnfc.yaml new file mode 100644 index 000000000..87828fe22 --- /dev/null +++ b/samples/tosca-templates/vnfd/test_tosca_vnfc.yaml @@ -0,0 +1,40 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 +metadata: + template_name: sample-tosca-vnfd-for-vnfc + +topology_template: + node_templates: + firewall_vnfc: + type: tosca.nodes.nfv.VNFC.Tacker + requirements: + - host: VDU1 + interfaces: + Standard: + create: install_vnfc.sh + + VDU1: + type: tosca.nodes.nfv.VDU.Tacker + properties: + image: fedora-software-config + flavor: m1.small + mgmt_driver: noop + key_name: stack_key + config: | + param0: key1 + param1: key2 + + CP1: + type: tosca.nodes.nfv.CP.Tacker + properties: + management: true + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL1 + - virtualBinding: + node: VDU1 + VL1: + type: tosca.nodes.nfv.VL + properties: + network_name: net1 + vendor: Tacker diff --git a/samples/tosca-templates/vnfd/test_tosca_vnfc_multiple_servers.yaml b/samples/tosca-templates/vnfd/test_tosca_vnfc_multiple_servers.yaml new file mode 100644 index 000000000..161177e97 --- /dev/null +++ b/samples/tosca-templates/vnfd/test_tosca_vnfc_multiple_servers.yaml @@ -0,0 +1,63 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 +metadata: + template_name: sample-tosca-vnfd-for-vnfc + +topology_template: + node_templates: + firewall_vnfc: + type: tosca.nodes.nfv.VNFC.Tacker + requirements: + - host: VDU1 + - host: VDU2 + interfaces: + Standard: + create: /home/bharatht/install_vnfc.sh + + VDU1: + type: tosca.nodes.nfv.VDU.Tacker + properties: + image: fedora-software-config + flavor: m1.small + mgmt_driver: noop + key_name: stack_key + config: | + param0: key1 + param1: key2 + + CP1: + type: tosca.nodes.nfv.CP.Tacker + properties: + management: true + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL1 + - virtualBinding: + node: VDU1 + VDU2: + type: tosca.nodes.nfv.VDU.Tacker + properties: + image: fedora-software-config + flavor: m1.small + mgmt_driver: noop + key_name: stack_key + config: | + param0: key1 + param1: key2 + + CP2: + type: tosca.nodes.nfv.CP.Tacker + properties: + management: true + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL1 + - virtualBinding: + node: VDU2 + + VL1: + type: tosca.nodes.nfv.VL + properties: + network_name: private + vendor: Tacker diff --git a/tacker/tests/constants.py b/tacker/tests/constants.py index 5de4cfef2..e907f6017 100644 --- a/tacker/tests/constants.py +++ b/tacker/tests/constants.py @@ -13,6 +13,7 @@ POLICY_ALARMING = 'tosca.policies.tacker.Alarming' DEFAULT_ALARM_ACTIONS = ['respawn', 'log', 'log_and_kill', 'notify'] VNF_CIRROS_CREATE_TIMEOUT = 300 +VNFC_CREATE_TIMEOUT = 600 VNF_CIRROS_DELETE_TIMEOUT = 300 VNF_CIRROS_DEAD_TIMEOUT = 250 ACTIVE_SLEEP_TIME = 3 diff --git a/tacker/tests/etc/samples/install_vnfc.sh b/tacker/tests/etc/samples/install_vnfc.sh new file mode 100644 index 000000000..250f3679e --- /dev/null +++ b/tacker/tests/etc/samples/install_vnfc.sh @@ -0,0 +1,2 @@ +#!/bin/sh +echo "Successfully installed VNFC" > /tacker diff --git a/tacker/tests/etc/samples/sample_tosca_vnfc.yaml b/tacker/tests/etc/samples/sample_tosca_vnfc.yaml new file mode 100644 index 000000000..daa9695dc --- /dev/null +++ b/tacker/tests/etc/samples/sample_tosca_vnfc.yaml @@ -0,0 +1,42 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 +metadata: + template_name: sample-tosca-vnfd-for-vnfc + +topology_template: + node_templates: + firewall_vnfc: + type: tosca.nodes.nfv.VNFC.Tacker + requirements: + - host: VDU1 + interfaces: + Standard: + create: install_vnfc.sh + + VDU1: + type: tosca.nodes.nfv.VDU.Tacker + properties: + flavor: m1.small + mgmt_driver: noop + config: | + param0: key1 + param1: key2 + artifacts: + fedora: + type: tosca.artifacts.Deployment.Image.VM + file: https://github.com/bharaththiruveedula/dotfiles/raw/master/fedora-sw.qcow2 + CP1: + type: tosca.nodes.nfv.CP.Tacker + properties: + management: true + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL1 + - virtualBinding: + node: VDU1 + + VL1: + type: tosca.nodes.nfv.VL + properties: + network_name: private + vendor: Tacker diff --git a/tacker/tests/functional/vnfm/test_tosca_vnfc.py b/tacker/tests/functional/vnfm/test_tosca_vnfc.py new file mode 100644 index 000000000..99ffe9159 --- /dev/null +++ b/tacker/tests/functional/vnfm/test_tosca_vnfc.py @@ -0,0 +1,110 @@ +# 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 oslo_config import cfg +from toscaparser import tosca_template +import yaml + +from tacker.common import utils +from tacker.plugins.common import constants as evt_constants +from tacker.tests import constants +from tacker.tests.functional import base +from tacker.tests.utils import read_file +from tacker.vnfm.tosca import utils as toscautils + +CONF = cfg.CONF +SOFTWARE_DEPLOYMENT = 'OS::Heat::SoftwareDeployment' + + +class VnfTestToscaVNFC(base.BaseTackerTest): + def test_create_delete_tosca_vnfc(self): + input_yaml = read_file('sample_tosca_vnfc.yaml') + tosca_dict = yaml.safe_load(input_yaml) + path = os.path.abspath(os.path.join( + os.path.dirname(__file__), "../../etc/samples")) + vnfd_name = 'sample-tosca-vnfc' + tosca_dict['topology_template']['node_templates' + ]['firewall_vnfc' + ]['interfaces' + ]['Standard']['create'] = path \ + + '/install_vnfc.sh' + tosca_arg = {'vnfd': {'name': vnfd_name, + 'attributes': {'vnfd': tosca_dict}}} + + # Create vnfd with tosca template + vnfd_instance = self.client.create_vnfd(body=tosca_arg) + self.assertIsNotNone(vnfd_instance) + + # Create vnf with vnfd_id + vnfd_id = vnfd_instance['vnfd']['id'] + vnf_arg = {'vnf': {'vnfd_id': vnfd_id, 'name': + "test_tosca_vnfc"}} + vnf_instance = self.client.create_vnf(body=vnf_arg) + + vnf_id = vnf_instance['vnf']['id'] + self.wait_until_vnf_active(vnf_id, + constants.VNFC_CREATE_TIMEOUT, + constants.ACTIVE_SLEEP_TIME) + self.assertEqual('ACTIVE', + self.client.show_vnf(vnf_id)['vnf']['status']) + self.validate_vnf_instance(vnfd_instance, vnf_instance) + + self.verify_vnf_crud_events( + vnf_id, evt_constants.RES_EVT_CREATE, evt_constants.PENDING_CREATE, + cnt=2) + self.verify_vnf_crud_events( + vnf_id, evt_constants.RES_EVT_CREATE, evt_constants.ACTIVE) + + # Validate mgmt_url with input yaml file + mgmt_url = self.client.show_vnf(vnf_id)['vnf']['mgmt_url'] + self.assertIsNotNone(mgmt_url) + mgmt_dict = yaml.load(str(mgmt_url)) + + input_dict = yaml.load(input_yaml) + toscautils.updateimports(input_dict) + + tosca = tosca_template.ToscaTemplate(parsed_params={}, a_file=False, + yaml_dict_tpl=input_dict) + + vdus = toscautils.findvdus(tosca) + + self.assertEqual(len(vdus), len(mgmt_dict.keys())) + for vdu in vdus: + self.assertIsNotNone(mgmt_dict[vdu.name]) + self.assertEqual(True, utils.is_valid_ipv4(mgmt_dict[vdu.name])) + + # Check the status of SoftwareDeployment + heat_stack_id = self.client.show_vnf(vnf_id)['vnf']['instance_id'] + resource_types = self.h_client.resources + resources = resource_types.list(stack_id=heat_stack_id) + for resource in resources: + resource = resource.to_dict() + if resource['resource_type'] == \ + SOFTWARE_DEPLOYMENT: + self.assertEqual('CREATE_COMPLETE', + resource['resource_status']) + break + + # Delete vnf_instance with vnf_id + try: + self.client.delete_vnf(vnf_id) + except Exception: + assert False, "vnf Delete of test_vnf_with_multiple_vdus failed" + + self.wait_until_vnf_delete(vnf_id, + constants.VNF_CIRROS_DELETE_TIMEOUT) + self.verify_vnf_crud_events(vnf_id, evt_constants.RES_EVT_DELETE, + evt_constants.PENDING_DELETE, cnt=2) + + # Delete vnfd_instance + self.addCleanup(self.client.delete_vnfd, vnfd_id) diff --git a/tacker/tests/unit/vm/infra_drivers/openstack/data/hot_tosca_vnfc.yaml b/tacker/tests/unit/vm/infra_drivers/openstack/data/hot_tosca_vnfc.yaml new file mode 100644 index 000000000..027396a88 --- /dev/null +++ b/tacker/tests/unit/vm/infra_drivers/openstack/data/hot_tosca_vnfc.yaml @@ -0,0 +1,36 @@ +heat_template_version: 2013-05-23 +parameters: {} +resources: + VDU1: + type: OS::Nova::Server + properties: + config_drive: false + flavor: m1.small + image: Fedora + networks: + - port: + get_resource: CP1 + user_data_format: SOFTWARE_CONFIG + CP1: + type: OS::Neutron::Port + properties: + network: existing_network_1 + port_security_enabled: false + firewall_vnfc_create_config: + type: OS::Heat::SoftwareConfig + properties: + config: 'echo "Test case for Tacker";' + group: script + firewall_vnfc_create_deploy: + type: OS::Heat::SoftwareDeployment + properties: + config: {get_resource: firewall_vnfc_create_config} + server: {get_resource: VDU1} + depends_on: + - VDU1 + +outputs: + mgmt_ip-VDU1: + value: + get_attr: [CP1, fixed_ips, 0, ip_address] + diff --git a/tacker/tests/unit/vm/infra_drivers/openstack/data/test_tosca_vnfc.yaml b/tacker/tests/unit/vm/infra_drivers/openstack/data/test_tosca_vnfc.yaml new file mode 100644 index 000000000..c1f628053 --- /dev/null +++ b/tacker/tests/unit/vm/infra_drivers/openstack/data/test_tosca_vnfc.yaml @@ -0,0 +1,39 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 +metadata: + template_name: sample-tosca-vnfd-for-vnfc + +topology_template: + node_templates: + firewall_vnfc: + type: tosca.nodes.nfv.VNFC.Tacker + requirements: + - host: VDU1 + interfaces: + Standard: + create: install_vnfc.sh + + VDU1: + type: tosca.nodes.nfv.VDU.Tacker + properties: + image: Fedora + flavor: m1.small + mgmt_driver: noop + config: | + param0: key1 + param1: key2 + + CP1: + type: tosca.nodes.nfv.CP.Tacker + properties: + management: true + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL1 + - virtualBinding: + node: VDU1 + VL1: + type: tosca.nodes.nfv.VL + properties: + network_name: net1 + vendor: Tacker diff --git a/tacker/vnfm/infra_drivers/openstack/openstack.py b/tacker/vnfm/infra_drivers/openstack/openstack.py index a53d747a0..be91dde99 100644 --- a/tacker/vnfm/infra_drivers/openstack/openstack.py +++ b/tacker/vnfm/infra_drivers/openstack/openstack.py @@ -39,7 +39,7 @@ OPTS = [ help=_("Number of attempts to retry for stack" " creation/deletion")), cfg.IntOpt('stack_retry_wait', - default=5, + default=10, help=_("Wait time (in seconds) between consecutive stack" " create/delete retries")), ] diff --git a/tacker/vnfm/tosca/lib/tacker_nfv_defs.yaml b/tacker/vnfm/tosca/lib/tacker_nfv_defs.yaml index 48f2d7787..346d4499d 100644 --- a/tacker/vnfm/tosca/lib/tacker_nfv_defs.yaml +++ b/tacker/vnfm/tosca/lib/tacker_nfv_defs.yaml @@ -257,3 +257,9 @@ node_types: required: true entry_schema: type: tosca.nfv.datatypes.pathType + tosca.nodes.nfv.VNFC.Tacker: + derived_from: tosca.nodes.SoftwareComponent + requirements: + - host: + node: tosca.nodes.nfv.VDU.Tacker + relationship: tosca.relationships.HostedOn diff --git a/tacker/vnfm/tosca/utils.py b/tacker/vnfm/tosca/utils.py index 24461f47d..b9d8f695f 100644 --- a/tacker/vnfm/tosca/utils.py +++ b/tacker/vnfm/tosca/utils.py @@ -35,6 +35,7 @@ TACKERVDU = 'tosca.nodes.nfv.VDU.Tacker' TOSCA_BINDS_TO = 'tosca.relationships.network.BindsTo' VDU = 'tosca.nodes.nfv.VDU' IMAGE = 'tosca.artifacts.Deployment.Image.VM' +HEAT_SOFTWARE_CONFIG = 'OS::Heat::SoftwareConfig' OS_RESOURCES = { 'flavor': 'get_flavor_dict', 'image': 'get_image_dict' @@ -254,6 +255,13 @@ def post_process_heat_template(heat_tpl, mgmt_ports, metadata, metadata_dict add_resources_tpl(heat_dict, res_tpl) + for res in heat_dict["resources"].values(): + if not res['type'] == HEAT_SOFTWARE_CONFIG: + continue + config = res["properties"]["config"] + if 'get_file' in config: + res["properties"]["config"] = open(config["get_file"]).read() + if unsupported_res_prop: convert_unsupported_res_prop(heat_dict, unsupported_res_prop) return yaml.dump(heat_dict)