Fix: VNF update_wait always raise exception

vnf-update don't change heat stack's state.
But update_wait function currently  check stack's state.
Therefore update_wait always raise exception,when tacker
execute update. The reason that this function execute
check process is because vdu_autoheal action shares
update_wait with update action.

this commit splits update_wait into heal_wait and update_wait.

Closes-Bug:#1837205

Change-Id: I7ab059bb30b5de38943555883a92d77a64a56d34
This commit is contained in:
Hiroya Nakaya 2019-08-20 07:23:04 +00:00
parent 3a198b0ba6
commit 3e29adbff9
6 changed files with 94 additions and 36 deletions

View File

@ -80,6 +80,10 @@ class VNFDeleteWaitFailed(exceptions.TackerException):
message = _('VNF Delete %(reason)s')
class VNFHealWaitFailed(exceptions.TackerException):
message = _('VNF Heal %(reason)s')
class VNFDeleteFailed(exceptions.TackerException):
message = _('%(reason)s')

View File

@ -148,8 +148,7 @@ class TestOpenStack(base.FixturedTestCase):
self.mock_log.warning.assert_called_once()
def test_update_wait(self):
self._response_in_wait_until_stack_ready(["UPDATE_IN_PROGRESS",
"UPDATE_COMPLETE"])
self._response_in_wait_until_stack_ready(["CREATE_COMPLETE"])
vnf_dict = utils.get_dummy_vnf(status='PENDING_UPDATE',
instance_id=self.instance_uuid)
self.openstack.update_wait(None, None, vnf_dict, None)
@ -158,33 +157,44 @@ class TestOpenStack(base.FixturedTestCase):
self.assertEqual('{"VDU1": "192.168.120.216"}',
vnf_dict['mgmt_ip_address'])
def test_update_wait_without_mgmt_ips(self):
def test_heal_wait(self):
self._response_in_wait_until_stack_ready(["UPDATE_IN_PROGRESS",
"UPDATE_COMPLETE"],
stack_outputs=False)
vnf_dict = utils.get_dummy_vnf(status='PENDING_UPDATE',
"UPDATE_COMPLETE"])
vnf_dict = utils.get_dummy_vnf(status='PENDING_HEAL',
instance_id=self.instance_uuid)
self.openstack.update_wait(None, None, vnf_dict, None)
self.openstack.heal_wait(None, None, vnf_dict, None)
self.mock_log.debug.assert_called_with('outputs %s',
fd_utils.get_dummy_stack()['outputs'])
self.assertEqual('{"VDU1": "192.168.120.216"}',
vnf_dict['mgmt_ip_address'])
def test_heal_wait_without_mgmt_ips(self):
self._response_in_wait_until_stack_ready(["UPDATE_IN_PROGRESS",
"UPDATE_COMPLETE"],
stack_outputs=False)
vnf_dict = utils.get_dummy_vnf(status='PENDING_HEAL',
instance_id=self.instance_uuid)
self.openstack.heal_wait(None, None, vnf_dict, None)
self.mock_log.debug.assert_called_with('outputs %s',
fd_utils.get_dummy_stack(outputs=False)['outputs'])
self.assertIsNone(vnf_dict['mgmt_ip_address'])
def test_update_wait_failed_with_retries_0(self):
def test_heal_wait_failed_with_retries_0(self):
self._response_in_wait_until_stack_ready(["UPDATE_IN_PROGRESS"])
vnf_dict = utils.get_dummy_vnf(status='PENDING_UPDATE',
vnf_dict = utils.get_dummy_vnf(status='PENDING_HEAL',
instance_id=self.instance_uuid)
self.assertRaises(vnfm.VNFUpdateWaitFailed,
self.openstack.update_wait,
self.assertRaises(vnfm.VNFHealWaitFailed,
self.openstack.heal_wait,
None, None, vnf_dict,
None)
def test_update_wait_failed_stack_retries_not_0(self):
def test_heal_wait_failed_stack_retries_not_0(self):
self._response_in_wait_until_stack_ready(["UPDATE_IN_PROGRESS",
"FAILED"])
vnf_dict = utils.get_dummy_vnf(status='PENDING_UPDATE',
vnf_dict = utils.get_dummy_vnf(status='PENDING_HEAL',
instance_id=self.instance_uuid)
self.assertRaises(vnfm.VNFUpdateWaitFailed,
self.openstack.update_wait,
self.assertRaises(vnfm.VNFHealWaitFailed,
self.openstack.heal_wait,
None, None, vnf_dict,
None)

View File

@ -169,6 +169,9 @@ class TestVNFMPlugin(db_base.SqlTestCase):
'openstack.OpenStack.scale_wait',
return_value=uuidutils.generate_uuid()).start()
self.heal_wait = mock.patch('tacker.vnfm.infra_drivers.openstack.'
'openstack.OpenStack.heal_wait').start()
def _fake_spawn(func, *args, **kwargs):
func(*args, **kwargs)

View File

@ -229,10 +229,21 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
@log.log
def update_wait(self, plugin, context, vnf_dict, auth_attr,
region_name=None):
# do nothing but checking if the stack exists at the moment
heatclient = hc.HeatClient(auth_attr, region_name)
stack = heatclient.get(vnf_dict['instance_id'])
mgmt_ips = self._find_mgmt_ips(stack.outputs)
if mgmt_ips:
vnf_dict['mgmt_ip_address'] = jsonutils.dump_as_bytes(mgmt_ips)
@log.log
def heal_wait(self, plugin, context, vnf_dict, auth_attr,
region_name=None):
stack = self._wait_until_stack_ready(vnf_dict['instance_id'],
auth_attr, infra_cnst.STACK_UPDATE_IN_PROGRESS,
infra_cnst.STACK_UPDATE_COMPLETE,
vnfm.VNFUpdateWaitFailed, region_name=region_name)
vnfm.VNFHealWaitFailed, region_name=region_name)
mgmt_ips = self._find_mgmt_ips(stack.outputs)

View File

@ -22,3 +22,4 @@ KEY_KWARGS = 'kwargs'
ACTION_CREATE_VNF = 'create_vnf'
ACTION_UPDATE_VNF = 'update_vnf'
ACTION_DELETE_VNF = 'delete_vnf'
ACTION_HEAL_VNF = 'heal_vnf'

View File

@ -445,8 +445,49 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
self._create_vnf_wait(context, vnf_dict, vim_auth, infra_driver)
return vnf_dict
def _update_vnf_wait(self, context, vnf_dict, vim_auth, driver_name,
vnf_heal=False):
def _heal_vnf_wait(self, context, vnf_dict, vim_auth, driver_name):
kwargs = {
mgmt_constants.KEY_ACTION: mgmt_constants.ACTION_HEAL_VNF,
mgmt_constants.KEY_KWARGS: {'vnf': vnf_dict},
}
new_status = constants.ACTIVE
placement_attr = vnf_dict['placement_attr']
region_name = placement_attr.get('region_name')
try:
self._vnf_manager.invoke(
driver_name, 'heal_wait', plugin=self,
context=context, vnf_dict=vnf_dict, auth_attr=vim_auth,
region_name=region_name)
self.mgmt_call(context, vnf_dict, kwargs)
except vnfm.VNFHealWaitFailed as e:
with excutils.save_and_reraise_exception():
new_status = constants.ERROR
self._vnf_monitor.delete_hosting_vnf(vnf_dict['id'])
self.set_vnf_error_status_reason(context, vnf_dict['id'],
six.text_type(e))
except exceptions.MgmtDriverException as e:
LOG.error('VNF configuration failed')
new_status = constants.ERROR
self._vnf_monitor.delete_hosting_vnf(vnf_dict['id'])
self.set_vnf_error_status_reason(context, vnf_dict['id'],
six.text_type(e))
vnf_dict['status'] = new_status
self.mgmt_update_post(context, vnf_dict)
# Update vnf status to 'ACTIVE' so that monitoring can be resumed.
evt_details = ("Ends the heal vnf request for VNF '%s'" %
vnf_dict['id'])
self._vnf_monitor.update_hosting_vnf(vnf_dict, evt_details)
# _update_vnf_post() method updates vnf_status and mgmt_ip_address
self._update_vnf_post(context, vnf_dict['id'],
new_status, vnf_dict,
constants.PENDING_HEAL,
constants.RES_EVT_HEAL)
def _update_vnf_wait(self, context, vnf_dict, vim_auth, driver_name):
kwargs = {
mgmt_constants.KEY_ACTION: mgmt_constants.ACTION_UPDATE_VNF,
mgmt_constants.KEY_KWARGS: {'vnf': vnf_dict},
@ -460,6 +501,7 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
driver_name, 'update_wait', plugin=self,
context=context, vnf_dict=vnf_dict, auth_attr=vim_auth,
region_name=region_name)
self.mgmt_call(context, vnf_dict, kwargs)
except vnfm.VNFUpdateWaitFailed as e:
with excutils.save_and_reraise_exception():
@ -475,22 +517,9 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
six.text_type(e))
vnf_dict['status'] = new_status
self.mgmt_update_post(context, vnf_dict)
if vnf_heal:
# Update vnf status to 'ACTIVE' so that monitoring can be resumed.
evt_details = ("Ends the heal vnf request for VNF '%s'" %
vnf_dict['id'])
self._vnf_monitor.update_hosting_vnf(vnf_dict, evt_details)
# _update_vnf_post() method updates vnf_status and mgmt_ip_address
self._update_vnf_post(context, vnf_dict['id'],
new_status, vnf_dict,
constants.PENDING_HEAL,
constants.RES_EVT_HEAL)
else:
self._update_vnf_post(context, vnf_dict['id'], new_status,
vnf_dict, constants.PENDING_UPDATE,
constants.RES_EVT_UPDATE)
self._update_vnf_post(context, vnf_dict['id'], new_status,
vnf_dict, constants.PENDING_UPDATE,
constants.RES_EVT_UPDATE)
def update_vnf(self, context, vnf_id, vnf):
vnf_attributes = vnf['vnf']['attributes']
@ -561,8 +590,8 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
vnf_dict, constants.PENDING_HEAL,
constants.RES_EVT_HEAL)
self.spawn_n(self._update_vnf_wait, context, vnf_dict, vim_auth,
driver_name, vnf_heal=True)
self.spawn_n(self._heal_vnf_wait, context, vnf_dict, vim_auth,
driver_name)
return vnf_dict