by pass to run workflow if there is no tasks at all

When system errors, for example, we failed to create the member
vnf of a ns, the workflow tasks to delete the ns will be empty.

This patch is to deal with this error situation. in this case,
the workflow execution is passed by, and the NS object is deleted.

Change-Id: Ib714ab0dcc38859314239facc3f18bfcc18c0682
Closes-bug: 1670921
This commit is contained in:
yong sheng gong 2017-03-23 09:30:33 +08:00
parent 8d6d76ff98
commit e22bb960f1
7 changed files with 137 additions and 32 deletions

View File

@ -309,7 +309,7 @@ class NSPluginDb(network_service.NSPluginBase, db_base.CommonDbMixin):
self._model_query(context, NS).
filter(NS.id == ns_id).
filter(NS.status == constants.PENDING_DELETE))
if mistral_obj.state == 'ERROR':
if mistral_obj and mistral_obj.state == 'ERROR':
query.update({'status': constants.ERROR})
self._cos_db_plg.create_event(
context, res_id=ns_id,

View File

@ -221,6 +221,11 @@ class NSDInUse(exceptions.InUse):
class NSInUse(exceptions.InUse):
message = _('NS %(ns_id)s is still in use')
class NoTasksException(exceptions.TackerException):
message = _('No tasks to run for %(action)s on %(resource)s')
RESOURCE_ATTRIBUTE_MAP = {
'vims': {

View File

@ -485,6 +485,8 @@ class OpenStack_Driver(abstract_vim_driver.VimAbstractDriver,
mistral_client = self.get_mistral_client(auth_dict)
wg = workflow_generator.WorkflowGenerator(resource, action)
wg.task(**kwargs)
if not wg.get_tasks():
raise nfvo.NoTasksException(resource=resource, action=action)
definition_yaml = yaml.safe_dump(wg.definition)
workflow = mistral_client.workflows.create(definition_yaml)
return {'id': workflow[0].id, 'input': wg.get_input_dict()}

View File

@ -55,6 +55,9 @@ class WorkflowGenerator(object):
def _get_description(self):
pass
def get_tasks(self):
return self.definition[self.wf_identifier]['tasks']
def _add_create_vnf_tasks(self, ns):
vnfds = ns['vnfd_details']
task_dict = dict()

View File

@ -582,12 +582,15 @@ class NfvoPlugin(nfvo_db.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
ns['vnfd_details'] = vnfd_dict
# Step-3
kwargs = {'ns': ns, 'params': param_values}
workflow = self._vim_drivers.invoke(driver_type,
'prepare_and_create_workflow',
resource='vnf',
action='create',
auth_dict=self.get_auth_dict(context),
kwargs=kwargs)
# NOTE NoTasksException is raised if no tasks.
workflow = self._vim_drivers.invoke(
driver_type,
'prepare_and_create_workflow',
resource='vnf',
action='create',
auth_dict=self.get_auth_dict(context),
kwargs=kwargs)
try:
mistral_execution = self._vim_drivers.invoke(
driver_type,
@ -674,26 +677,32 @@ class NfvoPlugin(nfvo_db.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
ns = super(NfvoPlugin, self).get_ns(context, ns_id)
vim_res = self.vim_client.get_vim(context, ns['vim_id'])
driver_type = vim_res['vim_type']
workflow = self._vim_drivers.invoke(driver_type,
'prepare_and_create_workflow',
resource='vnf',
action='delete',
auth_dict=self.get_auth_dict(context),
kwargs={'ns': ns})
workflow = None
try:
mistral_execution = self._vim_drivers.invoke(
driver_type,
'execute_workflow',
workflow=workflow,
auth_dict=self.get_auth_dict(context))
except Exception as ex:
LOG.error(_('Error while executing workflow: %s'), ex)
self._vim_drivers.invoke(driver_type,
'delete_workflow',
workflow_id=workflow['id'],
auth_dict=self.get_auth_dict(context))
workflow = self._vim_drivers.invoke(driver_type,
'prepare_and_create_workflow',
resource='vnf',
action='delete',
auth_dict=self.get_auth_dict(context),
kwargs={'ns': ns})
except nfvo.NoTasksException:
LOG.warning(_("No VNF deletion task(s)."))
if workflow:
try:
mistral_execution = self._vim_drivers.invoke(
driver_type,
'execute_workflow',
workflow=workflow,
auth_dict=self.get_auth_dict(context))
raise ex
except Exception as ex:
LOG.error(_('Error while executing workflow: %s'), ex)
self._vim_drivers.invoke(driver_type,
'delete_workflow',
workflow_id=workflow['id'],
auth_dict=self.get_auth_dict(context))
raise ex
super(NfvoPlugin, self).delete_ns(context, ns_id)
def _delete_ns_wait(ns_id, execution_id):
@ -731,5 +740,9 @@ class NfvoPlugin(nfvo_db.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
auth_dict=self.get_auth_dict(context))
super(NfvoPlugin, self).delete_ns_post(context, ns_id, exec_obj,
error_reason)
self.spawn_n(_delete_ns_wait, ns['id'], mistral_execution.id)
if workflow:
self.spawn_n(_delete_ns_wait, ns['id'], mistral_execution.id)
else:
super(NfvoPlugin, self).delete_ns_post(
context, ns_id, None, None)
return ns['id']

View File

@ -18,6 +18,9 @@ import os
import yaml
DUMMY_NS_2_NAME = 'dummy_ns_2'
def _get_template(name):
filename = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
@ -213,3 +216,15 @@ def get_dummy_ns_obj():
'attributes': {
'param_values': {'nsd': {'vl1_name': 'net_mgmt',
'vl2_name': 'net0'}}}}}
def get_dummy_ns_obj_2():
return {'ns': {'description': 'dummy_ns_description',
'id': u'ba6bf017-f6f7-45f1-a280-57b073bf78ea',
'nsd_id': u'eb094833-995e-49f0-a047-dfb56aaf7c4e',
'vim_id': u'6261579e-d6f3-49ad-8bc3-a9cb974778ff',
'tenant_id': u'ad7ebc56538745a08ef7c5e97f8bd437',
'name': DUMMY_NS_2_NAME,
'attributes': {
'param_values': {'nsd': {'vl1_name': 'net_mgmt',
'vl2_name': 'net0'}}}}}

View File

@ -37,6 +37,7 @@ from tacker.tests.unit.db import utils
from tacker.vnfm import vim_client
SECRET_PASSWORD = '***'
DUMMY_NS_2 = 'ba6bf017-f6f7-45f1-a280-57b073bf78ef'
def dummy_get_vim(*args, **kwargs):
@ -63,6 +64,14 @@ class FakeDriverManager(mock.Mock):
mock_execution.id.return_value = \
"ba6bf017-f6f7-45f1-a280-57b073bf78ea"
return mock_execution
elif ('prepare_and_create_workflow' in args and
'delete' == kwargs['action'] and
DUMMY_NS_2 == kwargs['kwargs']['ns']['id']):
raise nfvo.NoTasksException()
elif ('prepare_and_create_workflow' in args and
'create' == kwargs['action'] and
utils.DUMMY_NS_2_NAME == kwargs['kwargs']['ns']['ns']['name']):
raise nfvo.NoTasksException()
def get_fake_nsd():
@ -588,13 +597,25 @@ class TestNfvoPlugin(db_base.SqlTestCase):
session.flush()
return ns
def _insert_dummy_ns_2(self):
session = self.context.session
ns = ns_db.NS(
id=DUMMY_NS_2,
name='fake_ns',
tenant_id='ad7ebc56538745a08ef7c5e97f8bd437',
status='ACTIVE',
nsd_id='eb094833-995e-49f0-a047-dfb56aaf7c4e',
vim_id='6261579e-d6f3-49ad-8bc3-a9cb974778ff',
description='fake_ns_description')
session.add(ns)
session.flush()
return ns
def test_create_nsd(self):
nsd_obj = utils.get_dummy_nsd_obj()
with patch.object(TackerManager, 'get_service_plugins') as \
mock_plugins:
mock_plugins.return_value = {'VNFM': FakeVNFMPlugin()}
mock.patch('tacker.common.driver_manager.DriverManager',
side_effect=FakeDriverManager()).start()
result = self.nfvo_plugin.create_nsd(self.context, nsd_obj)
self.assertIsNotNone(result)
self.assertEqual(result['name'], 'dummy_NSD')
@ -614,8 +635,6 @@ class TestNfvoPlugin(db_base.SqlTestCase):
with patch.object(TackerManager, 'get_service_plugins') as \
mock_plugins:
mock_plugins.return_value = {'VNFM': FakeVNFMPlugin()}
mock.patch('tacker.common.driver_manager.DriverManager',
side_effect=FakeDriverManager()).start()
mock_get_by_name.return_value = get_by_name()
ns_obj = utils.get_dummy_ns_obj()
@ -627,6 +646,29 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertIn('status', result)
self.assertIn('tenant_id', result)
@mock.patch.object(nfvo_plugin.NfvoPlugin, 'get_auth_dict')
@mock.patch.object(vim_client.VimClient, 'get_vim')
@mock.patch.object(nfvo_plugin.NfvoPlugin, '_get_by_name')
def test_create_ns_workflow_no_task_exception(
self, mock_get_by_name, mock_get_vimi, mock_auth_dict):
self._insert_dummy_ns_template()
self._insert_dummy_vim()
mock_auth_dict.return_value = {
'auth_url': 'http://127.0.0.1',
'token': 'DummyToken',
'project_domain_name': 'dummy_domain',
'project_name': 'dummy_project'
}
with patch.object(TackerManager, 'get_service_plugins') as \
mock_plugins:
mock_plugins.return_value = {'VNFM': FakeVNFMPlugin()}
mock_get_by_name.return_value = get_by_name()
ns_obj = utils.get_dummy_ns_obj_2()
self.assertRaises(nfvo.NoTasksException,
self.nfvo_plugin.create_ns,
self.context, ns_obj)
@mock.patch.object(nfvo_plugin.NfvoPlugin, 'get_auth_dict')
@mock.patch.object(vim_client.VimClient, 'get_vim')
@mock.patch.object(nfvo_plugin.NfvoPlugin, '_get_by_name')
@ -644,9 +686,34 @@ class TestNfvoPlugin(db_base.SqlTestCase):
with patch.object(TackerManager, 'get_service_plugins') as \
mock_plugins:
mock_plugins.return_value = {'VNFM': FakeVNFMPlugin()}
mock.patch('tacker.common.driver_manager.DriverManager',
side_effect=FakeDriverManager()).start()
mock_get_by_name.return_value = get_by_name()
result = self.nfvo_plugin.delete_ns(self.context,
'ba6bf017-f6f7-45f1-a280-57b073bf78ea')
self.assertIsNotNone(result)
@mock.patch.object(nfvo_plugin.NfvoPlugin, 'get_auth_dict')
@mock.patch.object(vim_client.VimClient, 'get_vim')
@mock.patch.object(nfvo_plugin.NfvoPlugin, '_get_by_name')
@mock.patch("tacker.db.nfvo.ns_db.NSPluginDb.delete_ns_post")
def test_delete_ns_no_task_exception(
self, mock_delete_ns_post, mock_get_by_name, mock_get_vim,
mock_auth_dict):
self._insert_dummy_vim()
self._insert_dummy_ns_template()
self._insert_dummy_ns_2()
mock_auth_dict.return_value = {
'auth_url': 'http://127.0.0.1',
'token': 'DummyToken',
'project_domain_name': 'dummy_domain',
'project_name': 'dummy_project'
}
with patch.object(TackerManager, 'get_service_plugins') as \
mock_plugins:
mock_plugins.return_value = {'VNFM': FakeVNFMPlugin()}
mock_get_by_name.return_value = get_by_name()
self.nfvo_plugin.delete_ns(self.context,
DUMMY_NS_2)
mock_delete_ns_post.assert_called_with(
self.context, DUMMY_NS_2, None, None)