Merge "Fix DB integrity issues when using postgres"

This commit is contained in:
Jenkins 2013-11-14 17:37:02 +00:00 committed by Gerrit Code Review
commit 018c4c594d
2 changed files with 55 additions and 45 deletions

View File

@ -1416,7 +1416,11 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
self.delete_port(context, port['id']) self.delete_port(context, port['id'])
def _delete_port(self, context, id): def _delete_port(self, context, id):
port = self._get_port(context, id) query = (context.session.query(models_v2.Port).
enable_eagerloads(False).filter_by(id=id))
if not context.is_admin:
query = query.filter_by(tenant_id=context.tenant_id)
port = query.with_lockmode('update').one()
allocated_qry = context.session.query( allocated_qry = context.session.query(
models_v2.IPAllocation).with_lockmode('update') models_v2.IPAllocation).with_lockmode('update')

View File

@ -14,7 +14,7 @@
# under the License. # under the License.
from oslo.config import cfg from oslo.config import cfg
from sqlalchemy import orm from sqlalchemy import exc as sql_exc
from neutron.agent import securitygroups_rpc as sg_rpc from neutron.agent import securitygroups_rpc as sg_rpc
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
@ -36,6 +36,7 @@ from neutron.extensions import multiprovidernet as mpnet
from neutron.extensions import portbindings from neutron.extensions import portbindings
from neutron.extensions import providernet as provider from neutron.extensions import providernet as provider
from neutron import manager from neutron import manager
from neutron.openstack.common import db as os_db
from neutron.openstack.common import excutils from neutron.openstack.common import excutils
from neutron.openstack.common import importutils from neutron.openstack.common import importutils
from neutron.openstack.common import log from neutron.openstack.common import log
@ -378,52 +379,60 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
LOG.debug(_("Deleting network %s"), id) LOG.debug(_("Deleting network %s"), id)
session = context.session session = context.session
filter = {'network_id': [id]}
while True: while True:
with session.begin(subtransactions=True): try:
# Get ports to auto-delete. with session.begin(subtransactions=True):
ports = (self._get_ports_query(context, filters=filter). # Get ports to auto-delete.
all()) ports = (session.query(models_v2.Port).
LOG.debug(_("Ports to auto-delete: %s"), ports) enable_eagerloads(False).
only_auto_del = all(p.device_owner filter_by(network_id=id).
in db_base_plugin_v2. with_lockmode('update').all())
AUTO_DELETE_PORT_OWNERS LOG.debug(_("Ports to auto-delete: %s"), ports)
for p in ports) only_auto_del = all(p.device_owner
if not only_auto_del: in db_base_plugin_v2.
LOG.debug(_("Tenant-owned ports exist")) AUTO_DELETE_PORT_OWNERS
raise exc.NetworkInUse(net_id=id) for p in ports)
if not only_auto_del:
LOG.debug(_("Tenant-owned ports exist"))
raise exc.NetworkInUse(net_id=id)
# Get subnets to auto-delete. # Get subnets to auto-delete.
subnets = (session.query(models_v2.Subnet). subnets = (session.query(models_v2.Subnet).
filter_by(network_id=id). enable_eagerloads(False).
all()) filter_by(network_id=id).
LOG.debug(_("Subnets to auto-delete: %s"), subnets) with_lockmode('update').all())
LOG.debug(_("Subnets to auto-delete: %s"), subnets)
if not (ports or subnets): if not (ports or subnets):
network = self.get_network(context, id) network = self.get_network(context, id)
mech_context = driver_context.NetworkContext(self, mech_context = driver_context.NetworkContext(self,
context, context,
network) network)
self.mechanism_manager.delete_network_precommit( self.mechanism_manager.delete_network_precommit(
mech_context) mech_context)
LOG.debug(_("Deleting network record")) record = self._get_network(context, id)
record = self._get_network(context, id) LOG.debug(_("Deleting network record %s"), record)
session.delete(record) session.delete(record)
for segment in mech_context.network_segments: for segment in mech_context.network_segments:
self.type_manager.release_segment(session, segment) self.type_manager.release_segment(session, segment)
# The segment records are deleted via cascade from the # The segment records are deleted via cascade from the
# network record, so explicit removal is not necessary. # network record, so explicit removal is not necessary.
LOG.debug(_("Committing transaction")) LOG.debug(_("Committing transaction"))
break break
except os_db.exception.DBError as e:
if isinstance(e.inner_exception, sql_exc.IntegrityError):
msg = _("A concurrent port creation has occurred")
LOG.exception(msg)
continue
else:
raise
for port in ports: for port in ports:
try: try:
self.delete_port(context, port.id) self.delete_port(context, port.id)
except exc.PortNotFound:
LOG.debug(_("Port %s concurrently deleted"), port.id)
except Exception: except Exception:
LOG.exception(_("Exception auto-deleting port %s"), LOG.exception(_("Exception auto-deleting port %s"),
port.id) port.id)
@ -432,8 +441,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
for subnet in subnets: for subnet in subnets:
try: try:
self.delete_subnet(context, subnet.id) self.delete_subnet(context, subnet.id)
except exc.SubnetNotFound:
LOG.debug(_("Subnet %s concurrently deleted"), subnet.id)
except Exception: except Exception:
LOG.exception(_("Exception auto-deleting subnet %s"), LOG.exception(_("Exception auto-deleting subnet %s"),
subnet.id) subnet.id)
@ -493,11 +500,13 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
session = context.session session = context.session
while True: while True:
with session.begin(subtransactions=True): with session.begin(subtransactions=True):
subnet = self.get_subnet(context, id)
# Get ports to auto-delete. # Get ports to auto-delete.
allocated = (session.query(models_v2.IPAllocation). allocated = (session.query(models_v2.IPAllocation).
options(orm.joinedload('ports')).
filter_by(subnet_id=id). filter_by(subnet_id=id).
all()) join(models_v2.Port).
filter_by(network_id=subnet['network_id']).
with_lockmode('update').all())
LOG.debug(_("Ports to auto-delete: %s"), allocated) LOG.debug(_("Ports to auto-delete: %s"), allocated)
only_auto_del = all(not a.port_id or only_auto_del = all(not a.port_id or
a.ports.device_owner in db_base_plugin_v2. a.ports.device_owner in db_base_plugin_v2.
@ -508,7 +517,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
raise exc.SubnetInUse(subnet_id=id) raise exc.SubnetInUse(subnet_id=id)
if not allocated: if not allocated:
subnet = self.get_subnet(context, id)
mech_context = driver_context.SubnetContext(self, context, mech_context = driver_context.SubnetContext(self, context,
subnet) subnet)
self.mechanism_manager.delete_subnet_precommit( self.mechanism_manager.delete_subnet_precommit(
@ -524,8 +532,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
for a in allocated: for a in allocated:
try: try:
self.delete_port(context, a.port_id) self.delete_port(context, a.port_id)
except exc.PortNotFound:
LOG.debug(_("Port %s concurrently deleted"), a.port_id)
except Exception: except Exception:
LOG.exception(_("Exception auto-deleting port %s"), LOG.exception(_("Exception auto-deleting port %s"),
a.port_id) a.port_id)