NSX|V3: Support listener default pool with session persistence
Set/update/delete NSX session persistence profile, upon setting/removing lbaas
listener default pool.
Change-Id: I96c59c8f79ed7bdd6115ef77e45d1ba0f6c3fd08
(cherry picked from commit 33f5a6eaa3
)
This commit is contained in:
parent
6d4dc569d4
commit
884fad3969
@ -13,16 +13,22 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import functools
|
||||||
|
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.services.flavors import flavors_plugin
|
from neutron.services.flavors import flavors_plugin
|
||||||
from neutron_lib import exceptions as n_exc
|
from neutron_lib import exceptions as n_exc
|
||||||
from oslo_log import helpers as log_helpers
|
from oslo_log import helpers as log_helpers
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from vmware_nsx._i18n import _
|
from vmware_nsx._i18n import _
|
||||||
from vmware_nsx.db import db as nsx_db
|
from vmware_nsx.db import db as nsx_db
|
||||||
from vmware_nsx.services.lbaas import lb_const
|
from vmware_nsx.services.lbaas import lb_const
|
||||||
|
from vmware_nsxlib.v3 import load_balancer as nsxlib_lb
|
||||||
from vmware_nsxlib.v3 import nsx_constants
|
from vmware_nsxlib.v3 import nsx_constants
|
||||||
|
from vmware_nsxlib.v3 import utils
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
ADV_RULE_NAME = 'LB external VIP advertisement'
|
ADV_RULE_NAME = 'LB external VIP advertisement'
|
||||||
NO_ROUTER_ID = 'NO ROUTER'
|
NO_ROUTER_ID = 'NO ROUTER'
|
||||||
|
|
||||||
@ -242,3 +248,136 @@ def update_router_lb_vip_advertisement(context, core_plugin, router,
|
|||||||
'match_route_types': ['T1_LB_VIP']}}
|
'match_route_types': ['T1_LB_VIP']}}
|
||||||
core_plugin.nsxlib.logical_router.update_advertisement_rules(
|
core_plugin.nsxlib.logical_router.update_advertisement_rules(
|
||||||
nsx_router_id, [adv_rule], name_prefix=ADV_RULE_NAME)
|
nsx_router_id, [adv_rule], name_prefix=ADV_RULE_NAME)
|
||||||
|
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def validate_session_persistence(pool, listener, completor, old_pool=None):
|
||||||
|
sp = pool.get('session_persistence')
|
||||||
|
if not listener or not sp:
|
||||||
|
# safety first!
|
||||||
|
return
|
||||||
|
# L4 listeners only allow source IP persistence
|
||||||
|
if (listener['protocol'] == lb_const.LB_PROTOCOL_TCP and
|
||||||
|
sp['type'] != lb_const.LB_SESSION_PERSISTENCE_SOURCE_IP):
|
||||||
|
completor(success=False)
|
||||||
|
msg = (_("Invalid session persistence type %(sp_type)s for "
|
||||||
|
"pool on listener %(lst_id)s with %(proto)s protocol") %
|
||||||
|
{'sp_type': sp['type'],
|
||||||
|
'lst_id': listener['id'],
|
||||||
|
'proto': listener['protocol']})
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
|
||||||
|
# Cannot switch (yet) on update from source IP to cookie based, and
|
||||||
|
# vice versa
|
||||||
|
cookie_pers_types = (lb_const.LB_SESSION_PERSISTENCE_HTTP_COOKIE,
|
||||||
|
lb_const.LB_SESSION_PERSISTENCE_APP_COOKIE)
|
||||||
|
if old_pool:
|
||||||
|
oldsp = old_pool.get('session_persistence')
|
||||||
|
if not oldsp:
|
||||||
|
return
|
||||||
|
if ((sp['type'] == lb_const.LB_SESSION_PERSISTENCE_SOURCE_IP and
|
||||||
|
oldsp['type'] in cookie_pers_types) or
|
||||||
|
(sp['type'] in cookie_pers_types and
|
||||||
|
oldsp['type'] == lb_const.LB_SESSION_PERSISTENCE_SOURCE_IP)):
|
||||||
|
completor(success=False)
|
||||||
|
msg = (_("Cannot update session persistence type to "
|
||||||
|
"%(sp_type)s for pool on listener %(lst_id)s "
|
||||||
|
"from %(old_sp_type)s") %
|
||||||
|
{'sp_type': sp['type'],
|
||||||
|
'lst_id': listener['id'],
|
||||||
|
'old_sp_type': oldsp['type']})
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
|
||||||
|
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def delete_persistence_profile(nsxlib, persistence_profile_id):
|
||||||
|
if persistence_profile_id:
|
||||||
|
nsxlib.load_balancer.persistence_profile.delete(persistence_profile_id)
|
||||||
|
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def build_persistence_profile_tags(pool_tags, listener):
|
||||||
|
tags = pool_tags[:]
|
||||||
|
# With octavia loadbalancer name might not be among data passed
|
||||||
|
# down to the driver
|
||||||
|
lb_data = listener.get('loadbalancer')
|
||||||
|
if lb_data:
|
||||||
|
tags.append({
|
||||||
|
'scope': 'os-lbaas-lb-name',
|
||||||
|
'tag': lb_data['name'][:utils.MAX_TAG_LEN]})
|
||||||
|
tags.append({
|
||||||
|
'scope': 'os-lbaas-lb-id',
|
||||||
|
'tag': listener['loadbalancer_id']})
|
||||||
|
tags.append({
|
||||||
|
'scope': 'os-lbaas-listener-id',
|
||||||
|
'tag': listener['id']})
|
||||||
|
return tags
|
||||||
|
|
||||||
|
|
||||||
|
def get_pool_tags(context, core_plugin, pool):
|
||||||
|
return get_tags(core_plugin, pool['id'],
|
||||||
|
lb_const.LB_POOL_TYPE, pool['tenant_id'],
|
||||||
|
context.project_name)
|
||||||
|
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def setup_session_persistence(nsxlib, pool, pool_tags, listener, vs_data):
|
||||||
|
sp = pool.get('session_persistence')
|
||||||
|
pers_type = None
|
||||||
|
cookie_name = None
|
||||||
|
cookie_mode = None
|
||||||
|
if not sp:
|
||||||
|
LOG.debug("No session persistence info for pool %s", pool['id'])
|
||||||
|
elif sp['type'] == lb_const.LB_SESSION_PERSISTENCE_HTTP_COOKIE:
|
||||||
|
pers_type = nsxlib_lb.PersistenceProfileTypes.COOKIE
|
||||||
|
cookie_name = sp.get('cookie_name')
|
||||||
|
if not cookie_name:
|
||||||
|
cookie_name = lb_const.SESSION_PERSISTENCE_DEFAULT_COOKIE_NAME
|
||||||
|
cookie_mode = "INSERT"
|
||||||
|
elif sp['type'] == lb_const.LB_SESSION_PERSISTENCE_APP_COOKIE:
|
||||||
|
pers_type = nsxlib_lb.PersistenceProfileTypes.COOKIE
|
||||||
|
# In this case cookie name is mandatory
|
||||||
|
cookie_name = sp['cookie_name']
|
||||||
|
cookie_mode = "REWRITE"
|
||||||
|
else:
|
||||||
|
pers_type = nsxlib_lb.PersistenceProfileTypes.SOURCE_IP
|
||||||
|
|
||||||
|
if pers_type:
|
||||||
|
# There is a profile to create or update
|
||||||
|
pp_kwargs = {
|
||||||
|
'resource_type': pers_type,
|
||||||
|
'display_name': "persistence_%s" % utils.get_name_and_uuid(
|
||||||
|
pool['name'] or 'pool', pool['id'], maxlen=235),
|
||||||
|
'tags': build_persistence_profile_tags(pool_tags, listener)
|
||||||
|
}
|
||||||
|
if cookie_name:
|
||||||
|
pp_kwargs['cookie_name'] = cookie_name
|
||||||
|
pp_kwargs['cookie_mode'] = cookie_mode
|
||||||
|
|
||||||
|
pp_client = nsxlib.load_balancer.persistence_profile
|
||||||
|
persistence_profile_id = vs_data.get('persistence_profile_id')
|
||||||
|
if persistence_profile_id:
|
||||||
|
# NOTE: removal of the persistence profile must be executed
|
||||||
|
# after the virtual server has been updated
|
||||||
|
if pers_type:
|
||||||
|
# Update existing profile
|
||||||
|
LOG.debug("Updating persistence profile %(profile_id)s for "
|
||||||
|
"listener %(listener_id)s with pool %(pool_id)s",
|
||||||
|
{'profile_id': persistence_profile_id,
|
||||||
|
'listener_id': listener['id'],
|
||||||
|
'pool_id': pool['id']})
|
||||||
|
pp_client.update(persistence_profile_id, **pp_kwargs)
|
||||||
|
return persistence_profile_id, None
|
||||||
|
else:
|
||||||
|
# Prepare removal of persistence profile
|
||||||
|
return (None, functools.partial(delete_persistence_profile,
|
||||||
|
nsxlib, persistence_profile_id))
|
||||||
|
elif pers_type:
|
||||||
|
# Create persistence profile
|
||||||
|
pp_data = pp_client.create(**pp_kwargs)
|
||||||
|
LOG.debug("Created persistence profile %(profile_id)s for "
|
||||||
|
"listener %(listener_id)s with pool %(pool_id)s",
|
||||||
|
{'profile_id': pp_data['id'],
|
||||||
|
'listener_id': listener['id'],
|
||||||
|
'pool_id': pool['id']})
|
||||||
|
return pp_data['id'], None
|
||||||
|
return None, None
|
||||||
|
@ -109,7 +109,8 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
'tag': listener['loadbalancer_id']})
|
'tag': listener['loadbalancer_id']})
|
||||||
return tags
|
return tags
|
||||||
|
|
||||||
def _validate_default_pool(self, context, listener, vs_id, completor):
|
def _validate_default_pool(self, context, listener, vs_id, completor,
|
||||||
|
old_listener=None):
|
||||||
if listener.get('default_pool_id'):
|
if listener.get('default_pool_id'):
|
||||||
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
|
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
|
||||||
context.session, listener['loadbalancer']['id'],
|
context.session, listener['loadbalancer']['id'],
|
||||||
@ -121,18 +122,61 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
'listener') % listener['default_pool_id'])
|
'listener') % listener['default_pool_id'])
|
||||||
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
|
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
|
||||||
|
|
||||||
def _update_default_pool_binding(self, context, listener, vs_id):
|
# 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_utils.validate_session_persistence(
|
||||||
|
listener.get('default_pool'), listener, completor,
|
||||||
|
old_pool=old_pool)
|
||||||
|
|
||||||
|
def _update_default_pool_and_binding(self, context, listener, vs_data,
|
||||||
|
completor):
|
||||||
|
vs_client = self.core_plugin.nsxlib.load_balancer.virtual_server
|
||||||
if listener.get('default_pool_id'):
|
if listener.get('default_pool_id'):
|
||||||
|
vs_id = vs_data['id']
|
||||||
lb_id = listener['loadbalancer']['id']
|
lb_id = listener['loadbalancer']['id']
|
||||||
pool_id = listener['default_pool_id']
|
pool_id = listener['default_pool_id']
|
||||||
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
|
pool = listener['default_pool']
|
||||||
context.session, lb_id, pool_id)
|
try:
|
||||||
if pool_binding:
|
(persistence_profile_id,
|
||||||
|
post_process_func) = lb_utils.setup_session_persistence(
|
||||||
|
self.core_plugin.nsxlib,
|
||||||
|
pool,
|
||||||
|
lb_utils.get_pool_tags(context, self.core_plugin, 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(
|
||||||
|
vs_id,
|
||||||
|
persistence_profile_id=persistence_profile_id)
|
||||||
|
LOG.debug("Updated NSX virtual server %(vs_id)s with "
|
||||||
|
"persistence profile %(prof)s",
|
||||||
|
{'vs_id': vs_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, vs_id)
|
||||||
|
# Update the DB binding of the default pool
|
||||||
nsx_db.update_nsx_lbaas_pool_binding(
|
nsx_db.update_nsx_lbaas_pool_binding(
|
||||||
context.session, lb_id, pool_id, vs_id)
|
context.session, lb_id, pool_id, vs_id)
|
||||||
|
|
||||||
def _remove_default_pool_binding(self, context, listener):
|
def _remove_default_pool_binding(self, context, listener):
|
||||||
if listener.get('default_pool_id'):
|
if not listener.get('default_pool_id'):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Remove the current default pool from the DB bindings
|
||||||
lb_id = listener['loadbalancer']['id']
|
lb_id = listener['loadbalancer']['id']
|
||||||
pool_id = listener['default_pool_id']
|
pool_id = listener['default_pool_id']
|
||||||
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
|
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
|
||||||
@ -202,8 +246,8 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
nsx_db.add_nsx_lbaas_listener_binding(
|
nsx_db.add_nsx_lbaas_listener_binding(
|
||||||
context.session, lb_id, listener['id'], app_profile_id,
|
context.session, lb_id, listener['id'], app_profile_id,
|
||||||
virtual_server['id'])
|
virtual_server['id'])
|
||||||
self._update_default_pool_binding(
|
self._update_default_pool_and_binding(
|
||||||
context, listener, virtual_server['id'])
|
context, listener, virtual_server, completor)
|
||||||
completor(success=True)
|
completor(success=True)
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
@log_helpers.log_method_call
|
||||||
@ -230,7 +274,8 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
|
|
||||||
# Validate default pool
|
# Validate default pool
|
||||||
self._validate_default_pool(
|
self._validate_default_pool(
|
||||||
context, new_listener, binding['lb_vs_id'], completor)
|
context, new_listener, binding['lb_vs_id'], completor,
|
||||||
|
old_listener=old_listener)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
vs_id = binding['lb_vs_id']
|
vs_id = binding['lb_vs_id']
|
||||||
@ -238,21 +283,24 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
updated_kwargs = self._get_virtual_server_kwargs(
|
updated_kwargs = self._get_virtual_server_kwargs(
|
||||||
context, new_listener, vs_name, tags, app_profile_id,
|
context, new_listener, vs_name, tags, app_profile_id,
|
||||||
certificate)
|
certificate)
|
||||||
vs_client.update(vs_id, **updated_kwargs)
|
vs_data = vs_client.update(vs_id, **updated_kwargs)
|
||||||
if vs_name:
|
if vs_name:
|
||||||
app_client.update(app_profile_id, display_name=vs_name,
|
app_client.update(app_profile_id, display_name=vs_name,
|
||||||
tags=tags)
|
tags=tags)
|
||||||
completor(success=True)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
completor(success=False)
|
completor(success=False)
|
||||||
LOG.error('Failed to update listener %(listener)s with '
|
LOG.error('Failed to update listener %(listener)s with '
|
||||||
'error %(error)s',
|
'error %(error)s',
|
||||||
{'listener': old_listener['id'], 'error': e})
|
{'listener': old_listener['id'], 'error': e})
|
||||||
|
# Update default pool and session persistence
|
||||||
if (old_listener.get('default_pool_id') !=
|
if (old_listener.get('default_pool_id') !=
|
||||||
new_listener.get('default_pool_id')):
|
new_listener.get('default_pool_id')):
|
||||||
self._remove_default_pool_binding(context, old_listener)
|
self._remove_default_pool_binding(context, old_listener)
|
||||||
self._update_default_pool_binding(context, new_listener, vs_id)
|
self._update_default_pool_and_binding(context, new_listener,
|
||||||
|
vs_data, completor)
|
||||||
|
|
||||||
|
completor(success=True)
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
@log_helpers.log_method_call
|
||||||
def delete(self, context, listener, completor):
|
def delete(self, context, listener, completor):
|
||||||
@ -288,11 +336,17 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
{'listener': listener['id'], 'lbs': lbs_id})
|
{'listener': listener['id'], 'lbs': lbs_id})
|
||||||
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
|
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
|
||||||
try:
|
try:
|
||||||
|
persist_profile_id = None
|
||||||
if listener.get('default_pool_id'):
|
if listener.get('default_pool_id'):
|
||||||
vs_client.update(vs_id, pool_id='')
|
vs_data = vs_client.update(vs_id, pool_id='')
|
||||||
|
persist_profile_id = vs_data.get('persistence_profile_id')
|
||||||
# Update pool binding to disassociate virtual server
|
# Update pool binding to disassociate virtual server
|
||||||
self._remove_default_pool_binding(context, listener)
|
self._remove_default_pool_binding(context, listener)
|
||||||
vs_client.delete(vs_id)
|
vs_client.delete(vs_id)
|
||||||
|
# Also delete the old session persistence profile
|
||||||
|
if persist_profile_id:
|
||||||
|
lb_utils.delete_persistence_profile(
|
||||||
|
self.core_plugin.nsxlib, persist_profile_id)
|
||||||
except nsx_exc.NsxResourceNotFound:
|
except nsx_exc.NsxResourceNotFound:
|
||||||
msg = (_("virtual server not found on nsx: %(vs)s") %
|
msg = (_("virtual server not found on nsx: %(vs)s") %
|
||||||
{'vs': vs_id})
|
{'vs': vs_id})
|
||||||
|
@ -28,7 +28,6 @@ from vmware_nsx.services.lbaas import lb_common
|
|||||||
from vmware_nsx.services.lbaas import lb_const
|
from vmware_nsx.services.lbaas import lb_const
|
||||||
from vmware_nsx.services.lbaas.nsx_v3.implementation import lb_utils
|
from vmware_nsx.services.lbaas.nsx_v3.implementation import lb_utils
|
||||||
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||||
from vmware_nsxlib.v3 import load_balancer as nsxlib_lb
|
|
||||||
from vmware_nsxlib.v3 import utils
|
from vmware_nsxlib.v3 import utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -50,96 +49,6 @@ class EdgePoolManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
kwargs['snat_translation'] = {'type': "LbSnatAutoMap"}
|
kwargs['snat_translation'] = {'type': "LbSnatAutoMap"}
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
|
||||||
def _build_persistence_profile_tags(self, pool_tags, listener):
|
|
||||||
tags = pool_tags[:]
|
|
||||||
# With octavia loadbalancer name might not be among data passed
|
|
||||||
# down to the driver
|
|
||||||
lb_data = listener.get('loadbalancer')
|
|
||||||
if lb_data:
|
|
||||||
tags.append({
|
|
||||||
'scope': 'os-lbaas-lb-name',
|
|
||||||
'tag': lb_data['name'][:utils.MAX_TAG_LEN]})
|
|
||||||
tags.append({
|
|
||||||
'scope': 'os-lbaas-lb-id',
|
|
||||||
'tag': listener['loadbalancer_id']})
|
|
||||||
tags.append({
|
|
||||||
'scope': 'os-lbaas-listener-id',
|
|
||||||
'tag': listener['id']})
|
|
||||||
return tags
|
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
|
||||||
def _setup_session_persistence(self, pool, pool_tags,
|
|
||||||
listener, vs_data):
|
|
||||||
sp = pool.get('session_persistence')
|
|
||||||
pers_type = None
|
|
||||||
cookie_name = None
|
|
||||||
cookie_mode = None
|
|
||||||
if not sp:
|
|
||||||
LOG.debug("No session persistence info for pool %s", pool['id'])
|
|
||||||
elif sp['type'] == lb_const.LB_SESSION_PERSISTENCE_HTTP_COOKIE:
|
|
||||||
pers_type = nsxlib_lb.PersistenceProfileTypes.COOKIE
|
|
||||||
cookie_name = sp.get('cookie_name')
|
|
||||||
if not cookie_name:
|
|
||||||
cookie_name = lb_const.SESSION_PERSISTENCE_DEFAULT_COOKIE_NAME
|
|
||||||
cookie_mode = "INSERT"
|
|
||||||
elif sp['type'] == lb_const.LB_SESSION_PERSISTENCE_APP_COOKIE:
|
|
||||||
pers_type = nsxlib_lb.PersistenceProfileTypes.COOKIE
|
|
||||||
# In this case cookie name is mandatory
|
|
||||||
cookie_name = sp['cookie_name']
|
|
||||||
cookie_mode = "REWRITE"
|
|
||||||
else:
|
|
||||||
pers_type = nsxlib_lb.PersistenceProfileTypes.SOURCE_IP
|
|
||||||
|
|
||||||
if pers_type:
|
|
||||||
# There is a profile to create or update
|
|
||||||
pp_kwargs = {
|
|
||||||
'resource_type': pers_type,
|
|
||||||
'display_name': "persistence_%s" % utils.get_name_and_uuid(
|
|
||||||
pool['name'] or 'pool', pool['id'], maxlen=235),
|
|
||||||
'tags': self._build_persistence_profile_tags(
|
|
||||||
pool_tags, listener)
|
|
||||||
}
|
|
||||||
if cookie_name:
|
|
||||||
pp_kwargs['cookie_name'] = cookie_name
|
|
||||||
pp_kwargs['cookie_mode'] = cookie_mode
|
|
||||||
|
|
||||||
pp_client = self.core_plugin.nsxlib.load_balancer.persistence_profile
|
|
||||||
persistence_profile_id = vs_data.get('persistence_profile_id')
|
|
||||||
if persistence_profile_id:
|
|
||||||
# NOTE: removal of the persistence profile must be executed
|
|
||||||
# after the virtual server has been updated
|
|
||||||
if pers_type:
|
|
||||||
# Update existing profile
|
|
||||||
LOG.debug("Updating persistence profile %(profile_id)s for "
|
|
||||||
"listener %(listener_id)s with pool %(pool_id)s",
|
|
||||||
{'profile_id': persistence_profile_id,
|
|
||||||
'listener_id': listener['id'],
|
|
||||||
'pool_id': pool['id']})
|
|
||||||
pp_client.update(persistence_profile_id, **pp_kwargs)
|
|
||||||
return persistence_profile_id, None
|
|
||||||
else:
|
|
||||||
# Prepare removal of persistence profile
|
|
||||||
return (None, functools.partial(self._remove_persistence,
|
|
||||||
vs_data))
|
|
||||||
elif pers_type:
|
|
||||||
# Create persistence profile
|
|
||||||
pp_data = pp_client.create(**pp_kwargs)
|
|
||||||
LOG.debug("Created persistence profile %(profile_id)s for "
|
|
||||||
"listener %(listener_id)s with pool %(pool_id)s",
|
|
||||||
{'profile_id': pp_data['id'],
|
|
||||||
'listener_id': listener['id'],
|
|
||||||
'pool_id': pool['id']})
|
|
||||||
return pp_data['id'], None
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
|
||||||
def _remove_persistence(self, vs_data):
|
|
||||||
pp_client = self.core_plugin.nsxlib.load_balancer.persistence_profile
|
|
||||||
persistence_profile_id = vs_data.get('persistence_profile_id')
|
|
||||||
if persistence_profile_id:
|
|
||||||
pp_client.delete(persistence_profile_id)
|
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
@log_helpers.log_method_call
|
||||||
def _process_vs_update(self, context, pool, listener,
|
def _process_vs_update(self, context, pool, listener,
|
||||||
nsx_pool_id, nsx_vs_id, completor):
|
nsx_pool_id, nsx_vs_id, completor):
|
||||||
@ -150,12 +59,15 @@ class EdgePoolManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
vs_data = vs_client.get(nsx_vs_id)
|
vs_data = vs_client.get(nsx_vs_id)
|
||||||
if nsx_pool_id:
|
if nsx_pool_id:
|
||||||
(persistence_profile_id,
|
(persistence_profile_id,
|
||||||
post_process_func) = self._setup_session_persistence(
|
post_process_func) = lb_utils.setup_session_persistence(
|
||||||
|
self.core_plugin.nsxlib,
|
||||||
pool, self._get_pool_tags(context, pool),
|
pool, self._get_pool_tags(context, pool),
|
||||||
listener, vs_data)
|
listener, vs_data)
|
||||||
else:
|
else:
|
||||||
post_process_func = functools.partial(
|
post_process_func = functools.partial(
|
||||||
self._remove_persistence, vs_data)
|
lb_utils.delete_persistence_profile,
|
||||||
|
self.core_plugin.nsxlib,
|
||||||
|
vs_data.get('persistence_profile_id'))
|
||||||
persistence_profile_id = None
|
persistence_profile_id = None
|
||||||
except nsxlib_exc.ManagerError:
|
except nsxlib_exc.ManagerError:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
@ -181,9 +93,7 @@ class EdgePoolManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
|
|
||||||
@log_helpers.log_method_call
|
@log_helpers.log_method_call
|
||||||
def _get_pool_tags(self, context, pool):
|
def _get_pool_tags(self, context, pool):
|
||||||
return lb_utils.get_tags(self.core_plugin, pool['id'],
|
return lb_utils.get_pool_tags(context, self.core_plugin, pool)
|
||||||
lb_const.LB_POOL_TYPE, pool['tenant_id'],
|
|
||||||
context.project_name)
|
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
@log_helpers.log_method_call
|
||||||
def create(self, context, pool, completor):
|
def create(self, context, pool, completor):
|
||||||
|
@ -242,6 +242,7 @@ class BaseTestEdgeLbaasV2(base.BaseTestCase):
|
|||||||
'persistence_profile').start()
|
'persistence_profile').start()
|
||||||
self.tm_client = mock.patch.object(nsxlib,
|
self.tm_client = mock.patch.object(nsxlib,
|
||||||
'trust_management').start()
|
'trust_management').start()
|
||||||
|
self.nsxlib = nsxlib
|
||||||
|
|
||||||
def _unpatch_lb_plugin(self, lb_plugin, manager):
|
def _unpatch_lb_plugin(self, lb_plugin, manager):
|
||||||
setattr(lb_plugin, manager, self.real_manager)
|
setattr(lb_plugin, manager, self.real_manager)
|
||||||
@ -298,7 +299,8 @@ class TestEdgeLbaasV2Loadbalancer(BaseTestEdgeLbaasV2):
|
|||||||
return_value=LB_ROUTER_ID),\
|
return_value=LB_ROUTER_ID),\
|
||||||
mock.patch.object(self.service_client, 'get_router_lb_service',
|
mock.patch.object(self.service_client, 'get_router_lb_service',
|
||||||
return_value={'id': LB_SERVICE_ID}),\
|
return_value={'id': LB_SERVICE_ID}),\
|
||||||
mock.patch.object(self.service_client, 'create') as create_service,\
|
mock.patch.object(self.service_client,
|
||||||
|
'create') as create_service,\
|
||||||
mock.patch.object(nsx_db, 'add_nsx_lbaas_loadbalancer_binding'
|
mock.patch.object(nsx_db, 'add_nsx_lbaas_loadbalancer_binding'
|
||||||
) as add_binding:
|
) as add_binding:
|
||||||
mock_validate_lb_subnet.return_value = True
|
mock_validate_lb_subnet.return_value = True
|
||||||
@ -518,6 +520,7 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
|||||||
) as mock_add_virtual_server, \
|
) as mock_add_virtual_server, \
|
||||||
mock.patch.object(nsx_db, 'add_nsx_lbaas_listener_binding'
|
mock.patch.object(nsx_db, 'add_nsx_lbaas_listener_binding'
|
||||||
) as mock_add_listener_binding,\
|
) as mock_add_listener_binding,\
|
||||||
|
mock.patch.object(nsx_db, 'update_nsx_lbaas_pool_binding'),\
|
||||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||||
) as mock_get_pool_binding:
|
) as mock_get_pool_binding:
|
||||||
mock_get_floatingips.return_value = []
|
mock_get_floatingips.return_value = []
|
||||||
@ -559,6 +562,71 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
|||||||
self.edge_driver.listener.create,
|
self.edge_driver.listener.create,
|
||||||
self.context, listener)
|
self.context, listener)
|
||||||
|
|
||||||
|
def test_create_listener_with_session_persistence(self):
|
||||||
|
listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||||
|
'listener1', 'Dummy',
|
||||||
|
self.pool_persistency.id,
|
||||||
|
LB_ID, 'HTTP', protocol_port=80,
|
||||||
|
loadbalancer=self.lb,
|
||||||
|
default_pool=self.pool_persistency)
|
||||||
|
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, 'update_nsx_lbaas_pool_binding'),\
|
||||||
|
mock.patch.object(self.pp_client, 'create'
|
||||||
|
) as mock_create_pp, \
|
||||||
|
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_create_pp.assert_called_once()
|
||||||
|
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_session_persistence_fail(self):
|
||||||
|
listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||||
|
'listener1', 'Dummy',
|
||||||
|
self.pool_persistency.id,
|
||||||
|
LB_ID, 'TCP', protocol_port=80,
|
||||||
|
loadbalancer=self.lb,
|
||||||
|
default_pool=self.pool_persistency)
|
||||||
|
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 = None
|
||||||
|
|
||||||
|
self.assertRaises(n_exc.BadRequest,
|
||||||
|
self.edge_driver.listener.create,
|
||||||
|
self.context, listener)
|
||||||
|
|
||||||
def test_update(self):
|
def test_update(self):
|
||||||
new_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
new_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||||
'listener1-new', 'new-description',
|
'listener1-new', 'new-description',
|
||||||
@ -606,6 +674,76 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
|||||||
new_listener,
|
new_listener,
|
||||||
delete=False)
|
delete=False)
|
||||||
|
|
||||||
|
def test_update_with_session_persistence(self):
|
||||||
|
new_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||||
|
'listener1-new', 'new-description',
|
||||||
|
self.pool_persistency.id,
|
||||||
|
LB_ID, protocol='HTTP',
|
||||||
|
protocol_port=80,
|
||||||
|
loadbalancer=self.lb,
|
||||||
|
default_pool=self.pool_persistency)
|
||||||
|
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(self.vs_client, 'update',
|
||||||
|
return_value={'id': LB_VS_ID}), \
|
||||||
|
mock.patch.object(self.pp_client, 'create'
|
||||||
|
) as mock_create_pp, \
|
||||||
|
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_create_pp.assert_called_once()
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.listener.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
new_listener,
|
||||||
|
delete=False)
|
||||||
|
|
||||||
|
def test_update_with_session_persistence_fail(self):
|
||||||
|
old_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||||
|
'listener1', 'description',
|
||||||
|
self.pool_persistency.id,
|
||||||
|
LB_ID, protocol='HTTP',
|
||||||
|
protocol_port=80,
|
||||||
|
loadbalancer=self.lb,
|
||||||
|
default_pool=self.pool_persistency)
|
||||||
|
sess_persistence = lb_models.SessionPersistence(
|
||||||
|
POOL_ID, 'SOURCE_IP')
|
||||||
|
pool_persistency = lb_models.Pool(POOL_ID, LB_TENANT_ID,
|
||||||
|
'pool1', '', None, 'HTTP',
|
||||||
|
'ROUND_ROBIN', loadbalancer_id=LB_ID,
|
||||||
|
listener=self.listener,
|
||||||
|
listeners=[self.listener],
|
||||||
|
loadbalancer=self.lb,
|
||||||
|
session_persistence=sess_persistence)
|
||||||
|
new_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||||
|
'listener1-new', 'new-description',
|
||||||
|
pool_persistency.id,
|
||||||
|
LB_ID, protocol='HTTP',
|
||||||
|
protocol_port=80,
|
||||||
|
loadbalancer=self.lb,
|
||||||
|
default_pool=pool_persistency)
|
||||||
|
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_get_floatingips.return_value = []
|
||||||
|
mock_get_listener_binding.return_value = LISTENER_BINDING
|
||||||
|
mock_get_pool_binding.return_value = POOL_BINDING
|
||||||
|
|
||||||
|
self.assertRaises(n_exc.BadRequest,
|
||||||
|
self.edge_driver.listener.update,
|
||||||
|
self.context, old_listener, new_listener)
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_listener_binding'
|
with mock.patch.object(nsx_db, 'get_nsx_lbaas_listener_binding'
|
||||||
) as mock_get_listener_binding, \
|
) as mock_get_listener_binding, \
|
||||||
@ -1003,16 +1141,14 @@ class TestEdgeLbaasV2Pool(BaseTestEdgeLbaasV2):
|
|||||||
self.pool.session_persistence = session_persistence
|
self.pool.session_persistence = session_persistence
|
||||||
pool_dict = self.edge_driver.pool.translator(self.pool)
|
pool_dict = self.edge_driver.pool.translator(self.pool)
|
||||||
list_dict = self.edge_driver.listener.translator(self.listener)
|
list_dict = self.edge_driver.listener.translator(self.listener)
|
||||||
pool_impl = self.edge_driver.pool.implementor # make pep8 happy
|
pp_id, post_func = lb_utils.setup_session_persistence(
|
||||||
pp_id, post_func = pool_impl._setup_session_persistence(
|
self.nsxlib, pool_dict, [], list_dict, vs_data)
|
||||||
pool_dict, [], list_dict, vs_data)
|
|
||||||
|
|
||||||
if session_persistence:
|
if session_persistence:
|
||||||
self.assertEqual(LB_PP_ID, pp_id)
|
self.assertEqual(LB_PP_ID, pp_id)
|
||||||
else:
|
else:
|
||||||
self.assertIsNone(pp_id)
|
self.assertIsNone(pp_id)
|
||||||
self.assertEqual(({'id': LB_VS_ID,
|
self.assertEqual((self.nsxlib, LB_PP_ID,),
|
||||||
'persistence_profile_id': LB_PP_ID},),
|
|
||||||
post_func.args)
|
post_func.args)
|
||||||
verify_func(res_type, cookie_name, cookie_mode,
|
verify_func(res_type, cookie_name, cookie_mode,
|
||||||
mock_create_pp, mock_update_pp)
|
mock_create_pp, mock_update_pp)
|
||||||
|
Loading…
Reference in New Issue
Block a user