Fix SecurityGroupExists error when booting instances

Make sure we properly handle the case when multiple threads check
and create the default security group, if it hasn't existed yet.
One thread will succeed and others will fail (we have a unique
constraint in db to prevent a race condition), so just handle the
exception to let instance boot proceed.

Steps to reproduce:

1) install OpenStack with Rally using DevStack:

    https://github.com/stackforge/rally/tree/master/contrib/devstack

2) fetch the Rally task:

    http://boris-42.github.io/boot.yaml

3) run it

    rally -v task start boot.yaml

Closes-Bug: #1370782

Change-Id: I414637a31b0b540fefa6c1314be6e973e2d4a178
This commit is contained in:
Roman Podoliaka 2014-09-18 03:58:59 +03:00
parent af12271d29
commit bb0db95e67

View File

@ -1596,6 +1596,13 @@ def instance_create(context, values):
context - request context object context - request context object
values - dict containing column values. values - dict containing column values.
""" """
# NOTE(rpodolyaka): create the default security group, if it doesn't exist.
# This must be done in a separate transaction, so that this one is not
# aborted in case a concurrent one succeeds first and the unique constraint
# for security group names is violated by a concurrent INSERT
security_group_ensure_default(context)
values = values.copy() values = values.copy()
values['metadata'] = _metadata_refs( values['metadata'] = _metadata_refs(
values.get('metadata'), models.InstanceMetadata) values.get('metadata'), models.InstanceMetadata)
@ -3859,7 +3866,13 @@ def security_group_update(context, security_group_id, values,
def security_group_ensure_default(context): def security_group_ensure_default(context):
"""Ensure default security group exists for a project_id.""" """Ensure default security group exists for a project_id."""
try:
return _security_group_ensure_default(context) return _security_group_ensure_default(context)
except exception.SecurityGroupExists:
# NOTE(rpodolyaka): a concurrent transaction has succeeded first,
# suppress the error and proceed
return security_group_get_by_name(context, context.project_id,
'default')
def _security_group_ensure_default(context, session=None): def _security_group_ensure_default(context, session=None):