Add support for multiple L4 protocols withing same LB
This change introduces a way of providing multiple listeners and pools on the same Load Balancer, but with different L4 protocols. In case there are more than one unique protocol defined in Octavia pools or Octavia listeners the OVN driver now adds another Load_Balancer row per protocol, but with the same name. The selection of which OVN Load_Balancer should be used is done by a protocol key. This change also adds possibility to expose two listeners on the same port, but with different L4 protocol. The common use-case is providing a DNS service that listens both on UDP and TCP sockets. Partial-Bug: #1789157 Change-Id: I2ee13b75713e7538d1b4f70207a90a95315eb914
This commit is contained in:
parent
ec629c2e0c
commit
15260b7439
@ -237,6 +237,12 @@ class OvnProviderHelper(object):
|
|||||||
REQ_TYPE_HANDLE_VIP_FIP: self.handle_vip_fip,
|
REQ_TYPE_HANDLE_VIP_FIP: self.handle_vip_fip,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _is_lb_empty(external_ids):
|
||||||
|
"""Check if there is no pool or listener defined."""
|
||||||
|
return not any([k.startswith('listener') or k.startswith('pool')
|
||||||
|
for k in external_ids])
|
||||||
|
|
||||||
def _check_and_set_ssl_files(self):
|
def _check_and_set_ssl_files(self):
|
||||||
# TODO(reedip): Make ovsdb_monitor's _check_and_set_ssl_files() public
|
# TODO(reedip): Make ovsdb_monitor's _check_and_set_ssl_files() public
|
||||||
# This is a copy of ovsdb_monitor._check_and_set_ssl_files
|
# This is a copy of ovsdb_monitor._check_and_set_ssl_files
|
||||||
@ -304,6 +310,25 @@ class OvnProviderHelper(object):
|
|||||||
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY))
|
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY))
|
||||||
return router, network
|
return router, network
|
||||||
|
|
||||||
|
def _clean_lb_if_empty(self, ovn_lb, lb_id, external_ids):
|
||||||
|
commands = []
|
||||||
|
if OvnProviderHelper._is_lb_empty(external_ids):
|
||||||
|
# Verify if its only OVN LB defined. If so - leave with
|
||||||
|
# undefined protocol. If there is different for other protocol
|
||||||
|
# remove this one.
|
||||||
|
try:
|
||||||
|
defined_ovn_lbs = self._find_ovn_lbs(lb_id)
|
||||||
|
except idlutils.RowNotFound:
|
||||||
|
defined_ovn_lbs = []
|
||||||
|
if len(defined_ovn_lbs) == 1:
|
||||||
|
commands.append(
|
||||||
|
self.ovn_nbdb_api.db_set(
|
||||||
|
'Load_Balancer', ovn_lb.uuid, ('protocol', [])))
|
||||||
|
else:
|
||||||
|
# Delete the lb.
|
||||||
|
commands.append(self.ovn_nbdb_api.lb_del(ovn_lb.uuid))
|
||||||
|
return commands
|
||||||
|
|
||||||
def lb_delete_lrp_assoc_handler(self, row):
|
def lb_delete_lrp_assoc_handler(self, row):
|
||||||
try:
|
try:
|
||||||
router, network = self._get_nw_router_info_on_interface_event(row)
|
router, network = self._get_nw_router_info_on_interface_event(row)
|
||||||
@ -382,25 +407,26 @@ class OvnProviderHelper(object):
|
|||||||
port_name = vip_lp.external_ids.get(ovn_const.OVN_PORT_NAME_EXT_ID_KEY)
|
port_name = vip_lp.external_ids.get(ovn_const.OVN_PORT_NAME_EXT_ID_KEY)
|
||||||
lb_id = port_name[len(ovn_const.LB_VIP_PORT_PREFIX):]
|
lb_id = port_name[len(ovn_const.LB_VIP_PORT_PREFIX):]
|
||||||
try:
|
try:
|
||||||
ovn_lb = self._find_ovn_lb(lb_id)
|
ovn_lbs = self._find_ovn_lbs(lb_id)
|
||||||
except idlutils.RowNotFound:
|
except idlutils.RowNotFound:
|
||||||
LOG.debug("Loadbalancer %s not found!", lb_id)
|
LOG.debug("Loadbalancer %s not found!", lb_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
fip = vip_lp.external_ids.get(ovn_const.OVN_PORT_FIP_EXT_ID_KEY)
|
# Loop over all defined LBs with given ID, because it is possible
|
||||||
lb_vip_fip = ovn_lb.external_ids.get(LB_EXT_IDS_VIP_FIP_KEY)
|
# than there is more than one (for more than 1 L4 protocol).
|
||||||
request_info = {'lb_id': lb_id,
|
for lb in ovn_lbs:
|
||||||
'vip_fip': fip}
|
fip = vip_lp.external_ids.get(ovn_const.OVN_PORT_FIP_EXT_ID_KEY)
|
||||||
|
lb_vip_fip = lb.external_ids.get(LB_EXT_IDS_VIP_FIP_KEY)
|
||||||
if fip and fip != lb_vip_fip:
|
request_info = {'ovn_lb': lb,
|
||||||
request_info['action'] = REQ_INFO_ACTION_ASSOCIATE
|
'vip_fip': fip}
|
||||||
elif fip is None and fip != lb_vip_fip:
|
if fip and fip != lb_vip_fip:
|
||||||
request_info['action'] = REQ_INFO_ACTION_DISASSOCIATE
|
request_info['action'] = REQ_INFO_ACTION_ASSOCIATE
|
||||||
else:
|
elif fip is None and fip != lb_vip_fip:
|
||||||
return
|
request_info['action'] = REQ_INFO_ACTION_DISASSOCIATE
|
||||||
|
else:
|
||||||
self.add_request({'type': REQ_TYPE_HANDLE_VIP_FIP,
|
continue
|
||||||
'info': request_info})
|
self.add_request({'type': REQ_TYPE_HANDLE_VIP_FIP,
|
||||||
|
'info': request_info})
|
||||||
|
|
||||||
def _find_lb_in_ls(self, network):
|
def _find_lb_in_ls(self, network):
|
||||||
"""Find LB associated to a Network using Network information
|
"""Find LB associated to a Network using Network information
|
||||||
@ -454,18 +480,94 @@ class OvnProviderHelper(object):
|
|||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise driver_exceptions.UpdateStatusError(msg)
|
raise driver_exceptions.UpdateStatusError(msg)
|
||||||
|
|
||||||
def _find_ovn_lb(self, lb_id):
|
def _find_ovn_lbs(self, lb_id, protocol=None):
|
||||||
"""Find the Loadbalancer in OVN with the given lb_id as its name
|
"""Find the Loadbalancers in OVN with the given lb_id as its name
|
||||||
|
|
||||||
This function searches for the LoadBalancer whose Name has the pattern
|
This function searches for the LoadBalancers whose Name has the pattern
|
||||||
passed in lb_id.
|
passed in lb_id.
|
||||||
Input: String format of LoadBalancer ID provided by Octavia in its API
|
@param lb_id: LoadBalancer ID provided by Octavia in its API
|
||||||
request. Note that OVN saves the above ID in the 'name' column.
|
request. Note that OVN saves the above ID in the 'name' column.
|
||||||
Output: LoadBalancer row matching the lb_id
|
@type lb_id: str
|
||||||
Exception: RowNotFound can be generated if the LoadBalancer is not
|
@param protocol: Loadbalancer protocol.
|
||||||
found.
|
@type protocol: str or None if not defined.
|
||||||
|
|
||||||
|
:returns: LoadBalancer row if protocol specified
|
||||||
|
or list of rows matching the lb_id.
|
||||||
|
:raises: RowNotFound can be generated if the LoadBalancer is not
|
||||||
|
found.
|
||||||
"""
|
"""
|
||||||
return self.ovn_nbdb_api.lookup('Load_Balancer', lb_id)
|
lbs = self.ovn_nbdb_api.db_find_rows(
|
||||||
|
'Load_Balancer', ('name', '=', lb_id)).execute()
|
||||||
|
if not protocol:
|
||||||
|
if lbs:
|
||||||
|
return lbs
|
||||||
|
raise idlutils.RowNotFound(table='Load_Balancer',
|
||||||
|
col='name', match=lb_id)
|
||||||
|
# If there is only one LB without protocol defined, so
|
||||||
|
# it is 'clean' LB record without any listener.
|
||||||
|
if len(lbs) == 1 and not lbs[0].protocol:
|
||||||
|
return lbs[0]
|
||||||
|
# Search for other lbs.
|
||||||
|
for lb in lbs:
|
||||||
|
if lb.protocol[0].upper() == protocol.upper():
|
||||||
|
return lb
|
||||||
|
raise idlutils.RowNotFound(table='Load_Balancer',
|
||||||
|
col='name', match=lb_id)
|
||||||
|
|
||||||
|
def _get_or_create_ovn_lb(self, lb_id, protocol, admin_state_up):
|
||||||
|
"""Find or create ovn lb with given protocol
|
||||||
|
|
||||||
|
Find the loadbalancer configured with given protocol or
|
||||||
|
create required if not found
|
||||||
|
"""
|
||||||
|
# Make sure that its lowercase - OVN NBDB stores lowercases
|
||||||
|
# for this field.
|
||||||
|
protocol = protocol.lower()
|
||||||
|
ovn_lbs = self._find_ovn_lbs(lb_id)
|
||||||
|
lbs_with_required_protocol = [
|
||||||
|
ovn_lb for ovn_lb in ovn_lbs
|
||||||
|
if protocol in ovn_lb.protocol]
|
||||||
|
lbs_with_no_protocol = [ovn_lb for ovn_lb in ovn_lbs
|
||||||
|
if not ovn_lb.protocol]
|
||||||
|
if lbs_with_required_protocol:
|
||||||
|
# We found existing LB with required
|
||||||
|
# protocol, just return it.
|
||||||
|
return lbs_with_required_protocol[0]
|
||||||
|
elif lbs_with_no_protocol:
|
||||||
|
ovn_lb = lbs_with_no_protocol[0]
|
||||||
|
# Set required protocol here.
|
||||||
|
self.ovn_nbdb_api.db_set(
|
||||||
|
'Load_Balancer', ovn_lb.uuid,
|
||||||
|
('protocol', protocol)).execute(check_error=True)
|
||||||
|
else:
|
||||||
|
# NOTE(mjozefcz): Looks like loadbalancer with given protocol
|
||||||
|
# doesn't exist. Try to add it with required protocol
|
||||||
|
# by copy the existing one data.
|
||||||
|
lb_info = {
|
||||||
|
'id': lb_id,
|
||||||
|
'protocol': protocol,
|
||||||
|
'vip_address': ovn_lbs[0].external_ids.get(
|
||||||
|
LB_EXT_IDS_VIP_KEY),
|
||||||
|
'vip_port_id':
|
||||||
|
ovn_lbs[0].external_ids.get(
|
||||||
|
LB_EXT_IDS_VIP_PORT_ID_KEY),
|
||||||
|
LB_EXT_IDS_LR_REF_KEY:
|
||||||
|
ovn_lbs[0].external_ids.get(
|
||||||
|
LB_EXT_IDS_LR_REF_KEY),
|
||||||
|
LB_EXT_IDS_LS_REFS_KEY:
|
||||||
|
ovn_lbs[0].external_ids.get(
|
||||||
|
LB_EXT_IDS_LS_REFS_KEY),
|
||||||
|
'admin_state_up': admin_state_up}
|
||||||
|
# NOTE(mjozefcz): Handle vip_fip info if exists.
|
||||||
|
vip_fip = ovn_lbs[0].external_ids.get(LB_EXT_IDS_VIP_FIP_KEY)
|
||||||
|
if vip_fip:
|
||||||
|
lb_info.update({LB_EXT_IDS_VIP_FIP_KEY: vip_fip})
|
||||||
|
self.lb_create(lb_info, protocol=protocol)
|
||||||
|
# Looks like we've just added new LB
|
||||||
|
# or updated exising, empty one.
|
||||||
|
return self._find_ovn_lbs(
|
||||||
|
lb_id,
|
||||||
|
protocol=protocol)
|
||||||
|
|
||||||
def _find_ovn_lb_with_pool_key(self, pool_key):
|
def _find_ovn_lb_with_pool_key(self, pool_key):
|
||||||
lbs = self.ovn_nbdb_api.db_list_rows(
|
lbs = self.ovn_nbdb_api.db_list_rows(
|
||||||
@ -474,7 +576,7 @@ class OvnProviderHelper(object):
|
|||||||
if pool_key in lb.external_ids:
|
if pool_key in lb.external_ids:
|
||||||
return lb
|
return lb
|
||||||
|
|
||||||
def _find_ovn_lb_by_id(self, pool_id):
|
def _find_ovn_lb_by_pool_id(self, pool_id):
|
||||||
pool_key = self._get_pool_key(pool_id)
|
pool_key = self._get_pool_key(pool_id)
|
||||||
ovn_lb = self._find_ovn_lb_with_pool_key(pool_key)
|
ovn_lb = self._find_ovn_lb_with_pool_key(pool_key)
|
||||||
if not ovn_lb:
|
if not ovn_lb:
|
||||||
@ -591,13 +693,13 @@ class OvnProviderHelper(object):
|
|||||||
commands.append(self.ovn_nbdb_api.ls_lb_add(
|
commands.append(self.ovn_nbdb_api.ls_lb_add(
|
||||||
net, ovn_lb.uuid, may_exist=True))
|
net, ovn_lb.uuid, may_exist=True))
|
||||||
|
|
||||||
# Multiple routers in lr_rf are separated with ','
|
if ovn_lr.name not in str(lr_rf):
|
||||||
lr_rf = {LB_EXT_IDS_LR_REF_KEY: ovn_lr.name} if not lr_rf else {
|
# Multiple routers in lr_rf are separated with ','
|
||||||
LB_EXT_IDS_LR_REF_KEY: "%s,%s" % (lr_rf, ovn_lr.name)}
|
lr_rf = {LB_EXT_IDS_LR_REF_KEY: ovn_lr.name} if not lr_rf else {
|
||||||
commands.append(
|
LB_EXT_IDS_LR_REF_KEY: "%s,%s" % (lr_rf, ovn_lr.name)}
|
||||||
self.ovn_nbdb_api.db_set('Load_Balancer', ovn_lb.uuid,
|
commands.append(
|
||||||
('external_ids', lr_rf))
|
self.ovn_nbdb_api.db_set('Load_Balancer', ovn_lb.uuid,
|
||||||
)
|
('external_ids', lr_rf)))
|
||||||
return commands
|
return commands
|
||||||
|
|
||||||
def _update_lb_to_lr_association(self, ovn_lb, ovn_lr, delete=False):
|
def _update_lb_to_lr_association(self, ovn_lb, ovn_lr, delete=False):
|
||||||
@ -738,7 +840,7 @@ class OvnProviderHelper(object):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def check_lb_protocol(self, lb_id, listener_protocol):
|
def check_lb_protocol(self, lb_id, listener_protocol):
|
||||||
ovn_lb = self._find_ovn_lb(lb_id)
|
ovn_lb = self._find_ovn_lbs(lb_id, protocol=listener_protocol)
|
||||||
if not ovn_lb:
|
if not ovn_lb:
|
||||||
return False
|
return False
|
||||||
elif not self._is_listener_in_lb(ovn_lb):
|
elif not self._is_listener_in_lb(ovn_lb):
|
||||||
@ -746,13 +848,15 @@ class OvnProviderHelper(object):
|
|||||||
else:
|
else:
|
||||||
return str(listener_protocol).lower() in ovn_lb.protocol
|
return str(listener_protocol).lower() in ovn_lb.protocol
|
||||||
|
|
||||||
def lb_create(self, loadbalancer):
|
def lb_create(self, loadbalancer, protocol=None):
|
||||||
port = None
|
port = None
|
||||||
try:
|
network_driver = get_network_driver()
|
||||||
# Get the port id of the vip and store it in the external_ids.
|
if loadbalancer.get('vip_port_id'):
|
||||||
# This is required to delete the port when the loadbalancer is
|
# In case we don't have vip_network_id
|
||||||
# deleted.
|
port = network_driver.neutron_client.show_port(
|
||||||
network_driver = get_network_driver()
|
loadbalancer['vip_port_id'])['port']
|
||||||
|
elif (loadbalancer.get('vip_network_id') and
|
||||||
|
loadbalancer.get('vip_address')):
|
||||||
ports = network_driver.neutron_client.list_ports(
|
ports = network_driver.neutron_client.list_ports(
|
||||||
network_id=loadbalancer['vip_network_id'])
|
network_id=loadbalancer['vip_network_id'])
|
||||||
for p in ports['ports']:
|
for p in ports['ports']:
|
||||||
@ -760,25 +864,63 @@ class OvnProviderHelper(object):
|
|||||||
if ip['ip_address'] == loadbalancer['vip_address']:
|
if ip['ip_address'] == loadbalancer['vip_address']:
|
||||||
port = p
|
port = p
|
||||||
break
|
break
|
||||||
# In case port is not found for the vip_address we will see an
|
|
||||||
# exception when port['id'] is accessed.
|
# If protocol set make sure its lowercase
|
||||||
|
protocol = protocol.lower() if protocol else None
|
||||||
|
# In case port is not found for the vip_address we will see an
|
||||||
|
# exception when port['id'] is accessed.
|
||||||
|
external_ids = {
|
||||||
|
LB_EXT_IDS_VIP_KEY: loadbalancer['vip_address'],
|
||||||
|
LB_EXT_IDS_VIP_PORT_ID_KEY:
|
||||||
|
loadbalancer.get('vip_port_id') or port['id'],
|
||||||
|
'enabled': str(loadbalancer['admin_state_up'])}
|
||||||
|
# In case vip_fip was passed - use it.
|
||||||
|
vip_fip = loadbalancer.get(LB_EXT_IDS_VIP_FIP_KEY)
|
||||||
|
if vip_fip:
|
||||||
|
external_ids[LB_EXT_IDS_VIP_FIP_KEY] = vip_fip
|
||||||
|
# In case of lr_ref passed - use it.
|
||||||
|
lr_ref = loadbalancer.get(LB_EXT_IDS_LR_REF_KEY)
|
||||||
|
if lr_ref:
|
||||||
|
external_ids[LB_EXT_IDS_LR_REF_KEY] = lr_ref
|
||||||
|
|
||||||
|
try:
|
||||||
self.ovn_nbdb_api.db_create(
|
self.ovn_nbdb_api.db_create(
|
||||||
'Load_Balancer', name=loadbalancer['id'], protocol='tcp',
|
'Load_Balancer', name=loadbalancer['id'],
|
||||||
external_ids={LB_EXT_IDS_VIP_KEY: loadbalancer['vip_address'],
|
protocol=protocol,
|
||||||
LB_EXT_IDS_VIP_PORT_ID_KEY: port['id'],
|
external_ids=external_ids).execute(check_error=True)
|
||||||
'enabled': str(loadbalancer['admin_state_up'])}
|
ovn_lb = self._find_ovn_lbs(
|
||||||
).execute(check_error=True)
|
loadbalancer['id'],
|
||||||
ovn_lb = self._find_ovn_lb(loadbalancer['id'])
|
protocol=protocol)
|
||||||
|
ovn_lb = ovn_lb if protocol else ovn_lb[0]
|
||||||
commands = self._update_lb_to_ls_association(
|
commands = self._update_lb_to_ls_association(
|
||||||
ovn_lb, network_id=loadbalancer['vip_network_id'],
|
ovn_lb, network_id=port['network_id'],
|
||||||
associate=True)
|
associate=True)
|
||||||
ls_name = utils.ovn_name(loadbalancer['vip_network_id'])
|
ls_name = utils.ovn_name(port['network_id'])
|
||||||
ovn_ls = self.ovn_nbdb_api.ls_get(ls_name).execute(
|
ovn_ls = self.ovn_nbdb_api.ls_get(ls_name).execute(
|
||||||
check_error=True)
|
check_error=True)
|
||||||
ovn_lr = self._find_lr_of_ls(ovn_ls)
|
ovn_lr = self._find_lr_of_ls(ovn_ls)
|
||||||
if ovn_lr:
|
if ovn_lr:
|
||||||
commands.extend(self._update_lb_to_lr_association(
|
commands.extend(self._update_lb_to_lr_association(
|
||||||
ovn_lb, ovn_lr))
|
ovn_lb, ovn_lr))
|
||||||
|
|
||||||
|
# NOTE(mjozefcz): In case of LS references where passed -
|
||||||
|
# apply LS to the new LB. That could happend in case we
|
||||||
|
# need another loadbalancer for other L4 protocol.
|
||||||
|
ls_refs = loadbalancer.get(LB_EXT_IDS_LS_REFS_KEY)
|
||||||
|
if ls_refs:
|
||||||
|
try:
|
||||||
|
ls_refs = jsonutils.loads(ls_refs)
|
||||||
|
except ValueError:
|
||||||
|
ls_refs = {}
|
||||||
|
for ls in ls_refs:
|
||||||
|
# Skip previously added LS because we don't want
|
||||||
|
# to duplicate.
|
||||||
|
if ls == ovn_ls.name:
|
||||||
|
continue
|
||||||
|
commands.extend(self._update_lb_to_ls_association(
|
||||||
|
ovn_lb, network_id=ls.replace('neutron-', ''),
|
||||||
|
associate=True))
|
||||||
|
|
||||||
self._execute_commands(commands)
|
self._execute_commands(commands)
|
||||||
operating_status = constants.ONLINE
|
operating_status = constants.ONLINE
|
||||||
# The issue is that since OVN doesnt support any HMs,
|
# The issue is that since OVN doesnt support any HMs,
|
||||||
@ -809,101 +951,104 @@ class OvnProviderHelper(object):
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
def lb_delete(self, loadbalancer):
|
def lb_delete(self, loadbalancer):
|
||||||
commands = []
|
|
||||||
port_id = None
|
port_id = None
|
||||||
|
status = {'loadbalancers': [{"id": loadbalancer['id'],
|
||||||
|
"provisioning_status": "DELETED",
|
||||||
|
"operating_status": "OFFLINE"}],
|
||||||
|
'listeners': [],
|
||||||
|
'pools': [],
|
||||||
|
'members': []}
|
||||||
|
|
||||||
|
ovn_lbs = None
|
||||||
try:
|
try:
|
||||||
status = {'loadbalancers': [{"id": loadbalancer['id'],
|
ovn_lbs = self._find_ovn_lbs(loadbalancer['id'])
|
||||||
"provisioning_status": "DELETED",
|
except idlutils.RowNotFound:
|
||||||
"operating_status": "OFFLINE"}]}
|
LOG.warning("Loadbalancer %s not found in OVN Northbound DB. "
|
||||||
ovn_lb = None
|
"Setting the Loadbalancer status to DELETED "
|
||||||
try:
|
"in Octavia", str(loadbalancer['id']))
|
||||||
ovn_lb = self._find_ovn_lb(loadbalancer['id'])
|
return status
|
||||||
except idlutils.RowNotFound:
|
|
||||||
LOG.warning("Loadbalancer %s not found in OVN Northbound DB."
|
|
||||||
"Setting the Loadbalancer status to DELETED "
|
|
||||||
"in Octavia", str(loadbalancer['id']))
|
|
||||||
return status
|
|
||||||
if not ovn_lb:
|
|
||||||
return status
|
|
||||||
|
|
||||||
if loadbalancer['cascade']:
|
try:
|
||||||
status['members'] = []
|
port_id = ovn_lbs[0].external_ids[LB_EXT_IDS_VIP_PORT_ID_KEY]
|
||||||
status['pools'] = []
|
for ovn_lb in ovn_lbs:
|
||||||
status['listeners'] = []
|
status = self._lb_delete(loadbalancer, ovn_lb, status)
|
||||||
# Delete all pools
|
# Clear the status dict of any key having [] value
|
||||||
for key, value in ovn_lb.external_ids.items():
|
# Python 3.6 doesnt allow deleting an element in a
|
||||||
if key.startswith(LB_EXT_IDS_POOL_PREFIX):
|
# dict while iterating over it. So first get a list of keys.
|
||||||
pool_id = key.split('_')[1]
|
# https://cito.github.io/blog/never-iterate-a-changing-dict/
|
||||||
# Delete all members in the pool
|
status = {key: value for key, value in status.items() if value}
|
||||||
if value and len(value.split(',')) > 0:
|
|
||||||
for mem_info in value.split(','):
|
|
||||||
status['members'].append({
|
|
||||||
'id': mem_info.split('_')[1],
|
|
||||||
'provisioning_status': constants.DELETED})
|
|
||||||
status['pools'].append(
|
|
||||||
{"id": pool_id,
|
|
||||||
"provisioning_status": constants.DELETED})
|
|
||||||
|
|
||||||
if key.startswith(LB_EXT_IDS_LISTENER_PREFIX):
|
|
||||||
status['listeners'].append({
|
|
||||||
'id': key.split('_')[1],
|
|
||||||
'provisioning_status': constants.DELETED,
|
|
||||||
'operating_status': constants.OFFLINE})
|
|
||||||
# Clear the status dict of any key having [] value
|
|
||||||
# Python 3.6 doesnt allow deleting an element in a
|
|
||||||
# dict while iterating over it. So first get a list of keys.
|
|
||||||
# https://cito.github.io/blog/never-iterate-a-changing-dict/
|
|
||||||
status = {key: value for key, value in status.items() if value}
|
|
||||||
ls_refs = ovn_lb.external_ids.get(LB_EXT_IDS_LS_REFS_KEY, {})
|
|
||||||
if ls_refs:
|
|
||||||
try:
|
|
||||||
ls_refs = jsonutils.loads(ls_refs)
|
|
||||||
except ValueError:
|
|
||||||
ls_refs = {}
|
|
||||||
# Delete the VIP Port
|
|
||||||
self.delete_vip_port(ovn_lb.external_ids[
|
|
||||||
LB_EXT_IDS_VIP_PORT_ID_KEY])
|
|
||||||
for ls_name in ls_refs.keys():
|
|
||||||
ovn_ls = self.ovn_nbdb_api.ls_get(ls_name).execute(
|
|
||||||
check_error=True)
|
|
||||||
if ovn_ls:
|
|
||||||
commands.append(
|
|
||||||
self.ovn_nbdb_api.ls_lb_del(ovn_ls.uuid, ovn_lb.uuid))
|
|
||||||
# Delete LB from all Networks the LB is indirectly associated
|
|
||||||
for ls in self._find_lb_in_table(ovn_lb, 'Logical_Switch'):
|
|
||||||
commands.append(
|
|
||||||
self.ovn_nbdb_api.ls_lb_del(ls.uuid, ovn_lb.uuid,
|
|
||||||
if_exists=True))
|
|
||||||
lr_ref = ovn_lb.external_ids.get(LB_EXT_IDS_LR_REF_KEY, {})
|
|
||||||
if lr_ref:
|
|
||||||
for lr in self.ovn_nbdb_api.tables[
|
|
||||||
'Logical_Router'].rows.values():
|
|
||||||
if lr.name == lr_ref:
|
|
||||||
commands.append(self.ovn_nbdb_api.lr_lb_del(
|
|
||||||
lr.uuid, ovn_lb.uuid))
|
|
||||||
break
|
|
||||||
# Delete LB from all Routers the LB is indirectly associated
|
|
||||||
for lr in self._find_lb_in_table(ovn_lb, 'Logical_Router'):
|
|
||||||
commands.append(
|
|
||||||
self.ovn_nbdb_api.lr_lb_del(lr.uuid, ovn_lb.uuid,
|
|
||||||
if_exists=True))
|
|
||||||
# Save the port ID before deleting the LoadBalancer
|
|
||||||
port_id = ovn_lb.external_ids[LB_EXT_IDS_VIP_PORT_ID_KEY]
|
|
||||||
commands.append(self.ovn_nbdb_api.lb_del(ovn_lb.uuid))
|
|
||||||
self._execute_commands(commands)
|
|
||||||
# We need to delete the vip port but not fail LB delete if port
|
|
||||||
# delete fails. Can happen when Port deleted manually by user.
|
|
||||||
network_driver = get_network_driver()
|
|
||||||
network_driver.neutron_client.delete_port(port_id)
|
|
||||||
except n_exc.PortNotFoundClient:
|
|
||||||
LOG.warning("Port %s could not be found. Please "
|
|
||||||
"check Neutron logs", port_id)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception(EXCEPTION_MSG, "deletion of loadbalancer")
|
LOG.exception(EXCEPTION_MSG, "deletion of loadbalancer")
|
||||||
status = {
|
status = {
|
||||||
'loadbalancers': [{"id": loadbalancer['id'],
|
'loadbalancers': [{"id": loadbalancer['id'],
|
||||||
"provisioning_status": constants.ERROR,
|
"provisioning_status": constants.ERROR,
|
||||||
"operating_status": constants.ERROR}]}
|
"operating_status": constants.ERROR}]}
|
||||||
|
try:
|
||||||
|
# Delete VIP port from neutron.
|
||||||
|
self.delete_vip_port(port_id)
|
||||||
|
except n_exc.PortNotFoundClient:
|
||||||
|
LOG.warning("Port %s could not be found. Please "
|
||||||
|
"check Neutron logs", port_id)
|
||||||
|
return status
|
||||||
|
|
||||||
|
def _lb_delete(self, loadbalancer, ovn_lb, status):
|
||||||
|
commands = []
|
||||||
|
if loadbalancer['cascade']:
|
||||||
|
# Delete all pools
|
||||||
|
for key, value in ovn_lb.external_ids.items():
|
||||||
|
if key.startswith(LB_EXT_IDS_POOL_PREFIX):
|
||||||
|
pool_id = key.split('_')[1]
|
||||||
|
# Delete all members in the pool
|
||||||
|
if value and len(value.split(',')) > 0:
|
||||||
|
for mem_info in value.split(','):
|
||||||
|
status['members'].append({
|
||||||
|
'id': mem_info.split('_')[1],
|
||||||
|
'provisioning_status': constants.DELETED})
|
||||||
|
status['pools'].append(
|
||||||
|
{"id": pool_id,
|
||||||
|
"provisioning_status": constants.DELETED})
|
||||||
|
|
||||||
|
if key.startswith(LB_EXT_IDS_LISTENER_PREFIX):
|
||||||
|
status['listeners'].append({
|
||||||
|
'id': key.split('_')[1],
|
||||||
|
'provisioning_status': constants.DELETED,
|
||||||
|
'operating_status': constants.OFFLINE})
|
||||||
|
ls_refs = ovn_lb.external_ids.get(LB_EXT_IDS_LS_REFS_KEY, {})
|
||||||
|
if ls_refs:
|
||||||
|
try:
|
||||||
|
ls_refs = jsonutils.loads(ls_refs)
|
||||||
|
except ValueError:
|
||||||
|
ls_refs = {}
|
||||||
|
for ls_name in ls_refs.keys():
|
||||||
|
try:
|
||||||
|
ovn_ls = self.ovn_nbdb_api.ls_get(ls_name).execute(
|
||||||
|
check_error=True)
|
||||||
|
commands.append(
|
||||||
|
self.ovn_nbdb_api.ls_lb_del(ovn_ls.uuid, ovn_lb.uuid)
|
||||||
|
)
|
||||||
|
except idlutils.RowNotFound:
|
||||||
|
LOG.warning("LogicalSwitch %s could not be found. Cannot "
|
||||||
|
"delete LB from it", ovn_ls.uuid)
|
||||||
|
# Delete LB from all Networks the LB is indirectly associated
|
||||||
|
for ls in self._find_lb_in_table(ovn_lb, 'Logical_Switch'):
|
||||||
|
commands.append(
|
||||||
|
self.ovn_nbdb_api.ls_lb_del(ls.uuid, ovn_lb.uuid,
|
||||||
|
if_exists=True))
|
||||||
|
lr_ref = ovn_lb.external_ids.get(LB_EXT_IDS_LR_REF_KEY, {})
|
||||||
|
if lr_ref:
|
||||||
|
for lr in self.ovn_nbdb_api.tables[
|
||||||
|
'Logical_Router'].rows.values():
|
||||||
|
if lr.name == lr_ref:
|
||||||
|
commands.append(self.ovn_nbdb_api.lr_lb_del(
|
||||||
|
lr.uuid, ovn_lb.uuid))
|
||||||
|
break
|
||||||
|
# Delete LB from all Routers the LB is indirectly associated
|
||||||
|
for lr in self._find_lb_in_table(ovn_lb, 'Logical_Router'):
|
||||||
|
commands.append(
|
||||||
|
self.ovn_nbdb_api.lr_lb_del(lr.uuid, ovn_lb.uuid,
|
||||||
|
if_exists=True))
|
||||||
|
commands.append(self.ovn_nbdb_api.lb_del(ovn_lb.uuid))
|
||||||
|
self._execute_commands(commands)
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def lb_failover(self, loadbalancer):
|
def lb_failover(self, loadbalancer):
|
||||||
@ -913,30 +1058,36 @@ class OvnProviderHelper(object):
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
def lb_update(self, loadbalancer):
|
def lb_update(self, loadbalancer):
|
||||||
try:
|
lb_status = {'id': loadbalancer['id'],
|
||||||
lb_status = {'id': loadbalancer['id'],
|
'provisioning_status': constants.ACTIVE}
|
||||||
'provisioning_status': constants.ACTIVE}
|
status = {'loadbalancers': [lb_status]}
|
||||||
status = {'loadbalancers': [lb_status]}
|
if 'admin_state_up' not in loadbalancer:
|
||||||
if 'admin_state_up' not in loadbalancer:
|
return status
|
||||||
return status
|
lb_enabled = loadbalancer['admin_state_up']
|
||||||
lb_enabled = loadbalancer['admin_state_up']
|
|
||||||
|
|
||||||
ovn_lb = self._find_ovn_lb(loadbalancer['id'])
|
try:
|
||||||
if ovn_lb.external_ids['enabled'] != str(lb_enabled):
|
ovn_lbs = self._find_ovn_lbs(loadbalancer['id'])
|
||||||
commands = []
|
# It should be unique for all the LBS for all protocols,
|
||||||
enable_info = {'enabled': str(lb_enabled)}
|
# so we could just easly loop over all defined for given
|
||||||
ovn_lb.external_ids['enabled'] = str(lb_enabled)
|
# Octavia LB.
|
||||||
commands.append(
|
for ovn_lb in ovn_lbs:
|
||||||
self.ovn_nbdb_api.db_set('Load_Balancer', ovn_lb.uuid,
|
if str(ovn_lb.external_ids['enabled']) != str(lb_enabled):
|
||||||
('external_ids', enable_info)))
|
commands = []
|
||||||
commands.extend(
|
enable_info = {'enabled': str(lb_enabled)}
|
||||||
self._refresh_lb_vips(ovn_lb.uuid, ovn_lb.external_ids))
|
ovn_lb.external_ids['enabled'] = str(lb_enabled)
|
||||||
self._execute_commands(commands)
|
commands.append(
|
||||||
if lb_enabled:
|
self.ovn_nbdb_api.db_set('Load_Balancer', ovn_lb.uuid,
|
||||||
operating_status = constants.ONLINE
|
('external_ids', enable_info))
|
||||||
else:
|
)
|
||||||
operating_status = constants.OFFLINE
|
commands.extend(
|
||||||
lb_status['operating_status'] = operating_status
|
self._refresh_lb_vips(ovn_lb.uuid,
|
||||||
|
ovn_lb.external_ids))
|
||||||
|
self._execute_commands(commands)
|
||||||
|
if lb_enabled:
|
||||||
|
operating_status = constants.ONLINE
|
||||||
|
else:
|
||||||
|
operating_status = constants.OFFLINE
|
||||||
|
lb_status['operating_status'] = operating_status
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception(EXCEPTION_MSG, "update of loadbalancer")
|
LOG.exception(EXCEPTION_MSG, "update of loadbalancer")
|
||||||
lb_status['provisioning_status'] = constants.ERROR
|
lb_status['provisioning_status'] = constants.ERROR
|
||||||
@ -944,21 +1095,24 @@ class OvnProviderHelper(object):
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
def listener_create(self, listener):
|
def listener_create(self, listener):
|
||||||
|
ovn_lb = self._get_or_create_ovn_lb(
|
||||||
|
listener['loadbalancer_id'],
|
||||||
|
listener['protocol'],
|
||||||
|
listener['admin_state_up'])
|
||||||
|
|
||||||
|
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
||||||
|
listener_key = self._get_listener_key(
|
||||||
|
listener['id'], is_enabled=listener['admin_state_up'])
|
||||||
|
|
||||||
|
if listener.get('default_pool_id'):
|
||||||
|
pool_key = self._get_pool_key(listener['default_pool_id'])
|
||||||
|
else:
|
||||||
|
pool_key = ''
|
||||||
|
external_ids[listener_key] = self._make_listener_key_value(
|
||||||
|
listener['protocol_port'], pool_key)
|
||||||
|
|
||||||
|
listener_info = {listener_key: external_ids[listener_key]}
|
||||||
try:
|
try:
|
||||||
ovn_lb = self._find_ovn_lb(listener['loadbalancer_id'])
|
|
||||||
|
|
||||||
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
|
||||||
listener_key = self._get_listener_key(
|
|
||||||
listener['id'], is_enabled=listener['admin_state_up'])
|
|
||||||
|
|
||||||
if listener.get('default_pool_id'):
|
|
||||||
pool_key = self._get_pool_key(listener['default_pool_id'])
|
|
||||||
else:
|
|
||||||
pool_key = ''
|
|
||||||
external_ids[listener_key] = self._make_listener_key_value(
|
|
||||||
listener['protocol_port'], pool_key)
|
|
||||||
|
|
||||||
listener_info = {listener_key: external_ids[listener_key]}
|
|
||||||
commands = []
|
commands = []
|
||||||
commands.append(
|
commands.append(
|
||||||
self.ovn_nbdb_api.db_set('Load_Balancer', ovn_lb.uuid,
|
self.ovn_nbdb_api.db_set('Load_Balancer', ovn_lb.uuid,
|
||||||
@ -995,73 +1149,95 @@ class OvnProviderHelper(object):
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
def listener_delete(self, listener):
|
def listener_delete(self, listener):
|
||||||
|
status = {
|
||||||
|
'listeners': [{"id": listener['id'],
|
||||||
|
"provisioning_status": constants.DELETED,
|
||||||
|
"operating_status": constants.OFFLINE}],
|
||||||
|
'loadbalancers': [{"id": listener['loadbalancer_id'],
|
||||||
|
"provisioning_status": constants.ACTIVE}]}
|
||||||
try:
|
try:
|
||||||
ovn_lb = self._find_ovn_lb(listener['loadbalancer_id'])
|
ovn_lb = self._find_ovn_lbs(
|
||||||
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
listener['loadbalancer_id'],
|
||||||
listener_key = self._get_listener_key(listener['id'])
|
protocol=listener['protocol'])
|
||||||
|
except idlutils.RowNotFound:
|
||||||
|
# Listener already deleted.
|
||||||
|
return status
|
||||||
|
|
||||||
if listener_key in external_ids:
|
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
||||||
|
listener_key = self._get_listener_key(listener['id'])
|
||||||
|
if listener_key in external_ids:
|
||||||
|
try:
|
||||||
commands = []
|
commands = []
|
||||||
commands.append(
|
commands.append(
|
||||||
self.ovn_nbdb_api.db_remove(
|
self.ovn_nbdb_api.db_remove(
|
||||||
'Load_Balancer', ovn_lb.uuid, 'external_ids',
|
'Load_Balancer', ovn_lb.uuid, 'external_ids',
|
||||||
(listener_key))
|
(listener_key)))
|
||||||
)
|
# Drop current listener from LB.
|
||||||
|
|
||||||
del external_ids[listener_key]
|
del external_ids[listener_key]
|
||||||
|
|
||||||
|
# Set LB protocol to undefined only if there are no more
|
||||||
|
# listeners and pools defined in the LB.
|
||||||
commands.extend(
|
commands.extend(
|
||||||
self._refresh_lb_vips(ovn_lb.uuid, external_ids)
|
self._clean_lb_if_empty(
|
||||||
)
|
ovn_lb, listener['loadbalancer_id'], external_ids))
|
||||||
|
commands.extend(
|
||||||
|
self._refresh_lb_vips(ovn_lb.uuid, external_ids))
|
||||||
self._execute_commands(commands)
|
self._execute_commands(commands)
|
||||||
|
except Exception:
|
||||||
status = {
|
LOG.exception(EXCEPTION_MSG, "deletion of listener")
|
||||||
'listeners': [{"id": listener['id'],
|
status = {
|
||||||
"provisioning_status": constants.DELETED,
|
'listeners': [{
|
||||||
"operating_status": constants.OFFLINE}],
|
"id": listener['id'],
|
||||||
'loadbalancers': [{"id": listener['loadbalancer_id'],
|
"provisioning_status": constants.ERROR,
|
||||||
"provisioning_status": constants.ACTIVE}]}
|
"operating_status": constants.ERROR}],
|
||||||
except Exception:
|
'loadbalancers': [{
|
||||||
LOG.exception(EXCEPTION_MSG, "deletion of listener")
|
"id": listener['loadbalancer_id'],
|
||||||
status = {
|
"provisioning_status": constants.ACTIVE}]}
|
||||||
'listeners': [{"id": listener['id'],
|
|
||||||
"provisioning_status": constants.ERROR,
|
|
||||||
"operating_status": constants.ERROR}],
|
|
||||||
'loadbalancers': [{"id": listener['loadbalancer_id'],
|
|
||||||
"provisioning_status": constants.ACTIVE}]}
|
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def listener_update(self, listener):
|
def listener_update(self, listener):
|
||||||
|
# NOTE(mjozefcz): Based on
|
||||||
|
# https://docs.openstack.org/api-ref/load-balancer/v2/?expanded=update-a-listener-detail
|
||||||
|
# there is no possibility to update listener protocol or port.
|
||||||
|
listener_status = {'id': listener['id'],
|
||||||
|
'provisioning_status': constants.ACTIVE}
|
||||||
|
pool_status = []
|
||||||
|
status = {
|
||||||
|
'listeners': [listener_status],
|
||||||
|
'loadbalancers': [{'id': listener['loadbalancer_id'],
|
||||||
|
'provisioning_status': constants.ACTIVE}],
|
||||||
|
'pools': pool_status}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
listener_status = {'id': listener['id'],
|
ovn_lb = self._find_ovn_lbs(
|
||||||
'provisioning_status': constants.ACTIVE}
|
listener['loadbalancer_id'],
|
||||||
pool_status = []
|
protocol=listener['protocol'])
|
||||||
status = {
|
except idlutils.RowNotFound:
|
||||||
'listeners': [listener_status],
|
LOG.exception(EXCEPTION_MSG, "update of listener")
|
||||||
'loadbalancers': [{'id': listener['loadbalancer_id'],
|
# LB row not found during updating a listner. That is a problem.
|
||||||
'provisioning_status': constants.ACTIVE}],
|
status['listeners'][0]['provisioning_status'] = constants.ERROR
|
||||||
'pools': pool_status}
|
status['loadbalancers'][0]['provisioning_status'] = constants.ERROR
|
||||||
|
return status
|
||||||
|
|
||||||
ovn_lb = self._find_ovn_lb(listener['loadbalancer_id'])
|
l_key_when_enabled = self._get_listener_key(listener['id'])
|
||||||
l_key_when_enabled = self._get_listener_key(listener['id'])
|
l_key_when_disabled = self._get_listener_key(
|
||||||
l_key_when_disabled = self._get_listener_key(
|
listener['id'], is_enabled=False)
|
||||||
listener['id'], is_enabled=False)
|
|
||||||
|
|
||||||
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
||||||
|
if 'admin_state_up' not in listener and (
|
||||||
|
'default_pool_id' not in listener):
|
||||||
|
return status
|
||||||
|
|
||||||
if 'admin_state_up' not in listener and (
|
l_key_to_add = {}
|
||||||
'default_pool_id' not in listener):
|
if l_key_when_enabled in external_ids:
|
||||||
return status
|
present_l_key = l_key_when_enabled
|
||||||
|
elif l_key_when_disabled in external_ids:
|
||||||
l_key_to_add = {}
|
present_l_key = l_key_when_disabled
|
||||||
if l_key_when_enabled in external_ids:
|
else:
|
||||||
present_l_key = l_key_when_enabled
|
# Something is terribly wrong. This cannot happen.
|
||||||
elif l_key_when_disabled in external_ids:
|
return status
|
||||||
present_l_key = l_key_when_disabled
|
|
||||||
else:
|
|
||||||
# Something is terribly wrong. This cannot happen.
|
|
||||||
return status
|
|
||||||
|
|
||||||
|
try:
|
||||||
commands = []
|
commands = []
|
||||||
new_l_key = None
|
new_l_key = None
|
||||||
l_key_to_remove = None
|
l_key_to_remove = None
|
||||||
@ -1116,21 +1292,23 @@ class OvnProviderHelper(object):
|
|||||||
'provisioning_status': constants.ERROR}],
|
'provisioning_status': constants.ERROR}],
|
||||||
'loadbalancers': [{'id': listener['loadbalancer_id'],
|
'loadbalancers': [{'id': listener['loadbalancer_id'],
|
||||||
'provisioning_status': constants.ACTIVE}]}
|
'provisioning_status': constants.ACTIVE}]}
|
||||||
|
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def pool_create(self, pool):
|
def pool_create(self, pool):
|
||||||
|
ovn_lb = self._get_or_create_ovn_lb(
|
||||||
|
pool['loadbalancer_id'],
|
||||||
|
pool['protocol'],
|
||||||
|
pool['admin_state_up'])
|
||||||
|
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
||||||
|
pool_key = self._get_pool_key(pool['id'],
|
||||||
|
is_enabled=pool['admin_state_up'])
|
||||||
|
external_ids[pool_key] = ''
|
||||||
|
if pool['listener_id']:
|
||||||
|
listener_key = self._get_listener_key(pool['listener_id'])
|
||||||
|
if listener_key in ovn_lb.external_ids:
|
||||||
|
external_ids[listener_key] = str(
|
||||||
|
external_ids[listener_key]) + str(pool_key)
|
||||||
try:
|
try:
|
||||||
ovn_lb = self._find_ovn_lb(pool['loadbalancer_id'])
|
|
||||||
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
|
||||||
pool_key = self._get_pool_key(pool['id'],
|
|
||||||
is_enabled=pool['admin_state_up'])
|
|
||||||
external_ids[pool_key] = ''
|
|
||||||
if pool['listener_id']:
|
|
||||||
listener_key = self._get_listener_key(pool['listener_id'])
|
|
||||||
if listener_key in ovn_lb.external_ids:
|
|
||||||
external_ids[listener_key] = str(
|
|
||||||
external_ids[listener_key]) + str(pool_key)
|
|
||||||
self.ovn_nbdb_api.db_set(
|
self.ovn_nbdb_api.db_set(
|
||||||
'Load_Balancer', ovn_lb.uuid,
|
'Load_Balancer', ovn_lb.uuid,
|
||||||
('external_ids', external_ids)).execute(check_error=True)
|
('external_ids', external_ids)).execute(check_error=True)
|
||||||
@ -1162,11 +1340,23 @@ class OvnProviderHelper(object):
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
def pool_delete(self, pool):
|
def pool_delete(self, pool):
|
||||||
|
status = {
|
||||||
|
'pools': [{"id": pool['id'],
|
||||||
|
"provisioning_status": constants.DELETED}],
|
||||||
|
'loadbalancers': [{"id": pool['loadbalancer_id'],
|
||||||
|
"provisioning_status": constants.ACTIVE}]}
|
||||||
|
try:
|
||||||
|
ovn_lb = self._find_ovn_lbs(
|
||||||
|
pool['loadbalancer_id'],
|
||||||
|
pool['protocol'])
|
||||||
|
except idlutils.RowNotFound:
|
||||||
|
# LB row not found that means pool is deleted.
|
||||||
|
return status
|
||||||
|
|
||||||
|
pool_key = self._get_pool_key(pool['id'])
|
||||||
|
commands = []
|
||||||
|
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
||||||
try:
|
try:
|
||||||
ovn_lb = self._find_ovn_lb(pool['loadbalancer_id'])
|
|
||||||
pool_key = self._get_pool_key(pool['id'])
|
|
||||||
commands = []
|
|
||||||
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
|
||||||
if pool_key in ovn_lb.external_ids:
|
if pool_key in ovn_lb.external_ids:
|
||||||
commands.append(
|
commands.append(
|
||||||
self.ovn_nbdb_api.db_remove('Load_Balancer', ovn_lb.uuid,
|
self.ovn_nbdb_api.db_remove('Load_Balancer', ovn_lb.uuid,
|
||||||
@ -1196,13 +1386,11 @@ class OvnProviderHelper(object):
|
|||||||
'external_ids', (pool_key_when_disabled))
|
'external_ids', (pool_key_when_disabled))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
commands.extend(
|
||||||
|
self._clean_lb_if_empty(
|
||||||
|
ovn_lb, pool['loadbalancer_id'], external_ids))
|
||||||
self._execute_commands(commands)
|
self._execute_commands(commands)
|
||||||
|
|
||||||
status = {
|
|
||||||
'pools': [{"id": pool['id'],
|
|
||||||
"provisioning_status": constants.DELETED}],
|
|
||||||
'loadbalancers': [{"id": pool['loadbalancer_id'],
|
|
||||||
"provisioning_status": constants.ACTIVE}]}
|
|
||||||
if listener_id:
|
if listener_id:
|
||||||
status['listeners'] = [{
|
status['listeners'] = [{
|
||||||
'id': listener_id,
|
'id': listener_id,
|
||||||
@ -1218,24 +1406,32 @@ class OvnProviderHelper(object):
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
def pool_update(self, pool):
|
def pool_update(self, pool):
|
||||||
|
pool_status = {'id': pool['id'],
|
||||||
|
'provisioning_status': constants.ACTIVE}
|
||||||
|
status = {
|
||||||
|
'pools': [pool_status],
|
||||||
|
'loadbalancers': [{'id': pool['loadbalancer_id'],
|
||||||
|
'provisioning_status': constants.ACTIVE}]}
|
||||||
|
if 'admin_state_up' not in pool:
|
||||||
|
return status
|
||||||
try:
|
try:
|
||||||
pool_status = {'id': pool['id'],
|
ovn_lb = self._find_ovn_lbs(
|
||||||
'provisioning_status': constants.ACTIVE}
|
pool['loadbalancer_id'], protocol=pool['protocol'])
|
||||||
status = {
|
except idlutils.RowNotFound:
|
||||||
'pools': [pool_status],
|
LOG.exception(EXCEPTION_MSG, "update of pool")
|
||||||
'loadbalancers': [{'id': pool['loadbalancer_id'],
|
# LB row not found during updating a listner. That is a problem.
|
||||||
'provisioning_status': constants.ACTIVE}]}
|
status['pool'][0]['provisioning_status'] = constants.ERROR
|
||||||
if 'admin_state_up' not in pool:
|
status['loadbalancers'][0]['provisioning_status'] = constants.ERROR
|
||||||
return status
|
return status
|
||||||
|
|
||||||
ovn_lb = self._find_ovn_lb(pool['loadbalancer_id'])
|
pool_key = self._get_pool_key(pool['id'])
|
||||||
pool_key = self._get_pool_key(pool['id'])
|
p_key_when_disabled = self._get_pool_key(pool['id'],
|
||||||
p_key_when_disabled = self._get_pool_key(pool['id'],
|
is_enabled=False)
|
||||||
is_enabled=False)
|
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
||||||
|
p_key_to_remove = None
|
||||||
|
p_key_to_add = {}
|
||||||
|
|
||||||
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
try:
|
||||||
p_key_to_remove = None
|
|
||||||
p_key_to_add = {}
|
|
||||||
if pool['admin_state_up']:
|
if pool['admin_state_up']:
|
||||||
if p_key_when_disabled in external_ids:
|
if p_key_when_disabled in external_ids:
|
||||||
p_key_to_add[pool_key] = external_ids[p_key_when_disabled]
|
p_key_to_add[pool_key] = external_ids[p_key_when_disabled]
|
||||||
@ -1320,7 +1516,7 @@ class OvnProviderHelper(object):
|
|||||||
|
|
||||||
def member_create(self, member):
|
def member_create(self, member):
|
||||||
try:
|
try:
|
||||||
pool_key, ovn_lb = self._find_ovn_lb_by_id(
|
pool_key, ovn_lb = self._find_ovn_lb_by_pool_id(
|
||||||
member['pool_id'])
|
member['pool_id'])
|
||||||
self._add_member(member, ovn_lb, pool_key)
|
self._add_member(member, ovn_lb, pool_key)
|
||||||
pool = {"id": member['pool_id'],
|
pool = {"id": member['pool_id'],
|
||||||
@ -1386,7 +1582,7 @@ class OvnProviderHelper(object):
|
|||||||
|
|
||||||
def member_delete(self, member):
|
def member_delete(self, member):
|
||||||
try:
|
try:
|
||||||
pool_key, ovn_lb = self._find_ovn_lb_by_id(
|
pool_key, ovn_lb = self._find_ovn_lb_by_pool_id(
|
||||||
member['pool_id'])
|
member['pool_id'])
|
||||||
pool_status = self._remove_member(member, ovn_lb, pool_key)
|
pool_status = self._remove_member(member, ovn_lb, pool_key)
|
||||||
pool = {"id": member['pool_id'],
|
pool = {"id": member['pool_id'],
|
||||||
@ -1440,7 +1636,7 @@ class OvnProviderHelper(object):
|
|||||||
|
|
||||||
def member_update(self, member):
|
def member_update(self, member):
|
||||||
try:
|
try:
|
||||||
pool_key, ovn_lb = self._find_ovn_lb_by_id(
|
pool_key, ovn_lb = self._find_ovn_lb_by_pool_id(
|
||||||
member['pool_id'])
|
member['pool_id'])
|
||||||
status = {
|
status = {
|
||||||
'pools': [{'id': member['pool_id'],
|
'pools': [{'id': member['pool_id'],
|
||||||
@ -1476,7 +1672,7 @@ class OvnProviderHelper(object):
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
def _get_existing_pool_members(self, pool_id):
|
def _get_existing_pool_members(self, pool_id):
|
||||||
pool_key, ovn_lb = self._find_ovn_lb_by_id(pool_id)
|
pool_key, ovn_lb = self._find_ovn_lb_by_pool_id(pool_id)
|
||||||
if not ovn_lb:
|
if not ovn_lb:
|
||||||
msg = _("Loadbalancer with pool %s does not exist") % pool_key
|
msg = _("Loadbalancer with pool %s does not exist") % pool_key
|
||||||
raise driver_exceptions.DriverError(msg)
|
raise driver_exceptions.DriverError(msg)
|
||||||
@ -1535,11 +1731,7 @@ class OvnProviderHelper(object):
|
|||||||
network_driver.neutron_client.delete_port(port_id)
|
network_driver.neutron_client.delete_port(port_id)
|
||||||
|
|
||||||
def handle_vip_fip(self, fip_info):
|
def handle_vip_fip(self, fip_info):
|
||||||
try:
|
ovn_lb = fip_info['ovn_lb']
|
||||||
ovn_lb = self._find_ovn_lb(fip_info['lb_id'])
|
|
||||||
except idlutils.RowNotFound:
|
|
||||||
LOG.debug("Loadbalancer %s not found!", fip_info['lb_id'])
|
|
||||||
return
|
|
||||||
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
||||||
commands = []
|
commands = []
|
||||||
|
|
||||||
@ -1627,6 +1819,7 @@ class OvnProviderDriver(driver_base.ProviderDriver):
|
|||||||
admin_state_up = True
|
admin_state_up = True
|
||||||
request_info = {'id': pool.pool_id,
|
request_info = {'id': pool.pool_id,
|
||||||
'loadbalancer_id': pool.loadbalancer_id,
|
'loadbalancer_id': pool.loadbalancer_id,
|
||||||
|
'protocol': pool.protocol,
|
||||||
'listener_id': pool.listener_id,
|
'listener_id': pool.listener_id,
|
||||||
'admin_state_up': admin_state_up}
|
'admin_state_up': admin_state_up}
|
||||||
request = {'type': REQ_TYPE_POOL_CREATE,
|
request = {'type': REQ_TYPE_POOL_CREATE,
|
||||||
@ -1638,6 +1831,7 @@ class OvnProviderDriver(driver_base.ProviderDriver):
|
|||||||
self.member_delete(member)
|
self.member_delete(member)
|
||||||
|
|
||||||
request_info = {'id': pool.pool_id,
|
request_info = {'id': pool.pool_id,
|
||||||
|
'protocol': pool.protocol,
|
||||||
'loadbalancer_id': pool.loadbalancer_id}
|
'loadbalancer_id': pool.loadbalancer_id}
|
||||||
request = {'type': REQ_TYPE_POOL_DELETE,
|
request = {'type': REQ_TYPE_POOL_DELETE,
|
||||||
'info': request_info}
|
'info': request_info}
|
||||||
@ -1648,7 +1842,8 @@ class OvnProviderDriver(driver_base.ProviderDriver):
|
|||||||
self._check_for_supported_protocols(new_pool.protocol)
|
self._check_for_supported_protocols(new_pool.protocol)
|
||||||
if not isinstance(new_pool.lb_algorithm, o_datamodels.UnsetType):
|
if not isinstance(new_pool.lb_algorithm, o_datamodels.UnsetType):
|
||||||
self._check_for_supported_algorithms(new_pool.lb_algorithm)
|
self._check_for_supported_algorithms(new_pool.lb_algorithm)
|
||||||
request_info = {'id': new_pool.pool_id,
|
request_info = {'id': old_pool.pool_id,
|
||||||
|
'protocol': old_pool.protocol,
|
||||||
'loadbalancer_id': old_pool.loadbalancer_id}
|
'loadbalancer_id': old_pool.loadbalancer_id}
|
||||||
|
|
||||||
if not isinstance(new_pool.admin_state_up, o_datamodels.UnsetType):
|
if not isinstance(new_pool.admin_state_up, o_datamodels.UnsetType):
|
||||||
@ -1657,21 +1852,8 @@ class OvnProviderDriver(driver_base.ProviderDriver):
|
|||||||
'info': request_info}
|
'info': request_info}
|
||||||
self._ovn_helper.add_request(request)
|
self._ovn_helper.add_request(request)
|
||||||
|
|
||||||
# Listener
|
|
||||||
def _check_listener_protocol(self, listener):
|
|
||||||
self._check_for_supported_protocols(listener.protocol)
|
|
||||||
if not self._ovn_helper.check_lb_protocol(
|
|
||||||
listener.loadbalancer_id, listener.protocol):
|
|
||||||
msg = (_('The loadbalancer %(lb)s does not support %(proto)s '
|
|
||||||
'protocol') % {
|
|
||||||
'lb': listener.loadbalancer_id,
|
|
||||||
'proto': listener.protocol})
|
|
||||||
raise driver_exceptions.UnsupportedOptionError(
|
|
||||||
user_fault_string=msg,
|
|
||||||
operator_fault_string=msg)
|
|
||||||
|
|
||||||
def listener_create(self, listener):
|
def listener_create(self, listener):
|
||||||
self._check_listener_protocol(listener)
|
self._check_for_supported_protocols(listener.protocol)
|
||||||
admin_state_up = listener.admin_state_up
|
admin_state_up = listener.admin_state_up
|
||||||
if isinstance(admin_state_up, o_datamodels.UnsetType):
|
if isinstance(admin_state_up, o_datamodels.UnsetType):
|
||||||
admin_state_up = True
|
admin_state_up = True
|
||||||
@ -1688,16 +1870,16 @@ class OvnProviderDriver(driver_base.ProviderDriver):
|
|||||||
def listener_delete(self, listener):
|
def listener_delete(self, listener):
|
||||||
request_info = {'id': listener.listener_id,
|
request_info = {'id': listener.listener_id,
|
||||||
'loadbalancer_id': listener.loadbalancer_id,
|
'loadbalancer_id': listener.loadbalancer_id,
|
||||||
'protocol_port': listener.protocol_port}
|
'protocol_port': listener.protocol_port,
|
||||||
|
'protocol': listener.protocol}
|
||||||
request = {'type': REQ_TYPE_LISTENER_DELETE,
|
request = {'type': REQ_TYPE_LISTENER_DELETE,
|
||||||
'info': request_info}
|
'info': request_info}
|
||||||
self._ovn_helper.add_request(request)
|
self._ovn_helper.add_request(request)
|
||||||
|
|
||||||
def listener_update(self, old_listener, new_listener):
|
def listener_update(self, old_listener, new_listener):
|
||||||
if not isinstance(new_listener.protocol, o_datamodels.UnsetType):
|
|
||||||
self._check_listener_protocol(new_listener)
|
|
||||||
request_info = {'id': new_listener.listener_id,
|
request_info = {'id': new_listener.listener_id,
|
||||||
'loadbalancer_id': old_listener.loadbalancer_id,
|
'loadbalancer_id': old_listener.loadbalancer_id,
|
||||||
|
'protocol': old_listener.protocol,
|
||||||
'protocol_port': old_listener.protocol_port}
|
'protocol_port': old_listener.protocol_port}
|
||||||
|
|
||||||
if not isinstance(new_listener.admin_state_up, o_datamodels.UnsetType):
|
if not isinstance(new_listener.admin_state_up, o_datamodels.UnsetType):
|
||||||
@ -1721,7 +1903,7 @@ class OvnProviderDriver(driver_base.ProviderDriver):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def _ip_version_differs(self, member):
|
def _ip_version_differs(self, member):
|
||||||
_, ovn_lb = self._ovn_helper._find_ovn_lb_by_id(member.pool_id)
|
_, ovn_lb = self._ovn_helper._find_ovn_lb_by_pool_id(member.pool_id)
|
||||||
lb_vip = ovn_lb.external_ids[LB_EXT_IDS_VIP_KEY]
|
lb_vip = ovn_lb.external_ids[LB_EXT_IDS_VIP_KEY]
|
||||||
return netaddr.IPNetwork(lb_vip).version != (
|
return netaddr.IPNetwork(lb_vip).version != (
|
||||||
netaddr.IPNetwork(member.address).version)
|
netaddr.IPNetwork(member.address).version)
|
||||||
|
@ -13,8 +13,9 @@
|
|||||||
# 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 mock
|
import copy
|
||||||
|
|
||||||
|
import mock
|
||||||
from neutron.common import utils as n_utils
|
from neutron.common import utils as n_utils
|
||||||
from neutron_lib.plugins import directory
|
from neutron_lib.plugins import directory
|
||||||
from octavia_lib.api.drivers import data_models as octavia_data_model
|
from octavia_lib.api.drivers import data_models as octavia_data_model
|
||||||
@ -65,6 +66,8 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
self.fake_network_driver.get_subnet = self._mock_get_subnet
|
self.fake_network_driver.get_subnet = self._mock_get_subnet
|
||||||
self.fake_network_driver.neutron_client.list_ports = (
|
self.fake_network_driver.neutron_client.list_ports = (
|
||||||
self._mock_list_ports)
|
self._mock_list_ports)
|
||||||
|
self.fake_network_driver.neutron_client.show_port = (
|
||||||
|
self._mock_show_port)
|
||||||
self.fake_network_driver.neutron_client.\
|
self.fake_network_driver.neutron_client.\
|
||||||
delete_port.return_value = True
|
delete_port.return_value = True
|
||||||
self._local_net_cache = {}
|
self._local_net_cache = {}
|
||||||
@ -80,6 +83,11 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
def _mock_list_ports(self, **kwargs):
|
def _mock_list_ports(self, **kwargs):
|
||||||
return self._local_port_cache
|
return self._local_port_cache
|
||||||
|
|
||||||
|
def _mock_show_port(self, port_id):
|
||||||
|
for port in self._local_port_cache['ports']:
|
||||||
|
if port['id'] == port_id:
|
||||||
|
return {'port': port}
|
||||||
|
|
||||||
def _create_provider_network(self):
|
def _create_provider_network(self):
|
||||||
e1 = self._make_network(self.fmt, 'e1', True,
|
e1 = self._make_network(self.fmt, 'e1', True,
|
||||||
arg_list=('router:external',
|
arg_list=('router:external',
|
||||||
@ -129,7 +137,6 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
m_pool.loadbalancer_id = loadbalancer_id
|
m_pool.loadbalancer_id = loadbalancer_id
|
||||||
m_pool.members = []
|
m_pool.members = []
|
||||||
m_pool.admin_state_up = admin_state_up
|
m_pool.admin_state_up = admin_state_up
|
||||||
m_pool.protocol = protocol
|
|
||||||
m_pool.lb_algorithm = lb_algorithm
|
m_pool.lb_algorithm = lb_algorithm
|
||||||
if listener_id:
|
if listener_id:
|
||||||
m_pool.listener_id = listener_id
|
m_pool.listener_id = listener_id
|
||||||
@ -189,7 +196,26 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
|
|
||||||
def _validate_loadbalancers(self, expected_lbs):
|
def _validate_loadbalancers(self, expected_lbs):
|
||||||
observed_lbs = self._get_loadbalancers()
|
observed_lbs = self._get_loadbalancers()
|
||||||
self.assertItemsEqual(expected_lbs, observed_lbs)
|
# NOTE (mjozefcz): assertItemsEqual works only on first level
|
||||||
|
# of comparison, if dicts inside dics are in diffrent
|
||||||
|
# order it would fail.
|
||||||
|
self.assertEqual(len(expected_lbs),
|
||||||
|
len(observed_lbs))
|
||||||
|
for expected_lb in expected_lbs:
|
||||||
|
# search for LB with same name and protocol
|
||||||
|
found = False
|
||||||
|
for observed_lb in observed_lbs:
|
||||||
|
if (observed_lb.get('name') ==
|
||||||
|
expected_lb.get('name') and
|
||||||
|
observed_lb.get('protocol') ==
|
||||||
|
expected_lb.get('protocol')):
|
||||||
|
self.assertEqual(expected_lb, observed_lb)
|
||||||
|
found = True
|
||||||
|
if not found:
|
||||||
|
raise Exception("Expected LB %(name)s for protocol %(proto)s "
|
||||||
|
"not found in observed_lbs", {
|
||||||
|
'name': expected_lb.get('name'),
|
||||||
|
'proto': expected_lb.get('proto')})
|
||||||
|
|
||||||
def _is_lb_associated_to_ls(self, lb_name, ls_name):
|
def _is_lb_associated_to_ls(self, lb_name, ls_name):
|
||||||
return self._is_lb_associated_to_tab(
|
return self._is_lb_associated_to_tab(
|
||||||
@ -238,30 +264,54 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
net_id = LR_REF_KEY_HEADER + '%s' % net_id
|
net_id = LR_REF_KEY_HEADER + '%s' % net_id
|
||||||
|
|
||||||
if add_ref:
|
if add_ref:
|
||||||
if net_id in lb_data[ovn_driver.LB_EXT_IDS_LS_REFS_KEY]:
|
if net_id not in lb_data[ovn_driver.LB_EXT_IDS_LS_REFS_KEY]:
|
||||||
ref_ct = lb_data[
|
|
||||||
ovn_driver.LB_EXT_IDS_LS_REFS_KEY][net_id] + 1
|
|
||||||
lb_data[ovn_driver.LB_EXT_IDS_LS_REFS_KEY][net_id] = ref_ct
|
|
||||||
else:
|
|
||||||
lb_data[ovn_driver.LB_EXT_IDS_LS_REFS_KEY][net_id] = 1
|
lb_data[ovn_driver.LB_EXT_IDS_LS_REFS_KEY][net_id] = 1
|
||||||
else:
|
else:
|
||||||
ref_ct = lb_data[ovn_driver.LB_EXT_IDS_LS_REFS_KEY][net_id] - 1
|
ref_ct = lb_data[ovn_driver.LB_EXT_IDS_LS_REFS_KEY][net_id]
|
||||||
if ref_ct > 0:
|
if ref_ct <= 0:
|
||||||
lb_data[ovn_driver.LB_EXT_IDS_LS_REFS_KEY][net_id] = ref_ct
|
|
||||||
else:
|
|
||||||
del lb_data[ovn_driver.LB_EXT_IDS_LS_REFS_KEY][net_id]
|
del lb_data[ovn_driver.LB_EXT_IDS_LS_REFS_KEY][net_id]
|
||||||
|
|
||||||
def _wait_for_status(self, expected_status, check_call=True):
|
def _wait_for_status(self, expected_statuses, check_call=True):
|
||||||
call_count = len(expected_status)
|
call_count = len(expected_statuses)
|
||||||
expected_calls = [mock.call(status) for status in expected_status]
|
|
||||||
update_loadbalancer_status = (
|
update_loadbalancer_status = (
|
||||||
self._o_driver_lib.update_loadbalancer_status)
|
self._o_driver_lib.update_loadbalancer_status)
|
||||||
n_utils.wait_until_true(
|
n_utils.wait_until_true(
|
||||||
lambda: update_loadbalancer_status.call_count == call_count,
|
lambda: update_loadbalancer_status.call_count == call_count,
|
||||||
timeout=10)
|
timeout=10)
|
||||||
if check_call:
|
if check_call:
|
||||||
self._o_driver_lib.update_loadbalancer_status.assert_has_calls(
|
# NOTE(mjozefcz): The updates are send in parallel and includes
|
||||||
expected_calls, any_order=True)
|
# dicts with unordered lists inside. So we can't simply use
|
||||||
|
# assert_has_calls here. Sample structure:
|
||||||
|
# {'listeners': [],
|
||||||
|
# 'loadbalancers': [{'id': 'a', 'provisioning_status': 'ACTIVE'}],
|
||||||
|
# 'members': [{'id': 'b', 'provisioning_status': 'DELETED'},
|
||||||
|
# {'id': 'c', 'provisioning_status': 'DELETED'}],
|
||||||
|
# 'pools': [{'id': 'd', 'operating_status': 'ONLINE',
|
||||||
|
# 'provisioning_status': 'ACTIVE'}]},
|
||||||
|
updated_statuses = []
|
||||||
|
for call in update_loadbalancer_status.mock_calls:
|
||||||
|
updated_statuses.append(call.args[0])
|
||||||
|
calls_found = []
|
||||||
|
for expected_status in expected_statuses:
|
||||||
|
for updated_status in updated_statuses:
|
||||||
|
# Find status update having equal keys
|
||||||
|
if updated_status.keys() == expected_status.keys():
|
||||||
|
val_check = []
|
||||||
|
# Withing this status update check if all values of
|
||||||
|
# expected keys match.
|
||||||
|
for k, v in expected_status.items():
|
||||||
|
val_check.append(
|
||||||
|
sorted(expected_status[k],
|
||||||
|
key=lambda x: x['id']) ==
|
||||||
|
sorted(updated_status[k],
|
||||||
|
key=lambda x: x['id']))
|
||||||
|
if False in val_check:
|
||||||
|
# At least one value don't match.
|
||||||
|
continue
|
||||||
|
calls_found.append(expected_status)
|
||||||
|
break
|
||||||
|
# Validate if we found all expected calls.
|
||||||
|
self.assertItemsEqual(expected_statuses, calls_found)
|
||||||
|
|
||||||
def _wait_for_status_and_validate(self, lb_data, expected_status,
|
def _wait_for_status_and_validate(self, lb_data, expected_status,
|
||||||
check_call=True):
|
check_call=True):
|
||||||
@ -399,9 +449,55 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
'neutron:vip': lb_data['model'].vip_address,
|
'neutron:vip': lb_data['model'].vip_address,
|
||||||
'neutron:vip_port_id': vip_net_info[3],
|
'neutron:vip_port_id': vip_net_info[3],
|
||||||
'enabled': str(lb_data['model'].admin_state_up)}
|
'enabled': str(lb_data['model'].admin_state_up)}
|
||||||
|
# NOTE(mjozefcz): By default we don't set protocol. We don't know if
|
||||||
|
# listener/pool would be TCP or UDP, so do not set it.
|
||||||
|
expected_protocols = set()
|
||||||
|
|
||||||
|
# Lets fetch list of L4 protocols defined for this LB.
|
||||||
|
for p in lb_data['pools']:
|
||||||
|
expected_protocols.add(p.protocol.lower())
|
||||||
|
for l in lb_data['listeners']:
|
||||||
|
expected_protocols.add(l.protocol.lower())
|
||||||
|
# If there is no protocol lets add default - empty [].
|
||||||
|
expected_protocols = list(expected_protocols)
|
||||||
|
if len(expected_protocols) == 0:
|
||||||
|
expected_protocols.append(None)
|
||||||
|
|
||||||
|
expected_lbs = [{'name': lb_data['model'].loadbalancer_id,
|
||||||
|
'protocol': [protocol] if protocol else [],
|
||||||
|
'vips': {},
|
||||||
|
'external_ids': copy.deepcopy(external_ids)}
|
||||||
|
for protocol in expected_protocols]
|
||||||
|
|
||||||
|
def _get_lb_field_by_protocol(protocol, field='external_ids'):
|
||||||
|
"Get needed external_ids and pass by reference"
|
||||||
|
lb = [lb for lb in expected_lbs
|
||||||
|
if lb.get('protocol') == [protocol]]
|
||||||
|
return lb[0].get(field)
|
||||||
|
|
||||||
|
# For every connected subnet to the LB set the ref
|
||||||
|
# counter.
|
||||||
|
for net_id, ref_ct in lb_data[
|
||||||
|
ovn_driver.LB_EXT_IDS_LS_REFS_KEY].items():
|
||||||
|
for lb in expected_lbs:
|
||||||
|
# If given LB hasn't VIP configured from
|
||||||
|
# this network we shouldn't touch it here.
|
||||||
|
if net_id == 'neutron-%s' % lb_data['model'].vip_network_id:
|
||||||
|
lb.get('external_ids')[
|
||||||
|
ovn_driver.LB_EXT_IDS_LS_REFS_KEY][net_id] = 1
|
||||||
|
|
||||||
|
# For every connected router set it here.
|
||||||
|
if lb_data.get(ovn_driver.LB_EXT_IDS_LR_REF_KEY):
|
||||||
|
for lb in expected_lbs:
|
||||||
|
lb.get('external_ids')[
|
||||||
|
ovn_driver.LB_EXT_IDS_LR_REF_KEY] = lb_data[
|
||||||
|
ovn_driver.LB_EXT_IDS_LR_REF_KEY]
|
||||||
|
|
||||||
pool_info = {}
|
pool_info = {}
|
||||||
for p in lb_data.get('pools', []):
|
for p in lb_data.get('pools', []):
|
||||||
|
external_ids = _get_lb_field_by_protocol(
|
||||||
|
p.protocol.lower(),
|
||||||
|
field='external_ids')
|
||||||
p_members = ""
|
p_members = ""
|
||||||
for m in p.members:
|
for m in p.members:
|
||||||
if not m.admin_state_up:
|
if not m.admin_state_up:
|
||||||
@ -412,23 +508,31 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
p_members += "," + m_info
|
p_members += "," + m_info
|
||||||
else:
|
else:
|
||||||
p_members = m_info
|
p_members = m_info
|
||||||
|
# Bump up LS refs counter if needed.
|
||||||
|
if m.subnet_id:
|
||||||
|
# Need to get the network_id.
|
||||||
|
for port in self._local_port_cache['ports']:
|
||||||
|
for fixed_ip in port['fixed_ips']:
|
||||||
|
if fixed_ip['subnet_id'] == m.subnet_id:
|
||||||
|
ex = external_ids[
|
||||||
|
ovn_driver.LB_EXT_IDS_LS_REFS_KEY]
|
||||||
|
act = ex.get(
|
||||||
|
'neutron-%s' % port['network_id'], 0)
|
||||||
|
ex['neutron-%s' % port['network_id']] = act + 1
|
||||||
|
break
|
||||||
pool_key = 'pool_' + p.pool_id
|
pool_key = 'pool_' + p.pool_id
|
||||||
if not p.admin_state_up:
|
if not p.admin_state_up:
|
||||||
pool_key += ':D'
|
pool_key += ':D'
|
||||||
external_ids[pool_key] = p_members
|
external_ids[pool_key] = p_members
|
||||||
pool_info[p.pool_id] = p_members
|
pool_info[p.pool_id] = p_members
|
||||||
|
|
||||||
for net_id, ref_ct in lb_data[
|
|
||||||
ovn_driver.LB_EXT_IDS_LS_REFS_KEY].items():
|
|
||||||
external_ids[ovn_driver.LB_EXT_IDS_LS_REFS_KEY][net_id] = ref_ct
|
|
||||||
|
|
||||||
if lb_data.get(ovn_driver.LB_EXT_IDS_LR_REF_KEY):
|
|
||||||
external_ids[
|
|
||||||
ovn_driver.LB_EXT_IDS_LR_REF_KEY] = lb_data[
|
|
||||||
ovn_driver.LB_EXT_IDS_LR_REF_KEY]
|
|
||||||
expected_vips = {}
|
|
||||||
expected_protocol = ['tcp']
|
|
||||||
for l in lb_data['listeners']:
|
for l in lb_data['listeners']:
|
||||||
|
expected_vips = _get_lb_field_by_protocol(
|
||||||
|
l.protocol.lower(),
|
||||||
|
field='vips')
|
||||||
|
external_ids = _get_lb_field_by_protocol(
|
||||||
|
l.protocol.lower(),
|
||||||
|
field='external_ids')
|
||||||
listener_k = 'listener_' + str(l.listener_id)
|
listener_k = 'listener_' + str(l.listener_id)
|
||||||
if lb_data['model'].admin_state_up and l.admin_state_up:
|
if lb_data['model'].admin_state_up and l.admin_state_up:
|
||||||
vip_k = lb_data['model'].vip_address + ":" + str(
|
vip_k = lb_data['model'].vip_address + ":" + str(
|
||||||
@ -447,11 +551,6 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
elif lb_data.get('pools', []):
|
elif lb_data.get('pools', []):
|
||||||
external_ids[listener_k] += 'pool_' + lb_data[
|
external_ids[listener_k] += 'pool_' + lb_data[
|
||||||
'pools'][0].pool_id
|
'pools'][0].pool_id
|
||||||
|
|
||||||
expected_lbs = [{'name': lb_data['model'].loadbalancer_id,
|
|
||||||
'protocol': expected_protocol,
|
|
||||||
'vips': expected_vips,
|
|
||||||
'external_ids': external_ids}]
|
|
||||||
return expected_lbs
|
return expected_lbs
|
||||||
|
|
||||||
def _extract_member_info(self, member):
|
def _extract_member_info(self, member):
|
||||||
@ -462,10 +561,12 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
return mem_info[:-1]
|
return mem_info[:-1]
|
||||||
|
|
||||||
def _create_pool_and_validate(self, lb_data, pool_name,
|
def _create_pool_and_validate(self, lb_data, pool_name,
|
||||||
|
protocol=None,
|
||||||
listener_id=None):
|
listener_id=None):
|
||||||
lb_pools = lb_data['pools']
|
lb_pools = lb_data['pools']
|
||||||
m_pool = self._create_pool_model(lb_data['model'].loadbalancer_id,
|
m_pool = self._create_pool_model(lb_data['model'].loadbalancer_id,
|
||||||
pool_name,
|
pool_name,
|
||||||
|
protocol=protocol,
|
||||||
listener_id=listener_id)
|
listener_id=listener_id)
|
||||||
lb_pools.append(m_pool)
|
lb_pools.append(m_pool)
|
||||||
self._o_driver_lib.update_loadbalancer_status.reset_mock()
|
self._o_driver_lib.update_loadbalancer_status.reset_mock()
|
||||||
@ -567,9 +668,10 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
if pool_name and p.name == pool_name:
|
if pool_name and p.name == pool_name:
|
||||||
return p
|
return p
|
||||||
|
|
||||||
def _get_listener_from_lb_data(self, lb_data, protocol_port):
|
def _get_listener_from_lb_data(self, lb_data, protocol, protocol_port):
|
||||||
for l in lb_data['listeners']:
|
for l in lb_data['listeners']:
|
||||||
if l.protocol_port == protocol_port:
|
if (l.protocol_port == protocol_port and
|
||||||
|
l.protocol == protocol):
|
||||||
return l
|
return l
|
||||||
|
|
||||||
def _get_pool_listeners(self, lb_data, pool_id):
|
def _get_pool_listeners(self, lb_data, pool_id):
|
||||||
@ -721,9 +823,10 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
|
|
||||||
self._wait_for_status_and_validate(lb_data, [expected_status])
|
self._wait_for_status_and_validate(lb_data, [expected_status])
|
||||||
|
|
||||||
def _update_listener_and_validate(self, lb_data, protocol_port,
|
def _update_listener_and_validate(self, lb_data, protocol_port=80,
|
||||||
admin_state_up=None, protocol='TCP'):
|
admin_state_up=None, protocol='TCP'):
|
||||||
m_listener = self._get_listener_from_lb_data(lb_data, protocol_port)
|
m_listener = self._get_listener_from_lb_data(
|
||||||
|
lb_data, protocol, protocol_port)
|
||||||
self._o_driver_lib.update_loadbalancer_status.reset_mock()
|
self._o_driver_lib.update_loadbalancer_status.reset_mock()
|
||||||
old_admin_state_up = m_listener.admin_state_up
|
old_admin_state_up = m_listener.admin_state_up
|
||||||
operating_status = 'ONLINE'
|
operating_status = 'ONLINE'
|
||||||
@ -752,8 +855,10 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
|
|
||||||
self._wait_for_status_and_validate(lb_data, [expected_status])
|
self._wait_for_status_and_validate(lb_data, [expected_status])
|
||||||
|
|
||||||
def _delete_listener_and_validate(self, lb_data, protocol_port=80):
|
def _delete_listener_and_validate(self, lb_data, protocol='TCP',
|
||||||
m_listener = self._get_listener_from_lb_data(lb_data, protocol_port)
|
protocol_port=80):
|
||||||
|
m_listener = self._get_listener_from_lb_data(
|
||||||
|
lb_data, protocol, protocol_port)
|
||||||
lb_data['listeners'].remove(m_listener)
|
lb_data['listeners'].remove(m_listener)
|
||||||
self._o_driver_lib.update_loadbalancer_status.reset_mock()
|
self._o_driver_lib.update_loadbalancer_status.reset_mock()
|
||||||
self.ovn_driver.listener_delete(m_listener)
|
self.ovn_driver.listener_delete(m_listener)
|
||||||
@ -789,7 +894,10 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
expected_status = {
|
expected_status = {
|
||||||
'loadbalancers': [{"id": lb_data['model'].loadbalancer_id,
|
'loadbalancers': [{"id": lb_data['model'].loadbalancer_id,
|
||||||
"provisioning_status": "DELETED",
|
"provisioning_status": "DELETED",
|
||||||
"operating_status": "OFFLINE"}]
|
"operating_status": "OFFLINE"}],
|
||||||
|
'listeners': [],
|
||||||
|
'pools': [],
|
||||||
|
'members': [],
|
||||||
}
|
}
|
||||||
del lb_data['model']
|
del lb_data['model']
|
||||||
self._wait_for_status_and_validate(lb_data, [expected_status])
|
self._wait_for_status_and_validate(lb_data, [expected_status])
|
||||||
@ -798,12 +906,21 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
lb_data = self._create_load_balancer_and_validate(
|
lb_data = self._create_load_balancer_and_validate(
|
||||||
{'vip_network': 'vip_network',
|
{'vip_network': 'vip_network',
|
||||||
'cidr': '10.0.0.0/24'})
|
'cidr': '10.0.0.0/24'})
|
||||||
self._create_pool_and_validate(lb_data, "p1")
|
self._create_pool_and_validate(lb_data, "p1",
|
||||||
|
protocol='TCP')
|
||||||
self._update_pool_and_validate(lb_data, "p1")
|
self._update_pool_and_validate(lb_data, "p1")
|
||||||
self._update_pool_and_validate(lb_data, "p1", admin_state_up=True)
|
self._create_pool_and_validate(lb_data, "p2",
|
||||||
self._update_pool_and_validate(lb_data, "p1", admin_state_up=False)
|
protocol='UDP')
|
||||||
self._update_pool_and_validate(lb_data, "p1", admin_state_up=True)
|
self._create_pool_and_validate(lb_data, "p3",
|
||||||
self._create_pool_and_validate(lb_data, "p2")
|
protocol='TCP')
|
||||||
|
self._update_pool_and_validate(lb_data, "p3",
|
||||||
|
admin_state_up=False)
|
||||||
|
self._update_pool_and_validate(lb_data, "p3",
|
||||||
|
admin_state_up=True)
|
||||||
|
self._update_pool_and_validate(lb_data, "p3",
|
||||||
|
admin_state_up=False)
|
||||||
|
self._create_pool_and_validate(lb_data, "p4",
|
||||||
|
protocol='UDP')
|
||||||
self._delete_pool_and_validate(lb_data, "p2")
|
self._delete_pool_and_validate(lb_data, "p2")
|
||||||
self._delete_pool_and_validate(lb_data, "p1")
|
self._delete_pool_and_validate(lb_data, "p1")
|
||||||
self._delete_load_balancer_and_validate(lb_data)
|
self._delete_load_balancer_and_validate(lb_data)
|
||||||
@ -812,50 +929,72 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
lb_data = self._create_load_balancer_and_validate(
|
lb_data = self._create_load_balancer_and_validate(
|
||||||
{'vip_network': 'vip_network',
|
{'vip_network': 'vip_network',
|
||||||
'cidr': '10.0.0.0/24'})
|
'cidr': '10.0.0.0/24'})
|
||||||
self._create_pool_and_validate(lb_data, "p1")
|
|
||||||
pool_id = lb_data['pools'][0].pool_id
|
|
||||||
self._create_member_and_validate(
|
|
||||||
lb_data, pool_id, lb_data['vip_net_info'][1],
|
|
||||||
lb_data['vip_net_info'][0], '10.0.0.10')
|
|
||||||
self._update_member_and_validate(lb_data, pool_id, "10.0.0.10")
|
|
||||||
|
|
||||||
|
# TCP Pool
|
||||||
|
self._create_pool_and_validate(lb_data, "p1",
|
||||||
|
protocol='TCP')
|
||||||
|
|
||||||
|
# UDP Pool
|
||||||
|
self._create_pool_and_validate(lb_data, "p2",
|
||||||
|
protocol='UDP')
|
||||||
|
|
||||||
|
pool_1_id = lb_data['pools'][0].pool_id
|
||||||
|
pool_2_id = lb_data['pools'][1].pool_id
|
||||||
|
|
||||||
|
# Members for TCP Pool
|
||||||
self._create_member_and_validate(
|
self._create_member_and_validate(
|
||||||
lb_data, pool_id, lb_data['vip_net_info'][1],
|
lb_data, pool_1_id, lb_data['vip_net_info'][1],
|
||||||
|
lb_data['vip_net_info'][0], '10.0.0.10')
|
||||||
|
self._update_member_and_validate(lb_data, pool_1_id, "10.0.0.10")
|
||||||
|
self._create_member_and_validate(
|
||||||
|
lb_data, pool_1_id, lb_data['vip_net_info'][1],
|
||||||
|
lb_data['vip_net_info'][0], '10.0.0.11')
|
||||||
|
|
||||||
|
# Members for UDP Pool
|
||||||
|
self._create_member_and_validate(
|
||||||
|
lb_data, pool_2_id, lb_data['vip_net_info'][1],
|
||||||
|
lb_data['vip_net_info'][0], '10.0.0.10')
|
||||||
|
self._update_member_and_validate(lb_data, pool_1_id, "10.0.0.10")
|
||||||
|
self._create_member_and_validate(
|
||||||
|
lb_data, pool_2_id, lb_data['vip_net_info'][1],
|
||||||
lb_data['vip_net_info'][0], '10.0.0.11')
|
lb_data['vip_net_info'][0], '10.0.0.11')
|
||||||
|
|
||||||
# Disable loadbalancer
|
# Disable loadbalancer
|
||||||
self._update_load_balancer_and_validate(lb_data,
|
self._update_load_balancer_and_validate(lb_data,
|
||||||
admin_state_up=False)
|
admin_state_up=False)
|
||||||
|
|
||||||
# Enable loadbalancer back
|
# Enable loadbalancer back
|
||||||
self._update_load_balancer_and_validate(lb_data,
|
self._update_load_balancer_and_validate(lb_data,
|
||||||
admin_state_up=True)
|
admin_state_up=True)
|
||||||
self._delete_member_and_validate(lb_data, pool_id,
|
|
||||||
|
# Delete members from TCP Pool
|
||||||
|
self._delete_member_and_validate(lb_data, pool_1_id,
|
||||||
lb_data['vip_net_info'][0],
|
lb_data['vip_net_info'][0],
|
||||||
'10.0.0.10')
|
'10.0.0.10')
|
||||||
self._delete_member_and_validate(lb_data, pool_id,
|
self._delete_member_and_validate(lb_data, pool_1_id,
|
||||||
lb_data['vip_net_info'][0],
|
lb_data['vip_net_info'][0],
|
||||||
'10.0.0.11')
|
'10.0.0.11')
|
||||||
|
# Add again member to TCP Pool
|
||||||
self._create_member_and_validate(
|
self._create_member_and_validate(
|
||||||
lb_data, pool_id, lb_data['vip_net_info'][1],
|
lb_data, pool_1_id, lb_data['vip_net_info'][1],
|
||||||
lb_data['vip_net_info'][0], '10.0.0.10')
|
lb_data['vip_net_info'][0], '10.0.0.10')
|
||||||
|
|
||||||
|
# Create new networks and add member to TCP pool from it.
|
||||||
net20_info = self._create_net('net20', '20.0.0.0/24')
|
net20_info = self._create_net('net20', '20.0.0.0/24')
|
||||||
net20 = net20_info[0]
|
net20 = net20_info[0]
|
||||||
subnet20 = net20_info[1]
|
subnet20 = net20_info[1]
|
||||||
self._create_member_and_validate(lb_data, pool_id, subnet20, net20,
|
self._create_member_and_validate(lb_data, pool_1_id, subnet20, net20,
|
||||||
'20.0.0.4')
|
'20.0.0.4')
|
||||||
self._create_member_and_validate(lb_data, pool_id, subnet20, net20,
|
self._create_member_and_validate(lb_data, pool_1_id, subnet20, net20,
|
||||||
'20.0.0.6')
|
'20.0.0.6')
|
||||||
net30_info = self._create_net('net30', '30.0.0.0/24')
|
net30_info = self._create_net('net30', '30.0.0.0/24')
|
||||||
net30 = net30_info[0]
|
net30 = net30_info[0]
|
||||||
subnet30 = net30_info[1]
|
subnet30 = net30_info[1]
|
||||||
self._create_member_and_validate(lb_data, pool_id, subnet30, net30,
|
self._create_member_and_validate(lb_data, pool_1_id, subnet30, net30,
|
||||||
'30.0.0.6')
|
'30.0.0.6')
|
||||||
self._delete_member_and_validate(lb_data, pool_id, net20, '20.0.0.6')
|
self._delete_member_and_validate(lb_data, pool_1_id, net20, '20.0.0.6')
|
||||||
|
|
||||||
# Test creating Member without subnet
|
# Test creating Member without subnet
|
||||||
m_member = self._create_member_model(pool_id,
|
m_member = self._create_member_model(pool_1_id,
|
||||||
None,
|
None,
|
||||||
'30.0.0.7', 80)
|
'30.0.0.7', 80)
|
||||||
self.assertRaises(o_exceptions.UnsupportedOptionError,
|
self.assertRaises(o_exceptions.UnsupportedOptionError,
|
||||||
@ -863,36 +1002,76 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
|
|
||||||
# Deleting the pool should also delete the members.
|
# Deleting the pool should also delete the members.
|
||||||
self._delete_pool_and_validate(lb_data, "p1")
|
self._delete_pool_and_validate(lb_data, "p1")
|
||||||
|
|
||||||
|
# Delete the whole LB.
|
||||||
self._delete_load_balancer_and_validate(lb_data)
|
self._delete_load_balancer_and_validate(lb_data)
|
||||||
|
|
||||||
def test_listener(self):
|
def test_listener(self):
|
||||||
lb_data = self._create_load_balancer_and_validate(
|
lb_data = self._create_load_balancer_and_validate(
|
||||||
{'vip_network': 'vip_network',
|
{'vip_network': 'vip_network',
|
||||||
'cidr': '10.0.0.0/24'})
|
'cidr': '10.0.0.0/24'})
|
||||||
self._create_pool_and_validate(lb_data, "p1")
|
self._create_pool_and_validate(lb_data, "p1",
|
||||||
pool_id = lb_data['pools'][0].pool_id
|
protocol='TCP')
|
||||||
self._create_member_and_validate(
|
self._create_pool_and_validate(lb_data, "p2",
|
||||||
lb_data, pool_id, lb_data['vip_net_info'][1],
|
protocol='UDP')
|
||||||
lb_data['vip_net_info'][0], '10.0.0.4')
|
pool_1_id = lb_data['pools'][0].pool_id
|
||||||
|
pool_2_id = lb_data['pools'][1].pool_id
|
||||||
net_info = self._create_net('net1', '20.0.0.0/24')
|
net_info = self._create_net('net1', '20.0.0.0/24')
|
||||||
self._create_member_and_validate(lb_data, pool_id,
|
|
||||||
net_info[1], net_info[0], '20.0.0.4')
|
|
||||||
self._create_listener_and_validate(lb_data, pool_id, 80)
|
|
||||||
self._update_listener_and_validate(lb_data, 80)
|
|
||||||
self._update_listener_and_validate(lb_data, 80, admin_state_up=True)
|
|
||||||
self._update_listener_and_validate(lb_data, 80, admin_state_up=False)
|
|
||||||
self._update_listener_and_validate(lb_data, 80, admin_state_up=True)
|
|
||||||
self._create_listener_and_validate(lb_data, pool_id, 82)
|
|
||||||
|
|
||||||
self._delete_listener_and_validate(lb_data, 82)
|
# Create member in first pool
|
||||||
self._delete_listener_and_validate(lb_data, 80)
|
self._create_member_and_validate(
|
||||||
self._delete_member_and_validate(lb_data, pool_id,
|
lb_data, pool_1_id, lb_data['vip_net_info'][1],
|
||||||
|
lb_data['vip_net_info'][0], '10.0.0.4')
|
||||||
|
self._create_member_and_validate(lb_data, pool_1_id,
|
||||||
|
net_info[1], net_info[0], '20.0.0.4')
|
||||||
|
|
||||||
|
# Create member in second pool
|
||||||
|
self._create_member_and_validate(
|
||||||
|
lb_data, pool_2_id, lb_data['vip_net_info'][1],
|
||||||
|
lb_data['vip_net_info'][0], '10.0.0.4')
|
||||||
|
self._create_member_and_validate(lb_data, pool_2_id,
|
||||||
|
net_info[1], net_info[0], '20.0.0.4')
|
||||||
|
|
||||||
|
# Play around first listener linked to first pool.
|
||||||
|
self._create_listener_and_validate(
|
||||||
|
lb_data, pool_1_id, 80, protocol='TCP')
|
||||||
|
self._update_listener_and_validate(lb_data, protocol_port=80)
|
||||||
|
self._update_listener_and_validate(
|
||||||
|
lb_data, protocol_port=80, admin_state_up=True)
|
||||||
|
self._update_listener_and_validate(
|
||||||
|
lb_data, protocol_port=80, admin_state_up=False)
|
||||||
|
self._update_listener_and_validate(
|
||||||
|
lb_data, protocol_port=80, admin_state_up=True)
|
||||||
|
self._create_listener_and_validate(
|
||||||
|
lb_data, pool_1_id, protocol_port=82, protocol='TCP')
|
||||||
|
|
||||||
|
# Play around second listener linked to second pool.
|
||||||
|
self._create_listener_and_validate(
|
||||||
|
lb_data, pool_2_id, 53, protocol='UDP')
|
||||||
|
self._update_listener_and_validate(lb_data, 53, protocol='UDP')
|
||||||
|
self._update_listener_and_validate(
|
||||||
|
lb_data, protocol_port=53, protocol='UDP', admin_state_up=True)
|
||||||
|
self._update_listener_and_validate(
|
||||||
|
lb_data, protocol_port=53, protocol='UDP', admin_state_up=False)
|
||||||
|
self._update_listener_and_validate(
|
||||||
|
lb_data, protocol_port=53, protocol='UDP', admin_state_up=True)
|
||||||
|
self._create_listener_and_validate(
|
||||||
|
lb_data, pool_2_id, protocol_port=21, protocol='UDP')
|
||||||
|
|
||||||
|
# Delete listeners linked to first pool.
|
||||||
|
self._delete_listener_and_validate(
|
||||||
|
lb_data, protocol_port=82, protocol='TCP')
|
||||||
|
self._delete_listener_and_validate(
|
||||||
|
lb_data, protocol_port=80, protocol='TCP')
|
||||||
|
# Delete first pool members.
|
||||||
|
self._delete_member_and_validate(lb_data, pool_1_id,
|
||||||
net_info[0], '20.0.0.4')
|
net_info[0], '20.0.0.4')
|
||||||
self._delete_member_and_validate(lb_data, pool_id,
|
self._delete_member_and_validate(lb_data, pool_1_id,
|
||||||
lb_data['vip_net_info'][0],
|
lb_data['vip_net_info'][0],
|
||||||
'10.0.0.4')
|
'10.0.0.4')
|
||||||
|
# Delete empty, first pool
|
||||||
self._delete_pool_and_validate(lb_data, "p1")
|
self._delete_pool_and_validate(lb_data, "p1")
|
||||||
|
# Delete the rest
|
||||||
self._delete_load_balancer_and_validate(lb_data)
|
self._delete_load_balancer_and_validate(lb_data)
|
||||||
|
|
||||||
def _test_cascade_delete(self, pool=True, listener=True, member=True):
|
def _test_cascade_delete(self, pool=True, listener=True, member=True):
|
||||||
@ -900,14 +1079,22 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
{'vip_network': 'vip_network',
|
{'vip_network': 'vip_network',
|
||||||
'cidr': '10.0.0.0/24'})
|
'cidr': '10.0.0.0/24'})
|
||||||
if pool:
|
if pool:
|
||||||
self._create_pool_and_validate(lb_data, "p1")
|
self._create_pool_and_validate(lb_data, "p1", protocol='TCP')
|
||||||
pool_id = lb_data['pools'][0].pool_id
|
self._create_pool_and_validate(lb_data, "p2", protocol='UDP')
|
||||||
|
pool_1_id = lb_data['pools'][0].pool_id
|
||||||
|
pool_2_id = lb_data['pools'][1].pool_id
|
||||||
if member:
|
if member:
|
||||||
self._create_member_and_validate(
|
self._create_member_and_validate(
|
||||||
lb_data, pool_id, lb_data['vip_net_info'][1],
|
lb_data, pool_1_id, lb_data['vip_net_info'][1],
|
||||||
|
lb_data['vip_net_info'][0], '10.0.0.10')
|
||||||
|
self._create_member_and_validate(
|
||||||
|
lb_data, pool_2_id, lb_data['vip_net_info'][1],
|
||||||
lb_data['vip_net_info'][0], '10.0.0.10')
|
lb_data['vip_net_info'][0], '10.0.0.10')
|
||||||
if listener:
|
if listener:
|
||||||
self._create_listener_and_validate(lb_data, pool_id, 80)
|
self._create_listener_and_validate(
|
||||||
|
lb_data, pool_1_id, protocol_port=80, protocol='TCP')
|
||||||
|
self._create_listener_and_validate(
|
||||||
|
lb_data, pool_2_id, protocol_port=53, protocol='UDP')
|
||||||
|
|
||||||
self._delete_load_balancer_and_validate(lb_data, cascade=True)
|
self._delete_load_balancer_and_validate(lb_data, cascade=True)
|
||||||
|
|
||||||
@ -937,12 +1124,6 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
self.assertRaises(o_exceptions.UnsupportedOptionError,
|
self.assertRaises(o_exceptions.UnsupportedOptionError,
|
||||||
self.ovn_driver.listener_create, m_listener)
|
self.ovn_driver.listener_create, m_listener)
|
||||||
self._create_listener_and_validate(lb_data)
|
self._create_listener_and_validate(lb_data)
|
||||||
self.assertRaises(o_exceptions.UnsupportedOptionError,
|
|
||||||
self._create_listener_and_validate,
|
|
||||||
lb_data, protocol_port=80, protocol='UDP')
|
|
||||||
self.assertRaises(o_exceptions.UnsupportedOptionError,
|
|
||||||
self._update_listener_and_validate,
|
|
||||||
lb_data, protocol_port=80, protocol='UDP')
|
|
||||||
self._delete_load_balancer_and_validate(lb_data)
|
self._delete_load_balancer_and_validate(lb_data)
|
||||||
|
|
||||||
def _test_lrp_event_handler(self, cascade=False):
|
def _test_lrp_event_handler(self, cascade=False):
|
||||||
@ -1065,10 +1246,10 @@ class TestOctaviaOvnProviderDriver(
|
|||||||
{'vip_network': 'vip_network',
|
{'vip_network': 'vip_network',
|
||||||
'cidr': '10.0.0.0/24'})
|
'cidr': '10.0.0.0/24'})
|
||||||
self._create_listener_and_validate(lb_data)
|
self._create_listener_and_validate(lb_data)
|
||||||
self._create_pool_and_validate(lb_data, "p1",
|
self._create_pool_and_validate(
|
||||||
lb_data['listeners'][0].listener_id)
|
lb_data, "p1", listener_id=lb_data['listeners'][0].listener_id)
|
||||||
self._delete_pool_and_validate(lb_data, "p1",
|
self._delete_pool_and_validate(
|
||||||
lb_data['listeners'][0].listener_id)
|
lb_data, "p1", listener_id=lb_data['listeners'][0].listener_id)
|
||||||
self._delete_listener_and_validate(lb_data)
|
self._delete_listener_and_validate(lb_data)
|
||||||
self._delete_load_balancer_and_validate(lb_data)
|
self._delete_load_balancer_and_validate(lb_data)
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# 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 copy
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
@ -134,6 +135,7 @@ class TestOvnProviderDriver(TestOvnOctaviaBase):
|
|||||||
add_req_thread = mock.patch.object(ovn_driver.OvnProviderHelper,
|
add_req_thread = mock.patch.object(ovn_driver.OvnProviderHelper,
|
||||||
'add_request')
|
'add_request')
|
||||||
self.ovn_lb = mock.MagicMock()
|
self.ovn_lb = mock.MagicMock()
|
||||||
|
self.ovn_lb.name = 'foo_ovn_lb'
|
||||||
self.ovn_lb.external_ids = {
|
self.ovn_lb.external_ids = {
|
||||||
ovn_driver.LB_EXT_IDS_VIP_KEY: '10.22.33.4'}
|
ovn_driver.LB_EXT_IDS_VIP_KEY: '10.22.33.4'}
|
||||||
self.mock_add_request = add_req_thread.start()
|
self.mock_add_request = add_req_thread.start()
|
||||||
@ -262,8 +264,10 @@ class TestOvnProviderDriver(TestOvnOctaviaBase):
|
|||||||
project_id=self.project_id,
|
project_id=self.project_id,
|
||||||
vip_address=self.vip_address,
|
vip_address=self.vip_address,
|
||||||
vip_network_id=self.vip_network_id)
|
vip_network_id=self.vip_network_id)
|
||||||
mock.patch.object(ovn_driver.OvnProviderHelper, '_find_ovn_lb',
|
mock.patch.object(
|
||||||
return_value=self.ovn_lb).start()
|
ovn_driver.OvnProviderHelper, '_find_ovn_lbs',
|
||||||
|
side_effect=lambda x, protocol=None:
|
||||||
|
self.ovn_lb if protocol else [self.ovn_lb]).start()
|
||||||
mock.patch.object(
|
mock.patch.object(
|
||||||
ovn_driver.OvnProviderHelper, 'get_member_info',
|
ovn_driver.OvnProviderHelper, 'get_member_info',
|
||||||
return_value=[
|
return_value=[
|
||||||
@ -438,9 +442,32 @@ class TestOvnProviderDriver(TestOvnOctaviaBase):
|
|||||||
self.driver.listener_create(self.ref_listener)
|
self.driver.listener_create(self.ref_listener)
|
||||||
self.mock_add_request.assert_called_once_with(expected_dict)
|
self.mock_add_request.assert_called_once_with(expected_dict)
|
||||||
|
|
||||||
|
def test_listener_create_unsupported_protocol(self):
|
||||||
|
self.assertRaises(exceptions.UnsupportedOptionError,
|
||||||
|
self.driver.listener_create, self.fail_listener)
|
||||||
|
|
||||||
|
def test_listener_create_multiple_protocols(self):
|
||||||
|
self.ovn_lb.protocol = ['tcp']
|
||||||
|
info = {'id': self.ref_listener.listener_id,
|
||||||
|
'protocol': self.ref_listener.protocol,
|
||||||
|
'protocol_port': self.ref_listener.protocol_port,
|
||||||
|
'default_pool_id': self.ref_listener.default_pool_id,
|
||||||
|
'admin_state_up': self.ref_listener.admin_state_up,
|
||||||
|
'loadbalancer_id': self.ref_listener.loadbalancer_id}
|
||||||
|
expected_dict = {'type': ovn_driver.REQ_TYPE_LISTENER_CREATE,
|
||||||
|
'info': info}
|
||||||
|
self.driver.listener_create(self.ref_listener)
|
||||||
|
self.mock_add_request.assert_called_once_with(expected_dict)
|
||||||
|
self.ovn_lb.protocol = ['UDP']
|
||||||
|
info['protocol'] = 'UDP'
|
||||||
|
expected_dict = {'type': ovn_driver.REQ_TYPE_LISTENER_CREATE,
|
||||||
|
'info': info}
|
||||||
|
self.driver.listener_create(self.ref_listener)
|
||||||
|
|
||||||
def test_listener_update(self):
|
def test_listener_update(self):
|
||||||
info = {'id': self.ref_listener.listener_id,
|
info = {'id': self.ref_listener.listener_id,
|
||||||
'protocol_port': self.ref_listener.protocol_port,
|
'protocol_port': self.ref_listener.protocol_port,
|
||||||
|
'protocol': self.ref_pool.protocol,
|
||||||
'admin_state_up': self.ref_listener.admin_state_up,
|
'admin_state_up': self.ref_listener.admin_state_up,
|
||||||
'loadbalancer_id': self.ref_listener.loadbalancer_id}
|
'loadbalancer_id': self.ref_listener.loadbalancer_id}
|
||||||
if self.ref_listener.default_pool_id:
|
if self.ref_listener.default_pool_id:
|
||||||
@ -450,22 +477,10 @@ class TestOvnProviderDriver(TestOvnOctaviaBase):
|
|||||||
self.driver.listener_update(self.ref_listener, self.ref_listener)
|
self.driver.listener_update(self.ref_listener, self.ref_listener)
|
||||||
self.mock_add_request.assert_called_once_with(expected_dict)
|
self.mock_add_request.assert_called_once_with(expected_dict)
|
||||||
|
|
||||||
@mock.patch.object(ovn_driver.OvnProviderHelper, '_is_listener_in_lb',
|
|
||||||
return_value=True)
|
|
||||||
def test_listener_failure(self, mock_listener):
|
|
||||||
self.assertRaises(exceptions.UnsupportedOptionError,
|
|
||||||
self.driver.listener_create, self.fail_listener)
|
|
||||||
self.assertRaises(exceptions.UnsupportedOptionError,
|
|
||||||
self.driver.listener_update, self.ref_listener,
|
|
||||||
self.fail_listener)
|
|
||||||
self.ovn_lb.protocol = ['TCP']
|
|
||||||
self.assertRaises(exceptions.UnsupportedOptionError,
|
|
||||||
self.driver.listener_create,
|
|
||||||
self.ref_listener_udp)
|
|
||||||
|
|
||||||
def test_listener_delete(self):
|
def test_listener_delete(self):
|
||||||
info = {'id': self.ref_listener.listener_id,
|
info = {'id': self.ref_listener.listener_id,
|
||||||
'protocol_port': self.ref_listener.protocol_port,
|
'protocol_port': self.ref_listener.protocol_port,
|
||||||
|
'protocol': self.ref_pool.protocol,
|
||||||
'loadbalancer_id': self.ref_listener.loadbalancer_id}
|
'loadbalancer_id': self.ref_listener.loadbalancer_id}
|
||||||
expected_dict = {'type': ovn_driver.REQ_TYPE_LISTENER_DELETE,
|
expected_dict = {'type': ovn_driver.REQ_TYPE_LISTENER_DELETE,
|
||||||
'info': info}
|
'info': info}
|
||||||
@ -516,7 +531,7 @@ class TestOvnProviderDriver(TestOvnOctaviaBase):
|
|||||||
self.driver.loadbalancer_failover(info['id'])
|
self.driver.loadbalancer_failover(info['id'])
|
||||||
self.mock_add_request.assert_called_once_with(expected_dict)
|
self.mock_add_request.assert_called_once_with(expected_dict)
|
||||||
|
|
||||||
def test_pool_create_http(self):
|
def test_pool_create_unsupported_protocol(self):
|
||||||
self.ref_pool.protocol = 'HTTP'
|
self.ref_pool.protocol = 'HTTP'
|
||||||
self.assertRaises(exceptions.UnsupportedOptionError,
|
self.assertRaises(exceptions.UnsupportedOptionError,
|
||||||
self.driver.pool_create, self.ref_pool)
|
self.driver.pool_create, self.ref_pool)
|
||||||
@ -530,6 +545,7 @@ class TestOvnProviderDriver(TestOvnOctaviaBase):
|
|||||||
info = {'id': self.ref_pool.pool_id,
|
info = {'id': self.ref_pool.pool_id,
|
||||||
'loadbalancer_id': self.ref_pool.loadbalancer_id,
|
'loadbalancer_id': self.ref_pool.loadbalancer_id,
|
||||||
'listener_id': self.ref_pool.listener_id,
|
'listener_id': self.ref_pool.listener_id,
|
||||||
|
'protocol': self.ref_pool.protocol,
|
||||||
'admin_state_up': self.ref_pool.admin_state_up}
|
'admin_state_up': self.ref_pool.admin_state_up}
|
||||||
expected_dict = {'type': ovn_driver.REQ_TYPE_POOL_CREATE,
|
expected_dict = {'type': ovn_driver.REQ_TYPE_POOL_CREATE,
|
||||||
'info': info}
|
'info': info}
|
||||||
@ -540,6 +556,7 @@ class TestOvnProviderDriver(TestOvnOctaviaBase):
|
|||||||
self.ref_pool.admin_state_up = data_models.UnsetType()
|
self.ref_pool.admin_state_up = data_models.UnsetType()
|
||||||
info = {'id': self.ref_pool.pool_id,
|
info = {'id': self.ref_pool.pool_id,
|
||||||
'loadbalancer_id': self.ref_pool.loadbalancer_id,
|
'loadbalancer_id': self.ref_pool.loadbalancer_id,
|
||||||
|
'protocol': self.ref_pool.protocol,
|
||||||
'listener_id': self.ref_pool.listener_id,
|
'listener_id': self.ref_pool.listener_id,
|
||||||
'admin_state_up': True}
|
'admin_state_up': True}
|
||||||
expected_dict = {'type': ovn_driver.REQ_TYPE_POOL_CREATE,
|
expected_dict = {'type': ovn_driver.REQ_TYPE_POOL_CREATE,
|
||||||
@ -551,6 +568,7 @@ class TestOvnProviderDriver(TestOvnOctaviaBase):
|
|||||||
# Pretent we don't have members
|
# Pretent we don't have members
|
||||||
self.ref_pool.members = []
|
self.ref_pool.members = []
|
||||||
info = {'id': self.ref_pool.pool_id,
|
info = {'id': self.ref_pool.pool_id,
|
||||||
|
'protocol': self.ref_pool.protocol,
|
||||||
'loadbalancer_id': self.ref_pool.loadbalancer_id}
|
'loadbalancer_id': self.ref_pool.loadbalancer_id}
|
||||||
expected = {'type': ovn_driver.REQ_TYPE_POOL_DELETE,
|
expected = {'type': ovn_driver.REQ_TYPE_POOL_DELETE,
|
||||||
'info': info}
|
'info': info}
|
||||||
@ -559,6 +577,7 @@ class TestOvnProviderDriver(TestOvnOctaviaBase):
|
|||||||
|
|
||||||
def test_pool_delete_with_members(self):
|
def test_pool_delete_with_members(self):
|
||||||
info = {'id': self.ref_pool.pool_id,
|
info = {'id': self.ref_pool.pool_id,
|
||||||
|
'protocol': self.ref_pool.protocol,
|
||||||
'loadbalancer_id': self.ref_pool.loadbalancer_id}
|
'loadbalancer_id': self.ref_pool.loadbalancer_id}
|
||||||
expected = {'type': ovn_driver.REQ_TYPE_POOL_DELETE,
|
expected = {'type': ovn_driver.REQ_TYPE_POOL_DELETE,
|
||||||
'info': info}
|
'info': info}
|
||||||
@ -578,6 +597,7 @@ class TestOvnProviderDriver(TestOvnOctaviaBase):
|
|||||||
def test_pool_update(self):
|
def test_pool_update(self):
|
||||||
info = {'id': self.ref_update_pool.pool_id,
|
info = {'id': self.ref_update_pool.pool_id,
|
||||||
'loadbalancer_id': self.ref_update_pool.loadbalancer_id,
|
'loadbalancer_id': self.ref_update_pool.loadbalancer_id,
|
||||||
|
'protocol': self.ref_pool.protocol,
|
||||||
'admin_state_up': self.ref_update_pool.admin_state_up}
|
'admin_state_up': self.ref_update_pool.admin_state_up}
|
||||||
expected_dict = {'type': ovn_driver.REQ_TYPE_POOL_UPDATE,
|
expected_dict = {'type': ovn_driver.REQ_TYPE_POOL_UPDATE,
|
||||||
'info': info}
|
'info': info}
|
||||||
@ -629,10 +649,12 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
'admin_state_up': False}
|
'admin_state_up': False}
|
||||||
self.ports = {'ports': [{
|
self.ports = {'ports': [{
|
||||||
'fixed_ips': [{'ip_address': self.vip_address}],
|
'fixed_ips': [{'ip_address': self.vip_address}],
|
||||||
|
'network_id': self.vip_network_id,
|
||||||
'id': self.port1_id}]}
|
'id': self.port1_id}]}
|
||||||
self.pool = {'id': self.pool_id,
|
self.pool = {'id': self.pool_id,
|
||||||
'loadbalancer_id': self.loadbalancer_id,
|
'loadbalancer_id': self.loadbalancer_id,
|
||||||
'listener_id': self.listener_id,
|
'listener_id': self.listener_id,
|
||||||
|
'protocol': "TCP",
|
||||||
'admin_state_up': False}
|
'admin_state_up': False}
|
||||||
self.member = {'id': self.member_id,
|
self.member = {'id': self.member_id,
|
||||||
'address': self.member_address,
|
'address': self.member_address,
|
||||||
@ -646,6 +668,7 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
'add_request')
|
'add_request')
|
||||||
self.mock_add_request = add_req_thread.start()
|
self.mock_add_request = add_req_thread.start()
|
||||||
self.ovn_lb = mock.MagicMock()
|
self.ovn_lb = mock.MagicMock()
|
||||||
|
self.ovn_lb.protocol = ['tcp']
|
||||||
self.ovn_lb.uuid = uuidutils.generate_uuid()
|
self.ovn_lb.uuid = uuidutils.generate_uuid()
|
||||||
self.member_line = (
|
self.member_line = (
|
||||||
'member_%s_%s:%s' %
|
'member_%s_%s:%s' %
|
||||||
@ -664,8 +687,13 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
mock.patch.object(self.helper,
|
mock.patch.object(self.helper,
|
||||||
'_find_ovn_lb_with_pool_key',
|
'_find_ovn_lb_with_pool_key',
|
||||||
return_value=self.ovn_lb).start()
|
return_value=self.ovn_lb).start()
|
||||||
mock.patch.object(ovn_driver.OvnProviderHelper, '_find_ovn_lb',
|
|
||||||
return_value=self.ovn_lb).start()
|
self.mock_find_ovn_lbs = mock.patch.object(
|
||||||
|
ovn_driver.OvnProviderHelper, '_find_ovn_lbs',
|
||||||
|
side_effect=lambda x, protocol=None:
|
||||||
|
self.ovn_lb if protocol else [self.ovn_lb])
|
||||||
|
self.mock_find_ovn_lbs.start()
|
||||||
|
|
||||||
mock.patch.object(self.helper,
|
mock.patch.object(self.helper,
|
||||||
'_get_pool_listeners',
|
'_get_pool_listeners',
|
||||||
return_value=[]).start()
|
return_value=[]).start()
|
||||||
@ -727,6 +755,114 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
(self.helper.ovn_nbdb_api.ls_get.return_value.
|
(self.helper.ovn_nbdb_api.ls_get.return_value.
|
||||||
execute.return_value) = self.network
|
execute.return_value) = self.network
|
||||||
|
|
||||||
|
def test__is_lb_empty(self):
|
||||||
|
f = self.helper._is_lb_empty
|
||||||
|
self.assertFalse(f(self.ovn_lb.external_ids))
|
||||||
|
self.ovn_lb.external_ids.pop('listener_%s' % self.listener_id)
|
||||||
|
self.assertFalse(f(self.ovn_lb.external_ids))
|
||||||
|
self.ovn_lb.external_ids.pop('pool_%s' % self.pool_id)
|
||||||
|
self.assertTrue(f(self.ovn_lb.external_ids))
|
||||||
|
|
||||||
|
def test__find_ovn_lbs(self):
|
||||||
|
self.mock_find_ovn_lbs.stop()
|
||||||
|
f = self.helper._find_ovn_lbs
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
|
||||||
|
execute.return_value = [self.ovn_lb]
|
||||||
|
|
||||||
|
# Without protocol specified return a list
|
||||||
|
found = f(self.ovn_lb.id)
|
||||||
|
self.assertListEqual(found, [self.ovn_lb])
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.assert_called_once_with(
|
||||||
|
'Load_Balancer', ('name', '=', self.ovn_lb.id))
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.reset_mock()
|
||||||
|
|
||||||
|
# With protocol specified return an instance
|
||||||
|
found = f(self.ovn_lb.id, protocol='tcp')
|
||||||
|
self.assertEqual(found, self.ovn_lb)
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.reset_mock()
|
||||||
|
|
||||||
|
# LB with given protocol not found
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
|
||||||
|
execute.return_value = []
|
||||||
|
self.assertRaises(
|
||||||
|
idlutils.RowNotFound,
|
||||||
|
f,
|
||||||
|
self.ovn_lb.id,
|
||||||
|
protocol='UDP')
|
||||||
|
|
||||||
|
# Multiple protocols
|
||||||
|
udp_lb = copy.copy(self.ovn_lb)
|
||||||
|
udp_lb.protocol = ['udp']
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
|
||||||
|
execute.return_value = [self.ovn_lb, udp_lb]
|
||||||
|
found = f(self.ovn_lb.id)
|
||||||
|
self.assertListEqual(found, [self.ovn_lb, udp_lb])
|
||||||
|
|
||||||
|
def test__get_or_create_ovn_lb_no_lb_found(self):
|
||||||
|
self.mock_find_ovn_lbs.stop()
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
|
||||||
|
execute.return_value = []
|
||||||
|
self.assertRaises(
|
||||||
|
idlutils.RowNotFound,
|
||||||
|
self.helper._get_or_create_ovn_lb,
|
||||||
|
self.ovn_lb.name,
|
||||||
|
protocol='TCP',
|
||||||
|
admin_state_up='True')
|
||||||
|
|
||||||
|
@mock.patch.object(ovn_driver.OvnProviderHelper, 'lb_create')
|
||||||
|
def test__get_or_create_ovn_lb_required_proto_not_found(self, lbc):
|
||||||
|
udp_lb = copy.copy(self.ovn_lb)
|
||||||
|
udp_lb.protocol = ['udp']
|
||||||
|
self.mock_find_ovn_lbs.stop()
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
|
||||||
|
execute.side_effect = [[udp_lb], [self.ovn_lb]]
|
||||||
|
self.helper._get_or_create_ovn_lb(
|
||||||
|
self.ovn_lb.name,
|
||||||
|
protocol='TCP',
|
||||||
|
admin_state_up='True')
|
||||||
|
expected_lb_info = {
|
||||||
|
'id': self.ovn_lb.name,
|
||||||
|
'protocol': 'tcp',
|
||||||
|
'vip_address': udp_lb.external_ids.get(
|
||||||
|
ovn_driver.LB_EXT_IDS_VIP_KEY),
|
||||||
|
'vip_port_id':
|
||||||
|
udp_lb.external_ids.get(
|
||||||
|
ovn_driver.LB_EXT_IDS_VIP_PORT_ID_KEY),
|
||||||
|
ovn_driver.LB_EXT_IDS_LR_REF_KEY:
|
||||||
|
udp_lb.external_ids.get(
|
||||||
|
ovn_driver.LB_EXT_IDS_LR_REF_KEY),
|
||||||
|
ovn_driver.LB_EXT_IDS_LS_REFS_KEY:
|
||||||
|
udp_lb.external_ids.get(
|
||||||
|
ovn_driver.LB_EXT_IDS_LS_REFS_KEY),
|
||||||
|
'admin_state_up': 'True',
|
||||||
|
ovn_driver.LB_EXT_IDS_VIP_FIP_KEY:
|
||||||
|
udp_lb.external_ids.get(
|
||||||
|
ovn_driver.LB_EXT_IDS_VIP_FIP_KEY)}
|
||||||
|
lbc.assert_called_once_with(expected_lb_info, protocol='tcp')
|
||||||
|
|
||||||
|
def test__get_or_create_ovn_lb_found(self):
|
||||||
|
self.mock_find_ovn_lbs.stop()
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
|
||||||
|
execute.return_value = [self.ovn_lb]
|
||||||
|
found = self.helper._get_or_create_ovn_lb(
|
||||||
|
self.ovn_lb.name,
|
||||||
|
protocol='TCP',
|
||||||
|
admin_state_up='True')
|
||||||
|
self.assertEqual(found, self.ovn_lb)
|
||||||
|
|
||||||
|
def test__get_or_create_ovn_lb_lb_without_protocol(self):
|
||||||
|
self.mock_find_ovn_lbs.stop()
|
||||||
|
self.ovn_lb.protocol = []
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
|
||||||
|
execute.return_value = [self.ovn_lb]
|
||||||
|
found = self.helper._get_or_create_ovn_lb(
|
||||||
|
self.ovn_lb.name,
|
||||||
|
protocol='TCP',
|
||||||
|
admin_state_up='True')
|
||||||
|
self.assertEqual(found, self.ovn_lb)
|
||||||
|
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
|
||||||
|
'Load_Balancer', self.ovn_lb.uuid, ('protocol', 'tcp'))
|
||||||
|
|
||||||
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
||||||
def test_lb_create_disabled(self, net_dr):
|
def test_lb_create_disabled(self, net_dr):
|
||||||
self.lb['admin_state_up'] = False
|
self.lb['admin_state_up'] = False
|
||||||
@ -743,7 +879,7 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
ovn_driver.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
|
ovn_driver.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
|
||||||
'enabled': 'False'},
|
'enabled': 'False'},
|
||||||
name=mock.ANY,
|
name=mock.ANY,
|
||||||
protocol='tcp')
|
protocol=None)
|
||||||
|
|
||||||
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
||||||
def test_lb_create_enabled(self, net_dr):
|
def test_lb_create_enabled(self, net_dr):
|
||||||
@ -761,12 +897,43 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
ovn_driver.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
|
ovn_driver.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
|
||||||
'enabled': 'True'},
|
'enabled': 'True'},
|
||||||
name=mock.ANY,
|
name=mock.ANY,
|
||||||
protocol='tcp')
|
protocol=None)
|
||||||
|
|
||||||
|
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
||||||
|
def test_lb_create_on_multi_protocol(self, net_dr):
|
||||||
|
"""This test situation when new protocol is added
|
||||||
|
|
||||||
|
to the same loadbalancer and we need to add
|
||||||
|
additional OVN lb with the same name.
|
||||||
|
"""
|
||||||
|
self.lb['admin_state_up'] = True
|
||||||
|
self.lb['protocol'] = 'UDP'
|
||||||
|
self.lb[ovn_driver.LB_EXT_IDS_LR_REF_KEY] = 'foo'
|
||||||
|
self.lb[ovn_driver.LB_EXT_IDS_LS_REFS_KEY] = "{\"neutron-foo\": 1}"
|
||||||
|
net_dr.return_value.neutron_client.list_ports.return_value = (
|
||||||
|
self.ports)
|
||||||
|
status = self.helper.lb_create(self.lb, protocol='UDP')
|
||||||
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
|
constants.ACTIVE)
|
||||||
|
self.assertEqual(status['loadbalancers'][0]['operating_status'],
|
||||||
|
constants.ONLINE)
|
||||||
|
self.helper.ovn_nbdb_api.db_create.assert_called_once_with(
|
||||||
|
'Load_Balancer', external_ids={
|
||||||
|
ovn_driver.LB_EXT_IDS_VIP_KEY: mock.ANY,
|
||||||
|
ovn_driver.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
|
||||||
|
ovn_driver.LB_EXT_IDS_LR_REF_KEY: 'foo',
|
||||||
|
'enabled': 'True'},
|
||||||
|
name=mock.ANY,
|
||||||
|
protocol='udp')
|
||||||
|
self.helper._update_lb_to_ls_association.assert_has_calls([
|
||||||
|
mock.call(self.ovn_lb, associate=True,
|
||||||
|
network_id=self.lb['vip_network_id']),
|
||||||
|
mock.call(self.ovn_lb, associate=True, network_id='foo')])
|
||||||
|
|
||||||
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
||||||
@mock.patch.object(ovn_driver.OvnProviderHelper, 'delete_vip_port')
|
@mock.patch.object(ovn_driver.OvnProviderHelper, 'delete_vip_port')
|
||||||
def test_lb_create_exception(self, del_port, net_dr):
|
def test_lb_create_exception(self, del_port, net_dr):
|
||||||
self.helper._find_ovn_lb.side_effect = [RuntimeError]
|
self.helper._find_ovn_lbs.side_effect = [RuntimeError]
|
||||||
net_dr.return_value.neutron_client.list_ports.return_value = (
|
net_dr.return_value.neutron_client.list_ports.return_value = (
|
||||||
self.ports)
|
self.ports)
|
||||||
status = self.helper.lb_create(self.lb)
|
status = self.helper.lb_create(self.lb)
|
||||||
@ -791,7 +958,7 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
|
|
||||||
@mock.patch.object(ovn_driver.OvnProviderHelper, 'delete_vip_port')
|
@mock.patch.object(ovn_driver.OvnProviderHelper, 'delete_vip_port')
|
||||||
def test_lb_delete_row_not_found(self, del_port):
|
def test_lb_delete_row_not_found(self, del_port):
|
||||||
self.helper._find_ovn_lb.side_effect = [idlutils.RowNotFound]
|
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
|
||||||
status = self.helper.lb_delete(self.lb)
|
status = self.helper.lb_delete(self.lb)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
constants.DELETED)
|
constants.DELETED)
|
||||||
@ -803,13 +970,14 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
||||||
@mock.patch.object(ovn_driver.OvnProviderHelper, 'delete_vip_port')
|
@mock.patch.object(ovn_driver.OvnProviderHelper, 'delete_vip_port')
|
||||||
def test_lb_delete_exception(self, del_port, net_dr):
|
def test_lb_delete_exception(self, del_port, net_dr):
|
||||||
del_port.side_effect = [RuntimeError]
|
self.helper.ovn_nbdb_api.lb_del.side_effect = [RuntimeError]
|
||||||
status = self.helper.lb_delete(self.lb)
|
status = self.helper.lb_delete(self.lb)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
constants.ERROR)
|
constants.ERROR)
|
||||||
self.assertEqual(status['loadbalancers'][0]['operating_status'],
|
self.assertEqual(status['loadbalancers'][0]['operating_status'],
|
||||||
constants.ERROR)
|
constants.ERROR)
|
||||||
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
|
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
|
||||||
|
self.ovn_lb.uuid)
|
||||||
del_port.assert_called_once_with('foo_port')
|
del_port.assert_called_once_with('foo_port')
|
||||||
|
|
||||||
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
||||||
@ -817,12 +985,13 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
def test_lb_delete_port_not_found(self, del_port, net_dr):
|
def test_lb_delete_port_not_found(self, del_port, net_dr):
|
||||||
net_dr.return_value.neutron_client.delete_port.return_value = None
|
net_dr.return_value.neutron_client.delete_port.return_value = None
|
||||||
del_port.side_effect = [n_exc.PortNotFoundClient]
|
del_port.side_effect = [n_exc.PortNotFoundClient]
|
||||||
status = self.helper.lb_delete(self.lb)
|
status = self.helper.lb_delete(self.ovn_lb)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
constants.DELETED)
|
constants.DELETED)
|
||||||
self.assertEqual(status['loadbalancers'][0]['operating_status'],
|
self.assertEqual(status['loadbalancers'][0]['operating_status'],
|
||||||
constants.OFFLINE)
|
constants.OFFLINE)
|
||||||
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
|
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
|
||||||
|
self.ovn_lb.uuid)
|
||||||
del_port.assert_called_once_with('foo_port')
|
del_port.assert_called_once_with('foo_port')
|
||||||
|
|
||||||
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
||||||
@ -860,6 +1029,20 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
self.helper.ovn_nbdb_api.lr_lb_del.assert_called_once_with(
|
self.helper.ovn_nbdb_api.lr_lb_del.assert_called_once_with(
|
||||||
self.router.uuid, self.ovn_lb.uuid)
|
self.router.uuid, self.ovn_lb.uuid)
|
||||||
|
|
||||||
|
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
||||||
|
def test_lb_delete_multiple_protocols(self, net_dr):
|
||||||
|
net_dr.return_value.neutron_client.delete_port.return_value = None
|
||||||
|
self.mock_find_ovn_lbs.stop()
|
||||||
|
udp_lb = copy.copy(self.ovn_lb)
|
||||||
|
udp_lb.protocol = ['udp']
|
||||||
|
udp_lb.uuid = 'foo_uuid'
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
|
||||||
|
execute.return_value = [self.ovn_lb, udp_lb]
|
||||||
|
self.helper.lb_delete(self.lb)
|
||||||
|
self.helper.ovn_nbdb_api.lb_del.assert_has_calls([
|
||||||
|
mock.call(self.ovn_lb.uuid),
|
||||||
|
mock.call(udp_lb.uuid)])
|
||||||
|
|
||||||
def test_lb_failover(self):
|
def test_lb_failover(self):
|
||||||
status = self.helper.lb_failover(self.lb)
|
status = self.helper.lb_failover(self.lb)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
@ -867,6 +1050,7 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
|
|
||||||
@mock.patch.object(ovn_driver.OvnProviderHelper, '_refresh_lb_vips')
|
@mock.patch.object(ovn_driver.OvnProviderHelper, '_refresh_lb_vips')
|
||||||
def test_lb_update_disabled(self, refresh_vips):
|
def test_lb_update_disabled(self, refresh_vips):
|
||||||
|
self.lb['admin_state_up'] = False
|
||||||
status = self.helper.lb_update(self.lb)
|
status = self.helper.lb_update(self.lb)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
constants.ACTIVE)
|
constants.ACTIVE)
|
||||||
@ -880,6 +1064,8 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
|
|
||||||
@mock.patch.object(ovn_driver.OvnProviderHelper, '_refresh_lb_vips')
|
@mock.patch.object(ovn_driver.OvnProviderHelper, '_refresh_lb_vips')
|
||||||
def test_lb_update_enabled(self, refresh_vips):
|
def test_lb_update_enabled(self, refresh_vips):
|
||||||
|
# Change the mock, its enabled by default.
|
||||||
|
self.ovn_lb.external_ids.update({'enabled': False})
|
||||||
self.lb['admin_state_up'] = True
|
self.lb['admin_state_up'] = True
|
||||||
status = self.helper.lb_update(self.lb)
|
status = self.helper.lb_update(self.lb)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
@ -892,8 +1078,35 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
'Load_Balancer', self.ovn_lb.uuid,
|
'Load_Balancer', self.ovn_lb.uuid,
|
||||||
('external_ids', {'enabled': 'True'}))
|
('external_ids', {'enabled': 'True'}))
|
||||||
|
|
||||||
|
@mock.patch.object(ovn_driver.OvnProviderHelper, '_refresh_lb_vips')
|
||||||
|
def test_lb_update_enabled_multiple_protocols(self, refresh_vips):
|
||||||
|
self.mock_find_ovn_lbs.stop()
|
||||||
|
self.ovn_lb.external_ids.update({'enabled': 'False'})
|
||||||
|
udp_lb = copy.deepcopy(self.ovn_lb)
|
||||||
|
udp_lb.protocol = ['udp']
|
||||||
|
udp_lb.uuid = 'foo_uuid'
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
|
||||||
|
execute.return_value = [self.ovn_lb, udp_lb]
|
||||||
|
self.lb['admin_state_up'] = True
|
||||||
|
status = self.helper.lb_update(self.lb)
|
||||||
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
|
constants.ACTIVE)
|
||||||
|
self.assertEqual(status['loadbalancers'][0]['operating_status'],
|
||||||
|
constants.ONLINE)
|
||||||
|
refresh_vips.assert_has_calls([
|
||||||
|
mock.call(self.ovn_lb.uuid, self.ovn_lb.external_ids),
|
||||||
|
mock.ANY,
|
||||||
|
mock.ANY,
|
||||||
|
mock.call(udp_lb.uuid, udp_lb.external_ids)],
|
||||||
|
any_order=False)
|
||||||
|
self.helper.ovn_nbdb_api.db_set.assert_has_calls([
|
||||||
|
mock.call('Load_Balancer', self.ovn_lb.uuid,
|
||||||
|
('external_ids', {'enabled': 'True'})),
|
||||||
|
mock.call('Load_Balancer', udp_lb.uuid,
|
||||||
|
('external_ids', {'enabled': 'True'}))])
|
||||||
|
|
||||||
def test_lb_update_exception(self):
|
def test_lb_update_exception(self):
|
||||||
self.helper._find_ovn_lb.side_effect = [RuntimeError]
|
self.helper._find_ovn_lbs.side_effect = [RuntimeError]
|
||||||
status = self.helper.lb_update(self.lb)
|
status = self.helper.lb_update(self.lb)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
constants.ERROR)
|
constants.ERROR)
|
||||||
@ -966,7 +1179,7 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
self.helper.ovn_nbdb_api.db_set.call_count)
|
self.helper.ovn_nbdb_api.db_set.call_count)
|
||||||
|
|
||||||
def test_listener_create_exception(self):
|
def test_listener_create_exception(self):
|
||||||
self.helper._find_ovn_lb.side_effect = [RuntimeError]
|
self.helper.ovn_nbdb_api.db_set.side_effect = [RuntimeError]
|
||||||
status = self.helper.listener_create(self.listener)
|
status = self.helper.listener_create(self.listener)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
constants.ACTIVE)
|
constants.ACTIVE)
|
||||||
@ -996,14 +1209,23 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
self.assertEqual(status['pools'][0]['provisioning_status'],
|
self.assertEqual(status['pools'][0]['provisioning_status'],
|
||||||
constants.ACTIVE)
|
constants.ACTIVE)
|
||||||
|
|
||||||
def test_listener_update_exception(self):
|
def test_listener_update_row_not_found(self):
|
||||||
self.helper._find_ovn_lb.side_effect = [RuntimeError]
|
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
|
||||||
|
status = self.helper.listener_update(self.listener)
|
||||||
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
|
constants.ERROR)
|
||||||
|
self.assertEqual(status['listeners'][0]['provisioning_status'],
|
||||||
|
constants.ERROR)
|
||||||
|
self.helper.ovn_nbdb_api.db_set.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch.object(ovn_driver.OvnProviderHelper, '_refresh_lb_vips')
|
||||||
|
def test_listener_update_exception(self, refresh_vips):
|
||||||
|
refresh_vips.side_effect = [RuntimeError]
|
||||||
status = self.helper.listener_update(self.listener)
|
status = self.helper.listener_update(self.listener)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
constants.ACTIVE)
|
constants.ACTIVE)
|
||||||
self.assertEqual(status['listeners'][0]['provisioning_status'],
|
self.assertEqual(status['listeners'][0]['provisioning_status'],
|
||||||
constants.ERROR)
|
constants.ERROR)
|
||||||
self.helper.ovn_nbdb_api.db_set.assert_not_called()
|
|
||||||
|
|
||||||
@mock.patch.object(ovn_driver.OvnProviderHelper, '_refresh_lb_vips')
|
@mock.patch.object(ovn_driver.OvnProviderHelper, '_refresh_lb_vips')
|
||||||
def test_listener_update_listener_enabled(self, refresh_vips):
|
def test_listener_update_listener_enabled(self, refresh_vips):
|
||||||
@ -1064,8 +1286,18 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
constants.OFFLINE)
|
constants.OFFLINE)
|
||||||
self.helper.ovn_nbdb_api.db_remove.assert_not_called()
|
self.helper.ovn_nbdb_api.db_remove.assert_not_called()
|
||||||
|
|
||||||
|
def test_listener_delete_row_not_found(self):
|
||||||
|
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
|
||||||
|
status = self.helper.listener_delete(self.listener)
|
||||||
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
|
constants.ACTIVE)
|
||||||
|
self.assertEqual(status['listeners'][0]['provisioning_status'],
|
||||||
|
constants.DELETED)
|
||||||
|
self.assertEqual(status['listeners'][0]['operating_status'],
|
||||||
|
constants.OFFLINE)
|
||||||
|
|
||||||
def test_listener_delete_exception(self):
|
def test_listener_delete_exception(self):
|
||||||
self.helper._find_ovn_lb.side_effect = [RuntimeError]
|
self.helper.ovn_nbdb_api.db_remove.side_effect = [RuntimeError]
|
||||||
status = self.helper.listener_delete(self.listener)
|
status = self.helper.listener_delete(self.listener)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
constants.ACTIVE)
|
constants.ACTIVE)
|
||||||
@ -1090,6 +1322,41 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
refresh_vips.assert_called_once_with(
|
refresh_vips.assert_called_once_with(
|
||||||
self.ovn_lb.uuid, self.ovn_lb.external_ids)
|
self.ovn_lb.uuid, self.ovn_lb.external_ids)
|
||||||
|
|
||||||
|
@mock.patch.object(ovn_driver.OvnProviderHelper, '_is_lb_empty')
|
||||||
|
def test_listener_delete_ovn_lb_not_empty(self, lb_empty):
|
||||||
|
lb_empty.return_value = False
|
||||||
|
self.helper.listener_delete(self.listener)
|
||||||
|
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
|
||||||
|
'Load_Balancer', self.ovn_lb.uuid,
|
||||||
|
'external_ids', 'listener_%s' % self.listener_id)
|
||||||
|
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch.object(ovn_driver.OvnProviderHelper, '_is_lb_empty')
|
||||||
|
def test_listener_delete_ovn_lb_empty_lb_empty(self, lb_empty):
|
||||||
|
lb_empty.return_value = True
|
||||||
|
self.helper.listener_delete(self.listener)
|
||||||
|
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
|
||||||
|
'Load_Balancer', self.ovn_lb.uuid,
|
||||||
|
'external_ids', 'listener_%s' % self.listener_id)
|
||||||
|
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
|
||||||
|
# Assert that protocol has been set to [].
|
||||||
|
self.helper.ovn_nbdb_api.db_set.assert_has_calls([
|
||||||
|
mock.call('Load_Balancer', self.ovn_lb.uuid,
|
||||||
|
('protocol', []))])
|
||||||
|
|
||||||
|
@mock.patch.object(ovn_driver.OvnProviderHelper, '_is_lb_empty')
|
||||||
|
def test_listener_delete_ovn_lb_empty_lb_not_empty(self, lb_empty):
|
||||||
|
self.mock_find_ovn_lbs.stop()
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
|
||||||
|
execute.side_effect = [[self.ovn_lb], []]
|
||||||
|
lb_empty.return_value = True
|
||||||
|
self.helper.listener_delete(self.listener)
|
||||||
|
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
|
||||||
|
'Load_Balancer', self.ovn_lb.uuid,
|
||||||
|
'external_ids', 'listener_%s' % self.listener_id)
|
||||||
|
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
|
||||||
|
self.ovn_lb.uuid)
|
||||||
|
|
||||||
def test_pool_create(self):
|
def test_pool_create(self):
|
||||||
status = self.helper.pool_create(self.pool)
|
status = self.helper.pool_create(self.pool)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
@ -1111,7 +1378,7 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
constants.OFFLINE)
|
constants.OFFLINE)
|
||||||
|
|
||||||
def test_pool_create_exception(self):
|
def test_pool_create_exception(self):
|
||||||
self.helper._find_ovn_lb.side_effect = [RuntimeError]
|
self.helper.ovn_nbdb_api.db_set.side_effect = [RuntimeError]
|
||||||
status = self.helper.pool_update(self.pool)
|
status = self.helper.pool_update(self.pool)
|
||||||
self.assertEqual(status['pools'][0]['provisioning_status'],
|
self.assertEqual(status['pools'][0]['provisioning_status'],
|
||||||
constants.ERROR)
|
constants.ERROR)
|
||||||
@ -1223,15 +1490,23 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
self.helper.ovn_nbdb_api.db_set.assert_has_calls(
|
self.helper.ovn_nbdb_api.db_set.assert_has_calls(
|
||||||
expected_calls)
|
expected_calls)
|
||||||
|
|
||||||
|
def test_pool_delete_row_not_found(self):
|
||||||
|
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
|
||||||
|
status = self.helper.pool_delete(self.pool)
|
||||||
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
|
constants.ACTIVE)
|
||||||
|
self.assertEqual(status['pools'][0]['provisioning_status'],
|
||||||
|
constants.DELETED)
|
||||||
|
self.helper.ovn_nbdb_api.db_remove.assert_not_called()
|
||||||
|
self.helper.ovn_nbdb_api.db_set.assert_not_called()
|
||||||
|
|
||||||
def test_pool_delete_exception(self):
|
def test_pool_delete_exception(self):
|
||||||
self.helper._find_ovn_lb.side_effect = [RuntimeError]
|
self.helper.ovn_nbdb_api.db_set.side_effect = [RuntimeError]
|
||||||
status = self.helper.pool_delete(self.pool)
|
status = self.helper.pool_delete(self.pool)
|
||||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||||
constants.ACTIVE)
|
constants.ACTIVE)
|
||||||
self.assertEqual(status['pools'][0]['provisioning_status'],
|
self.assertEqual(status['pools'][0]['provisioning_status'],
|
||||||
constants.ERROR)
|
constants.ERROR)
|
||||||
self.helper.ovn_nbdb_api.db_remove.assert_not_called()
|
|
||||||
self.helper.ovn_nbdb_api.db_set.assert_not_called()
|
|
||||||
|
|
||||||
def test_pool_delete_associated_listeners(self):
|
def test_pool_delete_associated_listeners(self):
|
||||||
self.helper._get_pool_listeners.return_value = ['listener1']
|
self.helper._get_pool_listeners.return_value = ['listener1']
|
||||||
@ -1263,6 +1538,41 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
'Load_Balancer', self.ovn_lb.uuid,
|
'Load_Balancer', self.ovn_lb.uuid,
|
||||||
'external_ids', 'pool_%s:D' % self.pool_id)
|
'external_ids', 'pool_%s:D' % self.pool_id)
|
||||||
|
|
||||||
|
@mock.patch.object(ovn_driver.OvnProviderHelper, '_is_lb_empty')
|
||||||
|
def test_pool_delete_ovn_lb_not_empty(self, lb_empty):
|
||||||
|
lb_empty.return_value = False
|
||||||
|
self.helper.pool_delete(self.pool)
|
||||||
|
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
|
||||||
|
'Load_Balancer', self.ovn_lb.uuid,
|
||||||
|
'external_ids', 'pool_%s' % self.pool_id)
|
||||||
|
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch.object(ovn_driver.OvnProviderHelper, '_is_lb_empty')
|
||||||
|
def test_pool_delete_ovn_lb_empty_lb_empty(self, lb_empty):
|
||||||
|
lb_empty.return_value = True
|
||||||
|
self.helper.pool_delete(self.pool)
|
||||||
|
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
|
||||||
|
'Load_Balancer', self.ovn_lb.uuid,
|
||||||
|
'external_ids', 'pool_%s' % self.pool_id)
|
||||||
|
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
|
||||||
|
# Assert that protocol has been set to [].
|
||||||
|
self.helper.ovn_nbdb_api.db_set.assert_called_with(
|
||||||
|
'Load_Balancer', self.ovn_lb.uuid,
|
||||||
|
('protocol', []))
|
||||||
|
|
||||||
|
@mock.patch.object(ovn_driver.OvnProviderHelper, '_is_lb_empty')
|
||||||
|
def test_pool_delete_ovn_lb_empty_lb_not_empty(self, lb_empty):
|
||||||
|
self.mock_find_ovn_lbs.stop()
|
||||||
|
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
|
||||||
|
execute.side_effect = [[self.ovn_lb], []]
|
||||||
|
lb_empty.return_value = True
|
||||||
|
self.helper.pool_delete(self.pool)
|
||||||
|
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
|
||||||
|
'Load_Balancer', self.ovn_lb.uuid,
|
||||||
|
'external_ids', 'pool_%s' % self.pool_id)
|
||||||
|
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
|
||||||
|
self.ovn_lb.uuid)
|
||||||
|
|
||||||
def test_member_create(self):
|
def test_member_create(self):
|
||||||
self.ovn_lb.external_ids = mock.MagicMock()
|
self.ovn_lb.external_ids = mock.MagicMock()
|
||||||
status = self.helper.member_create(self.member)
|
status = self.helper.member_create(self.member)
|
||||||
@ -1959,7 +2269,7 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
'info':
|
'info':
|
||||||
{'action': 'associate',
|
{'action': 'associate',
|
||||||
'vip_fip': '10.0.0.1',
|
'vip_fip': '10.0.0.1',
|
||||||
'lb_id': 'foo'},
|
'ovn_lb': self.ovn_lb},
|
||||||
'type': 'handle_vip_fip'}
|
'type': 'handle_vip_fip'}
|
||||||
self.mock_add_request.assert_called_once_with(expected_call)
|
self.mock_add_request.assert_called_once_with(expected_call)
|
||||||
|
|
||||||
@ -1985,7 +2295,7 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
'info':
|
'info':
|
||||||
{'action': 'disassociate',
|
{'action': 'disassociate',
|
||||||
'vip_fip': None,
|
'vip_fip': None,
|
||||||
'lb_id': 'foo'},
|
'ovn_lb': self.ovn_lb},
|
||||||
'type': 'handle_vip_fip'}
|
'type': 'handle_vip_fip'}
|
||||||
self.mock_add_request.assert_called_once_with(expected_call)
|
self.mock_add_request.assert_called_once_with(expected_call)
|
||||||
|
|
||||||
@ -2000,7 +2310,7 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
self.mock_add_request.assert_not_called()
|
self.mock_add_request.assert_not_called()
|
||||||
|
|
||||||
@mock.patch('ovn_octavia_provider.driver.OvnProviderHelper.'
|
@mock.patch('ovn_octavia_provider.driver.OvnProviderHelper.'
|
||||||
'_find_ovn_lb')
|
'_find_ovn_lbs')
|
||||||
def test_vip_port_update_handler_lb_not_found(self, lb):
|
def test_vip_port_update_handler_lb_not_found(self, lb):
|
||||||
lb.side_effect = [idlutils.RowNotFound]
|
lb.side_effect = [idlutils.RowNotFound]
|
||||||
self.switch_port_event = ovn_driver.LogicalSwitchPortUpdateEvent(
|
self.switch_port_event = ovn_driver.LogicalSwitchPortUpdateEvent(
|
||||||
@ -2014,13 +2324,39 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
self.mock_add_request.assert_not_called()
|
self.mock_add_request.assert_not_called()
|
||||||
|
|
||||||
@mock.patch('ovn_octavia_provider.driver.OvnProviderHelper.'
|
@mock.patch('ovn_octavia_provider.driver.OvnProviderHelper.'
|
||||||
'_find_ovn_lb')
|
'_find_ovn_lbs')
|
||||||
|
def test_vip_port_update_handler_multiple_lbs(self, lb):
|
||||||
|
lb1 = mock.MagicMock()
|
||||||
|
lb2 = mock.MagicMock()
|
||||||
|
lb.return_value = [lb1, lb2]
|
||||||
|
self.switch_port_event = ovn_driver.LogicalSwitchPortUpdateEvent(
|
||||||
|
self.helper)
|
||||||
|
port_name = '%s%s' % (ovn_const.LB_VIP_PORT_PREFIX, 'foo')
|
||||||
|
attrs = {'external_ids':
|
||||||
|
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name}}
|
||||||
|
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
|
||||||
|
attrs=attrs)
|
||||||
|
self.switch_port_event.run(mock.ANY, row, mock.ANY)
|
||||||
|
|
||||||
|
def expected_call(lb):
|
||||||
|
return {'type': 'handle_vip_fip',
|
||||||
|
'info':
|
||||||
|
{'action': mock.ANY,
|
||||||
|
'vip_fip': None,
|
||||||
|
'ovn_lb': lb}}
|
||||||
|
|
||||||
|
self.mock_add_request.assert_has_calls([
|
||||||
|
mock.call(expected_call(lb1)),
|
||||||
|
mock.call(expected_call(lb2))])
|
||||||
|
|
||||||
|
@mock.patch('ovn_octavia_provider.driver.OvnProviderHelper.'
|
||||||
|
'_find_ovn_lbs')
|
||||||
def test_handle_vip_fip_disassociate(self, flb):
|
def test_handle_vip_fip_disassociate(self, flb):
|
||||||
|
lb = mock.MagicMock()
|
||||||
fip_info = {
|
fip_info = {
|
||||||
'action': 'disassociate',
|
'action': 'disassociate',
|
||||||
'vip_fip': None,
|
'vip_fip': None,
|
||||||
'lb_id': 'foo'}
|
'ovn_lb': lb}
|
||||||
lb = mock.MagicMock()
|
|
||||||
flb.return_value = lb
|
flb.return_value = lb
|
||||||
self.helper.handle_vip_fip(fip_info)
|
self.helper.handle_vip_fip(fip_info)
|
||||||
calls = [
|
calls = [
|
||||||
@ -2031,13 +2367,14 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
self.helper.ovn_nbdb_api.assert_has_calls(calls)
|
self.helper.ovn_nbdb_api.assert_has_calls(calls)
|
||||||
|
|
||||||
@mock.patch('ovn_octavia_provider.driver.OvnProviderHelper.'
|
@mock.patch('ovn_octavia_provider.driver.OvnProviderHelper.'
|
||||||
'_find_ovn_lb')
|
'_find_ovn_lbs')
|
||||||
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
||||||
def test_handle_vip_fip_associate(self, net_dr, fb):
|
def test_handle_vip_fip_associate(self, net_dr, fb):
|
||||||
|
lb = mock.MagicMock()
|
||||||
fip_info = {
|
fip_info = {
|
||||||
'action': 'associate',
|
'action': 'associate',
|
||||||
'vip_fip': '10.0.0.123',
|
'vip_fip': '10.0.0.123',
|
||||||
'lb_id': 'foo'}
|
'ovn_lb': lb}
|
||||||
members = 'member_%s_%s:%s' % (self.member_id,
|
members = 'member_%s_%s:%s' % (self.member_id,
|
||||||
self.member_address,
|
self.member_address,
|
||||||
self.member_port)
|
self.member_port)
|
||||||
@ -2046,7 +2383,6 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
'pool_%s' % self.pool_id: members,
|
'pool_%s' % self.pool_id: members,
|
||||||
'neutron:vip': '172.26.21.20'}
|
'neutron:vip': '172.26.21.20'}
|
||||||
|
|
||||||
lb = mock.MagicMock()
|
|
||||||
lb.external_ids = external_ids
|
lb.external_ids = external_ids
|
||||||
fb.return_value = lb
|
fb.return_value = lb
|
||||||
|
|
||||||
@ -2062,15 +2398,6 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
|
|||||||
'172.26.21.20:80': '192.168.2.149:1010'}))]
|
'172.26.21.20:80': '192.168.2.149:1010'}))]
|
||||||
self.helper.ovn_nbdb_api.assert_has_calls(calls)
|
self.helper.ovn_nbdb_api.assert_has_calls(calls)
|
||||||
|
|
||||||
@mock.patch('ovn_octavia_provider.driver.OvnProviderHelper.'
|
|
||||||
'_find_ovn_lb')
|
|
||||||
@mock.patch('ovn_octavia_provider.driver.get_network_driver')
|
|
||||||
def test_handle_vip_fip_lb_not_found(self, net_dr, fb):
|
|
||||||
fip_info = {'lb_id': 'foo'}
|
|
||||||
fb.side_effect = [idlutils.RowNotFound]
|
|
||||||
self.helper.handle_vip_fip(fip_info)
|
|
||||||
self.helper.ovn_nbdb_api.assert_not_called()
|
|
||||||
|
|
||||||
@mock.patch.object(ovn_driver, 'atexit')
|
@mock.patch.object(ovn_driver, 'atexit')
|
||||||
def test_ovsdb_connections(self, mock_atexit):
|
def test_ovsdb_connections(self, mock_atexit):
|
||||||
ovn_driver.OvnProviderHelper.ovn_nbdb_api = None
|
ovn_driver.OvnProviderHelper.ovn_nbdb_api = None
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
OVN Octavia provider driver now supports both TCP and UDP
|
||||||
|
pool/listener protocols configured in the same Octavia Load Balancer.
|
Loading…
Reference in New Issue
Block a user