Merge "NSX|V3: Forbid multiple listeners per LB pool"
This commit is contained in:
commit
9187915342
@ -109,6 +109,38 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
'tag': listener['loadbalancer_id']})
|
||||
return tags
|
||||
|
||||
def _validate_default_pool(self, context, listener, vs_id, completor):
|
||||
if listener.get('default_pool_id'):
|
||||
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
|
||||
context.session, listener['loadbalancer']['id'],
|
||||
listener['default_pool_id'])
|
||||
if (pool_binding and pool_binding['lb_vs_id'] and
|
||||
(vs_id is None or pool_binding['lb_vs_id'] != vs_id)):
|
||||
completor(success=False)
|
||||
msg = (_('Default pool %s is already used by another '
|
||||
'listener') % listener['default_pool_id'])
|
||||
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
|
||||
|
||||
def _update_default_pool_binding(self, context, listener, vs_id):
|
||||
if listener.get('default_pool_id'):
|
||||
lb_id = listener['loadbalancer']['id']
|
||||
pool_id = listener['default_pool_id']
|
||||
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
|
||||
context.session, lb_id, pool_id)
|
||||
if pool_binding:
|
||||
nsx_db.update_nsx_lbaas_pool_binding(
|
||||
context.session, lb_id, pool_id, vs_id)
|
||||
|
||||
def _remove_default_pool_binding(self, context, listener):
|
||||
if listener.get('default_pool_id'):
|
||||
lb_id = listener['loadbalancer']['id']
|
||||
pool_id = listener['default_pool_id']
|
||||
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
|
||||
context.session, lb_id, pool_id)
|
||||
if pool_binding:
|
||||
nsx_db.update_nsx_lbaas_pool_binding(
|
||||
context.session, lb_id, pool_id, None)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create(self, context, listener, completor,
|
||||
certificate=None):
|
||||
@ -128,11 +160,14 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
listener['protocol'] == lb_const.LB_PROTOCOL_HTTPS):
|
||||
profile_type = lb_const.LB_TCP_PROFILE
|
||||
else:
|
||||
completor(success=False)
|
||||
msg = (_('Cannot create listener %(listener)s with '
|
||||
'protocol %(protocol)s') %
|
||||
{'listener': listener['id'],
|
||||
'protocol': listener['protocol']})
|
||||
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
|
||||
# Validate default pool
|
||||
self._validate_default_pool(context, listener, None, completor)
|
||||
try:
|
||||
app_profile = app_client.create(
|
||||
display_name=vs_name, resource_type=profile_type, tags=tags)
|
||||
@ -167,6 +202,8 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
nsx_db.add_nsx_lbaas_listener_binding(
|
||||
context.session, lb_id, listener['id'], app_profile_id,
|
||||
virtual_server['id'])
|
||||
self._update_default_pool_binding(
|
||||
context, listener, virtual_server['id'])
|
||||
completor(success=True)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
@ -190,6 +227,11 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
msg = (_('Cannot find listener %(listener)s binding on NSX '
|
||||
'backend'), {'listener': old_listener['id']})
|
||||
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
|
||||
|
||||
# Validate default pool
|
||||
self._validate_default_pool(
|
||||
context, new_listener, binding['lb_vs_id'], completor)
|
||||
|
||||
try:
|
||||
vs_id = binding['lb_vs_id']
|
||||
app_profile_id = binding['app_profile_id']
|
||||
@ -207,6 +249,10 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
LOG.error('Failed to update listener %(listener)s with '
|
||||
'error %(error)s',
|
||||
{'listener': old_listener['id'], 'error': e})
|
||||
if (old_listener.get('default_pool_id') !=
|
||||
new_listener.get('default_pool_id')):
|
||||
self._remove_default_pool_binding(context, old_listener)
|
||||
self._update_default_pool_binding(context, new_listener, vs_id)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def delete(self, context, listener, completor):
|
||||
@ -245,12 +291,7 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
if listener.get('default_pool_id'):
|
||||
vs_client.update(vs_id, pool_id='')
|
||||
# Update pool binding to disassociate virtual server
|
||||
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
|
||||
context.session, lb_id, listener['default_pool_id'])
|
||||
if pool_binding:
|
||||
nsx_db.update_nsx_lbaas_pool_binding(
|
||||
context.session, lb_id,
|
||||
listener['default_pool_id'], None)
|
||||
self._remove_default_pool_binding(context, listener)
|
||||
vs_client.delete(vs_id)
|
||||
except nsx_exc.NsxResourceNotFound:
|
||||
msg = (_("virtual server not found on nsx: %(vs)s") %
|
||||
|
@ -230,6 +230,12 @@ class EdgePoolManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
tags = self._get_pool_tags(context, pool)
|
||||
description = pool.get('description')
|
||||
lb_algorithm = lb_const.LB_POOL_ALGORITHM_MAP.get(pool['lb_algorithm'])
|
||||
if pool.get('listeners') and len(pool['listeners']) > 1:
|
||||
completor(success=False)
|
||||
msg = (_('Failed to create pool: Multiple listeners are not '
|
||||
'supported.'))
|
||||
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
|
||||
|
||||
# NOTE(salv-orlando): Guard against accidental compat breakages
|
||||
try:
|
||||
listener = pool['listener'] or pool['listeners'][0]
|
||||
@ -268,6 +274,7 @@ class EdgePoolManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
nsx_db.update_nsx_lbaas_pool_binding(
|
||||
context.session, lb_id, pool['id'], vs_id)
|
||||
else:
|
||||
completor(success=False)
|
||||
msg = (_("Couldn't find binding on the listener: %s") %
|
||||
listener['id'])
|
||||
raise nsx_exc.NsxPluginException(err_msg=msg)
|
||||
@ -292,9 +299,15 @@ class EdgePoolManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
binding = nsx_db.get_nsx_lbaas_pool_binding(
|
||||
context.session, old_pool['loadbalancer_id'], old_pool['id'])
|
||||
if not binding:
|
||||
completor(success=False)
|
||||
msg = (_('Cannot find pool %(pool)s binding on NSX db '
|
||||
'mapping') % {'pool': old_pool['id']})
|
||||
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
|
||||
if new_pool.get('listeners') and len(new_pool['listeners']) > 1:
|
||||
completor(success=False)
|
||||
msg = (_('Failed to update pool %s: Multiple listeners are not '
|
||||
'supported.') % new_pool['id'])
|
||||
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
|
||||
# NOTE(salv-orlando): Guard against accidental compat breakages
|
||||
try:
|
||||
listener = new_pool['listener'] or new_pool['listeners'][0]
|
||||
|
@ -46,6 +46,8 @@ LB_NETWORK = {'router:external': False,
|
||||
'id': 'xxxxx',
|
||||
'name': 'network-1'}
|
||||
LISTENER_ID = 'listener-x'
|
||||
HTTP_LISTENER_ID = 'listener-http'
|
||||
HTTPS_LISTENER_ID = 'listener-https'
|
||||
APP_PROFILE_ID = 'appp-x'
|
||||
LB_VS_ID = 'vs-x'
|
||||
LB_APP_PROFILE = {
|
||||
@ -162,10 +164,10 @@ class BaseTestEdgeLbaasV2(base.BaseTestCase):
|
||||
'HTTP', protocol_port=80,
|
||||
loadbalancer=self.lb)
|
||||
self.https_listener = lb_models.Listener(
|
||||
LISTENER_ID, LB_TENANT_ID, 'listener1', '', None, LB_ID,
|
||||
HTTP_LISTENER_ID, LB_TENANT_ID, 'listener2', '', None, LB_ID,
|
||||
'HTTPS', protocol_port=443, loadbalancer=self.lb)
|
||||
self.terminated_https_listener = lb_models.Listener(
|
||||
LISTENER_ID, LB_TENANT_ID, 'listener1', '', None, LB_ID,
|
||||
HTTPS_LISTENER_ID, LB_TENANT_ID, 'listener3', '', None, LB_ID,
|
||||
'TERMINATED_HTTPS', protocol_port=443, loadbalancer=self.lb)
|
||||
self.pool = lb_models.Pool(POOL_ID, LB_TENANT_ID, 'pool1', '',
|
||||
None, 'HTTP', 'ROUND_ROBIN',
|
||||
@ -449,7 +451,7 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
||||
mock_add_virtual_server.assert_called_with(LB_SERVICE_ID,
|
||||
LB_VS_ID)
|
||||
mock_add_listener_binding.assert_called_with(
|
||||
self.context.session, LB_ID, LISTENER_ID, APP_PROFILE_ID,
|
||||
self.context.session, LB_ID, listener.id, APP_PROFILE_ID,
|
||||
LB_VS_ID)
|
||||
mock_successful_completion = (
|
||||
self.lbv2_driver.listener.successful_completion)
|
||||
@ -489,7 +491,7 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
||||
mock_add_virtual_server.assert_called_with(LB_SERVICE_ID,
|
||||
LB_VS_ID)
|
||||
mock_add_listener_binding.assert_called_with(
|
||||
self.context.session, LB_ID, LISTENER_ID, APP_PROFILE_ID,
|
||||
self.context.session, LB_ID, HTTPS_LISTENER_ID, APP_PROFILE_ID,
|
||||
LB_VS_ID)
|
||||
|
||||
mock_successful_completion = (
|
||||
@ -498,6 +500,65 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
||||
self.context, self.terminated_https_listener,
|
||||
delete=False)
|
||||
|
||||
def test_create_listener_with_default_pool(self):
|
||||
listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||
'listener1', 'Dummy', self.pool.id,
|
||||
LB_ID, 'HTTP', protocol_port=80,
|
||||
loadbalancer=self.lb,
|
||||
default_pool=self.pool)
|
||||
with mock.patch.object(self.core_plugin, 'get_floatingips'
|
||||
) as mock_get_floatingips, \
|
||||
mock.patch.object(self.app_client, 'create'
|
||||
) as mock_create_app_profile, \
|
||||
mock.patch.object(self.vs_client, 'create'
|
||||
) as mock_create_virtual_server, \
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_loadbalancer_binding'
|
||||
) as mock_get_lb_binding, \
|
||||
mock.patch.object(self.service_client, 'add_virtual_server'
|
||||
) as mock_add_virtual_server, \
|
||||
mock.patch.object(nsx_db, 'add_nsx_lbaas_listener_binding'
|
||||
) as mock_add_listener_binding,\
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||
) as mock_get_pool_binding:
|
||||
mock_get_floatingips.return_value = []
|
||||
mock_create_app_profile.return_value = {'id': APP_PROFILE_ID}
|
||||
mock_create_virtual_server.return_value = {'id': LB_VS_ID}
|
||||
mock_get_lb_binding.return_value = LB_BINDING
|
||||
mock_get_pool_binding.return_value = None
|
||||
|
||||
self.edge_driver.listener.create(self.context, listener)
|
||||
|
||||
mock_add_virtual_server.assert_called_with(LB_SERVICE_ID,
|
||||
LB_VS_ID)
|
||||
mock_add_listener_binding.assert_called_with(
|
||||
self.context.session, LB_ID, LISTENER_ID, APP_PROFILE_ID,
|
||||
LB_VS_ID)
|
||||
mock_successful_completion = (
|
||||
self.lbv2_driver.listener.successful_completion)
|
||||
mock_successful_completion.assert_called_with(self.context,
|
||||
listener,
|
||||
delete=False)
|
||||
|
||||
def test_create_listener_with_used_default_pool(self):
|
||||
listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||
'listener1', 'Dummy', self.pool.id,
|
||||
LB_ID, 'HTTP', protocol_port=80,
|
||||
loadbalancer=self.lb,
|
||||
default_pool=self.pool)
|
||||
with mock.patch.object(self.core_plugin, 'get_floatingips'
|
||||
) as mock_get_floatingips, \
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_loadbalancer_binding'
|
||||
) as mock_get_lb_binding, \
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||
) as mock_get_pool_binding:
|
||||
mock_get_floatingips.return_value = []
|
||||
mock_get_lb_binding.return_value = LB_BINDING
|
||||
mock_get_pool_binding.return_value = POOL_BINDING
|
||||
|
||||
self.assertRaises(n_exc.BadRequest,
|
||||
self.edge_driver.listener.create,
|
||||
self.context, listener)
|
||||
|
||||
def test_update(self):
|
||||
new_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||
'listener1-new', 'new-description',
|
||||
@ -519,6 +580,32 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
||||
new_listener,
|
||||
delete=False)
|
||||
|
||||
def test_update_with_default_pool(self):
|
||||
new_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||
'listener1-new', 'new-description',
|
||||
self.pool, LB_ID, protocol_port=80,
|
||||
loadbalancer=self.lb,
|
||||
default_pool=self.pool)
|
||||
with mock.patch.object(self.core_plugin, 'get_floatingips'
|
||||
) as mock_get_floatingips, \
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_listener_binding'
|
||||
) as mock_get_listener_binding,\
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||
) as mock_get_pool_binding,\
|
||||
mock.patch.object(nsx_db, 'update_nsx_lbaas_pool_binding'):
|
||||
mock_get_floatingips.return_value = []
|
||||
mock_get_listener_binding.return_value = LISTENER_BINDING
|
||||
mock_get_pool_binding.return_value = POOL_BINDING
|
||||
|
||||
self.edge_driver.listener.update(self.context, self.listener,
|
||||
new_listener)
|
||||
|
||||
mock_successful_completion = (
|
||||
self.lbv2_driver.listener.successful_completion)
|
||||
mock_successful_completion.assert_called_with(self.context,
|
||||
new_listener,
|
||||
delete=False)
|
||||
|
||||
def test_delete(self):
|
||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_listener_binding'
|
||||
) as mock_get_listener_binding, \
|
||||
@ -686,6 +773,18 @@ class TestEdgeLbaasV2Pool(BaseTestEdgeLbaasV2):
|
||||
self.pool_persistency.listeners = []
|
||||
self._test_create_with_persistency(vs_data, verify_func)
|
||||
|
||||
def test_create_multiple_listeners(self):
|
||||
"""Verify creation will fail if multiple listeners are set"""
|
||||
pool = lb_models.Pool(POOL_ID, LB_TENANT_ID, 'pool1', '',
|
||||
None, 'HTTP', 'ROUND_ROBIN',
|
||||
loadbalancer_id=LB_ID,
|
||||
listeners=[self.listener,
|
||||
self.https_listener],
|
||||
loadbalancer=self.lb)
|
||||
self.assertRaises(n_exc.BadRequest,
|
||||
self.edge_driver.pool.create,
|
||||
self.context, pool)
|
||||
|
||||
def test_update(self):
|
||||
new_pool = lb_models.Pool(POOL_ID, LB_TENANT_ID, 'pool-name', '',
|
||||
None, 'HTTP', 'LEAST_CONNECTIONS',
|
||||
@ -702,6 +801,21 @@ class TestEdgeLbaasV2Pool(BaseTestEdgeLbaasV2):
|
||||
new_pool,
|
||||
delete=False)
|
||||
|
||||
def test_update_multiple_listeners(self):
|
||||
"""Verify update action will fail if multiple listeners are set"""
|
||||
new_pool = lb_models.Pool(POOL_ID, LB_TENANT_ID, 'pool1', '',
|
||||
None, 'HTTP', 'ROUND_ROBIN',
|
||||
loadbalancer_id=LB_ID,
|
||||
listeners=[self.listener,
|
||||
self.https_listener],
|
||||
loadbalancer=self.lb)
|
||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||
) as mock_get_pool_binding:
|
||||
mock_get_pool_binding.return_value = POOL_BINDING
|
||||
self.assertRaises(n_exc.BadRequest,
|
||||
self.edge_driver.pool.update,
|
||||
self.context, self.pool, new_pool)
|
||||
|
||||
def _test_update_with_persistency(self, vs_data, old_pool, new_pool,
|
||||
verify_func):
|
||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||
|
Loading…
x
Reference in New Issue
Block a user