Improve Router callback system's publish events

When I writing 'ndp_proxy' service plugin, I found I couldn't get enough
informations about router from the callback system (Such as: the origin
request body of user send). So, for write service plugin that related
router plugin more concisely I commit this patch.

This patch proposal two changes about router callback publish events:
1. Add 'request_body' parameter to some event's payload
2. add 'BEFORE_UPDATE' event for router gateway

Related-bug: #1877301
Change-Id: I5f6a4e6f0b7c5feb794ddb7efbd07d01bad91af8
This commit is contained in:
yangjianfeng 2021-08-17 02:41:15 -04:00
parent 8123cc6ee3
commit e4c168b1fc
9 changed files with 248 additions and 47 deletions

View File

@ -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)

View File

@ -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:

View File

@ -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)

View File

@ -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']])))

View File

@ -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)

View File

@ -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):

View File

@ -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)

View File

@ -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:

View File

@ -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.