Skip to content

Commit cbed7c0

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Patching Octavia LB pool removal issue and adding updated unit tests"
2 parents 1d38443 + 80a6544 commit cbed7c0

File tree

2 files changed

+146
-14
lines changed

2 files changed

+146
-14
lines changed

ovn_octavia_provider/helper.py

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3520,18 +3520,52 @@ def _update_lbhc_vip_port(self, lbhc, vip_port):
35203520
self._execute_commands(commands)
35213521
return True
35223522

3523-
def _update_ip_port_mappings(self, ovn_lb, backend_ip, port_name, src_ip,
3524-
delete=False):
3525-
3523+
def _update_ip_port_mappings(
3524+
self,
3525+
ovn_lb,
3526+
backend_ip,
3527+
port_name,
3528+
src_ip,
3529+
pool_key,
3530+
delete=False):
35263531
# ip_port_mappings:${MEMBER_IP}=${LSP_NAME_MEMBER}:${HEALTH_SRC}
35273532
# where:
35283533
# MEMBER_IP: IP of member_lsp
35293534
# LSP_NAME_MEMBER: Logical switch port
35303535
# HEALTH_SRC: source IP of hm_port
35313536

35323537
if delete:
3533-
self.ovn_nbdb_api.lb_del_ip_port_mapping(ovn_lb.uuid,
3534-
backend_ip).execute()
3538+
# Before removing a member from ip_port_mappings,
3539+
# make sure no other
3540+
# pool uses the same member.
3541+
other_members = []
3542+
for k, v in ovn_lb.external_ids.items():
3543+
if ovn_const.LB_EXT_IDS_POOL_PREFIX in k and k != pool_key:
3544+
other_members.extend(self._extract_member_info(
3545+
ovn_lb.external_ids[k]))
3546+
member_statuses = ovn_lb.external_ids.get(
3547+
ovn_const.OVN_MEMBER_STATUS_KEY)
3548+
try:
3549+
member_statuses = jsonutils.loads(member_statuses)
3550+
except TypeError:
3551+
LOG.debug("No member status in external_ids: %s",
3552+
str(member_statuses))
3553+
member_statuses = {}
3554+
execute_delete = True
3555+
for member_id in [item[3] for item in other_members
3556+
if item[0] == backend_ip]:
3557+
if member_statuses.get(member_id, '') != constants.NO_MONITOR:
3558+
execute_delete = False
3559+
LOG.debug(
3560+
f"Backend {backend_ip} still in use by member"
3561+
f" {member_id}, "
3562+
f"so it won't be removed"
3563+
)
3564+
break
3565+
if execute_delete:
3566+
LOG.debug(f"Removing ip_port_mapping for {backend_ip}")
3567+
self.ovn_nbdb_api.lb_del_ip_port_mapping(
3568+
ovn_lb.uuid, backend_ip).execute()
35353569
else:
35363570
self.ovn_nbdb_api.lb_add_ip_port_mapping(ovn_lb.uuid,
35373571
backend_ip,
@@ -3620,8 +3654,11 @@ def _update_hm_member(self, ovn_lb, pool_key, backend_ip, delete=False):
36203654
'member': mb_ip,
36213655
'pool': pool_key})
36223656
return None
3623-
self._update_ip_port_mappings(ovn_lb, backend_ip,
3624-
member_lsp.name, hm_source_ip,
3657+
self._update_ip_port_mappings(ovn_lb,
3658+
backend_ip,
3659+
member_lsp.name,
3660+
hm_source_ip,
3661+
pool_key,
36253662
delete)
36263663
return constants.ONLINE
36273664

ovn_octavia_provider/tests/unit/test_helper.py

Lines changed: 102 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -336,15 +336,23 @@ def test__clean_ip_port_mappings_two_hm_pools_not_sharing_members(self):
336336
def test__update_ip_port_mappings_del_backend_member(self):
337337
src_ip = '10.22.33.4'
338338
self.helper._update_ip_port_mappings(
339-
self.ovn_lb, self.member_address, 'a-logical-port', src_ip,
339+
self.ovn_lb,
340+
self.member_address,
341+
'a-logical-port',
342+
src_ip,
343+
'test_pool_key',
340344
delete=True)
341345
self.helper.ovn_nbdb_api.lb_del_ip_port_mapping.\
342346
assert_called_once_with(self.ovn_lb.uuid, self.member_address)
343347

344348
def test__update_ip_port_mappings_add_backend_member(self):
345349
src_ip = '10.22.33.4'
346350
self.helper._update_ip_port_mappings(
347-
self.ovn_lb, self.member_address, 'a-logical-port', src_ip)
351+
self.ovn_lb,
352+
self.member_address,
353+
'a-logical-port',
354+
src_ip,
355+
'test_pool_key')
348356
self.helper.ovn_nbdb_api.lb_add_ip_port_mapping.\
349357
assert_called_once_with(self.ovn_lb.uuid, self.member_address,
350358
'a-logical-port', src_ip)
@@ -353,7 +361,11 @@ def test__update_ip_port_mappings_del_backend_member_ipv6(self):
353361
member_address = 'fda2:918e:5869:0:f816:3eff:feab:cdef'
354362
src_ip = 'fda2:918e:5869:0:f816:3eff:fecd:398a'
355363
self.helper._update_ip_port_mappings(
356-
self.ovn_lb, member_address, 'a-logical-port', src_ip,
364+
self.ovn_lb,
365+
member_address,
366+
'a-logical-port',
367+
src_ip,
368+
'test_pool_key',
357369
delete=True)
358370
self.helper.ovn_nbdb_api.lb_del_ip_port_mapping.\
359371
assert_called_once_with(self.ovn_lb.uuid, member_address)
@@ -362,10 +374,17 @@ def test__update_ip_port_mappings_add_backend_member_ipv6(self):
362374
member_address = 'fda2:918e:5869:0:f816:3eff:feab:cdef'
363375
src_ip = 'fda2:918e:5869:0:f816:3eff:fecd:398a'
364376
self.helper._update_ip_port_mappings(
365-
self.ovn_lb, member_address, 'a-logical-port', src_ip)
377+
self.ovn_lb,
378+
member_address,
379+
'a-logical-port',
380+
src_ip,
381+
'test_pool_key')
366382
self.helper.ovn_nbdb_api.lb_add_ip_port_mapping.\
367383
assert_called_once_with(
368-
self.ovn_lb.uuid, member_address, 'a-logical-port', src_ip)
384+
self.ovn_lb.uuid,
385+
member_address,
386+
'a-logical-port',
387+
src_ip)
369388

370389
def test__update_external_ids_member_status(self):
371390
self.helper._update_external_ids_member_status(
@@ -374,7 +393,10 @@ def test__update_external_ids_member_status(self):
374393
ovn_const.OVN_MEMBER_STATUS_KEY: '{"%s": "%s"}'
375394
% (self.member_id, constants.NO_MONITOR)}
376395
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
377-
'Load_Balancer', self.ovn_lb.uuid, ('external_ids', member_status))
396+
'Load_Balancer',
397+
self.ovn_lb.uuid,
398+
('external_ids',
399+
member_status))
378400

379401
def test__update_external_ids_member_status_delete(self):
380402
self.helper._update_external_ids_member_status(
@@ -390,7 +412,10 @@ def test__update_external_ids_member_status_delete_not_found(self):
390412
ovn_const.OVN_MEMBER_STATUS_KEY: '{"%s": "%s"}'
391413
% (self.member_id, constants.NO_MONITOR)}
392414
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
393-
'Load_Balancer', self.ovn_lb.uuid, ('external_ids', member_status))
415+
'Load_Balancer',
416+
self.ovn_lb.uuid,
417+
('external_ids',
418+
member_status))
394419

395420
def test__find_member_status(self):
396421
status = self.helper._find_member_status(self.ovn_lb, self.member_id)
@@ -6746,3 +6771,73 @@ def test_refresh_lb_vips_returns_db_operations_when_is_sync_false(
67466771
self.ovn_lb.uuid,
67476772
('vips', {'vip1:port1': 'ip1:port1,ip2:port1'})
67486773
)
6774+
6775+
def test_update_ip_port_mappings_add(self):
6776+
# Setup mock OVN load balancer
6777+
ovn_lb = mock.Mock()
6778+
ovn_lb.uuid = 'test-lb-uuid'
6779+
ovn_lb.external_ids = {}
6780+
6781+
# Call the method with delete=False
6782+
self.helper._update_ip_port_mappings(
6783+
ovn_lb, '10.0.0.1', 'port1', '192.168.0.1', 'pool1', delete=False
6784+
)
6785+
6786+
# Assert that lb_add_ip_port_mapping was called
6787+
self.helper.ovn_nbdb_api.lb_add_ip_port_mapping\
6788+
.assert_called_once_with(
6789+
'test-lb-uuid',
6790+
'10.0.0.1',
6791+
'port1',
6792+
'192.168.0.1',
6793+
)
6794+
6795+
def test_update_ip_port_mappings_delete_minimal(self):
6796+
ovn_lb = mock.Mock()
6797+
ovn_lb.uuid = 'test-lb-uuid'
6798+
ovn_lb.external_ids = {}
6799+
# Patch _extract_member_info to return no other members
6800+
self.helper._extract_member_info = mock.Mock(return_value=[])
6801+
# Also patch ovn_nbdb_api call
6802+
self.helper.ovn_nbdb_api.lb_del_ip_port_mapping = mock.Mock()
6803+
self.helper.ovn_nbdb_api.lb_add_ip_port_mapping = mock.Mock()
6804+
self.helper._update_ip_port_mappings(
6805+
ovn_lb,
6806+
backend_ip='10.0.0.1',
6807+
port_name='dummy-port',
6808+
src_ip='192.168.0.1',
6809+
pool_key='pool-test',
6810+
delete=True
6811+
)
6812+
self.helper.ovn_nbdb_api.\
6813+
lb_del_ip_port_mapping.\
6814+
assert_called_once_with(
6815+
'test-lb-uuid',
6816+
'10.0.0.1'
6817+
)
6818+
6819+
def test_update_ip_port_mappings_delete_with_other_members_present(self):
6820+
ovn_lb = mock.Mock()
6821+
ovn_lb.uuid = 'test-lb-uuid'
6822+
ovn_lb.external_ids = {
6823+
"pool_A": "member_memberA_10.0.0.1:80_subnetA",
6824+
"pool_B": "member_memberB_10.0.0.1:80_subnetA",
6825+
"neutron:member_statuses": '{"memberB": "ONLINE"}'
6826+
}
6827+
6828+
self.helper.ovn_nbdb_api.lb_del_ip_port_mapping = mock.Mock()
6829+
self.helper.ovn_nbdb_api.lb_add_ip_port_mapping = mock.Mock()
6830+
6831+
# Call the method under test
6832+
self.helper._update_ip_port_mappings(
6833+
ovn_lb,
6834+
backend_ip='10.0.0.1',
6835+
port_name='dummy-port',
6836+
src_ip='192.168.0.1',
6837+
pool_key='pool_A',
6838+
delete=True
6839+
)
6840+
6841+
# Should not call delete because memberB is ONLINE and shares the IP
6842+
self.helper.ovn_nbdb_api.lb_del_ip_port_mapping.assert_not_called()
6843+
self.helper.ovn_nbdb_api.lb_add_ip_port_mapping.assert_not_called()

0 commit comments

Comments
 (0)