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
This commit is contained in:
Eugene Nikanorov 2015-07-19 03:17:43 +04:00 committed by Oleg Bondarev
parent 194489b0f4
commit 80ee562dec
2 changed files with 23 additions and 13 deletions

View 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.

View 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)