use callback payloads for SECURITY_GROUP_RULE

This patch switches over to callback payloads for
SECURITY_GROUP_RULE events.

Change-Id: Id80dc6790226cc81cb6535dc1bcaba58e991fdcb
This commit is contained in:
Nurmatov Mamatisa 2021-05-25 09:44:28 +03:00
parent 1e2088abbe
commit 941be42a61
5 changed files with 109 additions and 63 deletions

View File

@ -394,17 +394,24 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase,
context, rule_dict, validate=False) context, rule_dict, validate=False)
ret.append(res_rule_dict) ret.append(res_rule_dict)
for rdict in ret: for rdict in ret:
registry.notify( registry.publish(resources.SECURITY_GROUP_RULE,
resources.SECURITY_GROUP_RULE, events.AFTER_CREATE, self, events.AFTER_CREATE,
context=context, security_group_rule=rdict) self,
payload=events.DBEventPayload(
context,
resource_id=rdict['id'],
states=(rdict,)))
return ret return ret
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def create_security_group_rule(self, context, security_group_rule): def create_security_group_rule(self, context, security_group_rule):
res = self._create_security_group_rule(context, security_group_rule) res = self._create_security_group_rule(context, security_group_rule)
registry.notify( registry.publish(resources.SECURITY_GROUP_RULE, events.AFTER_CREATE,
resources.SECURITY_GROUP_RULE, events.AFTER_CREATE, self, self, payload=events.DBEventPayload(
context=context, security_group_rule=res) context,
resource_id=res['id'],
states=(res,)))
return res return res
def _create_security_group_rule(self, context, security_group_rule, def _create_security_group_rule(self, context, security_group_rule,
@ -444,13 +451,14 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase,
if port_range_max is not None: if port_range_max is not None:
args['port_range_max'] = port_range_max args['port_range_max'] = port_range_max
kwargs = { self._registry_notify(
'context': context, resources.SECURITY_GROUP_RULE,
'security_group_rule': args events.BEFORE_CREATE,
} exc_cls=ext_sg.SecurityGroupConflict,
self._registry_notify(resources.SECURITY_GROUP_RULE, payload=events.DBEventPayload(
events.BEFORE_CREATE, context, resource_id=args['id'],
exc_cls=ext_sg.SecurityGroupConflict, **kwargs) states=(args,)))
with db_api.CONTEXT_WRITER.using(context): with db_api.CONTEXT_WRITER.using(context):
if validate: if validate:
self._check_for_duplicate_rules(context, sg_id, self._check_for_duplicate_rules(context, sg_id,
@ -463,11 +471,14 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase,
sg_rule = sg_obj.SecurityGroupRule.get_object(context, sg_rule = sg_obj.SecurityGroupRule.get_object(context,
id=sg_rule.id) id=sg_rule.id)
res_rule_dict = self._make_security_group_rule_dict(sg_rule.db_obj) res_rule_dict = self._make_security_group_rule_dict(sg_rule.db_obj)
kwargs['security_group_rule'] = res_rule_dict
self._registry_notify( self._registry_notify(
resources.SECURITY_GROUP_RULE, resources.SECURITY_GROUP_RULE,
events.PRECOMMIT_CREATE, events.PRECOMMIT_CREATE,
exc_cls=ext_sg.SecurityGroupConflict, **kwargs) exc_cls=ext_sg.SecurityGroupConflict,
payload=events.DBEventPayload(
context, resource_id=res_rule_dict['id'],
states=(res_rule_dict,)))
return res_rule_dict return res_rule_dict
def _get_ip_proto_number(self, protocol): def _get_ip_proto_number(self, protocol):
@ -833,26 +844,32 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase,
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def delete_security_group_rule(self, context, id): def delete_security_group_rule(self, context, id):
kwargs = {
'context': context,
'security_group_rule_id': id
}
self._registry_notify(resources.SECURITY_GROUP_RULE, self._registry_notify(resources.SECURITY_GROUP_RULE,
events.BEFORE_DELETE, id=id, events.BEFORE_DELETE,
exc_cls=ext_sg.SecurityGroupRuleInUse, **kwargs) exc_cls=ext_sg.SecurityGroupRuleInUse,
payload=events.DBEventPayload(
context, resource_id=id,))
with db_api.CONTEXT_WRITER.using(context): with db_api.CONTEXT_WRITER.using(context):
sgr = self._get_security_group_rule(context, id) sgr = self._get_security_group_rule(context, id)
kwargs['security_group_id'] = sgr['security_group_id'] self._registry_notify(
self._registry_notify(resources.SECURITY_GROUP_RULE, resources.SECURITY_GROUP_RULE,
events.PRECOMMIT_DELETE, events.PRECOMMIT_DELETE,
exc_cls=ext_sg.SecurityGroupRuleInUse, id=id, exc_cls=ext_sg.SecurityGroupRuleInUse,
**kwargs) payload=events.DBEventPayload(
context,
resource_id=id,
metadata={'security_group_id': sgr['security_group_id']}))
sgr.delete() sgr.delete()
registry.notify( registry.publish(
resources.SECURITY_GROUP_RULE, events.AFTER_DELETE, self, resources.SECURITY_GROUP_RULE,
**kwargs) events.AFTER_DELETE,
self,
payload=events.DBEventPayload(
context,
resource_id=id,
metadata={'security_group_id': sgr['security_group_id']}))
@staticmethod @staticmethod
@resource_extend.extends([port_def.COLLECTION_NAME]) @resource_extend.extends([port_def.COLLECTION_NAME])

View File

@ -379,26 +379,30 @@ class OVNMechanismDriver(api.MechanismDriver):
ovn_revision_numbers_db.bump_revision( ovn_revision_numbers_db.bump_revision(
kwargs['context'], security_group, ovn_const.TYPE_SECURITY_GROUPS) kwargs['context'], security_group, ovn_const.TYPE_SECURITY_GROUPS)
def _create_sg_rule_precommit(self, resource, event, trigger, **kwargs): def _create_sg_rule_precommit(self, resource, event, trigger,
sg_rule = kwargs.get('security_group_rule') payload):
context = kwargs.get('context') sg_rule = payload.latest_state
context = payload.context
ovn_revision_numbers_db.create_initial_revision( ovn_revision_numbers_db.create_initial_revision(
context, sg_rule['id'], ovn_const.TYPE_SECURITY_GROUP_RULES, context, sg_rule['id'], ovn_const.TYPE_SECURITY_GROUP_RULES,
std_attr_id=sg_rule['standard_attr_id']) std_attr_id=sg_rule['standard_attr_id'])
def _process_sg_rule_notification( def _process_sg_rule_notification(
self, resource, event, trigger, **kwargs): self, resource, event, trigger, payload):
context = payload.context
security_group_rule = payload.latest_state
security_group_rule_id = payload.resource_id
if event == events.AFTER_CREATE: if event == events.AFTER_CREATE:
self._ovn_client.create_security_group_rule( self._ovn_client.create_security_group_rule(
kwargs['context'], kwargs.get('security_group_rule')) context, security_group_rule)
elif event == events.BEFORE_DELETE: elif event == events.BEFORE_DELETE:
sg_rule = self._plugin.get_security_group_rule( sg_rule = self._plugin.get_security_group_rule(
kwargs['context'], kwargs.get('security_group_rule_id')) context, security_group_rule_id)
if sg_rule.get('remote_ip_prefix') is not None: if sg_rule.get('remote_ip_prefix') is not None:
if self._sg_has_rules_with_same_normalized_cidr(sg_rule): if self._sg_has_rules_with_same_normalized_cidr(sg_rule):
return return
self._ovn_client.delete_security_group_rule( self._ovn_client.delete_security_group_rule(
kwargs['context'], context,
sg_rule) sg_rule)
def _sg_has_rules_with_same_normalized_cidr(self, sg_rule): def _sg_has_rules_with_same_normalized_cidr(self, sg_rule):

View File

@ -37,7 +37,9 @@ LOG = logging.getLogger(__name__)
class _ObjectChangeHandler(object): class _ObjectChangeHandler(object):
_PAYLOAD_RESOURCES = (resources.NETWORK, resources.ADDRESS_GROUP,) _PAYLOAD_RESOURCES = (resources.NETWORK,
resources.ADDRESS_GROUP,
resources.SECURITY_GROUP_RULE,)
def __init__(self, resource, object_class, resource_push_api): def __init__(self, resource, object_class, resource_push_api):
self._resource = resource self._resource = resource

View File

@ -124,8 +124,8 @@ class SecurityGroupDbMixinTestCase(testlib_api.SqlTestCase):
with mock.patch.object(self.mixin, '_validate_security_group_rule'),\ with mock.patch.object(self.mixin, '_validate_security_group_rule'),\
mock.patch.object(self.mixin, mock.patch.object(self.mixin,
'_check_for_duplicate_rules'),\ '_check_for_duplicate_rules'),\
mock.patch.object(registry, "notify") as mock_notify: mock.patch.object(registry, "publish") as mock_publish:
mock_notify.side_effect = exceptions.CallbackFailure(Exception()) mock_publish.side_effect = exceptions.CallbackFailure(Exception())
with testtools.ExpectedException( with testtools.ExpectedException(
securitygroup.SecurityGroupConflict): securitygroup.SecurityGroupConflict):
self.mixin.create_security_group_rule( self.mixin.create_security_group_rule(
@ -201,8 +201,8 @@ class SecurityGroupDbMixinTestCase(testlib_api.SqlTestCase):
context, 'fake', [rule_dict]) context, 'fake', [rule_dict])
def test_delete_security_group_rule_in_use(self): def test_delete_security_group_rule_in_use(self):
with mock.patch.object(registry, "notify") as mock_notify: with mock.patch.object(registry, "publish") as mock_publish:
mock_notify.side_effect = exceptions.CallbackFailure(Exception()) mock_publish.side_effect = exceptions.CallbackFailure(Exception())
with testtools.ExpectedException( with testtools.ExpectedException(
securitygroup.SecurityGroupRuleInUse): securitygroup.SecurityGroupRuleInUse):
self.mixin.delete_security_group_rule(self.ctx, mock.ANY) self.mixin.delete_security_group_rule(self.ctx, mock.ANY)
@ -415,34 +415,54 @@ class SecurityGroupDbMixinTestCase(testlib_api.SqlTestCase):
sg_dict = self.mixin.create_security_group(self.ctx, FAKE_SECGROUP) sg_dict = self.mixin.create_security_group(self.ctx, FAKE_SECGROUP)
fake_rule = FAKE_SECGROUP_RULE fake_rule = FAKE_SECGROUP_RULE
fake_rule['security_group_rule']['security_group_id'] = sg_dict['id'] fake_rule['security_group_rule']['security_group_id'] = sg_dict['id']
with mock.patch.object(registry, "notify") as mock_notify, \ with mock.patch.object(registry, "publish") as mock_publish, \
mock.patch.object(self.mixin, '_get_security_group'): mock.patch.object(self.mixin, '_get_security_group'):
mock_notify.assert_has_calls([mock.call('security_group_rule', sg_rule = self.mixin.create_security_group_rule(self.ctx,
'precommit_create', mock.ANY, context=mock.ANY, fake_rule)
security_group_rule=self.mixin.create_security_group_rule( mock_publish.assert_has_calls([mock.call(
self.ctx, fake_rule))]) 'security_group_rule',
'precommit_create', mock.ANY, payload=mock.ANY)])
payload = mock_publish.mock_calls[1][2]['payload']
self.assertEqual(sg_rule['id'], payload.resource_id)
self.assertEqual(sg_rule, payload.latest_state)
def test_sg_rule_before_precommit_and_after_delete_event(self): def test_sg_rule_before_precommit_and_after_delete_event(self):
sg_dict = self.mixin.create_security_group(self.ctx, FAKE_SECGROUP) sg_dict = self.mixin.create_security_group(self.ctx, FAKE_SECGROUP)
fake_rule = FAKE_SECGROUP_RULE fake_rule = FAKE_SECGROUP_RULE
fake_rule['security_group_rule']['security_group_id'] = sg_dict['id'] fake_rule['security_group_rule']['security_group_id'] = sg_dict['id']
with mock.patch.object(registry, "notify") as mock_notify, \ with mock.patch.object(registry, "publish") as mock_publish, \
mock.patch.object(self.mixin, '_get_security_group'): mock.patch.object(self.mixin, '_get_security_group'):
sg_rule_dict = self.mixin.create_security_group_rule(self.ctx, sg_rule_dict = self.mixin.create_security_group_rule(self.ctx,
fake_rule) fake_rule)
self.mixin.delete_security_group_rule(self.ctx, self.mixin.delete_security_group_rule(self.ctx,
sg_rule_dict['id']) sg_rule_dict['id'])
mock_notify.assert_has_calls([mock.call('security_group_rule', mock_publish.assert_has_calls([mock.call('security_group_rule',
'before_delete', mock.ANY, context=mock.ANY, 'before_delete',
security_group_rule_id=sg_rule_dict['id'])]) mock.ANY,
mock_notify.assert_has_calls([mock.call('security_group_rule', payload=mock.ANY)])
'precommit_delete', mock.ANY, context=mock.ANY, mock_publish.assert_has_calls([mock.call('security_group_rule',
security_group_id=sg_dict['id'], 'precommit_delete',
security_group_rule_id=sg_rule_dict['id'])]) mock.ANY,
mock_notify.assert_has_calls([mock.call('security_group_rule', payload=mock.ANY)])
'after_delete', mock.ANY, context=mock.ANY, mock_publish.assert_has_calls([mock.call('security_group_rule',
security_group_rule_id=sg_rule_dict['id'], 'after_delete',
security_group_id=sg_dict['id'])]) mock.ANY,
payload=mock.ANY)])
payload = mock_publish.mock_calls[1][2]['payload']
self.assertEqual(mock.ANY, payload.context)
self.assertEqual(sg_rule_dict, payload.latest_state)
self.assertEqual(sg_rule_dict['id'], payload.resource_id)
payload = mock_publish.mock_calls[2][2]['payload']
self.assertEqual(mock.ANY, payload.context)
self.assertEqual(sg_rule_dict, payload.latest_state)
self.assertEqual(sg_rule_dict['id'], payload.resource_id)
payload = mock_publish.mock_calls[3][2]['payload']
self.assertEqual(mock.ANY, payload.context)
self.assertEqual(sg_rule_dict['id'], payload.resource_id)
def test_get_ip_proto_name_and_num(self): def test_get_ip_proto_name_and_num(self):
protocols = [constants.PROTO_NAME_UDP, str(constants.PROTO_NUM_TCP), protocols = [constants.PROTO_NAME_UDP, str(constants.PROTO_NUM_TCP),

View File

@ -258,7 +258,8 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
rule = {'security_group_id': 'sg_id'} rule = {'security_group_id': 'sg_id'}
self.mech_driver._process_sg_rule_notification( self.mech_driver._process_sg_rule_notification(
resources.SECURITY_GROUP_RULE, events.AFTER_CREATE, {}, resources.SECURITY_GROUP_RULE, events.AFTER_CREATE, {},
security_group_rule=rule, context=self.context) payload=events.DBEventPayload(
self.context, states=(rule,)))
has_same_rules.assert_not_called() has_same_rules.assert_not_called()
ovn_acl_up.assert_called_once_with( ovn_acl_up.assert_called_once_with(
mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY,
@ -278,7 +279,8 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
'remote_ip_prefix': '1.0.0.0/24'} 'remote_ip_prefix': '1.0.0.0/24'}
self.mech_driver._process_sg_rule_notification( self.mech_driver._process_sg_rule_notification(
resources.SECURITY_GROUP_RULE, events.AFTER_CREATE, {}, resources.SECURITY_GROUP_RULE, events.AFTER_CREATE, {},
security_group_rule=rule, context=self.context) payload=events.DBEventPayload(
self.context, states=(rule,)))
has_same_rules.assert_not_called() has_same_rules.assert_not_called()
ovn_acl_up.assert_called_once_with( ovn_acl_up.assert_called_once_with(
mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY,
@ -296,7 +298,8 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
return_value=rule): return_value=rule):
self.mech_driver._process_sg_rule_notification( self.mech_driver._process_sg_rule_notification(
resources.SECURITY_GROUP_RULE, events.BEFORE_DELETE, {}, resources.SECURITY_GROUP_RULE, events.BEFORE_DELETE, {},
security_group_rule=rule, context=self.context) payload=events.DBEventPayload(
self.context, states=(rule,)))
ovn_acl_up.assert_called_once_with( ovn_acl_up.assert_called_once_with(
mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY,
'sg_id', rule, is_add_acl=False, stateless_supported=False) 'sg_id', rule, is_add_acl=False, stateless_supported=False)