Reorder operations in create_vip

Previously VIP's port creation was moved outside the transaction
to avoid deadlocks related to rpc calls.
It led to small chance of VIP being fetched by rpc code with
port being still None.

This patch reorders VIP association with the pool so it's done
only after port has been created.

This patch also leaves small possibility of uncaught exception in
case of pool being concurrently deleted in the process of VIP creation

Change-Id: I584558aecc92db4d19fb72b1d006868b840a4d8c
Closes-Bug: #1356227
This commit is contained in:
Eugene Nikanorov 2014-08-13 15:10:45 +04:00
parent 2697d83e4d
commit b592d39d61

View File

@ -232,7 +232,10 @@ class LoadBalancerPluginDb(loadbalancer.LoadBalancerPluginBase,
########################################################
# VIP DB access
def _make_vip_dict(self, vip, fields=None):
fixed_ip = (vip.port.fixed_ips or [{}])[0]
fixed_ip = {}
# it's possible that vip doesn't have created port yet
if vip.port:
fixed_ip = (vip.port.fixed_ips or [{}])[0]
res = {'id': vip['id'],
'tenant_id': vip['tenant_id'],
@ -358,9 +361,6 @@ class LoadBalancerPluginDb(loadbalancer.LoadBalancerPluginBase,
if pool['status'] == constants.PENDING_DELETE:
raise loadbalancer.StateInvalid(state=pool['status'],
id=pool['id'])
else:
pool = None
vip_db = Vip(id=uuidutils.generate_uuid(),
tenant_id=tenant_id,
name=v['name'],
@ -386,8 +386,6 @@ class LoadBalancerPluginDb(loadbalancer.LoadBalancerPluginBase,
context.session.flush()
except exception.DBDuplicateEntry:
raise loadbalancer.VipExists(pool_id=v['pool_id'])
if pool:
pool['vip_id'] = vip_db['id']
try:
# create a port to reserve address for IPAM
@ -398,10 +396,18 @@ class LoadBalancerPluginDb(loadbalancer.LoadBalancerPluginBase,
# catch any kind of exceptions
with excutils.save_and_reraise_exception():
context.session.delete(vip_db)
if pool:
pool['vip_id'] = None
context.session.flush()
if v['pool_id']:
# fetching pool again
pool = self._get_resource(context, Pool, v['pool_id'])
# (NOTE): we rely on the fact that pool didn't change between
# above block and here
vip_db['pool_id'] = v['pool_id']
pool['vip_id'] = vip_db['id']
# explicitly flush changes as we're outside any transaction
context.session.flush()
return self._make_vip_dict(vip_db)
def update_vip(self, context, id, vip):