Cover the use case of a member non existing
When a HM is attached to a pool and a backend member in that pool is a fake member (e.g. due to a typo on creation) the member remains in ONLINE status. Basically this is due to the fact that there isn't any LSP attached to that member and no Service_Monitor entries will take care of it. This patch checks inmediatelly after creation the member and update the whole LB status to reflect this fake member that could help to the user to identify quickly those fake members. Closes-Bug: 2034522 Change-Id: I72b2d9c5f454f9b156414bf91ca7deb7f0e9d8b0
This commit is contained in:
parent
e02c1b9b3e
commit
fe6612f714
@ -1969,41 +1969,14 @@ class OvnProviderHelper():
|
||||
|
||||
def member_create(self, member):
|
||||
new_member = None
|
||||
pool_listeners = []
|
||||
try:
|
||||
pool_key, ovn_lb = self._find_ovn_lb_by_pool_id(
|
||||
member[constants.POOL_ID])
|
||||
pool_listeners = self._get_pool_listeners(ovn_lb, pool_key)
|
||||
new_member = self._add_member(member, ovn_lb, pool_key)
|
||||
pool = {constants.ID: member[constants.POOL_ID],
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE,
|
||||
constants.OPERATING_STATUS: constants.ONLINE}
|
||||
status = {
|
||||
constants.POOLS: [pool],
|
||||
constants.LOADBALANCERS: [
|
||||
{constants.ID: ovn_lb.name,
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE}]}
|
||||
operating_status = constants.NO_MONITOR
|
||||
except Exception:
|
||||
LOG.exception(ovn_const.EXCEPTION_MSG, "creation of member")
|
||||
status = {
|
||||
constants.POOLS: [
|
||||
{constants.ID: member[constants.POOL_ID],
|
||||
constants.PROVISIONING_STATUS: constants.ERROR}],
|
||||
constants.MEMBERS: [
|
||||
{constants.ID: member[constants.ID],
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE}],
|
||||
constants.LOADBALANCERS: [
|
||||
{constants.ID: ovn_lb.name,
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE}]}
|
||||
|
||||
listener_status = []
|
||||
for listener in pool_listeners:
|
||||
listener_status.append(
|
||||
{constants.ID: listener,
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE})
|
||||
status[constants.LISTENERS] = listener_status
|
||||
|
||||
operating_status = constants.NO_MONITOR
|
||||
operating_status = constants.ERROR
|
||||
if not member[constants.ADMIN_STATE_UP]:
|
||||
operating_status = constants.OFFLINE
|
||||
elif (new_member and operating_status == constants.NO_MONITOR and
|
||||
@ -2011,18 +1984,18 @@ class OvnProviderHelper():
|
||||
operating_status = constants.ONLINE
|
||||
mb_ip, mb_port, mb_subnet, mb_id = self._extract_member_info(
|
||||
new_member)[0]
|
||||
if not self._update_hm_member(ovn_lb, pool_key, mb_ip):
|
||||
operating_status = constants.ERROR
|
||||
member_status = {constants.ID: member[constants.ID],
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE,
|
||||
constants.OPERATING_STATUS: operating_status}
|
||||
status[constants.MEMBERS] = [member_status]
|
||||
mb_status = self._update_hm_member(ovn_lb, pool_key, mb_ip)
|
||||
operating_status = (
|
||||
constants.ERROR
|
||||
if mb_status != constants.ONLINE else mb_status
|
||||
)
|
||||
|
||||
self._update_external_ids_member_status(
|
||||
ovn_lb,
|
||||
member[constants.ID],
|
||||
operating_status)
|
||||
|
||||
status = self._get_current_operating_statuses(ovn_lb)
|
||||
return status
|
||||
|
||||
def _remove_member(self, member, ovn_lb, pool_key):
|
||||
@ -2063,71 +2036,39 @@ class OvnProviderHelper():
|
||||
operator_fault_string=msg)
|
||||
|
||||
def member_delete(self, member):
|
||||
pool_listeners = []
|
||||
error_deleting_member = False
|
||||
try:
|
||||
pool_key, ovn_lb = self._find_ovn_lb_by_pool_id(
|
||||
member[constants.POOL_ID])
|
||||
pool_listeners = self._get_pool_listeners(ovn_lb, pool_key)
|
||||
|
||||
pool_status = self._remove_member(member, ovn_lb, pool_key)
|
||||
pool = {constants.ID: member[constants.POOL_ID],
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE,
|
||||
constants.OPERATING_STATUS: pool_status}
|
||||
|
||||
if ovn_lb.health_check and pool_status == constants.OFFLINE:
|
||||
# NOTE(froyo): if the pool status is OFFLINE there are no more
|
||||
# members. So we should ensure the hm-port is deleted if no
|
||||
# more LB are using it. We need to do this call after the
|
||||
# cleaning of the ip_port_mappings for the ovn LB.
|
||||
self._clean_up_hm_port(member[constants.SUBNET_ID])
|
||||
|
||||
status = {
|
||||
constants.POOLS: [pool],
|
||||
constants.MEMBERS: [
|
||||
{constants.ID: member[constants.ID],
|
||||
constants.PROVISIONING_STATUS: constants.DELETED}],
|
||||
constants.LOADBALANCERS: [
|
||||
{constants.ID: ovn_lb.name,
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE}]}
|
||||
except Exception:
|
||||
LOG.exception(ovn_const.EXCEPTION_MSG, "deletion of member")
|
||||
status = {
|
||||
constants.POOLS: [
|
||||
{constants.ID: member[constants.POOL_ID],
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE}],
|
||||
constants.MEMBERS: [
|
||||
{constants.ID: member[constants.ID],
|
||||
constants.PROVISIONING_STATUS: constants.ERROR}],
|
||||
constants.LOADBALANCERS: [
|
||||
{constants.ID: ovn_lb.name,
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE}]}
|
||||
|
||||
error_deleting_member = True
|
||||
self._update_external_ids_member_status(
|
||||
ovn_lb, member[constants.ID], None, delete=True)
|
||||
|
||||
listener_status = []
|
||||
for listener in pool_listeners:
|
||||
listener_status.append(
|
||||
{constants.ID: listener,
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE})
|
||||
status[constants.LISTENERS] = listener_status
|
||||
|
||||
status = self._get_current_operating_statuses(ovn_lb)
|
||||
status[constants.MEMBERS] = [
|
||||
{constants.ID: member[constants.ID],
|
||||
constants.PROVISIONING_STATUS: constants.DELETED}]
|
||||
if error_deleting_member:
|
||||
status[constants.MEMBERS][0][constants.PROVISIONING_STATUS] = (
|
||||
constants.ERROR)
|
||||
return status
|
||||
|
||||
def member_update(self, member):
|
||||
pool_listeners = []
|
||||
try:
|
||||
error_updating_member = False
|
||||
pool_key, ovn_lb = self._find_ovn_lb_by_pool_id(
|
||||
member[constants.POOL_ID])
|
||||
member_status = {constants.ID: member[constants.ID],
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE}
|
||||
status = {
|
||||
constants.POOLS: [
|
||||
{constants.ID: member[constants.POOL_ID],
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE}],
|
||||
constants.MEMBERS: [member_status],
|
||||
constants.LOADBALANCERS: [
|
||||
{constants.ID: ovn_lb.name,
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE}]}
|
||||
pool_listeners = self._get_pool_listeners(ovn_lb, pool_key)
|
||||
member_operating_status = constants.NO_MONITOR
|
||||
last_status = self._find_member_status(
|
||||
ovn_lb, member[constants.ID])
|
||||
if constants.ADMIN_STATE_UP in member:
|
||||
@ -2136,30 +2077,25 @@ class OvnProviderHelper():
|
||||
# as the last status valid for the member
|
||||
if ovn_lb.health_check:
|
||||
# search status of member_uuid
|
||||
member_status[constants.OPERATING_STATUS] = last_status
|
||||
member_operating_status = last_status
|
||||
else:
|
||||
member_status[constants.OPERATING_STATUS] = (
|
||||
constants.NO_MONITOR)
|
||||
member_operating_status = constants.NO_MONITOR
|
||||
else:
|
||||
member_status[constants.OPERATING_STATUS] = (
|
||||
constants.OFFLINE)
|
||||
member_operating_status = constants.OFFLINE
|
||||
|
||||
if constants.OPERATING_STATUS in member_status:
|
||||
self._update_external_ids_member_status(
|
||||
ovn_lb,
|
||||
member[constants.ID],
|
||||
member_status[constants.OPERATING_STATUS])
|
||||
member_operating_status)
|
||||
|
||||
# NOTE(froyo): If we are toggling from/to OFFLINE due to an
|
||||
# admin_state_up change, in that case we should update vips
|
||||
if (
|
||||
last_status != constants.OFFLINE and
|
||||
member_status[constants.OPERATING_STATUS] ==
|
||||
constants.OFFLINE
|
||||
member_operating_status == constants.OFFLINE
|
||||
) or (
|
||||
last_status == constants.OFFLINE and
|
||||
member_status[constants.OPERATING_STATUS] !=
|
||||
constants.OFFLINE
|
||||
member_operating_status != constants.OFFLINE
|
||||
):
|
||||
commands = []
|
||||
commands.extend(self._refresh_lb_vips(ovn_lb,
|
||||
@ -2168,23 +2104,16 @@ class OvnProviderHelper():
|
||||
|
||||
except Exception:
|
||||
LOG.exception(ovn_const.EXCEPTION_MSG, "update of member")
|
||||
status = {
|
||||
constants.POOLS: [
|
||||
{constants.ID: member[constants.POOL_ID],
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE}],
|
||||
constants.MEMBERS: [
|
||||
{constants.ID: member[constants.ID],
|
||||
constants.PROVISIONING_STATUS: constants.ERROR}],
|
||||
constants.LOADBALANCERS: [
|
||||
{constants.ID: ovn_lb.name,
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE}]}
|
||||
error_updating_member = True
|
||||
|
||||
listener_status = []
|
||||
for listener in pool_listeners:
|
||||
listener_status.append(
|
||||
{constants.ID: listener,
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE})
|
||||
status[constants.LISTENERS] = listener_status
|
||||
status = self._get_current_operating_statuses(ovn_lb)
|
||||
status[constants.MEMBERS] = [
|
||||
{constants.ID: member[constants.ID],
|
||||
constants.PROVISIONING_STATUS: constants.ACTIVE,
|
||||
constants.OPERATING_STATUS: member_operating_status}]
|
||||
if error_updating_member:
|
||||
status[constants.MEMBERS][0][constants.PROVISIONING_STATUS] = (
|
||||
constants.ERROR)
|
||||
return status
|
||||
|
||||
def _get_existing_pool_members(self, pool_id):
|
||||
@ -2615,18 +2544,17 @@ class OvnProviderHelper():
|
||||
# Update just the backend_ip member
|
||||
for mb_ip, mb_port, mb_subnet, mb_id in self._extract_member_info(
|
||||
ovn_lb.external_ids[pool_key]):
|
||||
member_lsp = self._get_member_lsp(mb_ip, mb_subnet)
|
||||
if mb_ip == backend_ip:
|
||||
member_lsp = self._get_member_lsp(mb_ip, mb_subnet)
|
||||
if not member_lsp:
|
||||
# NOTE(froyo): In order to continue evaluating the rest of
|
||||
# the members, we just warn about the member issue,
|
||||
# assuming that it will be in OFFLINE status as soon as the
|
||||
# HM does the first evaluation.
|
||||
# No port found for the member backend IP, we can determine
|
||||
# that the port doesn't exists or a typo on creation of the
|
||||
# member, anyway put the member inmediatelly as ERROR
|
||||
LOG.error("Member %(member)s Logical_Switch_Port not "
|
||||
"found, when creating a Health Monitor for "
|
||||
"pool %(pool)s.",
|
||||
{'member': mb_ip, 'pool': pool_key})
|
||||
break
|
||||
return constants.ERROR
|
||||
|
||||
network_id = member_lsp.external_ids.get(
|
||||
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY).split('neutron-')[1]
|
||||
@ -2639,7 +2567,7 @@ class OvnProviderHelper():
|
||||
"health monitoring. Cannot find a Health "
|
||||
"Monitor for pool %(pool)s.",
|
||||
{'network': network_id, 'pool': pool_key})
|
||||
return False
|
||||
return None
|
||||
hm_source_ip = None
|
||||
for fixed_ip in hm_port['fixed_ips']:
|
||||
if fixed_ip['subnet_id'] == mb_subnet:
|
||||
@ -2652,15 +2580,14 @@ class OvnProviderHelper():
|
||||
{'subnet': mb_subnet,
|
||||
'member': mb_ip,
|
||||
'pool': pool_key})
|
||||
return False
|
||||
return None
|
||||
self._update_ip_port_mappings(ovn_lb, backend_ip,
|
||||
member_lsp.name, hm_source_ip,
|
||||
delete)
|
||||
return True
|
||||
return constants.ONLINE
|
||||
|
||||
# NOTE(froyo): If the backend is not located or just one member but not
|
||||
# found the lsp
|
||||
return True
|
||||
# NOTE(froyo): If the backend is not located
|
||||
return constants.ERROR
|
||||
|
||||
def _lookup_lbhcs_by_hm_id(self, hm_id):
|
||||
lbhc_rows = self.ovn_nbdb_api.db_list_rows(
|
||||
@ -2748,11 +2675,16 @@ class OvnProviderHelper():
|
||||
if hm_status[constants.PROVISIONING_STATUS] == constants.ACTIVE:
|
||||
for mb_ip, mb_port, mb_subnet, mb_id in self._extract_member_info(
|
||||
ovn_lb.external_ids[pool_key]):
|
||||
if not self._update_hm_member(ovn_lb, pool_key, mb_ip):
|
||||
mb_status = self._update_hm_member(ovn_lb, pool_key, mb_ip)
|
||||
if not mb_status:
|
||||
hm_status[constants.PROVISIONING_STATUS] = constants.ERROR
|
||||
hm_status[constants.OPERATING_STATUS] = constants.ERROR
|
||||
self._clean_ip_port_mappings(ovn_lb, pool_key)
|
||||
break
|
||||
self._update_external_ids_member_status(
|
||||
ovn_lb, mb_id, mb_status)
|
||||
else:
|
||||
status = self._get_current_operating_statuses(ovn_lb)
|
||||
status[constants.HEALTHMONITORS] = [hm_status]
|
||||
return status
|
||||
|
||||
@ -2999,11 +2931,12 @@ class OvnProviderHelper():
|
||||
for k, v in ovn_lb.external_ids.items():
|
||||
if ovn_const.LB_EXT_IDS_LISTENER_PREFIX in k:
|
||||
listeners[k.split('_')[1]] = [
|
||||
x.split('_')[1] for x in v.split(',')]
|
||||
x.split('_')[1] for x in v.split(',')
|
||||
if ovn_const.LB_EXT_IDS_POOL_PREFIX in x]
|
||||
continue
|
||||
if ovn_const.LB_EXT_IDS_POOL_PREFIX in k:
|
||||
pools[k.split('_')[1]] = [
|
||||
x.split('_')[1] for x in v.split(',')]
|
||||
x.split('_')[1] for x in v.split(',') if x]
|
||||
continue
|
||||
|
||||
for member_id, member_status in member_statuses.items():
|
||||
@ -3022,12 +2955,12 @@ class OvnProviderHelper():
|
||||
members[i] = constants.ONLINE
|
||||
|
||||
_pool = self._octavia_driver_lib.get_pool(pool_id)
|
||||
if not _pool.admin_state_up:
|
||||
if not _pool.admin_state_up or not member_statuses:
|
||||
pools[pool_id] = constants.OFFLINE
|
||||
elif all(constants.ERROR == member_status
|
||||
elif pools[pool_id] and all(constants.ERROR == member_status
|
||||
for member_status in pools[pool_id]):
|
||||
pools[pool_id] = constants.ERROR
|
||||
elif any(constants.ERROR == member_status
|
||||
elif pools[pool_id] and any(constants.ERROR == member_status
|
||||
for member_status in pools[pool_id]):
|
||||
pools[pool_id] = constants.DEGRADED
|
||||
else:
|
||||
|
@ -342,11 +342,12 @@ class TestOvnOctaviaBase(base.TestOVNFunctionalBase,
|
||||
# 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']))
|
||||
ex = sorted(expected_status[k],
|
||||
key=lambda x: x['id'])
|
||||
ox = sorted(updated_status[k],
|
||||
key=lambda x: x['id'])
|
||||
val_check.append(all(item in ox for item in ex))
|
||||
|
||||
if False in val_check:
|
||||
# At least one value don't match.
|
||||
continue
|
||||
@ -793,7 +794,8 @@ class TestOvnOctaviaBase(base.TestOVNFunctionalBase,
|
||||
"provisioning_status": o_constants.DELETED}],
|
||||
'loadbalancers': [{
|
||||
"id": p.loadbalancer_id,
|
||||
"provisioning_status": o_constants.ACTIVE}],
|
||||
"provisioning_status": o_constants.ACTIVE,
|
||||
'operating_status': o_constants.ONLINE}],
|
||||
'listeners': []})
|
||||
self._update_ls_refs(
|
||||
lb_data, self._local_net_cache[m.subnet_id], add_ref=False)
|
||||
@ -861,7 +863,8 @@ class TestOvnOctaviaBase(base.TestOVNFunctionalBase,
|
||||
self._update_ls_refs(lb_data, network_id)
|
||||
pool_listeners = self._get_pool_listeners(lb_data, pool_id)
|
||||
expected_listener_status = [
|
||||
{'id': listener.listener_id, 'provisioning_status': 'ACTIVE'}
|
||||
{'id': listener.listener_id, 'provisioning_status': 'ACTIVE',
|
||||
'operating_status': o_constants.ONLINE}
|
||||
for listener in pool_listeners]
|
||||
|
||||
expected_status = {
|
||||
@ -870,7 +873,8 @@ class TestOvnOctaviaBase(base.TestOVNFunctionalBase,
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": o_constants.NO_MONITOR}],
|
||||
'loadbalancers': [{'id': pool.loadbalancer_id,
|
||||
'provisioning_status': 'ACTIVE'}],
|
||||
'provisioning_status': 'ACTIVE',
|
||||
'operating_status': o_constants.ONLINE}],
|
||||
'listeners': expected_listener_status
|
||||
}
|
||||
self._wait_for_status_and_validate(lb_data, [expected_status])
|
||||
@ -898,11 +902,13 @@ class TestOvnOctaviaBase(base.TestOVNFunctionalBase,
|
||||
self.ovn_driver.member_update(old_member, member)
|
||||
expected_status = {
|
||||
'pools': [{'id': pool.pool_id,
|
||||
'provisioning_status': 'ACTIVE'}],
|
||||
'provisioning_status': 'ACTIVE',
|
||||
'operating_status': o_constants.ONLINE}],
|
||||
'members': [{"id": member.member_id,
|
||||
'provisioning_status': 'ACTIVE'}],
|
||||
'loadbalancers': [{'id': pool.loadbalancer_id,
|
||||
'provisioning_status': 'ACTIVE'}],
|
||||
'provisioning_status': 'ACTIVE',
|
||||
'operating_status': o_constants.ONLINE}],
|
||||
'listeners': []
|
||||
}
|
||||
if getattr(member, 'admin_state_up', None):
|
||||
@ -926,7 +932,8 @@ class TestOvnOctaviaBase(base.TestOVNFunctionalBase,
|
||||
'provisioning_status': 'ACTIVE',
|
||||
'operating_status': 'ONLINE'}],
|
||||
'loadbalancers': [{'id': pool.loadbalancer_id,
|
||||
'provisioning_status': 'ACTIVE'}],
|
||||
'provisioning_status': 'ACTIVE',
|
||||
'operating_status': o_constants.ONLINE}],
|
||||
'listeners': []})
|
||||
for m in pool.members:
|
||||
found = False
|
||||
@ -974,7 +981,8 @@ class TestOvnOctaviaBase(base.TestOVNFunctionalBase,
|
||||
'members': [{"id": member.member_id,
|
||||
"provisioning_status": "DELETED"}],
|
||||
'loadbalancers': [{"id": pool.loadbalancer_id,
|
||||
"provisioning_status": "ACTIVE"}],
|
||||
'provisioning_status': 'ACTIVE',
|
||||
'operating_status': o_constants.ONLINE}],
|
||||
'listeners': []}
|
||||
|
||||
self._update_ls_refs(lb_data, network_id, add_ref=False)
|
||||
@ -992,6 +1000,10 @@ class TestOvnOctaviaBase(base.TestOVNFunctionalBase,
|
||||
max_retries, hm_type)
|
||||
pool.healthmonitor = m_hm
|
||||
|
||||
self.ovn_driver._ovn_helper._update_hm_member = mock.MagicMock()
|
||||
self.ovn_driver._ovn_helper._update_hm_member.side_effect = [
|
||||
o_constants.ONLINE, o_constants.ONLINE]
|
||||
|
||||
self.ovn_driver.health_monitor_create(m_hm)
|
||||
pool_listeners = self._get_pool_listeners(lb_data, pool_id)
|
||||
expected_listener_status = [
|
||||
@ -1011,7 +1023,8 @@ class TestOvnOctaviaBase(base.TestOVNFunctionalBase,
|
||||
'pools': [pool_status],
|
||||
'members': expected_member_status,
|
||||
'loadbalancers': [{'id': pool.loadbalancer_id,
|
||||
'provisioning_status': o_constants.ACTIVE}],
|
||||
'provisioning_status': o_constants.ACTIVE,
|
||||
'operating_status': o_constants.ONLINE}],
|
||||
'listeners': expected_listener_status,
|
||||
'healthmonitors': [expected_hm_status]
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: 'foo_hm_port',
|
||||
ovn_const.LB_EXT_IDS_HMS_KEY: '["%s"]' % (self.ovn_hm.uuid),
|
||||
'enabled': True,
|
||||
'pool_%s' % self.pool_id: [],
|
||||
'pool_%s' % self.pool_id: '',
|
||||
'listener_%s' % self.listener_id: '80:pool_%s' % self.pool_id,
|
||||
ovn_const.OVN_MEMBER_STATUS_KEY: '{}'}
|
||||
self.helper.ovn_nbdb_api.db_find.return_value.\
|
||||
@ -233,20 +233,16 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
def test__update_hm_member_no_members(self):
|
||||
pool_key = 'pool_%s' % self.pool_id
|
||||
self.ovn_lb.external_ids[pool_key] = ''
|
||||
self.assertTrue(
|
||||
self.helper._update_hm_member(self.ovn_lb,
|
||||
pool_key,
|
||||
'10.0.0.4'))
|
||||
self.assertEqual(self.helper._update_hm_member(
|
||||
self.ovn_lb, pool_key, '10.0.0.4'), constants.ERROR)
|
||||
|
||||
def test__update_hm_member_backend_ip_not_match(self):
|
||||
pool_key = 'pool_%s' % self.pool_id
|
||||
self.ovn_lb.external_ids[pool_key] = self.member_line
|
||||
with mock.patch.object(ovn_helper.OvnProviderHelper,
|
||||
'_get_member_lsp'):
|
||||
self.assertTrue(
|
||||
self.helper._update_hm_member(self.ovn_lb,
|
||||
pool_key,
|
||||
'10.0.0.4'))
|
||||
self.assertEqual(self.helper._update_hm_member(
|
||||
self. ovn_lb, pool_key, '10.0.0.4'), constants.ERROR)
|
||||
|
||||
@mock.patch.object(ovn_helper.OvnProviderHelper, '_ensure_hm_ovn_port')
|
||||
def test__update_hm_member_hm_port_multiple_ip(self, ensure_hm_port):
|
||||
@ -260,10 +256,8 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
pool_key = 'pool_%s' % self.pool_id
|
||||
with mock.patch.object(ovn_helper.OvnProviderHelper,
|
||||
'_get_member_lsp'):
|
||||
self.assertTrue(
|
||||
self.helper._update_hm_member(self.ovn_lb,
|
||||
pool_key,
|
||||
self.member_address))
|
||||
self.assertEqual(self.helper._update_hm_member(
|
||||
self.ovn_lb, pool_key, self.member_address), constants.ONLINE)
|
||||
|
||||
@mock.patch.object(ovn_helper.OvnProviderHelper, '_ensure_hm_ovn_port')
|
||||
def test__update_hm_member_hm_port_not_found(self, ensure_hm_port):
|
||||
@ -271,7 +265,7 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
pool_key = 'pool_%s' % self.pool_id
|
||||
with mock.patch.object(ovn_helper.OvnProviderHelper,
|
||||
'_get_member_lsp'):
|
||||
self.assertFalse(
|
||||
self.assertIsNone(
|
||||
self.helper._update_hm_member(self.ovn_lb,
|
||||
pool_key,
|
||||
self.member_address))
|
||||
@ -1699,28 +1693,11 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
|
||||
self.ovn_lb.uuid)
|
||||
|
||||
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
|
||||
def test_member_create(self, net_cli):
|
||||
net_cli.return_value.show_subnet.side_effect = [idlutils.RowNotFound]
|
||||
self.ovn_lb.external_ids = mock.MagicMock()
|
||||
status = self.helper.member_create(self.member)
|
||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['pools'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['members'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['members'][0]['operating_status'],
|
||||
constants.NO_MONITOR)
|
||||
calls = [
|
||||
mock.call.db_clear('Load_Balancer', self.ovn_lb.uuid, 'vips'),
|
||||
mock.call.db_set('Load_Balancer', self.ovn_lb.uuid, ('vips', {}))]
|
||||
self.helper.ovn_nbdb_api.assert_has_calls(calls)
|
||||
|
||||
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
|
||||
def test_member_create_disabled(self, net_cli):
|
||||
net_cli.return_value.show_subnet.side_effect = [idlutils.RowNotFound]
|
||||
self.ovn_lb.external_ids = mock.MagicMock()
|
||||
self._update_external_ids_member_status(self.ovn_lb, self.member['id'],
|
||||
'offline')
|
||||
self.member['admin_state_up'] = False
|
||||
status = self.helper.member_create(self.member)
|
||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||
@ -1770,8 +1747,12 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
@mock.patch.object(ovn_helper.OvnProviderHelper, '_add_member')
|
||||
def test_member_create_exception(self, mock_add_member):
|
||||
mock_add_member.side_effect = [RuntimeError]
|
||||
self._update_external_ids_member_status(self.ovn_lb, self.member_id,
|
||||
'error')
|
||||
status = self.helper.member_create(self.member)
|
||||
self.assertEqual(status['pools'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['pools'][0]['operating_status'],
|
||||
constants.ERROR)
|
||||
|
||||
def test_member_create_lb_disabled(self):
|
||||
@ -1806,18 +1787,30 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
self.router)
|
||||
|
||||
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
|
||||
def test_member_create_listener(self, net_cli):
|
||||
def test_member_create(self, net_cli):
|
||||
net_cli.return_value.get_subnet.side_effect = [idlutils.RowNotFound]
|
||||
self.ovn_lb.external_ids = mock.MagicMock()
|
||||
self.helper._get_pool_listeners.return_value = ['listener1']
|
||||
status = self.helper.member_create(self.member)
|
||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['loadbalancers'][0]['operating_status'],
|
||||
constants.ONLINE)
|
||||
self.assertEqual(status['listeners'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['listeners'][0]['id'],
|
||||
'listener1')
|
||||
self.assertEqual(status['listeners'][0]['operating_status'],
|
||||
constants.ONLINE)
|
||||
self.assertEqual(status['pools'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['pools'][0]['operating_status'],
|
||||
constants.ONLINE)
|
||||
self.assertEqual(status['members'][0]['id'],
|
||||
self.member_id)
|
||||
self.assertEqual(status['members'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['members'][0]['operating_status'],
|
||||
constants.NO_MONITOR)
|
||||
|
||||
def test_member_create_already_exists(self):
|
||||
self.helper.member_create(self.member)
|
||||
status = self.helper.member_create(self.member)
|
||||
member_status = {
|
||||
ovn_const.OVN_MEMBER_STATUS_KEY: '{"%s": "%s"}'
|
||||
% (self.member_id, constants.NO_MONITOR)}
|
||||
@ -1825,6 +1818,14 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
'Load_Balancer',
|
||||
self.ovn_lb.uuid,
|
||||
('external_ids', member_status))
|
||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['pools'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['members'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['members'][0]['operating_status'],
|
||||
constants.NO_MONITOR)
|
||||
|
||||
def test_member_create_first_member_in_pool(self):
|
||||
self.ovn_lb.external_ids.update({
|
||||
@ -1873,7 +1874,6 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
expected_calls)
|
||||
|
||||
def test_member_update(self):
|
||||
self.ovn_lb.external_ids = mock.MagicMock()
|
||||
status = self.helper.member_update(self.member)
|
||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
@ -1884,6 +1884,8 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
self.assertEqual(status['members'][0]['operating_status'],
|
||||
constants.NO_MONITOR)
|
||||
self.member['admin_state_up'] = False
|
||||
self._update_external_ids_member_status(self.ovn_lb, self.member_id,
|
||||
'offline')
|
||||
status = self.helper.member_update(self.member)
|
||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
@ -1903,6 +1905,8 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
constants.ACTIVE)
|
||||
self.member['old_admin_state_up'] = False
|
||||
self.member['admin_state_up'] = True
|
||||
self._update_external_ids_member_status(self.ovn_lb, self.member_id,
|
||||
'online')
|
||||
status = self.helper.member_update(self.member)
|
||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
@ -1937,15 +1941,6 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
[mock.call('pool_%s' % self.pool_id),
|
||||
mock.call('pool_%s%s' % (self.pool_id, ':D'))])
|
||||
|
||||
def test_member_update_pool_listeners(self):
|
||||
self.ovn_lb.external_ids = mock.MagicMock()
|
||||
self.helper._get_pool_listeners.return_value = ['listener1']
|
||||
status = self.helper.member_update(self.member)
|
||||
self.assertEqual(status['listeners'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['listeners'][0]['id'],
|
||||
'listener1')
|
||||
|
||||
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_member_status')
|
||||
def test_member_update_exception(self, mock_find_member_status):
|
||||
mock_find_member_status.side_effect = [TypeError]
|
||||
@ -1964,7 +1959,11 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
self.assertEqual(status['members'][0]['provisioning_status'],
|
||||
constants.DELETED)
|
||||
|
||||
def test_member_delete_one_left(self):
|
||||
@mock.patch.object(ovn_helper.OvnProviderHelper, '_remove_member')
|
||||
@mock.patch.object(ovn_helper.OvnProviderHelper,
|
||||
'_update_external_ids_member_status')
|
||||
def test_member_delete_one_left(self, update_external_ids_members,
|
||||
rmmember):
|
||||
member2_id = uuidutils.generate_uuid()
|
||||
member2_port = '1010'
|
||||
member2_address = '192.168.2.150'
|
||||
@ -1977,6 +1976,10 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
self.ovn_lb.external_ids.update({
|
||||
'pool_' + self.pool_id: member_line})
|
||||
status = self.helper.member_delete(self.member)
|
||||
rmmember.assert_called_once_with(
|
||||
self.member, self.ovn_lb, 'pool_' + self.pool_id)
|
||||
update_external_ids_members.assert_called_once_with(
|
||||
self.ovn_lb, self.member_id, None, delete=True)
|
||||
self.assertEqual(status['members'][0]['provisioning_status'],
|
||||
constants.DELETED)
|
||||
self.assertEqual(status['pools'][0]['provisioning_status'],
|
||||
@ -1996,13 +1999,18 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
self.member_address,
|
||||
delete=True)
|
||||
|
||||
def test_member_delete_none(self):
|
||||
def test_member_delete_not_found_in_pool(self):
|
||||
self.ovn_lb.external_ids.update({'pool_' + self.pool_id: ''})
|
||||
self.ovn_lb.external_ids[ovn_const.OVN_MEMBER_STATUS_KEY] = '{}'
|
||||
status = self.helper.member_delete(self.member)
|
||||
self.assertEqual(status['members'][0]['provisioning_status'],
|
||||
constants.ERROR)
|
||||
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['listeners'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['pools'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['members'][0]['provisioning_status'],
|
||||
constants.ERROR)
|
||||
|
||||
@mock.patch.object(ovn_helper.OvnProviderHelper, '_remove_member')
|
||||
def test_member_delete_exception(self, mock_remove_member):
|
||||
@ -2019,20 +2027,6 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
[mock.call('pool_%s' % self.pool_id),
|
||||
mock.call('pool_%s%s' % (self.pool_id, ':D'))])
|
||||
|
||||
def test_member_delete_pool_listeners(self):
|
||||
member_line = (
|
||||
'member_%s_%s:%s_%s' %
|
||||
(self.member_id, self.member_address, self.member_port,
|
||||
self.member_subnet_id))
|
||||
self.ovn_lb.external_ids.update({
|
||||
'pool_' + self.pool_id: member_line})
|
||||
self.helper._get_pool_listeners.return_value = ['listener1']
|
||||
status = self.helper.member_delete(self.member)
|
||||
self.assertEqual(status['listeners'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
self.assertEqual(status['listeners'][0]['id'],
|
||||
'listener1')
|
||||
|
||||
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
|
||||
def test_logical_router_port_event_create(self, net_cli):
|
||||
self.router_port_event = ovn_event.LogicalRouterPortEvent(
|
||||
@ -3705,10 +3699,12 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
pool_key = 'pool_%s' % self.pool_id
|
||||
self.ovn_hm_lb.protocol = [protocol]
|
||||
folbpi.return_value = (pool_key, self.ovn_hm_lb)
|
||||
uhm.return_value = True
|
||||
uhm.return_value = constants.ONLINE
|
||||
net_cli.return_value.get_subnet.return_value = {'subnet': fake_subnet}
|
||||
if not fip:
|
||||
del self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_VIP_FIP_KEY]
|
||||
self._update_external_ids_member_status(self.ovn_hm_lb, self.member_id,
|
||||
'online')
|
||||
status = self.helper.hm_create(self.health_monitor)
|
||||
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
@ -3815,6 +3811,8 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
pool_key = 'pool_%s' % self.pool_id
|
||||
folbpi.return_value = (pool_key, self.ovn_hm_lb)
|
||||
self.health_monitor['admin_state_up'] = False
|
||||
self._update_external_ids_member_status(self.ovn_hm_lb, self.member_id,
|
||||
'online')
|
||||
status = self.helper.hm_create(self.health_monitor)
|
||||
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
|
||||
constants.ACTIVE)
|
||||
@ -4359,7 +4357,7 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
self._test_hm_update_no_member(False, True)
|
||||
|
||||
def _test_hm_update_status(self, ovn_lbs, member_id, ip, port,
|
||||
member_status):
|
||||
mb_status):
|
||||
info = {
|
||||
'ovn_lbs': ovn_lbs,
|
||||
'ip': ip,
|
||||
@ -4367,9 +4365,10 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
'src_ip': '10.22.33.4',
|
||||
'port': port,
|
||||
'protocol': ovn_lbs[0].protocol,
|
||||
'status': [member_status]}
|
||||
'status': [mb_status]}
|
||||
mb_status_ovn = 'error' if mb_status == 'offline' else mb_status
|
||||
self._update_external_ids_member_status(self.ovn_hm_lb, member_id,
|
||||
member_status)
|
||||
mb_status_ovn)
|
||||
status = self.helper.hm_update_event(info)
|
||||
return status
|
||||
|
||||
@ -4414,6 +4413,8 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
def _update_external_ids_member_status(self, lb, member_id, member_status):
|
||||
status = constants.ONLINE
|
||||
if member_status == 'offline':
|
||||
status = constants.OFFLINE
|
||||
elif member_status == 'error':
|
||||
status = constants.ERROR
|
||||
try:
|
||||
existing_member_status = lb.external_ids[
|
||||
@ -4657,9 +4658,9 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
'protocol': self.ovn_hm_lb.protocol,
|
||||
'status': ovn_const.HM_EVENT_MEMBER_PORT_OFFLINE}
|
||||
self._update_external_ids_member_status(self.ovn_hm_lb, member['id'],
|
||||
'offline')
|
||||
'error')
|
||||
self._update_external_ids_member_status(ovn_hm_lb_2, member_2['id'],
|
||||
'offline')
|
||||
'error')
|
||||
status = self.helper.hm_update_event(info)
|
||||
|
||||
self.assertEqual(status['pools'][0]['provisioning_status'],
|
||||
@ -4767,10 +4768,10 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
|
||||
member_lb2 = self._add_member(ovn_hm_lb2, fake_subnet, 8081,
|
||||
pool_id=pool_id_2, ip=ip_member)
|
||||
|
||||
# member lb2 OFFLINE, so lb2 operating_status should be ERROR
|
||||
# member lb2 ERROR, so lb2 operating_status should be ERROR
|
||||
# for Pool and Loadbalancer, but lb1 should keep ONLINE
|
||||
self._update_external_ids_member_status(ovn_hm_lb2, member_lb2['id'],
|
||||
'offline')
|
||||
'error')
|
||||
|
||||
info = {
|
||||
'ovn_lbs': [self.ovn_hm_lb, ovn_hm_lb2],
|
||||
|
Loading…
Reference in New Issue
Block a user