diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py index 507e4809b4f..ad2701c9194 100644 --- a/neutron/db/l3_db.py +++ b/neutron/db/l3_db.py @@ -47,6 +47,7 @@ from neutron.common import ipv6_utils from neutron.common import utils from neutron.db import _utils as db_utils from neutron.db.models import l3 as l3_models +from neutron.db.models import l3_attrs as l3_attrs_models from neutron.db import models_v2 from neutron.db import standardattrdescription_db as st_attr from neutron.extensions import l3 @@ -254,26 +255,36 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, states=(router,))) return router_db - def _update_gw_for_create_router(self, context, gw_info, router_id): + def _update_gw_for_create_router(self, context, gw_info, + request_body, router_id): if gw_info: with db_utils.context_if_transaction( context, not context.session.is_active, writer=False): router_db = self._get_router(context, router_id) self._update_router_gw_info(context, router_id, - gw_info, router=router_db) + gw_info, request_body, + router=router_db) return self._get_router(context, router_id), None return None, None + def _get_stripped_router(self, router_body): + stripped_router = {} + for key in router_body: + if getattr(l3_models.Router, key, None) or getattr( + l3_attrs_models.RouterExtraAttributes, key, None): + stripped_router[key] = router_body[key] + return stripped_router + @db_api.retry_if_session_inactive() def create_router(self, context, router): r = router['router'] - gw_info = r.pop(EXTERNAL_GW_INFO, None) + gw_info = r.get(EXTERNAL_GW_INFO, None) create = functools.partial(self._create_router_db, context, r, r['tenant_id']) delete = functools.partial(self.delete_router, context) update_gw = functools.partial(self._update_gw_for_create_router, - context, gw_info) + context, gw_info, r) router_db, _unused = db_utils.safe_creation(context, create, delete, update_gw, transaction=False) @@ -294,7 +305,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, router_db = self._get_router(context, router_id) old_router = self._make_router_dict(router_db) if data: - router_db.update(data) + router_db.update(self._get_stripped_router(data)) registry.publish(resources.ROUTER, events.PRECOMMIT_UPDATE, self, payload=events.DBEventPayload( context, request_body=data, @@ -305,10 +316,10 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, @db_api.retry_if_session_inactive() def update_router(self, context, id, router): r = router['router'] - gw_info = r.pop(EXTERNAL_GW_INFO, constants.ATTR_NOT_SPECIFIED) + gw_info = r.get(EXTERNAL_GW_INFO, constants.ATTR_NOT_SPECIFIED) original = self.get_router(context, id) if gw_info != constants.ATTR_NOT_SPECIFIED: - self._update_router_gw_info(context, id, gw_info) + self._update_router_gw_info(context, id, gw_info, r) router_db = self._update_router_db(context, id, r) updated = self._make_router_dict(router_db) @@ -409,7 +420,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, {'router_id': [router_id]})) def _delete_current_gw_port(self, context, router_id, router, - new_network_id): + new_network_id, request_body=None): """Delete gw port if attached to an old network.""" port_requires_deletion = ( router.gw_port and router.gw_port['network_id'] != new_network_id) @@ -423,7 +434,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, router_id=router_id, net_id=router.gw_port['network_id']) gw_ips = [x['ip_address'] for x in router.gw_port['fixed_ips']] gw_port_id = router.gw_port['id'] - self._delete_router_gw_port_db(context, router) + self._delete_router_gw_port_db(context, router, request_body) if admin_ctx.session.is_active: # TODO(ralonsoh): ML2 plugin "delete_port" should be called outside # a DB transaction. In this case an exception is made but in order @@ -443,7 +454,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, metadata=metadata, resource_id=router_id)) - def _delete_router_gw_port_db(self, context, router): + def _delete_router_gw_port_db(self, context, router, request_body): with db_api.CONTEXT_WRITER.using(context): router.gw_port = None if router not in context.session: @@ -453,6 +464,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, events.BEFORE_DELETE, self, payload=events.DBEventPayload( context, states=(router,), + request_body=request_body, resource_id=router.id)) except exceptions.CallbackFailure as e: # NOTE(armax): preserve old check's behavior @@ -475,7 +487,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, registry.publish( resources.ROUTER_GATEWAY, events.BEFORE_CREATE, self, payload=events.DBEventPayload( - context, request_body=router, + context, metadata={ 'network_id': new_network_id, 'subnets': subnets}, @@ -503,11 +515,17 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, 'network_id': new_network_id}, resource_id=router_id)) - def _update_current_gw_port(self, context, router_id, router, ext_ips): + def _update_current_gw_port(self, context, router_id, router, + ext_ips, request_body): + registry.publish(resources.ROUTER_GATEWAY, events.BEFORE_UPDATE, self, + payload=events.DBEventPayload( + context, request_body=request_body, + states=(router,))) self._core_plugin.update_port(context.elevated(), router.gw_port['id'], {'port': {'fixed_ips': ext_ips}}) - def _update_router_gw_info(self, context, router_id, info, router=None): + def _update_router_gw_info(self, context, router_id, info, + request_body, router=None): router = router or self._get_router(context, router_id) gw_port = router.gw_port ext_ips = info.get('external_fixed_ips', []) if info else [] @@ -516,10 +534,10 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, network_id = self._validate_gw_info(context, info, ext_ips, router) if gw_port and ext_ip_change and gw_port['network_id'] == network_id: self._update_current_gw_port(context, router_id, router, - ext_ips) + ext_ips, request_body) else: self._delete_current_gw_port(context, router_id, router, - network_id) + network_id, request_body) self._create_gw_port(context, router_id, router, network_id, ext_ips) diff --git a/neutron/db/l3_gateway_ip_qos.py b/neutron/db/l3_gateway_ip_qos.py index 190b7a9ea26..9e8f6fb276b 100644 --- a/neutron/db/l3_gateway_ip_qos.py +++ b/neutron/db/l3_gateway_ip_qos.py @@ -60,11 +60,12 @@ class L3_gw_ip_qos_dbonly_mixin(l3_gwmode_db.L3_NAT_dbonly_mixin): policy = policy_object.QosPolicy.get_policy_obj(context, policy_id) policy.detach_router(router_id) - def _update_router_gw_info(self, context, router_id, info, router=None): + def _update_router_gw_info(self, context, router_id, info, + request_body, router=None): # Calls superclass, pass router db object for avoiding re-loading router = super(L3_gw_ip_qos_dbonly_mixin, self)._update_router_gw_info( - context, router_id, info, router) + context, router_id, info, request_body, router) with db_api.CONTEXT_WRITER.using(context): if self._is_gw_ip_qos_supported and router.gw_port: diff --git a/neutron/db/l3_gwmode_db.py b/neutron/db/l3_gwmode_db.py index 9c74df8b16d..b5206218051 100644 --- a/neutron/db/l3_gwmode_db.py +++ b/neutron/db/l3_gwmode_db.py @@ -56,24 +56,23 @@ class L3_NAT_dbonly_mixin(l3_db.L3_NAT_dbonly_mixin): ] }) - def _update_router_gw_info(self, context, router_id, info, router=None): + def _update_router_gw_info(self, context, router_id, info, + request_body, router=None): with db_api.CONTEXT_WRITER.using(context): # Always load the router inside the DB context. router = self._get_router(context, router_id) old_router = self._make_router_dict(router) router.enable_snat = self._get_enable_snat(info) - router_body = {l3_apidef.ROUTER: - {l3_apidef.EXTERNAL_GW_INFO: info}} registry.publish(resources.ROUTER_GATEWAY, events.PRECOMMIT_UPDATE, self, payload=events.DBEventPayload( - context, request_body=router_body, + context, request_body=request_body, states=(old_router,), resource_id=router_id, desired_state=router)) # Calls superclass, pass router db object for avoiding re-loading super(L3_NAT_dbonly_mixin, self)._update_router_gw_info( - context, router_id, info, router=router) + context, router_id, info, request_body, router=router) # Returning the router might come back useful if this # method is overridden in child classes return self._get_router(context, router_id) diff --git a/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py b/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py index 4596f2cd831..97dd7da5839 100644 --- a/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py +++ b/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py @@ -119,9 +119,13 @@ class L3DvrTestCase(L3DvrTestCaseBase): ext_net_id = ext_net['network']['id'] net1_id = net1['network']['id'] # Set gateway to router + + gw_info = {'network_id': ext_net_id} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router1['id'], - {'network_id': ext_net_id}) + gw_info, request_body) # Now add router interface (subnet1) from net1 to router self.l3_plugin.add_router_interface( self.context, router1['id'], @@ -292,18 +296,24 @@ class L3DvrTestCase(L3DvrTestCaseBase): self.context, router1['id'], {'subnet_id': subnet1['subnet']['id']}) # Set gateway to first router + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router1['id'], - {'network_id': ext_net_id}) + gw_info, request_body) # Create second router and add an interface router2 = self._create_router() self.l3_plugin.add_router_interface( self.context, router2['id'], {'subnet_id': subnet2['subnet']['id']}) # Set gateway to second router + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router2['id'], - {'network_id': ext_net_id}) + gw_info, request_body) # Create an agent gateway port for the external network net_id, agent_gw_port = ( self.setup_create_agent_gw_port_for_network(network=ext_net)) @@ -312,13 +322,15 @@ class L3DvrTestCase(L3DvrTestCaseBase): self.l3_plugin._get_agent_gw_ports_exist_for_network( self.context, ext_net_id, "", self.l3_agent['id'])) self.l3_plugin._update_router_gw_info( - self.context, router1['id'], {}) + self.context, router1['id'], {}, + {l3_apidef.EXTERNAL_GW_INFO: {}}) # Check for agent gateway port after deleting one of the gw self.assertIsNotNone( self.l3_plugin._get_agent_gw_ports_exist_for_network( self.context, ext_net_id, "", self.l3_agent['id'])) self.l3_plugin._update_router_gw_info( - self.context, router2['id'], {}) + self.context, router2['id'], {}, + {l3_apidef.EXTERNAL_GW_INFO: {}}) # Check for agent gateway port after deleting last gw self.assertIsNone( self.l3_plugin._get_agent_gw_ports_exist_for_network( @@ -631,9 +643,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): self.fmt, ext_net, '2001:db8::1', '2001:db8::/64', ip_version=constants.IP_VERSION_6, enable_dhcp=True) router1 = self._create_router() + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router1['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) snat_router_intfs = self.l3_plugin._get_snat_sync_interfaces( self.context, [router1['id']]) self.assertEqual(0, len(snat_router_intfs[router1['id']])) @@ -703,9 +718,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): candidates=[self.l3_agent]) # Set gateway to router + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) private_subnet1 = self._make_subnet( self.fmt, private_net1, @@ -811,9 +829,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): candidates=[self.l3_agent]) # Set gateway to router + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) private_subnet1 = self._make_subnet( self.fmt, private_net1, @@ -891,9 +912,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): candidates=[self.l3_agent]) # Set gateway to router + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) private_subnet1 = self._make_subnet( self.fmt, private_net1, @@ -966,9 +990,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): candidates=[self.l3_agent]) # Set gateway to router + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) private_subnet1 = self._make_subnet( self.fmt, private_net1, @@ -1048,9 +1075,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): candidates=[self.l3_agent]) # Set gateway to router + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) private_subnet1 = self._make_subnet( self.fmt, private_net1, @@ -1177,9 +1207,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): router['id'], candidates=[self.l3_agent]) # Set gateway to router + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) private_subnet1 = self._make_subnet( self.fmt, private_net1, @@ -1217,9 +1250,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): router['id'], candidates=[self.l3_agent]) # Set gateway to router + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) private_subnet1 = self._make_subnet( self.fmt, private_net1, @@ -1349,9 +1385,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): self.subnet(network=ext_net),\ self.subnet(cidr='20.0.0.0/24') as subnet,\ self.port(subnet=subnet): + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) self.l3_plugin.add_router_interface( self.context, router['id'], {'subnet_id': subnet['subnet']['id']}) @@ -1380,9 +1419,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): self.core_plugin.update_port( self.context, port['port']['id'], {'port': {'binding:host_id': self.l3_agent['host']}}) + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) self.l3_plugin.add_router_interface( self.context, router['id'], {'subnet_id': subnet['subnet']['id']}) @@ -1620,9 +1662,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): with self.subnet() as subnet,\ self.network(**kwargs) as ext_net,\ self.subnet(network=ext_net, cidr='20.0.0.0/24'): + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) self.l3_plugin.add_router_interface( self.context, router['id'], {'subnet_id': subnet['subnet']['id']}) @@ -1655,9 +1700,12 @@ class L3DvrTestCase(L3DvrTestCaseBase): self.core_plugin.update_port( self.context, port['port']['id'], {'port': {'binding:host_id': self.l3_agent['host']}}) + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) self.l3_plugin.add_router_interface( self.context, router['id'], {'subnet_id': subnet['subnet']['id']}) @@ -2036,9 +2084,12 @@ class L3DvrTestCaseMigration(L3DvrTestCaseBase): self.l3_plugin.add_router_interface( self.context, router['id'], {'subnet_id': subnet1['subnet']['id']}) + gw_info = {'network_id': ext_net['network']['id']} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.l3_plugin._update_router_gw_info( self.context, router['id'], - {'network_id': ext_net['network']['id']}) + gw_info, request_body) self.assertEqual( 0, len(self.l3_plugin._get_snat_sync_interfaces( self.context, [router['id']]))) diff --git a/neutron/tests/unit/db/test_l3_db.py b/neutron/tests/unit/db/test_l3_db.py index 9f583427e35..22003c38c13 100644 --- a/neutron/tests/unit/db/test_l3_db.py +++ b/neutron/tests/unit/db/test_l3_db.py @@ -17,6 +17,8 @@ from unittest import mock import ddt import netaddr +from neutron_lib.api.definitions import external_net as extnet_apidef +from neutron_lib.api.definitions import l3 as l3_apidef from neutron_lib.callbacks import events from neutron_lib.callbacks import registry from neutron_lib.callbacks import resources @@ -30,6 +32,7 @@ from neutron_lib.plugins import directory from neutron_lib.plugins import utils as plugin_utils from oslo_utils import uuidutils import testtools +import webob.exc from neutron.db import extraroute_db from neutron.db import l3_db @@ -606,6 +609,10 @@ class L3TestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase): self.ctx, network_id=self.network['network']['id']) network_obj.Network.get_object( self.ctx, id=self.network['network']['id']).delete() + router_ports = l3_obj.RouterPort.get_objects( + self.ctx, **{'router_id': self.router['id']}) + for router_port in router_ports: + router_port.delete() l3_obj.Router.get_object(self.ctx, id=self.router['id']).delete() def create_router(self, router): @@ -708,3 +715,104 @@ class L3TestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase): mock_log.warning.assert_called_once_with(self.GET_PORTS_BY_ROUTER_MSG, msg_vars) self._check_routerports((False, True)) + + def test_create_router_notify(self): + with mock.patch.object(l3_db.registry, 'publish') as mock_publish: + router = {'router': {'name': 'foo_router', + 'admin_state_up': True, + 'tenant_id': 'foo_tenant'}} + self.create_router(router) + expected_calls = [ + mock.call(resources.ROUTER, events.BEFORE_CREATE, + self.mixin, payload=mock.ANY), + mock.call(resources.ROUTER, events.PRECOMMIT_CREATE, + self.mixin, payload=mock.ANY), + mock.call(resources.ROUTER, events.AFTER_CREATE, + self.mixin, payload=mock.ANY), + ] + mock_publish.assert_has_calls(expected_calls) + + def test_update_router_notify(self): + with mock.patch.object(l3_db.registry, 'publish') as mock_publish: + self.mixin.update_router(self.ctx, self.router['id'], + {'router': {'name': 'test1'}}) + expected_calls = [ + mock.call(resources.ROUTER, events.PRECOMMIT_UPDATE, + self.mixin, payload=mock.ANY), + mock.call(resources.ROUTER, events.AFTER_UPDATE, + self.mixin, payload=mock.ANY), + ] + mock_publish.assert_has_calls(expected_calls) + + def _create_external_network(self, name=None, **kwargs): + name = name or 'network1' + kwargs[extnet_apidef.EXTERNAL] = True + with db_api.CONTEXT_WRITER.using(self.ctx): + res = self._create_network( + self.fmt, name, True, + arg_list=(extnet_apidef.EXTERNAL,), **kwargs) + if res.status_int >= webob.exc.HTTPClientError.code: + raise webob.exc.HTTPClientError(code=res.status_int) + return self.deserialize(self.fmt, res) + + def test_update_router_gw_notify(self): + with mock.patch.object(l3_db.registry, 'publish') as mock_publish: + ext_net = self._create_external_network() + self.create_subnet(ext_net, '1.1.2.1', '1.1.2.0/24') + update_data = { + l3_apidef.EXTERNAL_GW_INFO: { + 'network_id': ext_net['network']['id']}} + self.mixin.update_router( + self.ctx, self.router['id'], {'router': update_data}) + expected_calls = [ + mock.call(resources.NETWORK, events.BEFORE_CREATE, + mock.ANY, payload=mock.ANY), + mock.call(resources.SEGMENT, events.PRECOMMIT_CREATE, + mock.ANY, payload=mock.ANY), + mock.call(resources.NETWORK, events.PRECOMMIT_CREATE, + mock.ANY, payload=mock.ANY), + mock.call(resources.NETWORK, events.AFTER_CREATE, + mock.ANY, payload=mock.ANY), + mock.call(resources.NETWORK, events.BEFORE_RESPONSE, + mock.ANY, payload=mock.ANY), + mock.call(resources.SUBNET, events.BEFORE_CREATE, + mock.ANY, payload=mock.ANY), + mock.call(resources.SUBNET, events.AFTER_CREATE, + mock.ANY, payload=mock.ANY), + mock.call(resources.SUBNET, events.BEFORE_RESPONSE, + mock.ANY, payload=mock.ANY), + mock.call(resources.ROUTER_GATEWAY, events.BEFORE_CREATE, + self.mixin, payload=mock.ANY), + mock.call(resources.PORT, events.BEFORE_CREATE, + mock.ANY, payload=mock.ANY), + mock.call(resources.PORT, events.PRECOMMIT_CREATE, + mock.ANY, payload=mock.ANY), + mock.call(resources.PORT, events.AFTER_CREATE, + mock.ANY, payload=mock.ANY), + mock.call(resources.ROUTER_GATEWAY, events.AFTER_CREATE, + mock.ANY, payload=mock.ANY), + mock.call(resources.ROUTER, events.PRECOMMIT_UPDATE, + self.mixin, payload=mock.ANY), + mock.call(resources.ROUTER, events.AFTER_UPDATE, + self.mixin, payload=mock.ANY)] + mock_publish.assert_has_calls(expected_calls) + mock_publish.reset_mock() + update_data = {l3_apidef.EXTERNAL_GW_INFO: {}} + self.mixin.update_router( + self.ctx, self.router['id'], {'router': update_data}) + expected_calls = [ + mock.call(resources.ROUTER_GATEWAY, events.BEFORE_DELETE, + self.mixin, payload=mock.ANY), + mock.call(resources.PORT, events.BEFORE_DELETE, + mock.ANY, payload=mock.ANY), + mock.call(resources.PORT, events.PRECOMMIT_DELETE, + mock.ANY, payload=mock.ANY), + mock.call(resources.PORT, events.AFTER_DELETE, + mock.ANY, payload=mock.ANY), + mock.call(resources.ROUTER_GATEWAY, events.AFTER_DELETE, + self.mixin, payload=mock.ANY), + mock.call(resources.ROUTER, events.PRECOMMIT_UPDATE, + self.mixin, payload=mock.ANY), + mock.call(resources.ROUTER, events.AFTER_UPDATE, + self.mixin, payload=mock.ANY)] + mock_publish.assert_has_calls(expected_calls) diff --git a/neutron/tests/unit/db/test_l3_dvr_db.py b/neutron/tests/unit/db/test_l3_dvr_db.py index 6a784e2359d..ac3631fcb73 100644 --- a/neutron/tests/unit/db/test_l3_dvr_db.py +++ b/neutron/tests/unit/db/test_l3_dvr_db.py @@ -389,7 +389,7 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase): '_create_snat_intf_ports_if_not_exists') as cs: self.mixin._create_gw_port( self.ctx, router_id, router_db, mock.ANY, - mock.ANY) + mock.ANY, mock.ANY) self.assertFalse(cs.call_count) def test_build_routers_list_with_gw_port_mismatch(self): diff --git a/neutron/tests/unit/db/test_l3_hamode_db.py b/neutron/tests/unit/db/test_l3_hamode_db.py index 53088c5f172..7d89663c637 100644 --- a/neutron/tests/unit/db/test_l3_hamode_db.py +++ b/neutron/tests/unit/db/test_l3_hamode_db.py @@ -16,6 +16,7 @@ from unittest import mock from neutron_lib.api.definitions import dvr as dvr_apidef from neutron_lib.api.definitions import external_net as extnet_apidef +from neutron_lib.api.definitions import l3 as l3_apidef from neutron_lib.api.definitions import l3_ext_ha_mode from neutron_lib.api.definitions import port as port_def from neutron_lib.api.definitions import portbindings @@ -1093,8 +1094,11 @@ class L3HAModeDbTestCase(L3HATestFramework): interface_info = {'subnet_id': subnet['id']} router = self._create_router() + gw_info = {'network_id': ext_net} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.plugin._update_router_gw_info(self.admin_ctx, router['id'], - {'network_id': ext_net}) + gw_info, request_body) self.plugin.add_router_interface(self.admin_ctx, router['id'], interface_info) @@ -1119,8 +1123,11 @@ class L3HAModeDbTestCase(L3HATestFramework): interface_info = {'subnet_id': subnet['id']} router = self._create_router() + gw_info = {'network_id': ext_net} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.plugin._update_router_gw_info(self.admin_ctx, router['id'], - {'network_id': ext_net}) + gw_info, request_body) iface = self.plugin.add_router_interface(self.admin_ctx, router['id'], interface_info) @@ -1177,8 +1184,11 @@ class L3HAModeDbTestCase(L3HATestFramework): int_net) interface_info = {'subnet_id': subnet['id']} router = self._create_router(ha=True, distributed=True) + gw_info = {'network_id': ext_net} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.plugin._update_router_gw_info(self.admin_ctx, router['id'], - {'network_id': ext_net}) + gw_info, request_body) self.plugin.add_router_interface(self.admin_ctx, router['id'], interface_info) @@ -1310,8 +1320,11 @@ class L3HAModeDbTestCase(L3HATestFramework): interface_info = {'subnet_id': subnet['id']} router = self._create_router() + gw_info = {'network_id': ext_net} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.plugin._update_router_gw_info(self.admin_ctx, router['id'], - {'network_id': ext_net}) + gw_info, request_body) self.plugin.add_router_interface(self.admin_ctx, router['id'], interface_info) diff --git a/neutron/tests/unit/extensions/test_l3_ext_gw_mode.py b/neutron/tests/unit/extensions/test_l3_ext_gw_mode.py index e0e61f524f8..3e2e617b02a 100644 --- a/neutron/tests/unit/extensions/test_l3_ext_gw_mode.py +++ b/neutron/tests/unit/extensions/test_l3_ext_gw_mode.py @@ -256,11 +256,15 @@ class TestL3GwModeMixin(testlib_api.SqlTestCase): if not current_enable_snat: previous_gw_info = {'network_id': self.ext_net_id, 'enable_snat': current_enable_snat} + request_body = { + l3_apidef.EXTERNAL_GW_INFO: previous_gw_info} self.target_object._update_router_gw_info( - self.context, self.router.id, previous_gw_info) + self.context, self.router.id, previous_gw_info, request_body) + request_body = { + l3_apidef.EXTERNAL_GW_INFO: gw_info} self.target_object._update_router_gw_info( - self.context, self.router.id, gw_info) + self.context, self.router.id, gw_info, request_body) router = self.target_object._get_router( self.context, self.router.id) try: diff --git a/releasenotes/notes/improve-router-callback-event-5ddd73679f23039b.yaml b/releasenotes/notes/improve-router-callback-event-5ddd73679f23039b.yaml new file mode 100644 index 00000000000..561febc905e --- /dev/null +++ b/releasenotes/notes/improve-router-callback-event-5ddd73679f23039b.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + Add ``request_body`` field to router callback event payloads. The field + record the origin request body from user. + - | + Add ``BEFORE_UPDATE`` callback event for router gateway.