Merge "Prevent deletion of in use ServiceChain Resources"
This commit is contained in:
commit
fc4daaf5d0
|
@ -20,11 +20,14 @@ from neutron.common import log
|
||||||
from neutron.db import common_db_mixin
|
from neutron.db import common_db_mixin
|
||||||
from neutron.db import model_base
|
from neutron.db import model_base
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
|
from neutron import manager
|
||||||
from neutron.openstack.common import jsonutils
|
from neutron.openstack.common import jsonutils
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from neutron.openstack.common import uuidutils
|
from neutron.openstack.common import uuidutils
|
||||||
|
from neutron.plugins.common import constants as pconst
|
||||||
|
|
||||||
from gbpservice.neutron.extensions import servicechain as schain
|
from gbpservice.neutron.extensions import servicechain as schain
|
||||||
|
from gbpservice.neutron.services.servicechain.common import exceptions as s_exc
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
MAX_IPV4_SUBNET_PREFIX_LENGTH = 31
|
MAX_IPV4_SUBNET_PREFIX_LENGTH = 31
|
||||||
|
@ -121,6 +124,17 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ServiceChainDbPlugin, self).__init__(*args, **kwargs)
|
super(ServiceChainDbPlugin, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _grouppolicy_plugin(self):
|
||||||
|
# REVISIT(Magesh): Need initialization method after all
|
||||||
|
# plugins are loaded to grab and store plugin.
|
||||||
|
plugins = manager.NeutronManager.get_service_plugins()
|
||||||
|
grouppolicy_plugin = plugins.get(pconst.GROUP_POLICY)
|
||||||
|
if not grouppolicy_plugin:
|
||||||
|
LOG.error(_("No Grouppolicy service plugin found."))
|
||||||
|
raise s_exc.ServiceChainDeploymentError()
|
||||||
|
return grouppolicy_plugin
|
||||||
|
|
||||||
def _get_servicechain_node(self, context, node_id):
|
def _get_servicechain_node(self, context, node_id):
|
||||||
try:
|
try:
|
||||||
return self._get_by_id(context, ServiceChainNode, node_id)
|
return self._get_by_id(context, ServiceChainNode, node_id)
|
||||||
|
@ -205,6 +219,9 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
node_db = self._get_servicechain_node(context,
|
node_db = self._get_servicechain_node(context,
|
||||||
servicechain_node_id)
|
servicechain_node_id)
|
||||||
|
if node_db.specs:
|
||||||
|
raise schain.ServiceChainNodeInUse(
|
||||||
|
node_id=servicechain_node_id)
|
||||||
context.session.delete(node_db)
|
context.session.delete(node_db)
|
||||||
|
|
||||||
@log.log
|
@log.log
|
||||||
|
@ -331,9 +348,15 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
|
||||||
|
|
||||||
@log.log
|
@log.log
|
||||||
def delete_servicechain_spec(self, context, spec_id):
|
def delete_servicechain_spec(self, context, spec_id):
|
||||||
|
policy_actions = self._grouppolicy_plugin.get_policy_actions(
|
||||||
|
context, filters={"action_value": [spec_id]})
|
||||||
|
if policy_actions:
|
||||||
|
raise schain.ServiceChainSpecInUse(spec_id=spec_id)
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
spec_db = self._get_servicechain_spec(context,
|
spec_db = self._get_servicechain_spec(context,
|
||||||
spec_id)
|
spec_id)
|
||||||
|
if spec_db.instances:
|
||||||
|
raise schain.ServiceChainSpecInUse(spec_id=spec_id)
|
||||||
context.session.delete(spec_db)
|
context.session.delete(spec_db)
|
||||||
|
|
||||||
@log.log
|
@log.log
|
||||||
|
|
|
@ -49,6 +49,16 @@ class ServiceChainInstanceNotFound(nexc.NotFound):
|
||||||
message = _("ServiceChainInstance %(sc_instance_id)s could not be found")
|
message = _("ServiceChainInstance %(sc_instance_id)s could not be found")
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceChainNodeInUse(nexc.InUse):
|
||||||
|
message = _("Unable to complete operation, ServiceChainNode "
|
||||||
|
"%(node_id)s is in use")
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceChainSpecInUse(nexc.InUse):
|
||||||
|
message = _("Unable to complete operation, ServiceChainSpec "
|
||||||
|
"%(spec_id)s is in use")
|
||||||
|
|
||||||
|
|
||||||
class ServiceTypeNotFound(nexc.NotFound):
|
class ServiceTypeNotFound(nexc.NotFound):
|
||||||
message = _("ServiceType %(service_type_id) could not be found")
|
message = _("ServiceType %(service_type_id) could not be found")
|
||||||
|
|
||||||
|
|
|
@ -206,6 +206,9 @@ class ServiceChainDBTestPlugin(svcchain_db.ServiceChainDbPlugin):
|
||||||
DB_GP_PLUGIN_KLASS = (ServiceChainDBTestPlugin.__module__ + '.' +
|
DB_GP_PLUGIN_KLASS = (ServiceChainDBTestPlugin.__module__ + '.' +
|
||||||
ServiceChainDBTestPlugin.__name__)
|
ServiceChainDBTestPlugin.__name__)
|
||||||
|
|
||||||
|
GP_PLUGIN_KLASS = (
|
||||||
|
"gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin")
|
||||||
|
|
||||||
|
|
||||||
class ServiceChainDbTestCase(ServiceChainDBTestBase,
|
class ServiceChainDbTestCase(ServiceChainDBTestBase,
|
||||||
test_db_plugin.NeutronDbPluginV2TestCase):
|
test_db_plugin.NeutronDbPluginV2TestCase):
|
||||||
|
@ -218,7 +221,8 @@ class ServiceChainDbTestCase(ServiceChainDBTestBase,
|
||||||
sc_plugin = DB_GP_PLUGIN_KLASS
|
sc_plugin = DB_GP_PLUGIN_KLASS
|
||||||
self.plugin = importutils.import_object(sc_plugin)
|
self.plugin = importutils.import_object(sc_plugin)
|
||||||
if not service_plugins:
|
if not service_plugins:
|
||||||
service_plugins = {'sc_plugin_name': sc_plugin}
|
service_plugins = {'gp_plugin_name': GP_PLUGIN_KLASS,
|
||||||
|
'sc_plugin_name': sc_plugin}
|
||||||
|
|
||||||
super(ServiceChainDbTestCase, self).setUp(
|
super(ServiceChainDbTestCase, self).setUp(
|
||||||
plugin=core_plugin, ext_mgr=ext_mgr,
|
plugin=core_plugin, ext_mgr=ext_mgr,
|
||||||
|
@ -290,9 +294,20 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||||
scn = self.create_servicechain_node()
|
scn = self.create_servicechain_node()
|
||||||
scn_id = scn['servicechain_node']['id']
|
scn_id = scn['servicechain_node']['id']
|
||||||
|
|
||||||
|
scs = self.create_servicechain_spec(nodes=[scn_id])
|
||||||
|
scs_id = scs['servicechain_spec']['id']
|
||||||
|
|
||||||
|
# Deleting Service Chain Node in use by a Spec should fail
|
||||||
|
self.assertRaises(service_chain.ServiceChainNodeInUse,
|
||||||
|
self.plugin.delete_servicechain_node, ctx, scn_id)
|
||||||
|
|
||||||
|
req = self.new_delete_request('servicechain_specs', scs_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
# After deleting the Service Chain Spec, node delete should succeed
|
||||||
req = self.new_delete_request('servicechain_nodes', scn_id)
|
req = self.new_delete_request('servicechain_nodes', scn_id)
|
||||||
res = req.get_response(self.ext_api)
|
res = req.get_response(self.ext_api)
|
||||||
|
|
||||||
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
|
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
|
||||||
self.assertRaises(service_chain.ServiceChainNodeNotFound,
|
self.assertRaises(service_chain.ServiceChainNodeNotFound,
|
||||||
self.plugin.get_servicechain_node,
|
self.plugin.get_servicechain_node,
|
||||||
|
@ -394,6 +409,46 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||||
self.assertRaises(service_chain.ServiceChainSpecNotFound,
|
self.assertRaises(service_chain.ServiceChainSpecNotFound,
|
||||||
self.plugin.get_servicechain_spec, ctx, scs_id)
|
self.plugin.get_servicechain_spec, ctx, scs_id)
|
||||||
|
|
||||||
|
def test_delete_spec_in_use_by_policy_action_rejected(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
scs_id = self.create_servicechain_spec()['servicechain_spec']['id']
|
||||||
|
data = {'policy_action': {'action_type': 'redirect',
|
||||||
|
'tenant_id': self._tenant_id,
|
||||||
|
'action_value': scs_id}}
|
||||||
|
pa_req = self.new_create_request('grouppolicy/policy_actions',
|
||||||
|
data, self.fmt)
|
||||||
|
res = pa_req.get_response(self.ext_api)
|
||||||
|
if res.status_int >= webob.exc.HTTPClientError.code:
|
||||||
|
raise webob.exc.HTTPClientError(code=res.status_int)
|
||||||
|
|
||||||
|
self.assertRaises(service_chain.ServiceChainSpecInUse,
|
||||||
|
self.plugin.delete_servicechain_spec, ctx, scs_id)
|
||||||
|
|
||||||
|
def test_delete_spec_in_use_by_instance_rejected(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
scs_id = self.create_servicechain_spec()['servicechain_spec']['id']
|
||||||
|
|
||||||
|
sci = self.create_servicechain_instance(servicechain_specs=[scs_id])
|
||||||
|
sci_id = sci['servicechain_instance']['id']
|
||||||
|
|
||||||
|
# Deleting the Spec used by Instance should not be allowed
|
||||||
|
self.assertRaises(service_chain.ServiceChainSpecInUse,
|
||||||
|
self.plugin.delete_servicechain_spec, ctx, scs_id)
|
||||||
|
|
||||||
|
req = self.new_delete_request('servicechain_instances', sci_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
|
||||||
|
self.assertRaises(service_chain.ServiceChainInstanceNotFound,
|
||||||
|
self.plugin.get_servicechain_instance,
|
||||||
|
ctx, sci_id)
|
||||||
|
|
||||||
|
# Deleting the spec should succeed after the instance is deleted
|
||||||
|
req = self.new_delete_request('servicechain_specs', scs_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
|
||||||
|
self.assertRaises(service_chain.ServiceChainSpecNotFound,
|
||||||
|
self.plugin.get_servicechain_spec, ctx, scs_id)
|
||||||
|
|
||||||
def test_create_and_show_servicechain_instance(self):
|
def test_create_and_show_servicechain_instance(self):
|
||||||
scs_id = self.create_servicechain_spec()['servicechain_spec']['id']
|
scs_id = self.create_servicechain_spec()['servicechain_spec']['id']
|
||||||
policy_target_group_id = uuidutils.generate_uuid()
|
policy_target_group_id = uuidutils.generate_uuid()
|
||||||
|
|
Loading…
Reference in New Issue