l3_db: refactor L3_NAT_DB_mixin

This patch refactors L3_NAT_DB_mixin to split out db operation and
rpc notification.

l3 plugin for routervm will implement the method for REST resource
operation as something like
    def op_resource():
        additional operation
        with session
            additional db operation
            db operation of super class => super().db_op_resoruce
            additional db operation
        additional operation
        l3 rpc notification

However, The current L3_NAT_DB_mixin intermixes db operations with l3 rpc.
So it is difficult to reuse the db operation code without l3 rpc.
This patch splits db operation from l3 rpc notification so that
db operation logic can be reused easily. Thus the l3 plugin for routervm
will be simplified with this patch.

Related to blueprint cisco-routing-service-vm
Related to blueprint l3-plugin-brocade-vyatta-vrouter

Change-Id: I88f6574f921596426e1a31c9ff2251aa6f4674b8
This commit is contained in:
Isaku Yamahata 2014-07-22 17:24:41 +09:00
parent 6bd6debebe
commit 748f0d53a1
4 changed files with 180 additions and 87 deletions

View File

@ -51,11 +51,11 @@ class RouterRoute(model_base.BASEV2, models_v2.Route):
cascade='delete')) cascade='delete'))
class ExtraRoute_db_mixin(l3_db.L3_NAT_db_mixin): class ExtraRoute_dbonly_mixin(l3_db.L3_NAT_dbonly_mixin):
"""Mixin class to support extra route configuration on router.""" """Mixin class to support extra route configuration on router."""
def _extend_router_dict_extraroute(self, router_res, router_db): def _extend_router_dict_extraroute(self, router_res, router_db):
router_res['routes'] = (ExtraRoute_db_mixin. router_res['routes'] = (ExtraRoute_dbonly_mixin.
_make_extra_route_list( _make_extra_route_list(
router_db['route_list'] router_db['route_list']
)) ))
@ -71,7 +71,7 @@ class ExtraRoute_db_mixin(l3_db.L3_NAT_db_mixin):
if 'routes' in r: if 'routes' in r:
self._update_extra_routes(context, router_db, r['routes']) self._update_extra_routes(context, router_db, r['routes'])
routes = self._get_extra_routes_by_router_id(context, id) routes = self._get_extra_routes_by_router_id(context, id)
router_updated = super(ExtraRoute_db_mixin, self).update_router( router_updated = super(ExtraRoute_dbonly_mixin, self).update_router(
context, id, router) context, id, router)
router_updated['routes'] = routes router_updated['routes'] = routes
@ -159,7 +159,7 @@ class ExtraRoute_db_mixin(l3_db.L3_NAT_db_mixin):
def get_router(self, context, id, fields=None): def get_router(self, context, id, fields=None):
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
router = super(ExtraRoute_db_mixin, self).get_router( router = super(ExtraRoute_dbonly_mixin, self).get_router(
context, id, fields) context, id, fields)
return router return router
@ -167,14 +167,15 @@ class ExtraRoute_db_mixin(l3_db.L3_NAT_db_mixin):
sorts=None, limit=None, marker=None, sorts=None, limit=None, marker=None,
page_reverse=False): page_reverse=False):
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
routers = super(ExtraRoute_db_mixin, self).get_routers( routers = super(ExtraRoute_dbonly_mixin, self).get_routers(
context, filters, fields, sorts=sorts, limit=limit, context, filters, fields, sorts=sorts, limit=limit,
marker=marker, page_reverse=page_reverse) marker=marker, page_reverse=page_reverse)
return routers return routers
def _confirm_router_interface_not_in_use(self, context, router_id, def _confirm_router_interface_not_in_use(self, context, router_id,
subnet_id): subnet_id):
super(ExtraRoute_db_mixin, self)._confirm_router_interface_not_in_use( super(ExtraRoute_dbonly_mixin,
self)._confirm_router_interface_not_in_use(
context, router_id, subnet_id) context, router_id, subnet_id)
subnet_db = self._core_plugin._get_subnet(context, subnet_id) subnet_db = self._core_plugin._get_subnet(context, subnet_id)
subnet_cidr = netaddr.IPNetwork(subnet_db['cidr']) subnet_cidr = netaddr.IPNetwork(subnet_db['cidr'])
@ -183,3 +184,8 @@ class ExtraRoute_db_mixin(l3_db.L3_NAT_db_mixin):
if netaddr.all_matching_cidrs(route['nexthop'], [subnet_cidr]): if netaddr.all_matching_cidrs(route['nexthop'], [subnet_cidr]):
raise extraroute.RouterInterfaceInUseByRoute( raise extraroute.RouterInterfaceInUseByRoute(
router_id=router_id, subnet_id=subnet_id) router_id=router_id, subnet_id=subnet_id)
class ExtraRoute_db_mixin(ExtraRoute_dbonly_mixin, l3_db.L3_NAT_db_mixin):
"""Mixin class to support extra route configuration on router with rpc."""
pass

View File

@ -78,7 +78,7 @@ class FloatingIP(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
status = sa.Column(sa.String(16)) status = sa.Column(sa.String(16))
class L3_NAT_db_mixin(l3.RouterPluginBase): class L3_NAT_dbonly_mixin(l3.RouterPluginBase):
"""Mixin class to add L3/NAT router methods to db_base_plugin_v2.""" """Mixin class to add L3/NAT router methods to db_base_plugin_v2."""
router_device_owners = ( router_device_owners = (
@ -87,16 +87,6 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
DEVICE_OWNER_FLOATINGIP DEVICE_OWNER_FLOATINGIP
) )
@property
def l3_rpc_notifier(self):
if not hasattr(self, '_l3_rpc_notifier'):
self._l3_rpc_notifier = l3_rpc_agent_api.L3AgentNotifyAPI()
return self._l3_rpc_notifier
@l3_rpc_notifier.setter
def l3_rpc_notifier(self, value):
self._l3_rpc_notifier = value
@property @property
def _core_plugin(self): def _core_plugin(self):
return manager.NeutronManager.get_plugin() return manager.NeutronManager.get_plugin()
@ -169,17 +159,13 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
if gw_info != attributes.ATTR_NOT_SPECIFIED: if gw_info != attributes.ATTR_NOT_SPECIFIED:
candidates = self._check_router_needs_rescheduling( candidates = self._check_router_needs_rescheduling(
context, id, gw_info) context, id, gw_info)
payload = {'gw_exists': True}
else: else:
candidates = None candidates = None
payload = {'gw_exists': False}
router_db = self._update_router_db(context, id, r, gw_info) router_db = self._update_router_db(context, id, r, gw_info)
if candidates: if candidates:
l3_plugin = manager.NeutronManager.get_service_plugins().get( l3_plugin = manager.NeutronManager.get_service_plugins().get(
constants.L3_ROUTER_NAT) constants.L3_ROUTER_NAT)
l3_plugin.reschedule_router(context, id, candidates) l3_plugin.reschedule_router(context, id, candidates)
self.l3_rpc_notifier.routers_updated(context, [router_db['id']],
None, payload)
return self._make_router_dict(router_db) return self._make_router_dict(router_db)
def _check_router_needs_rescheduling(self, context, router_id, gw_info): def _check_router_needs_rescheduling(self, context, router_id, gw_info):
@ -357,8 +343,6 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
self._core_plugin._delete_port(context.elevated(), self._core_plugin._delete_port(context.elevated(),
ports[0]['id']) ports[0]['id'])
self.l3_rpc_notifier.router_deleted(context, id)
def get_router(self, context, id, fields=None): def get_router(self, context, id, fields=None):
router = self._get_router(context, id) router = self._get_router(context, id)
return self._make_router_dict(router, fields) return self._make_router_dict(router, fields)
@ -469,23 +453,15 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
'device_owner': owner, 'device_owner': owner,
'name': ''}}) 'name': ''}})
def notify_router_interface_action( @staticmethod
self, context, router_id, tenant_id, port_id, subnet_id, action): def _make_router_interface_info(
l3_method = '%s_router_interface' % action router_id, tenant_id, port_id, subnet_id):
self.l3_rpc_notifier.routers_updated(context, [router_id], return {
l3_method, {'subnet_id': subnet_id})
mapping = {'add': 'create', 'remove': 'delete'}
info = {
'id': router_id, 'id': router_id,
'tenant_id': tenant_id, 'tenant_id': tenant_id,
'port_id': port_id, 'port_id': port_id,
'subnet_id': subnet_id 'subnet_id': subnet_id
} }
notifier = n_rpc.get_notifier('network')
router_event = 'router.interface.%s' % mapping[action]
notifier.info(context, router_event, {'router_interface': info})
return info
def add_router_interface(self, context, router_id, interface_info): def add_router_interface(self, context, router_id, interface_info):
add_by_port, add_by_sub = self._validate_interface_info(interface_info) add_by_port, add_by_sub = self._validate_interface_info(interface_info)
@ -498,9 +474,9 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
port = self._add_interface_by_subnet( port = self._add_interface_by_subnet(
context, router_id, interface_info['subnet_id'], device_owner) context, router_id, interface_info['subnet_id'], device_owner)
return self.notify_router_interface_action( return self._make_router_interface_info(
context, router_id, port['tenant_id'], port['id'], router_id, port['tenant_id'], port['id'],
port['fixed_ips'][0]['subnet_id'], 'add') port['fixed_ips'][0]['subnet_id'])
def _confirm_router_interface_not_in_use(self, context, router_id, def _confirm_router_interface_not_in_use(self, context, router_id,
subnet_id): subnet_id):
@ -568,9 +544,8 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
port, subnet = self._remove_interface_by_subnet( port, subnet = self._remove_interface_by_subnet(
context, router_id, subnet_id, device_owner) context, router_id, subnet_id, device_owner)
return self.notify_router_interface_action( return self._make_router_interface_info(router_id, port['tenant_id'],
context, router_id, port['tenant_id'], port['id'], port['id'], subnet['id'])
subnet['id'], 'remove')
def _get_floatingip(self, context, id): def _get_floatingip(self, context, id):
try: try:
@ -739,8 +714,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
'router_id': router_id, 'router_id': router_id,
'last_known_router_id': previous_router_id}) 'last_known_router_id': previous_router_id})
def create_floatingip( def create_floatingip(self, context, floatingip,
self, context, floatingip,
initial_status=l3_constants.FLOATINGIP_STATUS_ACTIVE): initial_status=l3_constants.FLOATINGIP_STATUS_ACTIVE):
fip = floatingip['floatingip'] fip = floatingip['floatingip']
tenant_id = self._get_tenant_id_for_create(context, fip) tenant_id = self._get_tenant_id_for_create(context, fip)
@ -785,34 +759,30 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
floatingip_db, external_port) floatingip_db, external_port)
context.session.add(floatingip_db) context.session.add(floatingip_db)
router_id = floatingip_db['router_id']
if router_id:
self.l3_rpc_notifier.routers_updated(
context, [router_id],
'create_floatingip', {})
return self._make_floatingip_dict(floatingip_db) return self._make_floatingip_dict(floatingip_db)
def update_floatingip(self, context, id, floatingip): def _update_floatingip(self, context, id, floatingip):
fip = floatingip['floatingip'] fip = floatingip['floatingip']
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
floatingip_db = self._get_floatingip(context, id) floatingip_db = self._get_floatingip(context, id)
old_floatingip = self._make_floatingip_dict(floatingip_db)
fip['tenant_id'] = floatingip_db['tenant_id'] fip['tenant_id'] = floatingip_db['tenant_id']
fip['id'] = id fip['id'] = id
fip_port_id = floatingip_db['floating_port_id'] fip_port_id = floatingip_db['floating_port_id']
before_router_id = floatingip_db['router_id']
self._update_fip_assoc(context, fip, floatingip_db, self._update_fip_assoc(context, fip, floatingip_db,
self._core_plugin.get_port( self._core_plugin.get_port(
context.elevated(), fip_port_id)) context.elevated(), fip_port_id))
router_ids = [] return old_floatingip, self._make_floatingip_dict(floatingip_db)
if before_router_id:
router_ids.append(before_router_id) def _floatingips_to_router_ids(self, floatingips):
router_id = floatingip_db['router_id'] return list(set([floatingip['router_id']
if router_id and router_id != before_router_id: for floatingip in floatingips
router_ids.append(router_id) if floatingip['router_id']]))
if router_ids:
self.l3_rpc_notifier.routers_updated( def update_floatingip(self, context, id, floatingip):
context, router_ids, 'update_floatingip', {}) _old_floatingip, floatingip = self._update_floatingip(
return self._make_floatingip_dict(floatingip_db) context, id, floatingip)
return floatingip
def update_floatingip_status(self, context, floatingip_id, status): def update_floatingip_status(self, context, floatingip_id, status):
"""Update operational status for floating IP in neutron DB.""" """Update operational status for floating IP in neutron DB."""
@ -820,7 +790,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
FloatingIP.id == floatingip_id) FloatingIP.id == floatingip_id)
fip_query.update({'status': status}, synchronize_session=False) fip_query.update({'status': status}, synchronize_session=False)
def delete_floatingip(self, context, id): def _delete_floatingip(self, context, id):
floatingip = self._get_floatingip(context, id) floatingip = self._get_floatingip(context, id)
router_id = floatingip['router_id'] router_id = floatingip['router_id']
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
@ -828,10 +798,10 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
self._core_plugin.delete_port(context.elevated(), self._core_plugin.delete_port(context.elevated(),
floatingip['floating_port_id'], floatingip['floating_port_id'],
l3_port_check=False) l3_port_check=False)
if router_id: return router_id
self.l3_rpc_notifier.routers_updated(
context, [router_id], def delete_floatingip(self, context, id):
'delete_floatingip', {}) self._delete_floatingip(context, id)
def get_floatingip(self, context, id, fields=None): def get_floatingip(self, context, id, fields=None):
floatingip = self._get_floatingip(context, id) floatingip = self._get_floatingip(context, id)
@ -890,7 +860,7 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
{'port_id': port_db['id'], {'port_id': port_db['id'],
'port_owner': port_db['device_owner']}) 'port_owner': port_db['device_owner']})
def disassociate_floatingips(self, context, port_id, do_notify=True): def disassociate_floatingips(self, context, port_id):
"""Disassociate all floating IPs linked to specific port. """Disassociate all floating IPs linked to specific port.
@param port_id: ID of the port to disassociate floating IPs. @param port_id: ID of the port to disassociate floating IPs.
@ -908,20 +878,8 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
floating_ip.update({'fixed_port_id': None, floating_ip.update({'fixed_port_id': None,
'fixed_ip_address': None, 'fixed_ip_address': None,
'router_id': None}) 'router_id': None})
if do_notify:
self.notify_routers_updated(context, router_ids)
# since caller assumes that we handled notifications on its
# behalf, return nothing
return
return router_ids return router_ids
def notify_routers_updated(self, context, router_ids):
if router_ids:
self.l3_rpc_notifier.routers_updated(
context, list(router_ids),
'disassociate_floatingips', {})
def _build_routers_list(self, context, routers, gw_ports): def _build_routers_list(self, context, routers, gw_ports):
for router in routers: for router in routers:
gw_port_id = router['gw_port_id'] gw_port_id = router['gw_port_id']
@ -1069,3 +1027,122 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
self._process_floating_ips(context, routers_dict, floating_ips) self._process_floating_ips(context, routers_dict, floating_ips)
self._process_interfaces(routers_dict, interfaces) self._process_interfaces(routers_dict, interfaces)
return routers_dict.values() return routers_dict.values()
class L3RpcNotifierMixin(object):
"""Mixin class to add rpc notifier attribute to db_base_plugin_v2."""
@property
def l3_rpc_notifier(self):
if not hasattr(self, '_l3_rpc_notifier'):
self._l3_rpc_notifier = l3_rpc_agent_api.L3AgentNotifyAPI()
return self._l3_rpc_notifier
@l3_rpc_notifier.setter
def l3_rpc_notifier(self, value):
self._l3_rpc_notifier = value
def notify_router_updated(self, context, router_id,
operation=None, data=None):
if router_id:
self.l3_rpc_notifier.routers_updated(
context, [router_id], operation, data)
def notify_routers_updated(self, context, router_ids,
operation=None, data=None):
if router_ids:
self.l3_rpc_notifier.routers_updated(
context, router_ids, operation, data)
def notify_router_deleted(self, context, router_id):
self.l3_rpc_notifier.router_deleted(context, router_id)
class L3_NAT_db_mixin(L3_NAT_dbonly_mixin, L3RpcNotifierMixin):
"""Mixin class to add rpc notifier methods to db_base_plugin_v2."""
def update_router(self, context, id, router):
r = router['router']
payload = {'gw_exists':
r.get(EXTERNAL_GW_INFO, attributes.ATTR_NOT_SPECIFIED) !=
attributes.ATTR_NOT_SPECIFIED}
router_dict = super(L3_NAT_db_mixin, self).update_router(context,
id, router)
self.notify_router_updated(context, router_dict['id'], None, payload)
return router_dict
def delete_router(self, context, id):
super(L3_NAT_db_mixin, self).delete_router(context, id)
self.notify_router_deleted(context, id)
def notify_router_interface_action(
self, context, router_interface_info, action):
l3_method = '%s_router_interface' % action
super(L3_NAT_db_mixin, self).notify_routers_updated(
context, [router_interface_info['id']], l3_method,
{'subnet_id': router_interface_info['subnet_id']})
mapping = {'add': 'create', 'remove': 'delete'}
notifier = n_rpc.get_notifier('network')
router_event = 'router.interface.%s' % mapping[action]
notifier.info(context, router_event,
{'router_interface': router_interface_info})
def add_router_interface(self, context, router_id, interface_info):
router_interface_info = super(
L3_NAT_db_mixin, self).add_router_interface(
context, router_id, interface_info)
self.notify_router_interface_action(
context, router_interface_info, 'add')
return router_interface_info
def remove_router_interface(self, context, router_id, interface_info):
router_interface_info = super(
L3_NAT_db_mixin, self).remove_router_interface(
context, router_id, interface_info)
self.notify_router_interface_action(
context, router_interface_info, 'remove')
return router_interface_info
def create_floatingip(self, context, floatingip,
initial_status=l3_constants.FLOATINGIP_STATUS_ACTIVE):
floatingip_dict = super(L3_NAT_db_mixin, self).create_floatingip(
context, floatingip, initial_status)
router_id = floatingip_dict['router_id']
self.notify_router_updated(context, router_id, 'create_floatingip', {})
return floatingip_dict
def update_floatingip(self, context, id, floatingip):
old_floatingip, floatingip = self._update_floatingip(
context, id, floatingip)
router_ids = self._floatingips_to_router_ids(
[old_floatingip, floatingip])
super(L3_NAT_db_mixin, self).notify_routers_updated(
context, router_ids, 'update_floatingip', {})
return floatingip
def delete_floatingip(self, context, id):
router_id = self._delete_floatingip(context, id)
self.notify_router_updated(context, router_id, 'delete_floatingip', {})
def disassociate_floatingips(self, context, port_id, do_notify=True):
"""Disassociate all floating IPs linked to specific port.
@param port_id: ID of the port to disassociate floating IPs.
@param do_notify: whether we should notify routers right away.
@return: set of router-ids that require notification updates
if do_notify is False, otherwise None.
"""
router_ids = super(L3_NAT_db_mixin, self).disassociate_floatingips(
context, port_id)
if do_notify:
self.notify_routers_updated(context, router_ids)
# since caller assumes that we handled notifications on its
# behalf, return nothing
return
return router_ids
def notify_routers_updated(self, context, router_ids):
super(L3_NAT_db_mixin, self).notify_routers_updated(
context, list(router_ids), 'disassociate_floatingips', {})

View File

@ -180,9 +180,12 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
context.elevated(), router_id, port['network_id'], context.elevated(), router_id, port['network_id'],
port['fixed_ips'][0]['subnet_id']) port['fixed_ips'][0]['subnet_id'])
return self.notify_router_interface_action( router_interface_info = self._make_router_interface_info(
context, router_id, port['tenant_id'], port['id'], router_id, port['tenant_id'], port['id'],
port['fixed_ips'][0]['subnet_id'], 'add') port['fixed_ips'][0]['subnet_id'])
self.notify_router_interface_action(
context, router_interface_info, 'add')
return router_interface_info
def remove_router_interface(self, context, router_id, interface_info): def remove_router_interface(self, context, router_id, interface_info):
if not interface_info: if not interface_info:
@ -205,9 +208,12 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
self.delete_csnat_router_interface_ports( self.delete_csnat_router_interface_ports(
context.elevated(), router, subnet_id=subnet_id) context.elevated(), router, subnet_id=subnet_id)
return self.notify_router_interface_action( router_interface_info = self._make_router_interface_info(
context, router_id, port['tenant_id'], port['id'], router_id, port['tenant_id'], port['id'],
subnet['id'], 'remove') port['fixed_ips'][0]['subnet_id'])
self.notify_router_interface_action(
context, router_interface_info, 'remove')
return router_interface_info
def get_snat_sync_interfaces(self, context, router_ids): def get_snat_sync_interfaces(self, context, router_ids):
"""Query router interfaces that relate to list of router_ids.""" """Query router interfaces that relate to list of router_ids."""

View File

@ -31,7 +31,7 @@ setattr(l3_db.Router, 'enable_snat',
nullable=False)) nullable=False))
class L3_NAT_db_mixin(l3_db.L3_NAT_db_mixin): class L3_NAT_dbonly_mixin(l3_db.L3_NAT_dbonly_mixin):
"""Mixin class to add configurable gateway modes.""" """Mixin class to add configurable gateway modes."""
# Register dict extend functions for ports and networks # Register dict extend functions for ports and networks
@ -56,7 +56,7 @@ class L3_NAT_db_mixin(l3_db.L3_NAT_db_mixin):
router.enable_snat = enable_snat router.enable_snat = enable_snat
# Calls superclass, pass router db object for avoiding re-loading # Calls superclass, pass router db object for avoiding re-loading
super(L3_NAT_db_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, 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
@ -70,3 +70,7 @@ class L3_NAT_db_mixin(l3_db.L3_NAT_db_mixin):
# Add enable_snat key # Add enable_snat key
rtr['enable_snat'] = rtr[EXTERNAL_GW_INFO]['enable_snat'] rtr['enable_snat'] = rtr[EXTERNAL_GW_INFO]['enable_snat']
return routers return routers
class L3_NAT_db_mixin(L3_NAT_dbonly_mixin, l3_db.L3_NAT_db_mixin):
pass