]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Lock tables for update on allocation/deletion
authorAnte Karamatic <ante.karamatic@canonical.com>
Thu, 7 Feb 2013 11:33:49 +0000 (12:33 +0100)
committerGary Kotton <gkotton@redhat.com>
Thu, 7 Mar 2013 18:45:44 +0000 (18:45 +0000)
Allocating, creating and deleting port might happen
in parallel and we need to make sure we don't
assign same IP to multiple different requests.

Added treatment for vlan tags and tunnel ID's

Fixes: bug #1110807
Change-Id: Idbb04d3ce6eacd308b05536f1942a35a0792199e

quantum/db/db_base_plugin_v2.py
quantum/plugins/linuxbridge/db/l2network_db_v2.py
quantum/plugins/openvswitch/ovs_db_v2.py

index 0a97fa67b00759976f71789adffbb35e39f0b7b6..36d1356c5602b7e500db04f887944fa7e158a340 100644 (file)
@@ -282,7 +282,8 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
 
     @staticmethod
     def _hold_ip(context, network_id, subnet_id, port_id, ip_address):
-        alloc_qry = context.session.query(models_v2.IPAllocation)
+        alloc_qry = context.session.query(
+            models_v2.IPAllocation).with_lockmode('update')
         allocated = alloc_qry.filter_by(network_id=network_id,
                                         port_id=port_id,
                                         ip_address=ip_address,
@@ -306,7 +307,8 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
         if network_id in getattr(context, '_recycled_networks', set()):
             return
 
-        expired_qry = context.session.query(models_v2.IPAllocation)
+        expired_qry = context.session.query(
+            models_v2.IPAllocation).with_lockmode('update')
         expired_qry = expired_qry.filter_by(network_id=network_id,
                                             port_id=None)
         expired_qry = expired_qry.filter(
@@ -329,7 +331,8 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
         subnet.
         """
         # Grab all allocation pools for the subnet
-        pool_qry = context.session.query(models_v2.IPAllocationPool)
+        pool_qry = context.session.query(
+            models_v2.IPAllocationPool).with_lockmode('update')
         allocation_pools = pool_qry.filter_by(subnet_id=subnet_id).all()
         # Find the allocation pool for the IP to recycle
         pool_id = None
@@ -350,7 +353,8 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
         # If 1 of the above holds true then the specific entry will be
         # modified. If both hold true then the two ranges will be merged.
         # If there are no entries then a single entry will be added.
-        range_qry = context.session.query(models_v2.IPAvailabilityRange)
+        range_qry = context.session.query(
+            models_v2.IPAvailabilityRange).with_lockmode('update')
         ip_first = str(netaddr.IPAddress(ip_address) + 1)
         ip_last = str(netaddr.IPAddress(ip_address) - 1)
         LOG.debug(_("Recycle %s"), ip_address)
@@ -433,7 +437,8 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
         # Delete the IP address from the IPAllocate table
         LOG.debug(_("Delete allocated IP %(ip_address)s "
                     "(%(network_id)s/%(subnet_id)s)"), locals())
-        alloc_qry = context.session.query(models_v2.IPAllocation)
+        alloc_qry = context.session.query(
+            models_v2.IPAllocation).with_lockmode('update')
         allocated = alloc_qry.filter_by(network_id=network_id,
                                         ip_address=ip_address,
                                         subnet_id=subnet_id).delete()
@@ -447,7 +452,7 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
         """
         range_qry = context.session.query(
             models_v2.IPAvailabilityRange).join(
-                models_v2.IPAllocationPool)
+                models_v2.IPAllocationPool).with_lockmode('update')
         for subnet in subnets:
             range = range_qry.filter_by(subnet_id=subnet['id']).first()
             if not range:
@@ -479,7 +484,7 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
         range_qry = context.session.query(
             models_v2.IPAvailabilityRange,
             models_v2.IPAllocationPool).join(
-                models_v2.IPAllocationPool)
+                models_v2.IPAllocationPool).with_lockmode('update')
         results = range_qry.filter_by(subnet_id=subnet_id).all()
         for (range, pool) in results:
             first = int(netaddr.IPAddress(range['first_ip']))
@@ -1356,7 +1361,8 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
     def _delete_port(self, context, id):
         port = self._get_port(context, id)
 
-        allocated_qry = context.session.query(models_v2.IPAllocation)
+        allocated_qry = context.session.query(
+            models_v2.IPAllocation).with_lockmode('update')
         # recycle all of the IP's
         allocated = allocated_qry.filter_by(port_id=id).all()
         if allocated:
index bd82e41e567effdc1c14edaba2b022953262922b..8f893294e57388b2ae2187d20f48ff0b4773799a 100644 (file)
@@ -111,6 +111,7 @@ def reserve_network(session):
     with session.begin(subtransactions=True):
         state = (session.query(l2network_models_v2.NetworkState).
                  filter_by(allocated=False).
+                 with_lockmode('update').
                  first())
         if not state:
             raise q_exc.NoNetworkAvailable()
@@ -128,6 +129,7 @@ def reserve_specific_network(session, physical_network, vlan_id):
             state = (session.query(l2network_models_v2.NetworkState).
                      filter_by(physical_network=physical_network,
                                vlan_id=vlan_id).
+                     with_lockmode('update').
                      one())
             if state.allocated:
                 if vlan_id == constants.FLAT_VLAN_ID:
@@ -153,6 +155,7 @@ def release_network(session, physical_network, vlan_id, network_vlan_ranges):
             state = (session.query(l2network_models_v2.NetworkState).
                      filter_by(physical_network=physical_network,
                                vlan_id=vlan_id).
+                     with_lockmode('update').
                      one())
             state.allocated = False
             inside = False
index c6984e9a32c36a071ee4c4263a2aaa42c7ee8807..3708c6fdbc50f0b42326924b0218878a61fe2b4a 100644 (file)
@@ -130,6 +130,7 @@ def reserve_vlan(session):
     with session.begin(subtransactions=True):
         alloc = (session.query(ovs_models_v2.VlanAllocation).
                  filter_by(allocated=False).
+                 with_lockmode('update').
                  first())
         if alloc:
             LOG.debug(_("Reserving vlan %(vlan_id)s on physical network "
@@ -147,6 +148,7 @@ def reserve_specific_vlan(session, physical_network, vlan_id):
             alloc = (session.query(ovs_models_v2.VlanAllocation).
                      filter_by(physical_network=physical_network,
                                vlan_id=vlan_id).
+                     with_lockmode('update').
                      one())
             if alloc.allocated:
                 if vlan_id == constants.FLAT_VLAN_ID:
@@ -173,6 +175,7 @@ def release_vlan(session, physical_network, vlan_id, network_vlan_ranges):
             alloc = (session.query(ovs_models_v2.VlanAllocation).
                      filter_by(physical_network=physical_network,
                                vlan_id=vlan_id).
+                     with_lockmode('update').
                      one())
             alloc.allocated = False
             inside = False
@@ -237,6 +240,7 @@ def get_tunnel_allocation(tunnel_id):
     try:
         alloc = (session.query(ovs_models_v2.TunnelAllocation).
                  filter_by(tunnel_id=tunnel_id).
+                 with_lockmode('update').
                  one())
         return alloc
     except exc.NoResultFound:
@@ -247,6 +251,7 @@ def reserve_tunnel(session):
     with session.begin(subtransactions=True):
         alloc = (session.query(ovs_models_v2.TunnelAllocation).
                  filter_by(allocated=False).
+                 with_lockmode('update').
                  first())
         if alloc:
             LOG.debug(_("Reserving tunnel %s from pool"), alloc.tunnel_id)
@@ -260,6 +265,7 @@ def reserve_specific_tunnel(session, tunnel_id):
         try:
             alloc = (session.query(ovs_models_v2.TunnelAllocation).
                      filter_by(tunnel_id=tunnel_id).
+                     with_lockmode('update').
                      one())
             if alloc.allocated:
                 raise q_exc.TunnelIdInUse(tunnel_id=tunnel_id)
@@ -278,6 +284,7 @@ def release_tunnel(session, tunnel_id, tunnel_id_ranges):
         try:
             alloc = (session.query(ovs_models_v2.TunnelAllocation).
                      filter_by(tunnel_id=tunnel_id).
+                     with_lockmode('update').
                      one())
             alloc.allocated = False
             inside = False
@@ -368,7 +375,7 @@ def add_tunnel_endpoint(ip):
     session = db.get_session()
     try:
         tunnel = (session.query(ovs_models_v2.TunnelEndpoint).
-                  filter_by(ip_address=ip).one())
+                  filter_by(ip_address=ip).with_lockmode('update').one())
     except exc.NoResultFound:
         id = _generate_tunnel_id(session)
         tunnel = ovs_models_v2.TunnelEndpoint(ip, id)