delete sg rule on sg deletion on ODL neutron northbound

When security group is deleted, rules belongs to that security groups are
automatically deleted by cascade=delete.
So rules need to be deleted explicitly when security group is deleted.
Otherwise stale rules remains.

Closes-Bug: #1663470
Change-Id: I44a07d27e44ef5ff17409163c3194cb47b1eede0
(cherry picked from commit c2d7228f1a)
This commit is contained in:
Isaku Yamahata
2017-02-09 20:19:56 -08:00
committed by juraj.linkes
parent 57d9b878c0
commit 58cba3a394
5 changed files with 74 additions and 18 deletions

View File

@@ -87,7 +87,10 @@ class OdlSecurityGroupsHandler(object):
'res_id': res_id, 'odl_res_dict': odl_res_dict,
'kwargs': kwargs})
callback(context, odl_ops, odl_res_type, res_id, odl_res_dict)
copy_kwargs = kwargs.copy()
copy_kwargs.pop('context')
callback(context, odl_ops, odl_res_type, res_id, odl_res_dict,
**copy_kwargs)
def sg_callback_precommit(self, resource, event, trigger, **kwargs):
self._sg_callback(self._precommit, resource, event, trigger, **kwargs)

View File

@@ -379,8 +379,8 @@ class OpenDaylightDriver(object):
'object_id': obj_id})
self.out_of_sync = True
def sync_from_callback(self, context,
operation, res_type, res_id, resource_dict):
def sync_from_callback(self, context, operation, res_type,
res_id, resource_dict, **kwrags):
object_type = odl_utils.neutronify(res_type.plural)
try:
if operation == odl_const.ODL_DELETE:

View File

@@ -178,7 +178,7 @@ class OpenDaylightMechanismDriver(api.MechanismDriver):
rule['id'], odl_const.ODL_CREATE, res_rule)
def sync_from_callback_precommit(self, context, operation, res_type,
res_id, resource_dict):
res_id, resource_dict, **kwargs):
object_type = res_type.singular
if resource_dict is not None:
resource_dict = resource_dict[object_type]
@@ -237,9 +237,18 @@ class OpenDaylightMechanismDriver(api.MechanismDriver):
_("unsupporetd bulk creation of security group rule"))
journal.record(context, None, object_type, object_uuid,
operation, resource_dict)
# NOTE(yamahata): DB auto deletion
# Security Group Rule under this Security Group needs to
# be deleted. At NeutronDB layer rules are auto deleted with
# cascade='all,delete'.
if (object_type == odl_const.ODL_SG and
operation == odl_const.ODL_DELETE):
for rule in kwargs['security_group'].rules:
journal.record(context, None, odl_const.ODL_SG_RULE,
rule.id, odl_const.ODL_DELETE, [object_uuid])
def sync_from_callback_postcommit(self, context, operation, res_type,
res_id, resource_dict):
res_id, resource_dict, **kwargs):
self._postcommit(context)
def _postcommit(self, context):

View File

@@ -50,7 +50,7 @@ class ODLCallbackTestCase(testtools.TestCase):
self._precommit.assert_called_with(
plugin_context_mock, op,
callback._RESOURCE_MAPPING[resources.SECURITY_GROUP], sg_id,
expected_dict)
expected_dict, security_group=sg, security_group_id=sg_id)
def _test_callback_postcommit_for_sg(self, event, op, sg, sg_id):
plugin_context_mock = mock.Mock()
@@ -66,7 +66,7 @@ class ODLCallbackTestCase(testtools.TestCase):
self._postcommit.assert_called_with(
plugin_context_mock, op,
callback._RESOURCE_MAPPING[resources.SECURITY_GROUP], sg_id,
expected_dict)
expected_dict, security_group=sg, security_group_id=sg_id)
def test_callback_precommit_sg_create(self):
sg = mock.Mock()
@@ -112,7 +112,8 @@ class ODLCallbackTestCase(testtools.TestCase):
self._precommit.assert_called_with(
plugin_context_mock, op,
callback._RESOURCE_MAPPING[resources.SECURITY_GROUP_RULE],
sg_rule_id, expected_dict)
sg_rule_id, expected_dict, security_group_rule=sg_rule,
security_group_rule_id=sg_rule_id)
@mock.patch.object(OpenDaylightDriver, 'sync_from_callback')
def _test_callback_postcommit_for_sg_rules(
@@ -130,7 +131,9 @@ class ODLCallbackTestCase(testtools.TestCase):
self._postcommit.assert_called_with(
plugin_context_mock, op,
callback._RESOURCE_MAPPING[resources.SECURITY_GROUP_RULE],
sg_rule_id, expected_dict)
sg_rule_id, expected_dict,
security_group_rule=sg_rule, security_group_rule_id=sg_rule_id,
)
def test_callback_precommit_sg_rules_create(self):
rule = mock.Mock()

View File

@@ -263,6 +263,7 @@ class OpenDaylightMechanismDriverTestCase(OpenDaylightConfigBase):
'project_id': 'test-tenant',
'tenant_id': 'test-tenant',
'description': 'test-description',
'rules': [],
'id': SG_FAKE_ID}}
return context
@@ -324,18 +325,26 @@ class OpenDaylightMechanismDriverTestCase(OpenDaylightConfigBase):
context_ = (copy.deepcopy(context)
if operation != odl_const.ODL_DELETE else None)
if (object_type == odl_const.ODL_SG and
operation == odl_const.ODL_CREATE):
operation in [odl_const.ODL_CREATE, odl_const.ODL_DELETE]):
# TODO(yamahata): remove this work around once
# https://review.openstack.org/#/c/281693/
# is merged.
sg = securitygroup.SecurityGroup(
id=res_id, name=context_[object_type]['name'],
tenant_id=context_[object_type]['tenant_id'],
description=context_[object_type]['description'])
plugin_context_mock.session.add(sg)
context_[odl_const.ODL_SG].pop('id', None)
self.mech.sync_from_callback_precommit(
plugin_context_mock, operation, res_type, res_id, context_)
if operation == odl_const.ODL_CREATE:
sg = securitygroup.SecurityGroup(
id=res_id, name=context_[object_type]['name'],
tenant_id=context_[object_type]['tenant_id'],
description=context_[object_type]['description'])
plugin_context_mock.session.add(sg)
context_[odl_const.ODL_SG].pop('id', None)
if operation == odl_const.ODL_DELETE:
sg = mock.Mock()
sg.rules = []
self.mech.sync_from_callback_precommit(
plugin_context_mock, operation, res_type, res_id, context_,
security_group=sg)
else:
self.mech.sync_from_callback_precommit(
plugin_context_mock, operation, res_type, res_id, context_)
else:
method = getattr(self.mech, '%s_%s_precommit' % (operation,
object_type))
@@ -375,6 +384,10 @@ class OpenDaylightMechanismDriverTestCase(OpenDaylightConfigBase):
else:
url = '%s/%ss' % (cfg.CONF.ml2_odl.url, url_object_type)
if (object_type == odl_const.ODL_SG and
operation == odl_const.ODL_CREATE):
context = copy.deepcopy(context)
context[odl_const.ODL_SG].pop('rules')
if operation in [odl_const.ODL_CREATE, odl_const.ODL_UPDATE]:
kwargs = {
'url': url,
@@ -594,6 +607,34 @@ class OpenDaylightMechanismDriverTestCase(OpenDaylightConfigBase):
def test_sg_rule(self):
self._test_object_type(odl_const.ODL_SG_RULE)
def test_sg_delete(self):
with mock.patch.object(journal, 'record') as record:
context = self._get_mock_operation_context(odl_const.ODL_SG)
res_id = context[odl_const.ODL_SG]['id']
plugin_context_mock = mock.Mock()
plugin_context_mock.session = neutron_db_api.get_session()
rule = mock.Mock()
rule.id = SG_RULE_FAKE_ID
rule.security_group_id = SG_FAKE_ID
sg = mock.Mock()
sg.id = SG_FAKE_ID
sg.rules = [rule]
kwargs = {'security_group': sg}
self.mech.sync_from_callback_precommit(
plugin_context_mock, odl_const.ODL_DELETE,
callback._RESOURCE_MAPPING[odl_const.ODL_SG],
res_id, context, **kwargs)
record.assert_has_calls(
[mock.call(mock.ANY, None, 'security_group', 'sg_fake_uuid',
'delete',
{'description': 'test-description',
'project_id': 'test-tenant',
'rules': [],
'tenant_id': 'test-tenant',
'id': 'sg_fake_uuid', 'name': 'test_sg'}),
mock.call(mock.ANY, None, 'security_group_rule',
'sg_rule_fake_uuid', 'delete', ['sg_fake_uuid'])])
def test_sync_multiple_updates(self):
# add 2 updates
for i in range(2):