Use callbacks to create DVR floating GW port

This stops the DVR mixin from overriding the '_update_fip_assoc'
function in order to create its agent floating IP gateway ports.
It instead now subscribes to the floating IP AFTER_UPDATE event
to create these ports.

Additionally, it fixes the semantics of the floating IP AFTER_UPDATE
event so it's emitted after the update is committed to the DB
so it's safe to call core plugin mutation methods and external systems.

In addition to fixing the callback semantics, this is part of the
effort to eliminate GUARD_TRANSACTION in-tree, which
should pave the way for ML2 to adopt the new engine facade and for
push notifications to safely transmit the latest DB state.

Related-Bug: #1540844
Partially-Implements: blueprint push-notifications
Partially-Implements: blueprint enginefacade-switch
Change-Id: I93e4d847f96707b17c4a7dfdb3bbf81d062fe3fb
This commit is contained in:
Kevin Benton 2016-11-10 00:30:42 -08:00 committed by Kevin Benton
parent 8eac5e2db7
commit 03f7ec38b6
4 changed files with 48 additions and 31 deletions

View File

@ -1166,18 +1166,15 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
if addr.version == lib_constants.IP_VERSION_4:
next_hop = fixed_ip.ip_address
break
args = {'fixed_ip_address': internal_ip_address,
return {'fixed_ip_address': internal_ip_address,
'fixed_port_id': port_id,
'router_id': router_id,
'last_known_router_id': previous_router_id,
'floating_ip_address': floatingip_db.floating_ip_address,
'floating_network_id': floatingip_db.floating_network_id,
'floating_ip_id': floatingip_db.id,
'next_hop': next_hop,
'context': context}
registry.notify(resources.FLOATING_IP,
events.AFTER_UPDATE,
self._update_fip_assoc,
**args)
def _is_ipv4_network(self, context, net_id):
net = self._core_plugin._get_network(context, net_id)
@ -1242,14 +1239,18 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
description=fip.get('description'))
# Update association with internal port
# and define external IP address
self._update_fip_assoc(context, fip,
floatingip_db, external_port)
assoc_result = self._update_fip_assoc(context, fip,
floatingip_db, external_port)
context.session.add(floatingip_db)
floatingip_dict = self._make_floatingip_dict(
floatingip_db, process_extensions=False)
if self._is_dns_integration_supported:
dns_data = self._process_dns_floatingip_create_precommit(
context, floatingip_dict, fip)
registry.notify(resources.FLOATING_IP,
events.AFTER_UPDATE,
self._update_fip_assoc,
**assoc_result)
if self._is_dns_integration_supported:
self._process_dns_floatingip_create_postcommit(context,
@ -1270,13 +1271,17 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
floatingip_db = self._get_floatingip(context, id)
old_floatingip = self._make_floatingip_dict(floatingip_db)
fip_port_id = floatingip_db['floating_port_id']
self._update_fip_assoc(context, fip, floatingip_db,
self._core_plugin.get_port(
context.elevated(), fip_port_id))
assoc_result = self._update_fip_assoc(
context, fip, floatingip_db,
self._core_plugin.get_port(context.elevated(), fip_port_id))
floatingip_dict = self._make_floatingip_dict(floatingip_db)
if self._is_dns_integration_supported:
dns_data = self._process_dns_floatingip_update_precommit(
context, floatingip_dict)
registry.notify(resources.FLOATING_IP,
events.AFTER_UPDATE,
self._update_fip_assoc,
**assoc_result)
if self._is_dns_integration_supported:
self._process_dns_floatingip_update_postcommit(context,

View File

@ -70,6 +70,12 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
'default': cfg.CONF.router_distributed
}])
def __new__(cls, *args, **kwargs):
n = super(L3_NAT_with_dvr_db_mixin, cls).__new__(cls, *args, **kwargs)
registry.subscribe(n._create_dvr_floating_gw_port,
resources.FLOATING_IP, events.AFTER_UPDATE)
return n
def _create_router_db(self, context, router, tenant_id):
"""Create a router db object with dvr additions."""
with context.session.begin(subtransactions=True):
@ -221,39 +227,33 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
models_v2.Port.admin_state_up == True) # noqa
return query.all()
def _update_fip_assoc(self, context, fip, floatingip_db, external_port):
"""Override to create floating agent gw port for DVR.
def _create_dvr_floating_gw_port(self, resource, event, trigger, context,
router_id, fixed_port_id, floating_ip_id,
floating_network_id, fixed_ip_address,
**kwargs):
"""Create floating agent gw port for DVR.
Floating IP Agent gateway port will be created when a
floatingIP association happens.
"""
fip_port = fip.get('port_id')
super(L3_NAT_with_dvr_db_mixin, self)._update_fip_assoc(
context, fip, floatingip_db, external_port)
associate_fip = fip_port and floatingip_db['id']
if associate_fip and floatingip_db.get('router_id'):
associate_fip = fixed_port_id and floating_ip_id
if associate_fip and router_id:
admin_ctx = context.elevated()
router_dict = self.get_router(
admin_ctx, floatingip_db['router_id'])
router_dict = self.get_router(admin_ctx, router_id)
# Check if distributed router and then create the
# FloatingIP agent gateway port
if router_dict.get('distributed'):
hostid = self._get_dvr_service_port_hostid(
context, fip_port)
hostid = self._get_dvr_service_port_hostid(context,
fixed_port_id)
if hostid:
# FIXME (Swami): This FIP Agent Gateway port should be
# created only once and there should not be a duplicate
# for the same host. Until we find a good solution for
# augmenting multiple server requests we should use the
# existing flow.
# FIXME(kevinbenton): refactor so this happens outside
# of floating IP transaction since it creates a port
# via ML2.
setattr(admin_ctx, 'GUARD_TRANSACTION', False)
fip_agent_port = (
self.create_fip_agent_gw_port_if_not_exists(
admin_ctx, external_port['network_id'],
hostid))
admin_ctx, floating_network_id, hostid))
LOG.debug("FIP Agent gateway port: %s", fip_agent_port)
else:
# If not hostid check if the fixed ip provided has to
@ -261,7 +261,7 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
# port. Get the port_dict, inherit the service port host
# and device owner(if it does not exist).
port = self._core_plugin.get_port(
admin_ctx, fip_port)
admin_ctx, fixed_port_id)
allowed_device_owners = (
n_utils.get_dvr_allowed_address_pair_device_owners())
# NOTE: We just need to deal with ports that do not
@ -273,7 +273,7 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
addr_pair_active_service_port_list = (
self._get_ports_for_allowed_address_pair_ip(
admin_ctx, port['network_id'],
floatingip_db['fixed_ip_address']))
fixed_ip_address))
if not addr_pair_active_service_port_list:
return
if len(addr_pair_active_service_port_list) > 1:

View File

@ -19,6 +19,9 @@ from neutron_lib import exceptions
from oslo_utils import uuidutils
import testtools
from neutron.callbacks import events
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.common import constants as n_const
from neutron import context
from neutron.db import agents_db
@ -445,8 +448,11 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
grtr.return_value = router_db
vmp.return_value = 'my-host'
mvmp.return_value = 'my-future-host'
self.mixin._update_fip_assoc(
self.ctx, fip, floatingip_db, port)
registry.notify(resources.FLOATING_IP, events.AFTER_UPDATE, self,
context=mock.Mock(), router_id=router_db['id'],
fixed_port_id=port['id'], floating_ip_id=fip['id'],
floating_network_id=fip['floating_network_id'],
fixed_ip_address='1.2.3.4')
return c_fip
def test_create_floatingip_agent_gw_port_with_dvr_router(self):
@ -457,6 +463,7 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
router = {'id': 'foo_router_id', 'distributed': True}
fip = {
'id': _uuid(),
'floating_network_id': _uuid(),
'port_id': _uuid()
}
create_fip = (
@ -472,6 +479,7 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
router = {'id': 'foo_router_id', 'distributed': False}
fip = {
'id': _uuid(),
'floating_network_id': _uuid(),
'port_id': _uuid()
}
create_fip = (

View File

@ -2347,6 +2347,7 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
{'floatingip': {'port_id': port_id}})
fip_addr = fip['floatingip']['floating_ip_address']
fip_network_id = fip['floatingip']['floating_network_id']
fip_id = fip['floatingip']['id']
router_id = body['floatingip']['router_id']
body = self._show('routers', router_id)
ext_gw_info = body['router']['external_gateway_info']
@ -2360,6 +2361,7 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
floating_ip_address=fip_addr,
floating_network_id=fip_network_id,
last_known_router_id=None,
floating_ip_id=fip_id,
router_id=router_id,
next_hop=ext_fixed_ip['ip_address'])
@ -2375,6 +2377,7 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
with mock.patch.object(registry, 'notify') as notify:
fip_addr = fip['floatingip']['floating_ip_address']
fip_network_id = fip['floatingip']['floating_network_id']
fip_id = fip['floatingip']['id']
router_id = body['floatingip']['router_id']
self._update('floatingips',
fip['floatingip']['id'],
@ -2388,6 +2391,7 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
floating_ip_address=fip_addr,
floating_network_id=fip_network_id,
last_known_router_id=router_id,
floating_ip_id=fip_id,
router_id=None,
next_hop=None)