]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Fix _ensure_default_security_group logic
authorEugene Nikanorov <enikanorov@mirantis.com>
Sat, 18 Jul 2015 23:17:43 +0000 (03:17 +0400)
committerOleg Bondarev <obondarev@mirantis.com>
Thu, 20 Aug 2015 09:26:31 +0000 (12:26 +0300)
In a case when first attempt to fetch default security group
fails and attempt to add it fails too due to a concurrent insertion,
later attempt to fetch the same default sg may fail due to
REPEATABLE READ transaction isolation level.
For this case RetryRequest should be issued to restart the
whole transaction and be able to see default group.

The patch also removes 'while True' logic as it's unsafe

Closes-Bug: #1475938
Change-Id: I20f65d3eae9421429aced1f4586cb6988ab577ff

neutron/db/securitygroups_db.py
neutron/plugins/ml2/plugin.py

index e2f050fa6a7c6251e861e3031bd7bb5237ab0d99..e04634e94e517ae5fc1653f1b5fd54d92c43fef6 100644 (file)
@@ -13,7 +13,7 @@
 #    under the License.
 
 import netaddr
-from oslo_db import exception
+from oslo_db import exception as db_exc
 from oslo_log import log as logging
 from oslo_utils import uuidutils
 import sqlalchemy as sa
@@ -649,14 +649,23 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase):
     def _ensure_default_security_group(self, context, tenant_id):
         """Create a default security group if one doesn't exist.
 
-        :returns: the default security group id.
+        :returns: the default security group id for given tenant.
         """
-        query = self._model_query(context, DefaultSecurityGroup)
-        # the next loop should do 2 iterations at max
-        while True:
+        # Make no more than two attempts
+        for attempts in (1, 2):
             try:
+                query = self._model_query(context, DefaultSecurityGroup)
                 default_group = query.filter_by(tenant_id=tenant_id).one()
-            except exc.NoResultFound:
+                return default_group['security_group_id']
+            except exc.NoResultFound as ex:
+                if attempts > 1:
+                    # the second iteration means that attempt to add default
+                    # group failed with duplicate error. Since we're still
+                    # not seeing this group we're most probably inside a
+                    # transaction with REPEATABLE READ isolation level ->
+                    # need to restart the whole transaction
+                    raise db_exc.RetryRequest(ex)
+
                 security_group = {
                     'security_group':
                         {'name': 'default',
@@ -664,16 +673,13 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase):
                          'description': _('Default security group')}
                 }
                 try:
-                    ret = self.create_security_group(
+                    security_group = self.create_security_group(
                         context, security_group, default_sg=True)
-                except exception.DBDuplicateEntry as ex:
+                    return security_group['id']
+                except db_exc.DBDuplicateEntry as ex:
+                    # default security group was created concurrently
                     LOG.debug("Duplicate default security group %s was "
                               "not created", ex.value)
-                    continue
-                else:
-                    return ret['id']
-            else:
-                return default_group['security_group_id']
 
     def _get_security_groups_on_port(self, context, port):
         """Check that all security groups on port belong to tenant.
index 904abe9c1a7369cb085235b580a9312424ee3ffd..5d9a21361963c7911d274c578ba30c01798cd9ce 100644 (file)
@@ -563,6 +563,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
                               {'res': resource,
                                'id': obj['result']['id']})
 
+    @oslo_db_api.wrap_db_retry(max_retries=db_api.MAX_RETRIES,
+                               retry_on_request=True)
     def _create_bulk_ml2(self, resource, context, request_items):
         objects = []
         collection = "%ss" % resource
@@ -1004,6 +1006,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
 
         return result, mech_context
 
+    @oslo_db_api.wrap_db_retry(max_retries=db_api.MAX_RETRIES,
+                               retry_on_request=True)
     def create_port(self, context, port):
         attrs = port[attributes.PORT]
         result, mech_context = self._create_port_db(context, port)