NSX|P: Support listener default pool with session persistence
Set/update/delete NSX session persistence profile, upon setting/removing lbaas listener default pool. Change-Id: I2a007a11ae30b166c0dd4e01525a5917da5ff1d4
This commit is contained in:
parent
248744b7c5
commit
2be77ef707
@ -19,7 +19,6 @@ from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
from vmware_nsx._i18n import _
|
||||
from vmware_nsx.common import exceptions as nsx_exc
|
||||
from vmware_nsx.services.lbaas import base_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_p.implementation import lb_utils
|
||||
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||
@ -79,7 +78,7 @@ class EdgeL7PolicyManagerFromDict(base_mgr.NsxpLoadbalancerBaseManager):
|
||||
try:
|
||||
vs_client.remove_lb_rule(policy['listener_id'],
|
||||
policy_name)
|
||||
except nsx_exc.NsxResourceNotFound:
|
||||
except nsxlib_exc.ResourceNotFound:
|
||||
pass
|
||||
except nsxlib_exc.ManagerError:
|
||||
completor(success=False)
|
||||
|
@ -216,11 +216,9 @@ def setup_session_persistence(nsxpolicy, pool, pool_tags, listener, vs_data):
|
||||
else:
|
||||
pp_client = lb_client.lb_source_ip_persistence_profile
|
||||
pers_type = nsxlib_lb.PersistenceProfileTypes.SOURCE_IP
|
||||
|
||||
if pers_type:
|
||||
# There is a profile to create or update
|
||||
pp_kwargs = {
|
||||
'persistence_profile_id': pool['id'],
|
||||
'name': "persistence_%s" % utils.get_name_and_uuid(
|
||||
pool['name'] or 'pool', pool['id'], maxlen=235),
|
||||
'tags': lb_utils.build_persistence_profile_tags(
|
||||
@ -230,8 +228,8 @@ def setup_session_persistence(nsxpolicy, pool, pool_tags, listener, vs_data):
|
||||
pp_kwargs['cookie_name'] = cookie_name
|
||||
pp_kwargs['cookie_mode'] = cookie_mode
|
||||
|
||||
persistence_profile_id = p_utils.path_to_id(
|
||||
vs_data.get('lb_persistence_profile_path', ''))
|
||||
profile_path = vs_data.get('lb_persistence_profile_path', '')
|
||||
persistence_profile_id = p_utils.path_to_id(profile_path)
|
||||
if persistence_profile_id:
|
||||
# NOTE: removal of the persistence profile must be executed
|
||||
# after the virtual server has been updated
|
||||
@ -246,7 +244,6 @@ def setup_session_persistence(nsxpolicy, pool, pool_tags, listener, vs_data):
|
||||
return persistence_profile_id, None
|
||||
else:
|
||||
# Prepare removal of persistence profile
|
||||
profile_path = vs_data.get('lb_persistence_profile_path', '')
|
||||
return (None, functools.partial(delete_persistence_profile,
|
||||
nsxpolicy, profile_path))
|
||||
elif pers_type:
|
||||
|
@ -21,8 +21,8 @@ from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
from vmware_nsx._i18n import _
|
||||
from vmware_nsx.common import exceptions as nsx_exc
|
||||
from vmware_nsx.services.lbaas import base_mgr
|
||||
from vmware_nsx.services.lbaas import lb_common
|
||||
from vmware_nsx.services.lbaas import lb_const
|
||||
from vmware_nsx.services.lbaas.nsx_p.implementation import lb_utils
|
||||
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||
@ -135,19 +135,29 @@ class EdgeListenerManagerFromDict(base_mgr.NsxpLoadbalancerBaseManager):
|
||||
|
||||
return app_client
|
||||
|
||||
def _validate_default_pool(self, listener, completor):
|
||||
l_pool_id = listener.get('default_pool_id')
|
||||
if l_pool_id:
|
||||
def _validate_default_pool(self, listener, completor,
|
||||
old_listener=None):
|
||||
def_pool_id = listener.get('default_pool_id')
|
||||
if def_pool_id:
|
||||
vs_client = self.core_plugin.nsxpolicy.load_balancer.virtual_server
|
||||
vs_list = vs_client.list()
|
||||
for vs in vs_list:
|
||||
pool_id = p_utils.path_to_id(vs.get('pool_path', ''))
|
||||
if pool_id == l_pool_id:
|
||||
if pool_id == def_pool_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)
|
||||
|
||||
# Perform additional validation for session persistence before
|
||||
# creating resources in the backend
|
||||
old_pool = None
|
||||
if old_listener:
|
||||
old_pool = old_listener.get('default_pool')
|
||||
lb_common.validate_session_persistence(
|
||||
listener.get('default_pool'), listener, completor,
|
||||
old_pool=old_pool)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create(self, context, listener, completor,
|
||||
certificate=None):
|
||||
@ -169,8 +179,54 @@ class EdgeListenerManagerFromDict(base_mgr.NsxpLoadbalancerBaseManager):
|
||||
msg = _('Failed to create virtual server at NSX backend')
|
||||
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
|
||||
|
||||
self._update_default_pool(context, listener, completor)
|
||||
|
||||
completor(success=True)
|
||||
|
||||
def _get_pool_tags(self, context, pool):
|
||||
return lb_utils.get_tags(self.core_plugin, pool['id'],
|
||||
lb_const.LB_POOL_TYPE, pool['tenant_id'],
|
||||
context.project_name)
|
||||
|
||||
def _update_default_pool(self, context, listener, completor):
|
||||
if not listener.get('default_pool_id'):
|
||||
return
|
||||
nsxlib_lb = self.core_plugin.nsxpolicy.load_balancer
|
||||
vs_client = nsxlib_lb.virtual_server
|
||||
vs_data = vs_client.get(listener['id'])
|
||||
pool_id = listener['default_pool_id']
|
||||
pool = listener['default_pool']
|
||||
try:
|
||||
(persistence_profile_id,
|
||||
post_process_func) = lb_utils.setup_session_persistence(
|
||||
self.core_plugin.nsxpolicy,
|
||||
pool,
|
||||
self._get_pool_tags(context, pool),
|
||||
listener, vs_data)
|
||||
except nsxlib_exc.ManagerError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
completor(success=False)
|
||||
LOG.error("Failed to configure session persistence "
|
||||
"profile for listener %s", listener['id'])
|
||||
try:
|
||||
# Update persistence profile and pool on virtual server
|
||||
vs_client.update(
|
||||
listener['id'],
|
||||
pool_id=pool_id,
|
||||
lb_persistence_profile_id=persistence_profile_id)
|
||||
LOG.debug("Updated NSX virtual server %(vs_id)s with "
|
||||
"persistence profile %(prof)s",
|
||||
{'vs_id': listener['id'],
|
||||
'prof': persistence_profile_id})
|
||||
if post_process_func:
|
||||
post_process_func()
|
||||
except nsxlib_exc.ManagerError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
completor(success=False)
|
||||
LOG.error("Failed to attach persistence profile %s to "
|
||||
"virtual server %s",
|
||||
persistence_profile_id, listener['id'])
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def update(self, context, old_listener, new_listener, completor,
|
||||
certificate=None):
|
||||
@ -180,7 +236,8 @@ class EdgeListenerManagerFromDict(base_mgr.NsxpLoadbalancerBaseManager):
|
||||
|
||||
vs_name = None
|
||||
tags = None
|
||||
self._validate_default_pool(new_listener, completor)
|
||||
self._validate_default_pool(new_listener, completor,
|
||||
old_listener=old_listener)
|
||||
if new_listener['name'] != old_listener['name']:
|
||||
vs_name = utils.get_name_and_uuid(
|
||||
new_listener['name'] or 'listener',
|
||||
@ -201,6 +258,11 @@ class EdgeListenerManagerFromDict(base_mgr.NsxpLoadbalancerBaseManager):
|
||||
LOG.error('Failed to update listener %(listener)s with '
|
||||
'error %(error)s',
|
||||
{'listener': old_listener['id'], 'error': e})
|
||||
|
||||
# Update default pool and session persistence
|
||||
if (old_listener.get('default_pool_id') !=
|
||||
new_listener.get('default_pool_id')):
|
||||
self._update_default_pool(context, new_listener, completor)
|
||||
completor(success=True)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
@ -213,8 +275,16 @@ class EdgeListenerManagerFromDict(base_mgr.NsxpLoadbalancerBaseManager):
|
||||
app_profile_id = listener['id']
|
||||
|
||||
try:
|
||||
profile_path = None
|
||||
if listener.get('default_pool_id'):
|
||||
vs_data = vs_client.get(vs_id)
|
||||
profile_path = vs_data.get('lb_persistence_profile_path', '')
|
||||
vs_client.delete(vs_id)
|
||||
except nsx_exc.NsxResourceNotFound:
|
||||
# Also delete the old session persistence profile
|
||||
if profile_path:
|
||||
lb_utils.delete_persistence_profile(
|
||||
self.core_plugin.nsxpolicy, profile_path)
|
||||
except nsxlib_exc.ResourceNotFound:
|
||||
LOG.error("virtual server not found on nsx: %(vs)s", {'vs': vs_id})
|
||||
except nsxlib_exc.ManagerError:
|
||||
completor(success=False)
|
||||
@ -224,10 +294,9 @@ class EdgeListenerManagerFromDict(base_mgr.NsxpLoadbalancerBaseManager):
|
||||
|
||||
try:
|
||||
app_client.delete(app_profile_id)
|
||||
except nsx_exc.NsxResourceNotFound:
|
||||
except nsxlib_exc.ResourceNotFound:
|
||||
LOG.error("application profile not found on nsx: %s",
|
||||
app_profile_id)
|
||||
|
||||
except nsxlib_exc.ManagerError:
|
||||
completor(success=False)
|
||||
msg = (_('Failed to delete application profile: %(app)s') %
|
||||
@ -239,7 +308,7 @@ class EdgeListenerManagerFromDict(base_mgr.NsxpLoadbalancerBaseManager):
|
||||
cert_client = self.core_plugin.nsxpolicy.certificate
|
||||
try:
|
||||
cert_client.delete(listener['id'])
|
||||
except nsx_exc.NsxResourceNotFound:
|
||||
except nsxlib_exc.ResourceNotFound:
|
||||
LOG.error("Certificate not found on nsx: %s", listener['id'])
|
||||
|
||||
except nsxlib_exc.ManagerError:
|
||||
|
@ -272,7 +272,7 @@ class BaseTestEdgeLbaasV2(base.BaseTestCase):
|
||||
self.pp_cookie_client = mock.patch.object(
|
||||
load_balancer, 'lb_cookie_persistence_profile').start()
|
||||
self.pp_generic_client = mock.patch.object(
|
||||
load_balancer, 'lb_generic_persistence_profile').start()
|
||||
load_balancer, 'lb_persistence_profile').start()
|
||||
self.tm_client = mock.patch.object(nsxpolicy,
|
||||
'trust_management').start()
|
||||
self.nsxpolicy = nsxpolicy
|
||||
@ -520,9 +520,6 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
||||
self.completor)
|
||||
|
||||
def test_create_listener_with_session_persistence(self):
|
||||
# TODO(asarfaty): add this test after supporting default pool
|
||||
# session persistence
|
||||
return
|
||||
listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||
'listener1', 'Dummy',
|
||||
self.pool_persistency.id,
|
||||
@ -537,7 +534,9 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
||||
return_value=(None, None)), \
|
||||
mock.patch.object(self.vs_client, 'create_or_overwrite'
|
||||
) as mock_add_virtual_server,\
|
||||
mock.patch.object(self.pp_client, 'create_or_overwrite'
|
||||
mock.patch.object(self.vs_client, 'get', return_value={}),\
|
||||
mock.patch.object(self.edge_driver.listener, '_get_pool_tags'),\
|
||||
mock.patch.object(self.pp_cookie_client, 'create_or_overwrite'
|
||||
) as mock_create_pp:
|
||||
mock_get_floatingips.return_value = []
|
||||
|
||||
@ -559,9 +558,6 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
||||
self.assertTrue(self.last_completor_succees)
|
||||
|
||||
def test_create_listener_with_session_persistence_fail(self):
|
||||
# TODO(asarfaty): add this test after supporting default pool
|
||||
# session persistence
|
||||
return
|
||||
listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||
'listener1', 'Dummy',
|
||||
self.pool_persistency.id,
|
||||
@ -623,9 +619,6 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
||||
self.assertTrue(self.last_completor_succees)
|
||||
|
||||
def test_update_with_session_persistence(self):
|
||||
# TODO(asarfaty): add this test after supporting default pool
|
||||
# session persistence
|
||||
return
|
||||
new_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||
'listener1-new', 'new-description',
|
||||
self.pool_persistency.id,
|
||||
@ -640,9 +633,11 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
||||
mock.patch.object(self.core_plugin,
|
||||
'get_waf_profile_path_and_mode',
|
||||
return_value=(None, None)), \
|
||||
mock.patch.object(self.edge_driver.listener, '_get_pool_tags'),\
|
||||
mock.patch.object(self.vs_client, 'get', return_value={}),\
|
||||
mock.patch.object(self.vs_client, 'update',
|
||||
return_value={'id': LB_VS_ID}), \
|
||||
mock.patch.object(self.pp_client, 'create_or_overwrite'
|
||||
mock.patch.object(self.pp_cookie_client, 'create_or_overwrite'
|
||||
) as mock_create_pp:
|
||||
mock_get_floatingips.return_value = []
|
||||
|
||||
@ -653,9 +648,6 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
||||
self.assertTrue(self.last_completor_succees)
|
||||
|
||||
def test_update_with_session_persistence_fail(self):
|
||||
# TODO(asarfaty): add this test after supporting default pool
|
||||
# session persistence
|
||||
return
|
||||
old_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||
'listener1', 'description',
|
||||
self.pool_persistency.id,
|
||||
@ -781,8 +773,7 @@ class TestEdgeLbaasV2Pool(BaseTestEdgeLbaasV2):
|
||||
cookie_mode='INSERT',
|
||||
cookie_name='meh_cookie',
|
||||
name=mock.ANY,
|
||||
tags=mock.ANY,
|
||||
persistence_profile_id=POOL_ID)
|
||||
tags=mock.ANY)
|
||||
mock_vs_update.assert_called_once_with(
|
||||
LB_VS_ID, pool_id=LB_POOL_ID,
|
||||
lb_persistence_profile_id=LB_PP_ID)
|
||||
@ -897,10 +888,6 @@ class TestEdgeLbaasV2Pool(BaseTestEdgeLbaasV2):
|
||||
cookie=True)
|
||||
|
||||
def test_update_remove_persistency(self):
|
||||
# TODO(asarfaty): add this test after supporting default pool
|
||||
# session persistence
|
||||
return
|
||||
|
||||
def verify_func(mock_create_pp, mock_update_pp,
|
||||
mock_delete_pp, mock_vs_update):
|
||||
mock_create_pp.assert_not_called()
|
||||
@ -929,10 +916,6 @@ class TestEdgeLbaasV2Pool(BaseTestEdgeLbaasV2):
|
||||
self.assertTrue(self.last_completor_succees)
|
||||
|
||||
def test_delete_with_persistency(self):
|
||||
# TODO(asarfaty): add this test after supporting default pool
|
||||
# session persistence
|
||||
return
|
||||
|
||||
with mock.patch.object(self.vs_client, 'get'
|
||||
) as mock_vs_get, \
|
||||
mock.patch.object(self.vs_client, 'update', return_value=None
|
||||
@ -982,14 +965,12 @@ class TestEdgeLbaasV2Pool(BaseTestEdgeLbaasV2):
|
||||
cookie_name=cookie_name,
|
||||
cookie_mode=cookie_mode,
|
||||
name=mock.ANY,
|
||||
tags=mock.ANY,
|
||||
persistence_profile_id=POOL_ID)
|
||||
tags=mock.ANY)
|
||||
else:
|
||||
mock_update_pp.assert_called_once_with(
|
||||
LB_PP_ID,
|
||||
name=mock.ANY,
|
||||
tags=mock.ANY,
|
||||
persistence_profile_id=POOL_ID)
|
||||
tags=mock.ANY)
|
||||
# Compare tags - kw args are the last item of a mock call tuple
|
||||
self.assertItemsEqual(mock_update_pp.mock_calls[0][-1]['tags'],
|
||||
[{'scope': 'os-lbaas-lb-id', 'tag': 'xxx-xxx'},
|
||||
|
Loading…
Reference in New Issue
Block a user