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 model_base
|
||||
from neutron.db import models_v2
|
||||
from neutron import manager
|
||||
from neutron.openstack.common import jsonutils
|
||||
from neutron.openstack.common import log as logging
|
||||
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.services.servicechain.common import exceptions as s_exc
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
MAX_IPV4_SUBNET_PREFIX_LENGTH = 31
|
||||
|
@ -121,6 +124,17 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
|
|||
def __init__(self, *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):
|
||||
try:
|
||||
return self._get_by_id(context, ServiceChainNode, node_id)
|
||||
|
@ -205,6 +219,9 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
|
|||
with context.session.begin(subtransactions=True):
|
||||
node_db = self._get_servicechain_node(context,
|
||||
servicechain_node_id)
|
||||
if node_db.specs:
|
||||
raise schain.ServiceChainNodeInUse(
|
||||
node_id=servicechain_node_id)
|
||||
context.session.delete(node_db)
|
||||
|
||||
@log.log
|
||||
|
@ -331,9 +348,15 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
|
|||
|
||||
@log.log
|
||||
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):
|
||||
spec_db = self._get_servicechain_spec(context,
|
||||
spec_id)
|
||||
if spec_db.instances:
|
||||
raise schain.ServiceChainSpecInUse(spec_id=spec_id)
|
||||
context.session.delete(spec_db)
|
||||
|
||||
@log.log
|
||||
|
|
|
@ -49,6 +49,16 @@ class ServiceChainInstanceNotFound(nexc.NotFound):
|
|||
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):
|
||||
message = _("ServiceType %(service_type_id) could not be found")
|
||||
|
||||
|
|
|
@ -206,6 +206,9 @@ class ServiceChainDBTestPlugin(svcchain_db.ServiceChainDbPlugin):
|
|||
DB_GP_PLUGIN_KLASS = (ServiceChainDBTestPlugin.__module__ + '.' +
|
||||
ServiceChainDBTestPlugin.__name__)
|
||||
|
||||
GP_PLUGIN_KLASS = (
|
||||
"gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin")
|
||||
|
||||
|
||||
class ServiceChainDbTestCase(ServiceChainDBTestBase,
|
||||
test_db_plugin.NeutronDbPluginV2TestCase):
|
||||
|
@ -218,7 +221,8 @@ class ServiceChainDbTestCase(ServiceChainDBTestBase,
|
|||
sc_plugin = DB_GP_PLUGIN_KLASS
|
||||
self.plugin = importutils.import_object(sc_plugin)
|
||||
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(
|
||||
plugin=core_plugin, ext_mgr=ext_mgr,
|
||||
|
@ -290,9 +294,20 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
|||
scn = self.create_servicechain_node()
|
||||
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)
|
||||
res = req.get_response(self.ext_api)
|
||||
|
||||
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
|
||||
self.assertRaises(service_chain.ServiceChainNodeNotFound,
|
||||
self.plugin.get_servicechain_node,
|
||||
|
@ -394,6 +409,46 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
|||
self.assertRaises(service_chain.ServiceChainSpecNotFound,
|
||||
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):
|
||||
scs_id = self.create_servicechain_spec()['servicechain_spec']['id']
|
||||
policy_target_group_id = uuidutils.generate_uuid()
|
||||
|
|
Loading…
Reference in New Issue