From e8418071bf3fb4555bd546c21b010d6c855357e6 Mon Sep 17 00:00:00 2001 From: Sripriya Date: Thu, 25 Aug 2016 15:11:01 -0700 Subject: [PATCH] modify vnfd, param & config attr. to dict objects vnfd templates, parameter and config files are sent as yaml strings in requests body to tacker server. Change the attributes to dictionary objects. New behavior is applicable to tosca templates only. Also, this change may mangle the order of nodes in tosca templates. In order to address this concern and preserve the network interfaces order in these nodes, there will be follow on patch to address this. Change-Id: I05a1d60dc643dca864aff559f37491914b1fcfc3 Partial-Bug: #1591361 --- tacker/common/utils.py | 7 +++ .../tests/functional/vnfm/test_tosca_vnf.py | 22 ++++----- .../vnfm/test_tosca_vnf_multiple_vdu.py | 6 +-- .../tests/functional/vnfm/test_tosca_vnfd.py | 8 ++-- .../tests/functional/vnfm/test_vnfm_param.py | 48 +++++++++++-------- tacker/tests/unit/db/utils.py | 3 +- tacker/vm/plugin.py | 45 ++++++++++++++++- 7 files changed, 98 insertions(+), 41 deletions(-) diff --git a/tacker/common/utils.py b/tacker/common/utils.py index 97f2c7edf..bff05f592 100644 --- a/tacker/common/utils.py +++ b/tacker/common/utils.py @@ -35,6 +35,7 @@ import netaddr from oslo_concurrency import lockutils from oslo_config import cfg from oslo_log import log as logging +from oslo_log import versionutils from oslo_utils import importutils from six import iteritems from stevedore import driver @@ -391,3 +392,9 @@ def deep_update(orig_dict, new_dict): continue orig_dict[key] = value + + +def deprecate_warning(what, as_of, in_favor_of=None, remove_in=1): + versionutils.deprecation_warning(as_of=as_of, what=what, + in_favor_of=in_favor_of, + remove_in=remove_in) diff --git a/tacker/tests/functional/vnfm/test_tosca_vnf.py b/tacker/tests/functional/vnfm/test_tosca_vnf.py index b58b1a995..eae87dbcf 100644 --- a/tacker/tests/functional/vnfm/test_tosca_vnf.py +++ b/tacker/tests/functional/vnfm/test_tosca_vnf.py @@ -14,6 +14,7 @@ from novaclient import exceptions from oslo_config import cfg +import yaml from tacker.tests import constants from tacker.tests.functional import base @@ -26,12 +27,11 @@ VNF_CIRROS_CREATE_TIMEOUT = 120 class VnfTestToscaCreate(base.BaseTackerTest): def test_create_delete_vnf_tosca_no_monitoring(self): - data = dict() - data['tosca'] = read_file('sample-tosca-vnfd.yaml') + input_yaml = read_file('sample-tosca-vnfd.yaml') vnfd_name = 'test_tosca_vnf_with_cirros_no_monitoring' - toscal = data['tosca'] + tosca_dict = yaml.safe_load(input_yaml) tosca_arg = {'vnfd': {'name': vnfd_name, - 'attributes': {'vnfd': toscal}}} + 'attributes': {'vnfd': tosca_dict}}} # Create vnfd with tosca template vnfd_instance = self.client.create_vnfd(body=tosca_arg) @@ -67,12 +67,11 @@ class VnfTestToscaCreate(base.BaseTackerTest): class VnfTestToscaCreateFlavorCreation(base.BaseTackerTest): def test_create_delete_vnf_tosca_no_monitoring(self): - data = dict() vnfd_name = 'tosca_vnfd_with_auto_flavor' - data['tosca'] = read_file('sample-tosca-vnfd-flavor.yaml') - toscal = data['tosca'] + input_yaml = read_file('sample-tosca-vnfd-flavor.yaml') + tosca_dict = yaml.safe_load(input_yaml) tosca_arg = {'vnfd': {'name': vnfd_name, 'attributes': {'vnfd': - toscal}}} + tosca_dict}}} # Create vnfd with tosca template vnfd_instance = self.client.create_vnfd(body=tosca_arg) @@ -122,12 +121,11 @@ class VnfTestToscaCreateFlavorCreation(base.BaseTackerTest): class VnfTestToscaCreateImageCreation(base.BaseTackerTest): def test_create_delete_vnf_tosca_no_monitoring(self): - data = dict() vnfd_name = 'tosca_vnfd_with_auto_image' - data['tosca'] = read_file('sample-tosca-vnfd-image.yaml') - toscal = data['tosca'] + input_yaml = read_file('sample-tosca-vnfd-image.yaml') + tosca_dict = yaml.safe_load(input_yaml) tosca_arg = {'vnfd': {'name': vnfd_name, 'attributes': {'vnfd': - toscal}}} + tosca_dict}}} # Create vnfd with tosca template vnfd_instance = self.client.create_vnfd(body=tosca_arg) diff --git a/tacker/tests/functional/vnfm/test_tosca_vnf_multiple_vdu.py b/tacker/tests/functional/vnfm/test_tosca_vnf_multiple_vdu.py index a278a9b08..dcfea3750 100644 --- a/tacker/tests/functional/vnfm/test_tosca_vnf_multiple_vdu.py +++ b/tacker/tests/functional/vnfm/test_tosca_vnf_multiple_vdu.py @@ -26,13 +26,11 @@ CONF = cfg.CONF class VnfTestToscaMultipleVDU(base.BaseTackerTest): def test_create_delete_tosca_vnf_with_multiple_vdus(self): - data = dict() input_yaml = read_file('sample-tosca-vnfd-multi-vdu.yaml') - data['tosca'] = input_yaml - toscal = data['tosca'] + tosca_dict = yaml.safe_load(input_yaml) vnfd_name = 'sample-tosca-vnfd-multi-vdu' tosca_arg = {'vnfd': {'name': vnfd_name, - 'attributes': {'vnfd': toscal}}} + 'attributes': {'vnfd': tosca_dict}}} # Create vnfd with tosca template vnfd_instance = self.client.create_vnfd(body=tosca_arg) diff --git a/tacker/tests/functional/vnfm/test_tosca_vnfd.py b/tacker/tests/functional/vnfm/test_tosca_vnfd.py index 3f61eb523..edad78e1b 100644 --- a/tacker/tests/functional/vnfm/test_tosca_vnfd.py +++ b/tacker/tests/functional/vnfm/test_tosca_vnfd.py @@ -13,6 +13,7 @@ # under the License. from oslo_config import cfg +import yaml from tacker.tests.functional import base from tacker.tests.utils import read_file @@ -22,12 +23,11 @@ CONF = cfg.CONF class VnfdTestCreate(base.BaseTackerTest): def _test_create_list_delete_tosca_vnfd(self, tosca_vnfd_file): - data = dict() - data['tosca'] = read_file(tosca_vnfd_file) - toscal = data['tosca'] + input_yaml = read_file(tosca_vnfd_file) + tosca_dict = yaml.safe_load(input_yaml) vnfd_name = 'sample-tosca-vnfd' tosca_arg = {'vnfd': {'name': vnfd_name, - 'attributes': {'vnfd': toscal}}} + 'attributes': {'vnfd': tosca_dict}}} vnfd_instance = self.client.create_vnfd(body=tosca_arg) self.assertIsNotNone(vnfd_instance) diff --git a/tacker/tests/functional/vnfm/test_vnfm_param.py b/tacker/tests/functional/vnfm/test_vnfm_param.py index 3d51d7ee1..8874664ba 100644 --- a/tacker/tests/functional/vnfm/test_vnfm_param.py +++ b/tacker/tests/functional/vnfm/test_vnfm_param.py @@ -21,12 +21,14 @@ from tacker.tests.utils import read_file class VnfmTestParam(base.BaseTackerTest): def _test_vnfd_create(self, vnfd_file): - yaml_input = dict() - yaml_input['tosca'] = read_file(vnfd_file) + yaml_input = read_file(vnfd_file) vnfd_name = 'sample_cirros_vnf' - toscal = yaml_input['tosca'] + # TODO(anyone) remove this condition check once old templates + # are deprecated + if "tosca_definitions_version" in yaml_input: + yaml_input = yaml.safe_load(yaml_input) req_dict = {'vnfd': {'name': vnfd_name, - 'attributes': {'vnfd': toscal}}} + 'attributes': {'vnfd': yaml_input}}} # Create vnfd vnfd_instance = self.client.create_vnfd(body=req_dict) @@ -48,15 +50,13 @@ class VnfmTestParam(base.BaseTackerTest): except Exception: assert True, "Vnfd Delete success" + str(vfnd_d) + str(Exception) - def _test_vnf_create(self, vnfd_instance, vnf_name, vnf_value_file): + def _test_vnf_create(self, vnfd_instance, vnf_name, param_values): # Create the vnf with values vnfd_id = vnfd_instance['vnfd']['id'] - values_str = read_file(vnf_value_file) - # Create vnf with values file vnf_dict = dict() vnf_dict = {'vnf': {'vnfd_id': vnfd_id, 'name': vnf_name, - 'attributes': {'param_values': values_str}}} + 'attributes': {'param_values': param_values}}} vnf_instance = self.client.create_vnf(body=vnf_dict) self.validate_vnf_instance(vnfd_instance, vnf_instance) @@ -70,11 +70,11 @@ class VnfmTestParam(base.BaseTackerTest): vnf_instance = self.client.show_vnf(vnf_id) # Verify values dictionary is same as param values from vnf_show - input_dict = yaml.load(values_str) + param_values = vnf_instance['vnf']['attributes']['param_values'] - param_values_dict = yaml.load(param_values) - self.assertEqual(input_dict, param_values_dict) - return vnf_instance + param_values_dict = yaml.safe_load(param_values) + + return vnf_instance, param_values_dict def _test_vnf_delete(self, vnf_instance): # Delete Vnf @@ -90,10 +90,15 @@ class VnfmTestParam(base.BaseTackerTest): assert True, "Vnf Delete success" + str(vfn_d) + str(Exception) def test_vnf_param(self): - vnfd_instance = self._test_vnfd_create('sample_cirros_vnf_param.yaml') - vnf_instance = self._test_vnf_create(vnfd_instance, + vnfd_instance = self._test_vnfd_create( + 'sample_cirros_vnf_param.yaml') + values_str = read_file('sample_cirros_vnf_values.yaml') + vnf_instance, param_values_dict = self._test_vnf_create(vnfd_instance, 'test_vnf_with_parameters', - 'sample_cirros_vnf_values.yaml') + values_str) + # Verify values dictionary is same as param values from vnf_show + input_dict = yaml.safe_load(values_str) + self.assertEqual(input_dict, param_values_dict) self._test_vnf_delete(vnf_instance) vnf_id = vnf_instance['vnf']['id'] self.addCleanup(self.client.delete_vnfd, vnfd_instance['vnfd']['id']) @@ -101,14 +106,19 @@ class VnfmTestParam(base.BaseTackerTest): constants.VNF_CIRROS_DELETE_TIMEOUT) def test_vnfd_param_tosca_template(self): - vnfd_instance = self._test_vnfd_create('sample-tosca-vnfd-param.yaml') + vnfd_instance = self._test_vnfd_create( + 'sample-tosca-vnfd-param.yaml') self._test_vnfd_delete(vnfd_instance) def test_vnf_param_tosca_template(self): - vnfd_instance = self._test_vnfd_create('sample-tosca-vnfd-param.yaml') - vnf_instance = self._test_vnf_create(vnfd_instance, + vnfd_instance = self._test_vnfd_create( + 'sample-tosca-vnfd-param.yaml') + values_str = read_file('sample-tosca-vnf-values.yaml') + values_dict = yaml.safe_load(values_str) + vnf_instance, param_values_dict = self._test_vnf_create(vnfd_instance, 'test_vnf_with_parameters_tosca_template', - 'sample-tosca-vnf-values.yaml') + values_dict) + self.assertEqual(values_dict, param_values_dict) self._test_vnf_delete(vnf_instance) vnf_id = vnf_instance['vnf']['id'] self.addCleanup(self.client.delete_vnfd, vnfd_instance['vnfd']['id']) diff --git a/tacker/tests/unit/db/utils.py b/tacker/tests/unit/db/utils.py index 0b7b5a06b..0e2ee8519 100644 --- a/tacker/tests/unit/db/utils.py +++ b/tacker/tests/unit/db/utils.py @@ -15,6 +15,7 @@ import codecs import os +import yaml def _get_template(name): @@ -38,7 +39,7 @@ def get_dummy_vnfd_obj(): 'tenant_id': u'ad7ebc56538745a08ef7c5e97f8bd437', u'mgmt_driver': u'noop', u'infra_driver': u'fake_driver', - u'attributes': {u'vnfd': vnfd_openwrt}, + u'attributes': {u'vnfd': yaml.safe_load(vnfd_openwrt)}, 'description': 'dummy_vnfd_description'}, u'auth': {u'tenantName': u'admin', u'passwordCredentials': { u'username': u'admin', u'password': u'devstack'}}} diff --git a/tacker/vm/plugin.py b/tacker/vm/plugin.py index 670aba227..d537b46ae 100644 --- a/tacker/vm/plugin.py +++ b/tacker/vm/plugin.py @@ -28,6 +28,7 @@ from tacker._i18n import _LE from tacker.api.v1 import attributes from tacker.common import driver_manager from tacker.common import exceptions +from tacker.common import utils from tacker.db.vm import vm_db from tacker.extensions import vnfm from tacker.plugins.common import constants @@ -132,7 +133,16 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin): def create_vnfd(self, context, vnfd): vnfd_data = vnfd['vnfd'] - if "tosca_definitions_version" not in vnfd_data['attributes']['vnfd']: + template = vnfd_data['attributes'].get('vnfd') + if isinstance(template, dict): + # TODO(sripriya) remove this yaml dump once db supports storing + # json format of yaml files in a separate column instead of + # key value string pairs in vnf attributes table + vnfd_data['attributes']['vnfd'] = yaml.safe_dump( + template) + elif isinstance(template, str): + self._report_deprecated_yaml_str() + if "tosca_definitions_version" not in template: versionutils.report_deprecated_feature(LOG, 'VNFD legacy vnfds' ' are deprecated since Mitaka release and will be removed in' ' Ocata release. Please use NFV TOSCA vnfds.') @@ -279,6 +289,25 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin): def create_vnf(self, context, vnf): vnf_info = vnf['vnf'] + vnf_attributes = vnf_info['attributes'] + if vnf_attributes.get('param_values'): + param = vnf_attributes['param_values'] + if isinstance(param, dict): + # TODO(sripriya) remove this yaml dump once db supports storing + # json format of yaml files in a separate column instead of + # key value string pairs in vnf attributes table + vnf_attributes['param_values'] = yaml.safe_dump(param) + else: + self._report_deprecated_yaml_str() + if vnf_attributes.get('config'): + config = vnf_attributes['config'] + if isinstance(config, dict): + # TODO(sripriya) remove this yaml dump once db supports storing + # json format of yaml files in a separate column instead of + # key value string pairs in vnf attributes table + vnf_attributes['config'] = yaml.safe_dump(config) + else: + self._report_deprecated_yaml_str() vim_auth = self.get_vim(context, vnf_info) vnf_dict = self._create_vnf(context, vnf_info, vim_auth) @@ -326,6 +355,16 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin): new_status, vnf_dict) def update_vnf(self, context, vnf_id, vnf): + vnf_attributes = vnf['vnf']['attributes'] + if vnf_attributes.get('config'): + config = vnf_attributes['config'] + if isinstance(config, dict): + # TODO(sripriya) remove this yaml dump once db supports storing + # json format of yaml files in a separate column instead of + # key value string pairs in vnf attributes table + vnf_attributes['config'] = yaml.safe_dump(config) + else: + self._report_deprecated_yaml_str() vnf_dict = self._update_vnf_pre(context, vnf_id) vim_auth = self.get_vim(context, vnf_dict) driver_name = self._infra_driver_name(vnf_dict) @@ -531,6 +570,10 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin): return policy + def _report_deprecated_yaml_str(self): + utils.deprecate_warning(what='yaml as string', + as_of='N', in_favor_of='yaml as dictionary') + def _make_policy_dict(self, vnf, name, policy): p = {} p['type'] = policy['type']