From: Eugene Nikanorov Date: Sat, 18 Jul 2015 23:17:43 +0000 (+0400) Subject: Fix _ensure_default_security_group logic X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=80ee562dec3f397ea6c18a4ca3a1e69ab996341e;p=openstack-build%2Fneutron-build.git Fix _ensure_default_security_group logic 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 --- diff --git a/neutron/db/securitygroups_db.py b/neutron/db/securitygroups_db.py index e2f050fa6..e04634e94 100644 --- a/neutron/db/securitygroups_db.py +++ b/neutron/db/securitygroups_db.py @@ -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. diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index 904abe9c1..5d9a21361 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -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)