Move loadbalancer vip port creation outside of transaction
Currently _create_port_for_vip calls ml2 create_port() method which includes rpc notification. That leads to lock wait timeouts in certain cases. The patch fixes that while making VIP creation process non-atomic. But that is fine as long until create_vip() returns vip id, it's not usable from API. Change-Id: Ie30973de80118a6b022e8c3bb07ca48122ebcd29 Partial-Bug: #1334226
This commit is contained in:
parent
732c99ee12
commit
2b2a04f98e
@ -337,6 +337,8 @@ class LoadBalancerPluginDb(loadbalancer.LoadBalancerPluginBase,
|
||||
|
||||
port = self._core_plugin.create_port(context, {'port': port_data})
|
||||
vip_db.port_id = port['id']
|
||||
# explicitly sync session with db
|
||||
context.session.flush()
|
||||
|
||||
def create_vip(self, context, vip):
|
||||
v = vip['vip']
|
||||
@ -384,18 +386,22 @@ class LoadBalancerPluginDb(loadbalancer.LoadBalancerPluginBase,
|
||||
context.session.flush()
|
||||
except exception.DBDuplicateEntry:
|
||||
raise loadbalancer.VipExists(pool_id=v['pool_id'])
|
||||
|
||||
# create a port to reserve address for IPAM
|
||||
self._create_port_for_vip(
|
||||
context,
|
||||
vip_db,
|
||||
v['subnet_id'],
|
||||
v.get('address')
|
||||
)
|
||||
|
||||
if pool:
|
||||
pool['vip_id'] = vip_db['id']
|
||||
|
||||
try:
|
||||
# create a port to reserve address for IPAM
|
||||
# do it outside the transaction to avoid rpc calls
|
||||
self._create_port_for_vip(
|
||||
context, vip_db, v['subnet_id'], v.get('address'))
|
||||
except Exception:
|
||||
# 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()
|
||||
|
||||
return self._make_vip_dict(vip_db)
|
||||
|
||||
def update_vip(self, context, id, vip):
|
||||
|
@ -23,12 +23,14 @@ import webob.exc
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.common import config
|
||||
from neutron.common import exceptions as n_exc
|
||||
from neutron import context
|
||||
import neutron.db.l3_db # noqa
|
||||
from neutron.db.loadbalancer import loadbalancer_db as ldb
|
||||
from neutron.db import servicetype_db as sdb
|
||||
import neutron.extensions
|
||||
from neutron.extensions import loadbalancer
|
||||
from neutron import manager
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.services.loadbalancer import (
|
||||
plugin as loadbalancer_plugin
|
||||
@ -369,6 +371,26 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
|
||||
)
|
||||
return vip
|
||||
|
||||
def test_create_vip_create_port_fails(self):
|
||||
with self.subnet() as subnet:
|
||||
with self.pool() as pool:
|
||||
lb_plugin = (manager.NeutronManager.
|
||||
get_instance().
|
||||
get_service_plugins()[constants.LOADBALANCER])
|
||||
with mock.patch.object(
|
||||
lb_plugin, '_create_port_for_vip') as cp:
|
||||
#some exception that can show up in port creation
|
||||
cp.side_effect = n_exc.IpAddressGenerationFailure(
|
||||
net_id=subnet['subnet']['network_id'])
|
||||
self._create_vip(self.fmt, "vip",
|
||||
pool['pool']['id'], "HTTP", "80", True,
|
||||
subnet_id=subnet['subnet']['id'],
|
||||
expected_res_status=409)
|
||||
req = self.new_list_request('vips')
|
||||
res = self.deserialize(self.fmt,
|
||||
req.get_response(self.ext_api))
|
||||
self.assertFalse(res['vips'])
|
||||
|
||||
def test_create_vip_twice_for_same_pool(self):
|
||||
"""Test loadbalancer db plugin via extension and directly."""
|
||||
with self.subnet() as subnet:
|
||||
|
Loading…
x
Reference in New Issue
Block a user