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.common import utils
from neutron.db import _utils as db_utils from neutron.db import _utils as db_utils
from neutron.db.models import l3 as l3_models 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 models_v2
from neutron.db import standardattrdescription_db as st_attr from neutron.db import standardattrdescription_db as st_attr
from neutron.extensions import l3 from neutron.extensions import l3
@ -254,26 +255,36 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
states=(router,))) states=(router,)))
return router_db 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: if gw_info:
with db_utils.context_if_transaction( with db_utils.context_if_transaction(
context, not context.session.is_active, writer=False): context, not context.session.is_active, writer=False):
router_db = self._get_router(context, router_id) router_db = self._get_router(context, router_id)
self._update_router_gw_info(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 self._get_router(context, router_id), None
return None, 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() @db_api.retry_if_session_inactive()
def create_router(self, context, router): def create_router(self, context, router):
r = router['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, create = functools.partial(self._create_router_db, context, r,
r['tenant_id']) r['tenant_id'])
delete = functools.partial(self.delete_router, context) delete = functools.partial(self.delete_router, context)
update_gw = functools.partial(self._update_gw_for_create_router, 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, router_db, _unused = db_utils.safe_creation(context, create,
delete, update_gw, delete, update_gw,
transaction=False) transaction=False)
@ -294,7 +305,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
router_db = self._get_router(context, router_id) router_db = self._get_router(context, router_id)
old_router = self._make_router_dict(router_db) old_router = self._make_router_dict(router_db)
if data: if data:
router_db.update(data) router_db.update(self._get_stripped_router(data))
registry.publish(resources.ROUTER, events.PRECOMMIT_UPDATE, self, registry.publish(resources.ROUTER, events.PRECOMMIT_UPDATE, self,
payload=events.DBEventPayload( payload=events.DBEventPayload(
context, request_body=data, context, request_body=data,
@ -305,10 +316,10 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def update_router(self, context, id, router): def update_router(self, context, id, router):
r = router['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) original = self.get_router(context, id)
if gw_info != constants.ATTR_NOT_SPECIFIED: 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) router_db = self._update_router_db(context, id, r)
updated = self._make_router_dict(router_db) updated = self._make_router_dict(router_db)
@ -409,7 +420,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
{'router_id': [router_id]})) {'router_id': [router_id]}))
def _delete_current_gw_port(self, context, router_id, router, 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.""" """Delete gw port if attached to an old network."""
port_requires_deletion = ( port_requires_deletion = (
router.gw_port and router.gw_port['network_id'] != new_network_id) 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']) 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_ips = [x['ip_address'] for x in router.gw_port['fixed_ips']]
gw_port_id = router.gw_port['id'] 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: if admin_ctx.session.is_active:
# TODO(ralonsoh): ML2 plugin "delete_port" should be called outside # TODO(ralonsoh): ML2 plugin "delete_port" should be called outside
# a DB transaction. In this case an exception is made but in order # 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, metadata=metadata,
resource_id=router_id)) 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): with db_api.CONTEXT_WRITER.using(context):
router.gw_port = None router.gw_port = None
if router not in context.session: if router not in context.session:
@ -453,6 +464,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
events.BEFORE_DELETE, self, events.BEFORE_DELETE, self,
payload=events.DBEventPayload( payload=events.DBEventPayload(
context, states=(router,), context, states=(router,),
request_body=request_body,
resource_id=router.id)) resource_id=router.id))
except exceptions.CallbackFailure as e: except exceptions.CallbackFailure as e:
# NOTE(armax): preserve old check's behavior # NOTE(armax): preserve old check's behavior
@ -475,7 +487,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
registry.publish( registry.publish(
resources.ROUTER_GATEWAY, events.BEFORE_CREATE, self, resources.ROUTER_GATEWAY, events.BEFORE_CREATE, self,
payload=events.DBEventPayload( payload=events.DBEventPayload(
context, request_body=router, context,
metadata={ metadata={
'network_id': new_network_id, 'network_id': new_network_id,
'subnets': subnets}, 'subnets': subnets},
@ -503,11 +515,17 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
'network_id': new_network_id}, 'network_id': new_network_id},
resource_id=router_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'], self._core_plugin.update_port(context.elevated(), router.gw_port['id'],
{'port': {'fixed_ips': ext_ips}}) {'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) router = router or self._get_router(context, router_id)
gw_port = router.gw_port gw_port = router.gw_port
ext_ips = info.get('external_fixed_ips', []) if info else [] 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) 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: if gw_port and ext_ip_change and gw_port['network_id'] == network_id:
self._update_current_gw_port(context, router_id, router, self._update_current_gw_port(context, router_id, router,
ext_ips) ext_ips, request_body)
else: else:
self._delete_current_gw_port(context, router_id, router, 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, self._create_gw_port(context, router_id, router, network_id,
ext_ips) 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 = policy_object.QosPolicy.get_policy_obj(context, policy_id)
policy.detach_router(router_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 # Calls superclass, pass router db object for avoiding re-loading
router = super(L3_gw_ip_qos_dbonly_mixin, router = super(L3_gw_ip_qos_dbonly_mixin,
self)._update_router_gw_info( self)._update_router_gw_info(
context, router_id, info, router) context, router_id, info, request_body, router)
with db_api.CONTEXT_WRITER.using(context): with db_api.CONTEXT_WRITER.using(context):
if self._is_gw_ip_qos_supported and router.gw_port: 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): with db_api.CONTEXT_WRITER.using(context):
# Always load the router inside the DB context. # Always load the router inside the DB context.
router = self._get_router(context, router_id) router = self._get_router(context, router_id)
old_router = self._make_router_dict(router) old_router = self._make_router_dict(router)
router.enable_snat = self._get_enable_snat(info) router.enable_snat = self._get_enable_snat(info)
router_body = {l3_apidef.ROUTER:
{l3_apidef.EXTERNAL_GW_INFO: info}}
registry.publish(resources.ROUTER_GATEWAY, registry.publish(resources.ROUTER_GATEWAY,
events.PRECOMMIT_UPDATE, self, events.PRECOMMIT_UPDATE, self,
payload=events.DBEventPayload( payload=events.DBEventPayload(
context, request_body=router_body, context, request_body=request_body,
states=(old_router,), resource_id=router_id, states=(old_router,), resource_id=router_id,
desired_state=router)) desired_state=router))
# Calls superclass, pass router db object for avoiding re-loading # Calls superclass, pass router db object for avoiding re-loading
super(L3_NAT_dbonly_mixin, self)._update_router_gw_info( 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 # Returning the router might come back useful if this
# method is overridden in child classes # method is overridden in child classes
return self._get_router(context, router_id) return self._get_router(context, router_id)

View File

@ -119,9 +119,13 @@ class L3DvrTestCase(L3DvrTestCaseBase):
ext_net_id = ext_net['network']['id'] ext_net_id = ext_net['network']['id']
net1_id = net1['network']['id'] net1_id = net1['network']['id']
# Set gateway to router # 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.l3_plugin._update_router_gw_info(
self.context, router1['id'], self.context, router1['id'],
{'network_id': ext_net_id}) gw_info, request_body)
# Now add router interface (subnet1) from net1 to router # Now add router interface (subnet1) from net1 to router
self.l3_plugin.add_router_interface( self.l3_plugin.add_router_interface(
self.context, router1['id'], self.context, router1['id'],
@ -292,18 +296,24 @@ class L3DvrTestCase(L3DvrTestCaseBase):
self.context, router1['id'], self.context, router1['id'],
{'subnet_id': subnet1['subnet']['id']}) {'subnet_id': subnet1['subnet']['id']})
# Set gateway to first router # 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.l3_plugin._update_router_gw_info(
self.context, router1['id'], self.context, router1['id'],
{'network_id': ext_net_id}) gw_info, request_body)
# Create second router and add an interface # Create second router and add an interface
router2 = self._create_router() router2 = self._create_router()
self.l3_plugin.add_router_interface( self.l3_plugin.add_router_interface(
self.context, router2['id'], self.context, router2['id'],
{'subnet_id': subnet2['subnet']['id']}) {'subnet_id': subnet2['subnet']['id']})
# Set gateway to second router # 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.l3_plugin._update_router_gw_info(
self.context, router2['id'], self.context, router2['id'],
{'network_id': ext_net_id}) gw_info, request_body)
# Create an agent gateway port for the external network # Create an agent gateway port for the external network
net_id, agent_gw_port = ( net_id, agent_gw_port = (
self.setup_create_agent_gw_port_for_network(network=ext_net)) 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.l3_plugin._get_agent_gw_ports_exist_for_network(
self.context, ext_net_id, "", self.l3_agent['id'])) self.context, ext_net_id, "", self.l3_agent['id']))
self.l3_plugin._update_router_gw_info( 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 # Check for agent gateway port after deleting one of the gw
self.assertIsNotNone( self.assertIsNotNone(
self.l3_plugin._get_agent_gw_ports_exist_for_network( self.l3_plugin._get_agent_gw_ports_exist_for_network(
self.context, ext_net_id, "", self.l3_agent['id'])) self.context, ext_net_id, "", self.l3_agent['id']))
self.l3_plugin._update_router_gw_info( 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 # Check for agent gateway port after deleting last gw
self.assertIsNone( self.assertIsNone(
self.l3_plugin._get_agent_gw_ports_exist_for_network( 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', self.fmt, ext_net, '2001:db8::1', '2001:db8::/64',
ip_version=constants.IP_VERSION_6, enable_dhcp=True) ip_version=constants.IP_VERSION_6, enable_dhcp=True)
router1 = self._create_router() 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.l3_plugin._update_router_gw_info(
self.context, router1['id'], self.context, router1['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
snat_router_intfs = self.l3_plugin._get_snat_sync_interfaces( snat_router_intfs = self.l3_plugin._get_snat_sync_interfaces(
self.context, [router1['id']]) self.context, [router1['id']])
self.assertEqual(0, len(snat_router_intfs[router1['id']])) self.assertEqual(0, len(snat_router_intfs[router1['id']]))
@ -703,9 +718,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
candidates=[self.l3_agent]) candidates=[self.l3_agent])
# Set gateway to router # 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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
private_subnet1 = self._make_subnet( private_subnet1 = self._make_subnet(
self.fmt, self.fmt,
private_net1, private_net1,
@ -811,9 +829,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
candidates=[self.l3_agent]) candidates=[self.l3_agent])
# Set gateway to router # 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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
private_subnet1 = self._make_subnet( private_subnet1 = self._make_subnet(
self.fmt, self.fmt,
private_net1, private_net1,
@ -891,9 +912,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
candidates=[self.l3_agent]) candidates=[self.l3_agent])
# Set gateway to router # 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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
private_subnet1 = self._make_subnet( private_subnet1 = self._make_subnet(
self.fmt, self.fmt,
private_net1, private_net1,
@ -966,9 +990,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
candidates=[self.l3_agent]) candidates=[self.l3_agent])
# Set gateway to router # 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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
private_subnet1 = self._make_subnet( private_subnet1 = self._make_subnet(
self.fmt, self.fmt,
private_net1, private_net1,
@ -1048,9 +1075,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
candidates=[self.l3_agent]) candidates=[self.l3_agent])
# Set gateway to router # 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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
private_subnet1 = self._make_subnet( private_subnet1 = self._make_subnet(
self.fmt, self.fmt,
private_net1, private_net1,
@ -1177,9 +1207,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
router['id'], router['id'],
candidates=[self.l3_agent]) candidates=[self.l3_agent])
# Set gateway to router # 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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
private_subnet1 = self._make_subnet( private_subnet1 = self._make_subnet(
self.fmt, self.fmt,
private_net1, private_net1,
@ -1217,9 +1250,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
router['id'], router['id'],
candidates=[self.l3_agent]) candidates=[self.l3_agent])
# Set gateway to router # 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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
private_subnet1 = self._make_subnet( private_subnet1 = self._make_subnet(
self.fmt, self.fmt,
private_net1, private_net1,
@ -1349,9 +1385,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
self.subnet(network=ext_net),\ self.subnet(network=ext_net),\
self.subnet(cidr='20.0.0.0/24') as subnet,\ self.subnet(cidr='20.0.0.0/24') as subnet,\
self.port(subnet=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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
self.l3_plugin.add_router_interface( self.l3_plugin.add_router_interface(
self.context, router['id'], self.context, router['id'],
{'subnet_id': subnet['subnet']['id']}) {'subnet_id': subnet['subnet']['id']})
@ -1380,9 +1419,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
self.core_plugin.update_port( self.core_plugin.update_port(
self.context, port['port']['id'], self.context, port['port']['id'],
{'port': {'binding:host_id': self.l3_agent['host']}}) {'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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
self.l3_plugin.add_router_interface( self.l3_plugin.add_router_interface(
self.context, router['id'], self.context, router['id'],
{'subnet_id': subnet['subnet']['id']}) {'subnet_id': subnet['subnet']['id']})
@ -1620,9 +1662,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
with self.subnet() as subnet,\ with self.subnet() as subnet,\
self.network(**kwargs) as ext_net,\ self.network(**kwargs) as ext_net,\
self.subnet(network=ext_net, cidr='20.0.0.0/24'): 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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
self.l3_plugin.add_router_interface( self.l3_plugin.add_router_interface(
self.context, router['id'], self.context, router['id'],
{'subnet_id': subnet['subnet']['id']}) {'subnet_id': subnet['subnet']['id']})
@ -1655,9 +1700,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
self.core_plugin.update_port( self.core_plugin.update_port(
self.context, port['port']['id'], self.context, port['port']['id'],
{'port': {'binding:host_id': self.l3_agent['host']}}) {'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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
self.l3_plugin.add_router_interface( self.l3_plugin.add_router_interface(
self.context, router['id'], self.context, router['id'],
{'subnet_id': subnet['subnet']['id']}) {'subnet_id': subnet['subnet']['id']})
@ -2036,9 +2084,12 @@ class L3DvrTestCaseMigration(L3DvrTestCaseBase):
self.l3_plugin.add_router_interface( self.l3_plugin.add_router_interface(
self.context, router['id'], self.context, router['id'],
{'subnet_id': subnet1['subnet']['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.l3_plugin._update_router_gw_info(
self.context, router['id'], self.context, router['id'],
{'network_id': ext_net['network']['id']}) gw_info, request_body)
self.assertEqual( self.assertEqual(
0, len(self.l3_plugin._get_snat_sync_interfaces( 0, len(self.l3_plugin._get_snat_sync_interfaces(
self.context, [router['id']]))) self.context, [router['id']])))

View File

@ -17,6 +17,8 @@ from unittest import mock
import ddt import ddt
import netaddr 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 events
from neutron_lib.callbacks import registry from neutron_lib.callbacks import registry
from neutron_lib.callbacks import resources 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 neutron_lib.plugins import utils as plugin_utils
from oslo_utils import uuidutils from oslo_utils import uuidutils
import testtools import testtools
import webob.exc
from neutron.db import extraroute_db from neutron.db import extraroute_db
from neutron.db import l3_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']) self.ctx, network_id=self.network['network']['id'])
network_obj.Network.get_object( network_obj.Network.get_object(
self.ctx, id=self.network['network']['id']).delete() 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() l3_obj.Router.get_object(self.ctx, id=self.router['id']).delete()
def create_router(self, router): 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, mock_log.warning.assert_called_once_with(self.GET_PORTS_BY_ROUTER_MSG,
msg_vars) msg_vars)
self._check_routerports((False, True)) 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: '_create_snat_intf_ports_if_not_exists') as cs:
self.mixin._create_gw_port( self.mixin._create_gw_port(
self.ctx, router_id, router_db, mock.ANY, self.ctx, router_id, router_db, mock.ANY,
mock.ANY) mock.ANY, mock.ANY)
self.assertFalse(cs.call_count) self.assertFalse(cs.call_count)
def test_build_routers_list_with_gw_port_mismatch(self): 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 dvr as dvr_apidef
from neutron_lib.api.definitions import external_net as extnet_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 l3_ext_ha_mode
from neutron_lib.api.definitions import port as port_def from neutron_lib.api.definitions import port as port_def
from neutron_lib.api.definitions import portbindings from neutron_lib.api.definitions import portbindings
@ -1093,8 +1094,11 @@ class L3HAModeDbTestCase(L3HATestFramework):
interface_info = {'subnet_id': subnet['id']} interface_info = {'subnet_id': subnet['id']}
router = self._create_router() 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'], 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, self.plugin.add_router_interface(self.admin_ctx,
router['id'], router['id'],
interface_info) interface_info)
@ -1119,8 +1123,11 @@ class L3HAModeDbTestCase(L3HATestFramework):
interface_info = {'subnet_id': subnet['id']} interface_info = {'subnet_id': subnet['id']}
router = self._create_router() 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'], 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, iface = self.plugin.add_router_interface(self.admin_ctx,
router['id'], router['id'],
interface_info) interface_info)
@ -1177,8 +1184,11 @@ class L3HAModeDbTestCase(L3HATestFramework):
int_net) int_net)
interface_info = {'subnet_id': subnet['id']} interface_info = {'subnet_id': subnet['id']}
router = self._create_router(ha=True, distributed=True) 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'], 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, self.plugin.add_router_interface(self.admin_ctx,
router['id'], router['id'],
interface_info) interface_info)
@ -1310,8 +1320,11 @@ class L3HAModeDbTestCase(L3HATestFramework):
interface_info = {'subnet_id': subnet['id']} interface_info = {'subnet_id': subnet['id']}
router = self._create_router() 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'], 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, self.plugin.add_router_interface(self.admin_ctx,
router['id'], router['id'],
interface_info) interface_info)

View File

@ -256,11 +256,15 @@ class TestL3GwModeMixin(testlib_api.SqlTestCase):
if not current_enable_snat: if not current_enable_snat:
previous_gw_info = {'network_id': self.ext_net_id, previous_gw_info = {'network_id': self.ext_net_id,
'enable_snat': current_enable_snat} 'enable_snat': current_enable_snat}
request_body = {
l3_apidef.EXTERNAL_GW_INFO: previous_gw_info}
self.target_object._update_router_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.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( router = self.target_object._get_router(
self.context, self.router.id) self.context, self.router.id)
try: 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.