Browse Source

Merge "Support updating VNF parameters in tacker"

tags/3.0.0.0rc1
Zuul 3 months ago
committed by Gerrit Code Review
parent
commit
ecd94b1a89
17 changed files with 425 additions and 7 deletions
  1. +15
    -2
      doc/source/user/vnfm_usage_guide.rst
  2. +4
    -0
      tacker/extensions/vnfm.py
  3. +1
    -0
      tacker/tests/constants.py
  4. +3
    -0
      tacker/tests/etc/samples/sample-tosca-vnf-update-values.yaml
  5. +64
    -1
      tacker/tests/functional/vnfm/test_vnfm_param.py
  6. +59
    -0
      tacker/tests/unit/db/utils.py
  7. +27
    -0
      tacker/tests/unit/vnfm/infra_drivers/openstack/data/hot_data.yaml
  8. +2
    -0
      tacker/tests/unit/vnfm/infra_drivers/openstack/data/param_data.yaml
  9. +44
    -0
      tacker/tests/unit/vnfm/infra_drivers/openstack/data/test_tosca_openwrt_param.yaml
  10. +2
    -0
      tacker/tests/unit/vnfm/infra_drivers/openstack/data/update_invalid_param_data.yaml
  11. +3
    -0
      tacker/tests/unit/vnfm/infra_drivers/openstack/data/update_new_param_data.yaml
  12. +2
    -0
      tacker/tests/unit/vnfm/infra_drivers/openstack/data/update_param_data.yaml
  13. +80
    -0
      tacker/tests/unit/vnfm/infra_drivers/openstack/test_openstack.py
  14. +51
    -0
      tacker/tests/unit/vnfm/test_plugin.py
  15. +5
    -1
      tacker/vnfm/infra_drivers/openstack/heat_client.py
  16. +44
    -3
      tacker/vnfm/infra_drivers/openstack/openstack.py
  17. +19
    -0
      tacker/vnfm/plugin.py

+ 15
- 2
doc/source/user/vnfm_usage_guide.rst View File

@@ -19,8 +19,8 @@ VNF Manager User Guide
======================

Tacker VNF Manager (VNFM) component manages the life-cycle of a Virtual Network
Function (VNF). VNFM takes care of deployment, monitoring, scaling and removal
of VNFs on a Virtual Infrastructure Manager (VIM).
Function (VNF). VNFM takes care of deployment, monitoring, updating, scaling
and removal of VNFs on a Virtual Infrastructure Manager (VIM).


Onboarding VNF
@@ -122,6 +122,19 @@ Status of various VNFM resources can be checked by following commands.

..

Updating VNF
============

VNFs can be updated as shown below.
--config, --config-file and --param-file can not be specified together.

.. code-block:: console

openstack vnf set --config <CONFIG-DATA> <VNF_ID/NAME>
openstack vnf set --config-file <CONFIG-FILE-NAME> <VNF_ID/NAME>
openstack vnf set --param-file <PARAMETER-FILE-NAME> <VNF_ID/NAME>
..

Deleting VNF and VNFD
=====================



+ 4
- 0
tacker/extensions/vnfm.py View File

@@ -64,6 +64,10 @@ class VNFCreateFailed(exceptions.TackerException):
message = _('creating VNF based on %(vnfd_id)s failed')


class VNFUpdateInvalidInput(exceptions.TackerException):
message = _('VNF Update Invalid Input %(reason)s')


class VNFUpdateWaitFailed(exceptions.TackerException):
message = _('VNF Update %(reason)s')



+ 1
- 0
tacker/tests/constants.py View File

@@ -15,6 +15,7 @@ DEFAULT_ALARM_ACTIONS = ['respawn', 'log', 'log_and_kill', 'notify']
POLICY_RESERVATION = 'tosca.policies.tacker.Reservation'
VNF_CIRROS_CREATE_TIMEOUT = 300
VNFC_CREATE_TIMEOUT = 600
VNF_CIRROS_UPDATE_TIMEOUT = 300
VNF_CIRROS_DELETE_TIMEOUT = 300
VNF_CIRROS_DEAD_TIMEOUT = 500
ACTIVE_SLEEP_TIME = 3


+ 3
- 0
tacker/tests/etc/samples/sample-tosca-vnf-update-values.yaml View File

@@ -0,0 +1,3 @@
{
flavor: 'm1.small'
}

+ 64
- 1
tacker/tests/functional/vnfm/test_vnfm_param.py View File

@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.

import time
import unittest
import yaml

@@ -85,6 +86,48 @@ class VnfmTestParam(base.BaseTackerTest):

return vnf_instance, param_values_dict

def _test_vnf_update(self, vnf_instance, param_values):
# Update Vnf
vnf_id = vnf_instance['vnf']['id']
new_param_values = {'vnf': {'attributes': {
'param_values': param_values}}}
self.client.update_vnf(vnf_id, new_param_values)
self.wait_until_vnf_active(
vnf_id,
constants.VNF_CIRROS_UPDATE_TIMEOUT,
constants.ACTIVE_SLEEP_TIME)

# Wait until the update on the heat side is completed,
# because vnf deletion will cause a conflict without waiting for this.
stack_id = self.client.show_vnf(vnf_id)['vnf']['instance_id']
start_time = int(time.time())
while True:
vdu_resource = self.get_vdu_resource(stack_id, "VDU1")
vdu_resource_dict = vdu_resource.to_dict()
vdu_resource_status = vdu_resource_dict['resource_status']
if ((int(time.time()) - start_time >
constants.VNF_CIRROS_UPDATE_TIMEOUT) or
(vdu_resource_status == 'UPDATE_COMPLETE')):
break
time.sleep(constants.ACTIVE_SLEEP_TIME)

self.verify_vnf_crud_events(
vnf_id, evt_constants.RES_EVT_UPDATE, evt_constants.PENDING_UPDATE)
self.verify_vnf_crud_events(
vnf_id, evt_constants.RES_EVT_UPDATE, evt_constants.ACTIVE)

# Verify vnf_param_values_dict is same as param values from vnf_show
vnf_instance = self.client.show_vnf(vnf_id)
vnf_param_values = vnf_instance['vnf']['attributes']['param_values']
vnf_param_values_dict = yaml.safe_load(vnf_param_values)

# Verify stack_parameters is same as parameters from stack_show
instance_id = vnf_instance['vnf']['instance_id']
stack_values = self.h_client.stacks.get(instance_id)
stack_parameters = stack_values.parameters

return vnf_param_values_dict, stack_parameters

def _test_vnf_delete(self, vnf_instance):
# Delete Vnf
vnf_id = vnf_instance['vnf']['id']
@@ -126,11 +169,32 @@ class VnfmTestParam(base.BaseTackerTest):
def _test_vnf_param_tosca_template(self, vnfd_file, vnfd_name,
param_file, vnf_name):
vnfd_instance = self._test_vnfd_create(vnfd_file, vnfd_name)

# Get vnfd_id
vnfd_id = vnfd_instance['vnfd']['id']

# Add vnfd delete to cleanup job so that if vnf_instance fails to
# create or update then it will be cleaned-up automatically
# in tearDown()
self.addCleanup(self.client.delete_vnfd, vnfd_id)

# Create vnf instance
values_str = read_file(param_file)
values_dict = yaml.safe_load(values_str)
vnf_instance, param_values_dict = self._test_vnf_create(
vnfd_instance, vnf_name, values_dict)
self.assertEqual(values_dict, param_values_dict)

new_values_str = read_file('sample-tosca-vnf-update-values.yaml')
new_values_dict = yaml.safe_load(new_values_str)
vnf_param_values_dict, stack_parameters = self._test_vnf_update(
vnf_instance, new_values_dict)
for key, value in new_values_dict.items():
if vnf_param_values_dict.get(key):
self.assertEqual(value, vnf_param_values_dict[key])
if stack_parameters.get(key):
self.assertEqual(value, stack_parameters[key])

self._test_vnf_delete(vnf_instance)
vnf_id = vnf_instance['vnf']['id']
self.verify_vnf_crud_events(
@@ -142,4 +206,3 @@ class VnfmTestParam(base.BaseTackerTest):
constants.VNF_CIRROS_DELETE_TIMEOUT)
self.verify_vnf_crud_events(vnf_id, evt_constants.RES_EVT_DELETE,
evt_constants.PENDING_DELETE, cnt=2)
self.addCleanup(self.client.delete_vnfd, vnfd_instance['vnfd']['id'])

+ 59
- 0
tacker/tests/unit/db/utils.py View File

@@ -30,9 +30,15 @@ def _get_template(name):
return f.read()

tosca_vnfd_openwrt = _get_template('test_tosca_openwrt.yaml')
tosca_vnfd_openwrt_param = _get_template('test_tosca_openwrt_param.yaml')
tosca_invalid_vnfd = _get_template('test_tosca_parser_failure.yaml')
config_data = _get_template('config_data.yaml')
update_config_data = _get_template('update_config_data.yaml')
hot_data = _get_template('hot_data.yaml')
param_data = _get_template('param_data.yaml')
update_param_data = _get_template('update_param_data.yaml')
update_invalid_param_data = _get_template('update_invalid_param_data.yaml')
update_new_param_data = _get_template('update_new_param_data.yaml')
vnffg_params = _get_template('vnffg_params.yaml')
vnffg_multi_params = _get_template('vnffg_multi_params.yaml')
vnffgd_template = yaml.safe_load(_get_template('vnffgd_template.yaml'))
@@ -129,6 +135,24 @@ def get_dummy_vnf_config_obj():
'config': {'firewall': 'dummy_firewall_values'}}}}}}}


def get_dummy_vnf_invalid_config_type_obj():
return {'vnf': {u'attributes': {u'config': 'dummy_config'}}}


def get_dummy_vnf_invalid_param_content():
return {'vnf': {u'attributes': {u'param_values': {}}}}


def get_dummy_vnf_param_obj():
return {'vnf': {u'attributes': {u'param_values':
{'flavor': 'm1.tiny',
'reservation_id': '99999999-3925-4c9e-9074-239a902b68d7'}}}}


def get_dummy_vnf_invalid_param_type_obj():
return {'vnf': {u'attributes': {u'param_values': 'dummy_param'}}}


def get_dummy_vnf(status='PENDING_CREATE', scaling_group=False,
instance_id=None):
dummy_vnf = {'status': status, 'instance_id': instance_id, 'name':
@@ -172,10 +196,45 @@ def get_dummy_vnf_config_attr():
'description': u'OpenWRT with services'}


def get_dummy_vnf_param_attr():
return {'status': 'PENDING_CREATE', 'instance_id': None, 'name':
u'test_openwrt', 'tenant_id': u'ad7ebc56538745a08ef7c5e97f8bd437',
'vnfd_id': u'eb094833-995e-49f0-a047-dfb56aaf7c4e',
'vnfd': {'service_types': [{'service_type': u'vnfd',
'id': u'4a4c2d44-8a52-4895-9a75-9d1c76c3e738'}],
'description': u'OpenWRT with services',
'tenant_id': u'ad7ebc56538745a08ef7c5e97f8bd437',
'mgmt_driver': u'openwrt',
'attributes': {u'vnfd': tosca_vnfd_openwrt_param},
'id': u'fb048660-dc1b-4f0f-bd89-b023666650ec',
'name': u'openwrt_services'},
'mgmt_url': None, 'service_context': [],
'attributes': {'heat_template': hot_data,
'param_values': param_data},
'id': 'eb84260e-5ff7-4332-b032-50a14d6c1123',
'description': u'OpenWRT with services'}


def get_dummy_vnf_update_config():
return {'vnf': {'attributes': {'config': update_config_data}}}


def get_dummy_vnf_update_param():
return {'vnf': {'attributes': {'param_values': update_param_data}}}


def get_dummy_vnf_update_new_param():
return {'vnf': {'attributes': {'param_values': update_new_param_data}}}


def get_dummy_vnf_update_invalid_param():
return {'vnf': {'attributes': {'param_values': update_invalid_param_data}}}


def get_dummy_vnf_update_empty_param():
return {'vnf': {'attributes': {'param_values': {}}}}


def get_vim_obj():
return {'vim': {'type': 'openstack',
'auth_url': 'http://localhost/identity',


+ 27
- 0
tacker/tests/unit/vnfm/infra_drivers/openstack/data/hot_data.yaml View File

@@ -0,0 +1,27 @@
heat_template_version: 2013-05-23
description: 'OpenWRT with services

'
parameters:
flavor: {type: string, default: m1.tiny}
reservation_id: {type: string, default: 891cd152-3925-4c9e-9074-239a902b68d7}
resources:
VDU1:
type: OS::Nova::Server
properties:
networks:
- port: {get_resource: CP1}
image: OpenWRT
user_data_format: SOFTWARE_CONFIG
config_drive: false
flavor: {get_param: flavor}
scheduler_hints:
reservation: {get_param: reservation_id}
CP1:
type: OS::Neutron::Port
properties: {network: existing_network_1, port_security_enabled: false}

outputs:
mgmt_ip-VDU1:
value:
get_attr: [CP1, fixed_ips, 0, ip_address]

+ 2
- 0
tacker/tests/unit/vnfm/infra_drivers/openstack/data/param_data.yaml View File

@@ -0,0 +1,2 @@
flavor: m1.tiny
reservation_id: 891cd152-3925-4c9e-9074-239a902b68d7

+ 44
- 0
tacker/tests/unit/vnfm/infra_drivers/openstack/data/test_tosca_openwrt_param.yaml View File

@@ -0,0 +1,44 @@
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0

description: OpenWRT with services

metadata:
template_name: OpenWRT

topology_template:
inputs:
flavor:
type: string
reservation_id:
type: string

node_templates:

VDU1:
type: tosca.nodes.nfv.VDU.Tacker
properties:
image: OpenWRT
flavor: {get_input: flavor}
reservation: {get_input: reservation_id}
config: |
param0: key1
param1: key2
mgmt_driver: openwrt

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: existing_network_1
vendor: Tacker


+ 2
- 0
tacker/tests/unit/vnfm/infra_drivers/openstack/data/update_invalid_param_data.yaml View File

@@ -0,0 +1,2 @@
flavor: m1.tiny
reservation_id: 891cd152-3925-4c9e-9074-239a902b68d7

+ 3
- 0
tacker/tests/unit/vnfm/infra_drivers/openstack/data/update_new_param_data.yaml View File

@@ -0,0 +1,3 @@
flavor: m1.tiny
reservation_id: 99999999-3925-4c9e-9074-239a902b68d7
new_param_key: new_param_value

+ 2
- 0
tacker/tests/unit/vnfm/infra_drivers/openstack/data/update_param_data.yaml View File

@@ -0,0 +1,2 @@
flavor: m1.tiny
reservation_id: 99999999-3925-4c9e-9074-239a902b68d7

+ 80
- 0
tacker/tests/unit/vnfm/infra_drivers/openstack/test_openstack.py View File

@@ -105,6 +105,7 @@ class TestOpenStack(base.TestCase):
hot_param_template = _get_template('hot_openwrt_params.yaml')
hot_ipparam_template = _get_template('hot_openwrt_ipparams.yaml')
tosca_vnfd_openwrt = _get_template('test_tosca_openwrt.yaml')
tosca_vnfd_openwrt_param = _get_template('test_tosca_openwrt_param.yaml')
config_data = _get_template('config_data.yaml')

def setUp(self):
@@ -196,6 +197,40 @@ class TestOpenStack(base.TestCase):
'id': 'eb84260e-5ff7-4332-b032-50a14d6c1123', 'description':
u'OpenWRT with services'}

def _get_expected_vnf_update_param_obj(self):
return {'status': 'PENDING_CREATE', 'instance_id': None, 'name':
u'test_openwrt', 'tenant_id':
u'ad7ebc56538745a08ef7c5e97f8bd437', 'vnfd_id':
u'eb094833-995e-49f0-a047-dfb56aaf7c4e', 'vnfd': {
'service_types': [{'service_type': u'vnfd', 'id':
u'4a4c2d44-8a52-4895-9a75-9d1c76c3e738'}], 'description':
u'OpenWRT with services', 'tenant_id':
u'ad7ebc56538745a08ef7c5e97f8bd437', 'mgmt_driver': u'openwrt',
'attributes': {u'vnfd': self.tosca_vnfd_openwrt_param},
'id': u'fb048660-dc1b-4f0f-bd89-b023666650ec', 'name':
u'openwrt_services'}, 'mgmt_url': None, 'service_context': [],
'attributes': {'heat_template': utils.hot_data,
'param_values': utils.update_param_data},
'id': 'eb84260e-5ff7-4332-b032-50a14d6c1123', 'description':
u'OpenWRT with services'}

def _get_expected_vnf_update_new_param_obj(self):
return {'status': 'PENDING_CREATE', 'instance_id': None, 'name':
u'test_openwrt', 'tenant_id':
u'ad7ebc56538745a08ef7c5e97f8bd437', 'vnfd_id':
u'eb094833-995e-49f0-a047-dfb56aaf7c4e', 'vnfd': {
'service_types': [{'service_type': u'vnfd', 'id':
u'4a4c2d44-8a52-4895-9a75-9d1c76c3e738'}], 'description':
u'OpenWRT with services', 'tenant_id':
u'ad7ebc56538745a08ef7c5e97f8bd437', 'mgmt_driver': u'openwrt',
'attributes': {u'vnfd': self.tosca_vnfd_openwrt_param},
'id': u'fb048660-dc1b-4f0f-bd89-b023666650ec', 'name':
u'openwrt_services'}, 'mgmt_url': None, 'service_context': [],
'attributes': {'heat_template': utils.hot_data,
'param_values': utils.update_new_param_data},
'id': 'eb84260e-5ff7-4332-b032-50a14d6c1123', 'description':
u'OpenWRT with services'}

def _get_expected_active_vnf(self):
return {'status': 'ACTIVE',
'instance_id': None,
@@ -259,6 +294,51 @@ class TestOpenStack(base.TestCase):
mock_log.error.assert_called_with(
"VNF '%s' failed to heal", vnf_dict['id'])

def test_update_new_param(self):
vnf_obj = utils.get_dummy_vnf_param_attr()
vnf_param_obj = utils.get_dummy_vnf_update_new_param()
expected_vnf_update = self._get_expected_vnf_update_new_param_obj()
vnf_id = '4a4c2d44-8a52-4895-9a75-9d1c76c3e738'
self.infra_driver.update(plugin=None, context=self.context,
vnf_id=vnf_id, vnf_dict=vnf_obj,
vnf=vnf_param_obj,
auth_attr=utils.get_vim_auth_obj())
expected_vnf_update['attributes']['param_values'] = yaml.safe_load(
expected_vnf_update['attributes']['param_values'])
vnf_obj['attributes']['param_values'] = yaml.safe_load(
vnf_obj['attributes']['param_values'])
self.assertEqual(expected_vnf_update, vnf_obj)

@mock.patch('tacker.vnfm.infra_drivers.openstack.openstack.LOG')
def test_update_invalid_param(self, mock_log):
vnf_obj = utils.get_dummy_vnf_param_attr()
vnf_param_obj = utils.get_dummy_vnf_update_invalid_param()
vnf_id = '4a4c2d44-8a52-4895-9a75-9d1c76c3e738'
self.assertRaises(vnfm.VNFUpdateInvalidInput,
self.infra_driver.update,
plugin=None, context=self.context,
vnf_id=vnf_id, vnf_dict=vnf_obj,
vnf=vnf_param_obj,
auth_attr=utils.get_vim_auth_obj())
log_msg = "at vnf_id {} because all parameters "\
"match the existing one.".format(vnf_id)
mock_log.warning.assert_called_with(log_msg)

@mock.patch('tacker.vnfm.infra_drivers.openstack.openstack.LOG')
def test_update_empty_param(self, mock_log):
vnf_obj = utils.get_dummy_vnf_param_attr()
vnf_param_obj = utils.get_dummy_vnf_update_empty_param()
vnf_id = '4a4c2d44-8a52-4895-9a75-9d1c76c3e738'
self.assertRaises(vnfm.VNFUpdateInvalidInput,
self.infra_driver.update,
plugin=None, context=self.context,
vnf_id=vnf_id, vnf_dict=vnf_obj,
vnf=vnf_param_obj,
auth_attr=utils.get_vim_auth_obj())
log_msg = "at vnf_id {} because the target "\
"yaml is empty.".format(vnf_id)
mock_log.warning.assert_called_with(log_msg)

def _get_expected_fields_tosca(self, template):
return {'stack_name':
'test_openwrt_eb84260e-5ff7-4332-b032-50a14d6c1123',


+ 51
- 0
tacker/tests/unit/vnfm/test_plugin.py View File

@@ -824,6 +824,57 @@ class TestVNFMPlugin(db_base.SqlTestCase):
dummy_vnf_obj['id'],
'VNF Update failed')

def test_update_vnf_param(self):
self._insert_dummy_vnf_template()
dummy_device_obj = self._insert_dummy_vnf()
vnf_param_obj = utils.get_dummy_vnf_param_obj()
result = self.vnfm_plugin.update_vnf(self.context,
dummy_device_obj['id'],
vnf_param_obj)
self.assertIsNotNone(result)
self.assertEqual(dummy_device_obj['id'], result['id'])
self.assertIn('instance_id', result)
self.assertIn('status', result)
self.assertIn('attributes', result)
self.assertIn('mgmt_ip_address', result)
self.assertIn('updated_at', result)
self._cos_db_plugin.create_event.assert_called_with(
self.context, evt_type=constants.RES_EVT_UPDATE, res_id=mock.ANY,
res_state=mock.ANY, res_type=constants.RES_TYPE_VNF,
tstamp=mock.ANY)

def test_update_vnf_invalid_config_type(self):
self._insert_dummy_vnf_template()
dummy_device_obj = self._insert_dummy_vnf()
vnf_param_obj = utils.get_dummy_vnf_invalid_config_type_obj()
self.assertRaises(vnfm.InvalidAPIAttributeType,
self.vnfm_plugin.update_vnf,
self.context,
dummy_device_obj['id'],
vnf_param_obj)

def test_update_vnf_invalid_param_type(self):
self._insert_dummy_vnf_template()
dummy_device_obj = self._insert_dummy_vnf()
vnf_param_obj = utils.get_dummy_vnf_invalid_param_type_obj()
self.assertRaises(vnfm.InvalidAPIAttributeType,
self.vnfm_plugin.update_vnf,
self.context,
dummy_device_obj['id'],
vnf_param_obj)

def test_update_vnf_invalid_param_content(self):
self.update.side_effect = vnfm.VNFUpdateInvalidInput(
reason='failed')
self._insert_dummy_vnf_template()
dummy_device_obj = self._insert_dummy_vnf()
vnf_param_obj = utils.get_dummy_vnf_invalid_param_content()
self.assertRaises(vnfm.VNFUpdateInvalidInput,
self.vnfm_plugin.update_vnf,
self.context,
dummy_device_obj['id'],
vnf_param_obj)

def _get_dummy_scaling_policy(self, type):
vnf_scale = {}
vnf_scale['scale'] = {}


+ 5
- 1
tacker/vnfm/infra_drivers/openstack/heat_client.py View File

@@ -54,7 +54,11 @@ class HeatClient(object):
return self.stacks.get(stack_id)

def update(self, stack_id, **kwargs):
return self.stacks.update(stack_id, **kwargs)
try:
return self.stacks.update(stack_id, **kwargs)
except heatException.HTTPException:
type_, value, tb = sys.exc_info()
raise vnfm.HeatClientException(msg=value)

def resource_attr_support(self, resource_name, property_name):
resource = self.resource_types.get(resource_name)


+ 44
- 3
tacker/vnfm/infra_drivers/openstack/openstack.py View File

@@ -202,11 +202,52 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
heatclient = hc.HeatClient(auth_attr, region_name)
heatclient.get(vnf_id)

update_param_yaml = vnf['vnf'].get('attributes', {}).get(
'param_values', '')
update_config_yaml = vnf['vnf'].get('attributes', {}).get(
'config', '')

if update_param_yaml:
# conversion param_values
param_yaml = vnf_dict.get('attributes', {}).get('param_values', '')
param_dict = yaml.safe_load(param_yaml)
update_param_dict = yaml.safe_load(update_param_yaml)

# check update values
update_values = {}
for key, value in update_param_dict.items():
if key not in param_dict or\
update_param_dict[key] != param_dict[key]:
update_values[key] = value

if not update_values:
error_reason = _("at vnf_id {} because all parameters "
"match the existing one.").format(vnf_id)
LOG.warning(error_reason)
raise vnfm.VNFUpdateInvalidInput(reason=error_reason)

# update vnf_dict
utils.deep_update(param_dict, update_param_dict)
new_param_yaml = yaml.safe_dump(param_dict)
vnf_dict.setdefault(
'attributes', {})['param_values'] = new_param_yaml

# run stack update
stack_update_param = {
'parameters': update_values,
'existing': True}
heatclient.update(vnf_id, **stack_update_param)

elif not update_param_yaml and not update_config_yaml:
error_reason = _("at vnf_id {} because the target "
"yaml is empty.").format(vnf_id)
LOG.warning(error_reason)
raise vnfm.VNFUpdateInvalidInput(reason=error_reason)

# update config attribute
config_yaml = vnf_dict.get('attributes', {}).get('config', '')
update_yaml = vnf['vnf'].get('attributes', {}).get('config', '')
LOG.debug('yaml orig %(orig)s update %(update)s',
{'orig': config_yaml, 'update': update_yaml})
{'orig': config_yaml, 'update': update_config_yaml})

# If config_yaml is None, yaml.safe_load() will raise Attribute Error.
# So set config_yaml to {}, if it is None.
@@ -214,7 +255,7 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
config_dict = {}
else:
config_dict = yaml.safe_load(config_yaml) or {}
update_dict = yaml.safe_load(update_yaml)
update_dict = yaml.safe_load(update_config_yaml)
if not update_dict:
return



+ 19
- 0
tacker/vnfm/plugin.py View File

@@ -115,6 +115,7 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):

Plugin which supports Tacker framework
"""

OPTS_INFRA_DRIVER = [
cfg.ListOpt(
'infra_driver', default=['noop', 'openstack', 'kubernetes'],
@@ -532,6 +533,17 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
vnf_attributes['config'] = yaml.safe_dump(config)
else:
raise vnfm.InvalidAPIAttributeType(atype=type(config))

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:
raise vnfm.InvalidAPIAttributeType(atype=type(param))

vnf_dict = self._update_vnf_pre(context, vnf_id,
constants.PENDING_UPDATE)
driver_name, vim_auth = self._get_infra_driver(context, vnf_dict)
@@ -543,6 +555,13 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
driver_name, 'update', plugin=self, context=context,
vnf_id=instance_id, vnf_dict=vnf_dict,
vnf=vnf, auth_attr=vim_auth)
except vnfm.VNFUpdateInvalidInput:
with excutils.save_and_reraise_exception():
vnf_dict['status'] = constants.ACTIVE
self._update_vnf_post(context, vnf_id,
constants.ACTIVE,
vnf_dict, constants.PENDING_UPDATE,
constants.RES_EVT_UPDATE)
except Exception as e:
with excutils.save_and_reraise_exception():
vnf_dict['status'] = constants.ERROR


Loading…
Cancel
Save