From acbabaa3db2c12a41c52662a82e9a900d5929846 Mon Sep 17 00:00:00 2001 From: Kevin Benton Date: Wed, 7 Sep 2016 18:42:40 -0700 Subject: [PATCH] Make l2/l3 operations retriable at plugin level This adds decorators to ML2/db_base_plugin_v2 and the L3 DB modules to make L2 and L3 resource operations retriable at the plugin level. Retrying the L2 operations in particular at this level should go a long way to improving the reliability of complex operations that require L2 resources in the face of deadlocks under high concurrency. Partial-Bug: #1612798 Partial-Bug: #1596075 Change-Id: I3c9437f7ecdd5ebb188b622144b7bd7bed74231d --- neutron/db/db_base_plugin_v2.py | 30 ++++++++++++++++++++++++ neutron/db/l3_db.py | 23 +++++++++++++++--- neutron/db/l3_dvr_db.py | 5 ++++ neutron/db/l3_hamode_db.py | 11 ++++++++- neutron/plugins/ml2/common/exceptions.py | 2 +- neutron/plugins/ml2/plugin.py | 20 +++++++++++++++- neutron/tests/unit/db/test_l3_db.py | 2 +- 7 files changed, 86 insertions(+), 7 deletions(-) diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index b1669e9aa1b..4f589ed8b38 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -41,6 +41,7 @@ from neutron.common import exceptions as n_exc from neutron.common import ipv6_utils from neutron.common import utils from neutron import context as ctx +from neutron.db import api as db_api from neutron.db import db_base_plugin_common from neutron.db import ipam_pluggable_backend from neutron.db import models_v2 @@ -142,6 +143,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, registry.subscribe(self.validate_network_rbac_policy_change, rbac_mixin.RBAC_POLICY, e) + @db_api.retry_if_session_inactive() def validate_network_rbac_policy_change(self, resource, event, trigger, context, object_type, policy, **kwargs): @@ -329,9 +331,11 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, {'resource': resource, 'item': item}) return objects + @db_api.retry_if_session_inactive() def create_network_bulk(self, context, networks): return self._create_bulk('network', context, networks) + @db_api.retry_if_session_inactive() def create_network(self, context, network): """Handle creation of a single network.""" net_db = self.create_network_db(context, network) @@ -360,6 +364,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, context.session.add(network) return network + @db_api.retry_if_session_inactive() def update_network(self, context, id, network): n = network['network'] with context.session.begin(subtransactions=True): @@ -390,6 +395,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, models_v2.Network)) return self._make_network_dict(network, context=context) + @db_api.retry_if_session_inactive() def delete_network(self, context, id): with context.session.begin(subtransactions=True): network = self._get_network(context, id) @@ -412,10 +418,12 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, context.session.delete(network) + @db_api.retry_if_session_inactive() def get_network(self, context, id, fields=None): network = self._get_network(context, id) return self._make_network_dict(network, fields, context=context) + @db_api.retry_if_session_inactive() def get_networks(self, context, filters=None, fields=None, sorts=None, limit=None, marker=None, page_reverse=False): @@ -430,10 +438,12 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, marker_obj=marker_obj, page_reverse=page_reverse) + @db_api.retry_if_session_inactive() def get_networks_count(self, context, filters=None): return self._get_collection_count(context, models_v2.Network, filters=filters) + @db_api.retry_if_session_inactive() def create_subnet_bulk(self, context, subnets): return self._create_bulk('subnet', context, subnets) @@ -666,6 +676,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, msg = _('No default subnetpool found for IPv%s') % ip_version raise exc.BadRequest(resource='subnets', msg=msg) + @db_api.retry_if_session_inactive() def create_subnet(self, context, subnet): s = subnet['subnet'] @@ -719,6 +730,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, 'end': str(netaddr.IPAddress(p.last, subnet['ip_version']))} for p in allocation_pools] + @db_api.retry_if_session_inactive() def update_subnet(self, context, id, subnet): """Update the subnet with new info. @@ -846,6 +858,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, "cannot delete", subnet_id) raise exc.SubnetInUse(subnet_id=subnet_id) + @db_api.retry_if_session_inactive() def delete_subnet(self, context, id): with context.session.begin(subtransactions=True): subnet = self._get_subnet(context, id) @@ -895,20 +908,24 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, # since there is no FK relationship self.ipam.delete_subnet(context, id) + @db_api.retry_if_session_inactive() def get_subnet(self, context, id, fields=None): subnet = self._get_subnet(context, id) return self._make_subnet_dict(subnet, fields, context=context) + @db_api.retry_if_session_inactive() def get_subnets(self, context, filters=None, fields=None, sorts=None, limit=None, marker=None, page_reverse=False): return self._get_subnets(context, filters, fields, sorts, limit, marker, page_reverse) + @db_api.retry_if_session_inactive() def get_subnets_count(self, context, filters=None): return self._get_collection_count(context, models_v2.Subnet, filters=filters) + @db_api.retry_if_session_inactive() def get_subnets_by_network(self, context, network_id): return [self._make_subnet_dict(subnet_db) for subnet_db in self._get_subnets_by_network(context, network_id)] @@ -982,6 +999,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, "been set. Only one default may exist per IP family") raise exc.InvalidInput(error_message=msg) + @db_api.retry_if_session_inactive() def create_subnetpool(self, context, subnetpool): sp = subnetpool['subnetpool'] sp_reader = subnet_alloc.SubnetPoolReader(sp) @@ -1012,6 +1030,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, return self._make_subnetpool_dict(subnetpool) + @db_api.retry_if_session_inactive() def update_subnetpool(self, context, id, subnetpool): new_sp = subnetpool['subnetpool'] @@ -1049,10 +1068,12 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, updated, orig_sp) return updated + @db_api.retry_if_session_inactive() def get_subnetpool(self, context, id, fields=None): subnetpool = self._get_subnetpool(context, id) return self._make_subnetpool_dict(subnetpool, fields) + @db_api.retry_if_session_inactive() def get_subnetpools(self, context, filters=None, fields=None, sorts=None, limit=None, marker=None, page_reverse=False): @@ -1064,6 +1085,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, for pool in subnetpools ] + @db_api.retry_if_session_inactive() def get_default_subnetpool(self, context, ip_version): """Retrieve the default subnetpool for the given IP version.""" filters = {'is_default': True, @@ -1072,6 +1094,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, if subnetpool: return subnetpool[0] + @db_api.retry_if_session_inactive() def delete_subnetpool(self, context, id): with context.session.begin(subtransactions=True): subnetpool = self._get_subnetpool(context, id=id) @@ -1088,6 +1111,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, op=_("mac address update"), port_id=id, device_owner=device_owner) + @db_api.retry_if_session_inactive() def create_port_bulk(self, context, ports): return self._create_bulk('port', context, ports) @@ -1104,6 +1128,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, context.session.add(db_port) return db_port + @db_api.retry_if_session_inactive() def create_port(self, context, port): db_port = self.create_port_db(context, port) return self._make_port_dict(db_port, process_extensions=False) @@ -1157,6 +1182,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, self._check_mac_addr_update(context, db_port, new_mac, current_owner) + @db_api.retry_if_session_inactive() def update_port(self, context, id, port): new_port = port['port'] @@ -1184,6 +1210,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, result = self._make_port_dict(db_port) return result + @db_api.retry_if_session_inactive() def delete_port(self, context, id): with context.session.begin(subtransactions=True): self.ipam.delete_port(context, id) @@ -1204,6 +1231,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, "The port has already been deleted.", port_id) + @db_api.retry_if_session_inactive() def get_port(self, context, id, fields=None): port = self._get_port(context, id) return self._make_port_dict(port, fields) @@ -1238,6 +1266,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, sort_dirs=sort_dirs) return query + @db_api.retry_if_session_inactive() def get_ports(self, context, filters=None, fields=None, sorts=None, limit=None, marker=None, page_reverse=False): @@ -1251,6 +1280,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, items.reverse() return items + @db_api.retry_if_session_inactive() def get_ports_count(self, context, filters=None): return self._get_ports_query(context, filters).count() diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py index bb3344d388e..f273e24d8f3 100644 --- a/neutron/db/l3_db.py +++ b/neutron/db/l3_db.py @@ -266,6 +266,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, self._update_router_gw_info(context, router_id, gw_info, router=router_db) + @db_api.retry_if_session_inactive() def create_router(self, context, router): r = router['router'] gw_info = r.pop(EXTERNAL_GW_INFO, None) @@ -293,6 +294,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, old_router=old_router) return router_db + @db_api.retry_if_session_inactive() def update_router(self, context, id, router): r = router['router'] gw_info = r.pop(EXTERNAL_GW_INFO, lib_constants.ATTR_NOT_SPECIFIED) @@ -562,6 +564,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, raise l3.RouterInUse(router_id=router_id) return router + @db_api.retry_if_session_inactive() def delete_router(self, context, id): #TODO(nati) Refactor here when we have router insertion model @@ -578,10 +581,12 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, self, context=context, router_id=id) context.session.delete(router) + @db_api.retry_if_session_inactive() def get_router(self, context, id, fields=None): router = self._get_router(context, id) return self._make_router_dict(router, fields) + @db_api.retry_if_session_inactive() def get_routers(self, context, filters=None, fields=None, sorts=None, limit=None, marker=None, page_reverse=False): @@ -594,6 +599,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, marker_obj=marker_obj, page_reverse=page_reverse) + @db_api.retry_if_session_inactive() def get_routers_count(self, context, filters=None): return self._get_collection_count(context, Router, filters=filters) @@ -750,7 +756,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, port = self._find_ipv6_router_port_by_network(router, subnet['network_id']) if port: - fixed_ips = list(port['port']['fixed_ips']) + fixed_ips = list(map(dict, port['port']['fixed_ips'])) fixed_ips.append(fixed_ip) return self._core_plugin.update_port(context, port['port_id'], {'port': @@ -778,6 +784,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, 'subnet_ids': subnet_ids } + @db_api.retry_if_session_inactive() def add_router_interface(self, context, router_id, interface_info): router = self._get_router(context, router_id) add_by_port, add_by_sub = self._validate_interface_info(interface_info) @@ -918,8 +925,8 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, port_subnets = [fip['subnet_id'] for fip in p['fixed_ips']] if subnet_id in port_subnets and len(port_subnets) > 1: # multiple prefix port - delete prefix from port - fixed_ips = [fip for fip in p['fixed_ips'] if - fip['subnet_id'] != subnet_id] + fixed_ips = [dict(fip) for fip in p['fixed_ips'] + if fip['subnet_id'] != subnet_id] self._core_plugin.update_port(context, p['id'], {'port': {'fixed_ips': fixed_ips}}) @@ -934,6 +941,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, raise l3.RouterInterfaceNotFoundForSubnet(router_id=router_id, subnet_id=subnet_id) + @db_api.retry_if_session_inactive() def remove_router_interface(self, context, router_id, interface_info): remove_by_port, remove_by_subnet = ( self._validate_interface_info(interface_info, for_removal=True) @@ -1282,6 +1290,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, floatingip_db) return floatingip_dict + @db_api.retry_if_session_inactive() def create_floatingip(self, context, floatingip, initial_status=lib_constants.FLOATINGIP_STATUS_ACTIVE): return self._create_floatingip(context, floatingip, initial_status) @@ -1312,11 +1321,13 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, for floatingip in floatingips if floatingip['router_id']])) + @db_api.retry_if_session_inactive() def update_floatingip(self, context, id, floatingip): _old_floatingip, floatingip = self._update_floatingip( context, id, floatingip) return floatingip + @db_api.retry_if_session_inactive() def update_floatingip_status(self, context, floatingip_id, status): """Update operational status for floating IP in neutron DB.""" fip_query = self._model_query(context, FloatingIP).filter( @@ -1337,13 +1348,16 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, l3_port_check=False) return floatingip_dict + @db_api.retry_if_session_inactive() def delete_floatingip(self, context, id): self._delete_floatingip(context, id) + @db_api.retry_if_session_inactive() def get_floatingip(self, context, id, fields=None): floatingip = self._get_floatingip(context, id) return self._make_floatingip_dict(floatingip, fields) + @db_api.retry_if_session_inactive() def get_floatingips(self, context, filters=None, fields=None, sorts=None, limit=None, marker=None, page_reverse=False): @@ -1362,6 +1376,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, marker_obj=marker_obj, page_reverse=page_reverse) + @db_api.retry_if_session_inactive() def delete_disassociated_floatingips(self, context, network_id): query = self._model_query(context, FloatingIP) query = query.filter_by(floating_network_id=network_id, @@ -1370,6 +1385,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, for fip in query: self.delete_floatingip(context, fip.id) + @db_api.retry_if_session_inactive() def get_floatingips_count(self, context, filters=None): return self._get_collection_count(context, FloatingIP, filters=filters) @@ -1435,6 +1451,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, raise n_exc.ServicePortInUse(port_id=port['id'], reason=reason) + @db_api.retry_if_session_inactive() def disassociate_floatingips(self, context, port_id, do_notify=True): """Disassociate all floating IPs linked to specific port. diff --git a/neutron/db/l3_dvr_db.py b/neutron/db/l3_dvr_db.py index cc3e252730a..e4a4608bddc 100644 --- a/neutron/db/l3_dvr_db.py +++ b/neutron/db/l3_dvr_db.py @@ -305,6 +305,7 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, floating_ip = fip_qry.filter_by(fixed_port_id=port_id) return floating_ip.first() + @db_api.retry_if_session_inactive() def add_router_interface(self, context, router_id, interface_info): add_by_port, add_by_sub = self._validate_interface_info(interface_info) router = self._get_router(context, router_id) @@ -486,6 +487,7 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, return True return False + @db_api.retry_if_session_inactive() def remove_router_interface(self, context, router_id, interface_info): router = self._get_router(context, router_id) if not router.extra_attributes.distributed: @@ -968,6 +970,7 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, p['id'], l3_port_check=False) + @db_api.retry_if_session_inactive() def create_floatingip(self, context, floatingip, initial_status=const.FLOATINGIP_STATUS_ACTIVE): floating_ip = self._create_floatingip( @@ -1003,6 +1006,7 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, else: self.notify_router_updated(context, router_id) + @db_api.retry_if_session_inactive() def update_floatingip(self, context, id, floatingip): old_floatingip, floatingip = self._update_floatingip( context, id, floatingip) @@ -1012,6 +1016,7 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, self._notify_floating_ip_change(context, floatingip) return floatingip + @db_api.retry_if_session_inactive() def delete_floatingip(self, context, id): floating_ip = self._delete_floatingip(context, id) self._notify_floating_ip_change(context, floating_ip) diff --git a/neutron/db/l3_hamode_db.py b/neutron/db/l3_hamode_db.py index 35d2298ae6a..e7151fa9323 100644 --- a/neutron/db/l3_hamode_db.py +++ b/neutron/db/l3_hamode_db.py @@ -35,6 +35,7 @@ from neutron.api.v2 import attributes from neutron.common import constants as n_const from neutron.common import utils as n_utils from neutron.db import agents_db +from neutron.db import api as db_api from neutron.db.availability_zone import router as router_az_db from neutron.db import common_db_mixin from neutron.db import l3_db @@ -204,7 +205,10 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin, return allocated_vr_ids + @db_api.retry_if_session_inactive() def _allocate_vr_id(self, context, network_id, router_id): + # TODO(kevinbenton): let decorator handle duplicate retry + # like in review.openstack.org/#/c/367179/1/neutron/db/l3_hamode_db.py for count in range(MAX_ALLOCATION_TRIES): try: # NOTE(kevinbenton): we disallow subtransactions because the @@ -235,6 +239,7 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin, network_id=network_id, router_id=router_id, max_tries=MAX_ALLOCATION_TRIES) + @db_api.retry_if_session_inactive() def _delete_vr_id_allocation(self, context, ha_network, vr_id): with context.session.begin(subtransactions=True): context.session.query(L3HARouterVRIdAllocation).filter_by( @@ -460,6 +465,7 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin, return n_utils.create_object_with_dependency( creator, dep_getter, dep_creator, dep_id_attr, dep_deleter) + @db_api.retry_if_session_inactive() def create_router(self, context, router): is_ha = self._is_ha(router['router']) router['router']['ha'] = is_ha @@ -492,6 +498,7 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin, self.delete_router(context, router_dict['id']) return router_dict + @db_api.retry_if_session_inactive() def _update_router_db(self, context, router_id, data): router_db = self._get_router(context, router_id) @@ -602,6 +609,7 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin, "%(tenant)s."), {'network': ha_network.network_id, 'tenant': tenant_id}) + @db_api.retry_if_session_inactive() def delete_router(self, context, id): router_db = self._get_router(context, id) super(L3_HA_NAT_db_mixin, self).delete_router(context, id) @@ -748,6 +756,7 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin, # Take concurrently deleted routers in to account pass + @db_api.retry_if_session_inactive() def update_routers_states(self, context, states, host): """Receive dict of router ID to state and update them all.""" @@ -758,7 +767,7 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin, def _update_router_port_bindings(self, context, states, host): admin_ctx = context.elevated() - device_filter = {'device_id': states.keys(), + device_filter = {'device_id': list(states.keys()), 'device_owner': [constants.DEVICE_OWNER_HA_REPLICATED_INT, constants.DEVICE_OWNER_ROUTER_SNAT]} diff --git a/neutron/plugins/ml2/common/exceptions.py b/neutron/plugins/ml2/common/exceptions.py index adac5d60646..106d4275fa5 100644 --- a/neutron/plugins/ml2/common/exceptions.py +++ b/neutron/plugins/ml2/common/exceptions.py @@ -28,7 +28,7 @@ class MechanismDriverError(exceptions.MultipleExceptions): # MultipleExceptions and return inner exceptions. Keep it # for backward-compatibility, in case other code use it. self.message = _("%s failed.") % method - super(MechanismDriverError, self).__init__(errors) + super(MechanismDriverError, self).__init__(errors or []) class ExtensionDriverError(exceptions.InvalidInput): diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index 6b1575e95ed..6de5cc571c0 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -772,6 +772,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return result, mech_context @utils.transaction_guard + @db_api.retry_if_session_inactive() def create_network(self, context, network): result, mech_context = self._create_network_db(context, network) kwargs = {'context': context, 'network': result} @@ -787,11 +788,13 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return result @utils.transaction_guard + @db_api.retry_if_session_inactive() def create_network_bulk(self, context, networks): objects = self._create_bulk_ml2(attributes.NETWORK, context, networks) return [obj['result'] for obj in objects] @utils.transaction_guard + @db_api.retry_if_session_inactive() def update_network(self, context, id, network): net_data = network[attributes.NETWORK] provider._raise_if_updates_provider_attributes(net_data) @@ -833,6 +836,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, self.notifier.network_update(context, updated_network) return updated_network + @db_api.retry_if_session_inactive() def get_network(self, context, id, fields=None): session = context.session with session.begin(subtransactions=True): @@ -842,6 +846,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return self._fields(result, fields) + @db_api.retry_if_session_inactive() def get_networks(self, context, filters=None, fields=None, sorts=None, limit=None, marker=None, page_reverse=False): session = context.session @@ -886,6 +891,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, _LE("Exception auto-deleting subnet %s"), subnet_id) @utils.transaction_guard + @db_api.retry_if_session_inactive() def delete_network(self, context, id): # REVISIT(rkukura) The super(Ml2Plugin, self).delete_network() # function is not used because it auto-deletes ports and @@ -993,6 +999,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return result, mech_context @utils.transaction_guard + @db_api.retry_if_session_inactive() def create_subnet(self, context, subnet): result, mech_context = self._create_subnet_db(context, subnet) kwargs = {'context': context, 'subnet': result} @@ -1007,11 +1014,13 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return result @utils.transaction_guard + @db_api.retry_if_session_inactive() def create_subnet_bulk(self, context, subnets): objects = self._create_bulk_ml2(attributes.SUBNET, context, subnets) return [obj['result'] for obj in objects] @utils.transaction_guard + @db_api.retry_if_session_inactive() def update_subnet(self, context, id, subnet): session = context.session with session.begin(subtransactions=True): @@ -1037,6 +1046,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return updated_subnet @utils.transaction_guard + @db_api.retry_if_session_inactive() def delete_subnet(self, context, id): # REVISIT(rkukura) The super(Ml2Plugin, self).delete_subnet() # function is not used because it deallocates the subnet's addresses @@ -1246,6 +1256,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return result, mech_context @utils.transaction_guard + @db_api.retry_if_session_inactive() def create_port(self, context, port): result, mech_context = self._create_port_db(context, port) # notify any plugin that is interested in port create events @@ -1282,6 +1293,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return bound_context.current @utils.transaction_guard + @db_api.retry_if_session_inactive() def create_port_bulk(self, context, ports): objects = self._create_bulk_ml2(attributes.PORT, context, ports) @@ -1352,6 +1364,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, raise psec.PortSecurityPortHasSecurityGroup() @utils.transaction_guard + @db_api.retry_if_session_inactive() def update_port(self, context, id, port): attrs = port[attributes.PORT] need_port_update_notify = False @@ -1489,6 +1502,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, binding.router_id = attrs and attrs.get('device_id') @utils.transaction_guard + @db_api.retry_if_session_inactive() def update_distributed_port_binding(self, context, id, port): attrs = port[attributes.PORT] @@ -1546,6 +1560,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, raise exc.ServicePortInUse(port_id=port_id, reason=e) @utils.transaction_guard + @db_api.retry_if_session_inactive() def delete_port(self, context, id, l3_port_check=True): self._pre_delete_port(context, id, l3_port_check) # TODO(armax): get rid of the l3 dependency in the with block @@ -1616,6 +1631,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, self.notify_security_groups_member_updated(context, port) @utils.transaction_guard + @db_api.retry_if_session_inactive(context_var_name='plugin_context') def get_bound_port_context(self, plugin_context, port_id, host=None, cached_networks=None): session = plugin_context.session @@ -1668,7 +1684,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return self._bind_port_if_needed(port_context) @utils.transaction_guard - @db_api.retry_db_errors + @db_api.retry_if_session_inactive() def update_port_status(self, context, port_id, status, host=None, network=None): """ @@ -1746,6 +1762,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return port['id'] + @db_api.retry_if_session_inactive() def port_bound_to_host(self, context, port_id, host): if not host: return @@ -1765,6 +1782,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, port_host = db.get_port_binding_host(context.session, port_id) return port if (port_host == host) else None + @db_api.retry_if_session_inactive() def get_ports_from_devices(self, context, devices): port_ids_to_devices = dict( (self._device_to_port_id(context, device), device) diff --git a/neutron/tests/unit/db/test_l3_db.py b/neutron/tests/unit/db/test_l3_db.py index 4124f2d9b4b..262298f6d43 100644 --- a/neutron/tests/unit/db/test_l3_db.py +++ b/neutron/tests/unit/db/test_l3_db.py @@ -234,7 +234,7 @@ class L3_NAT_db_mixin(base.BaseTestCase): mock.patch.object(l3_db.L3_NAT_db_mixin, 'notify_router_updated')\ as nru: - self.db.create_router(mock.ANY, router_input) + self.db.create_router(mock.Mock(), router_input) self.assertTrue(crd.called) if external_gateway_info: self.assertTrue(urgi.called)