Skip to content

Commit f100aec

Browse files
authored
Merge pull request #81 from stackhpc/upstream/master-2025-11-17
Synchronise master with upstream
2 parents 60ac578 + be8fd5c commit f100aec

File tree

5 files changed

+157
-7
lines changed

5 files changed

+157
-7
lines changed

ovn_octavia_provider/helper.py

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4039,6 +4039,24 @@ def sm_update_event_handler(self, row, sm_delete_event=False):
40394039
self.add_request({'type': ovn_const.REQ_TYPE_HM_UPDATE_EVENT,
40404040
'info': request_info})
40414041

4042+
# NOTE(froyo) those methods are to get the admin_state_up of the pool or
4043+
# listener independently of the type, octavia_lib when is requested by full
4044+
# lb is returning listeners and pools as dicts, but if a pool or listener
4045+
# is requested by id is returning the object.
4046+
def _get_pool_admin_state(self, pool):
4047+
if hasattr(pool, 'admin_state_up'):
4048+
return pool.admin_state_up
4049+
elif isinstance(pool, dict):
4050+
return pool.get('admin_state_up', True)
4051+
return None
4052+
4053+
def _get_listener_admin_state(self, listener):
4054+
if hasattr(listener, 'admin_state_up'):
4055+
return listener.admin_state_up
4056+
elif isinstance(listener, dict):
4057+
return listener.get('admin_state_up', True)
4058+
return None
4059+
40424060
def _get_current_operating_statuses(self, ovn_lb):
40434061
# NOTE (froyo) We would base all logic in the external_ids field
40444062
# 'neutron:member_status' that should include all LB member status
@@ -4080,6 +4098,17 @@ def _get_current_operating_statuses(self, ovn_lb):
40804098
constants.PROVISIONING_STATUS: constants.ACTIVE,
40814099
constants.OPERATING_STATUS: member_status})
40824100

4101+
_lb = self._octavia_driver_lib.get_loadbalancer(ovn_lb.name)
4102+
4103+
lb_pools = {}
4104+
if hasattr(_lb, "pools") and _lb.pools is not None:
4105+
lb_pools = {pool['pool_id']: pool for pool in _lb.pools}
4106+
4107+
lb_listeners = {}
4108+
if hasattr(_lb, "listeners") and _lb.listeners is not None:
4109+
lb_listeners = {listener['listener_id']: listener
4110+
for listener in _lb.listeners}
4111+
40834112
# get pool statuses
40844113
for pool_id, members in pools.items():
40854114
for i, member in enumerate(members):
@@ -4089,8 +4118,10 @@ def _get_current_operating_statuses(self, ovn_lb):
40894118
# if we don't have local info we assume best option
40904119
members[i] = constants.ONLINE
40914120

4092-
_pool = self._octavia_driver_lib.get_pool(pool_id)
4093-
if not _pool.admin_state_up or not member_statuses:
4121+
_pool = lb_pools.get(pool_id)
4122+
if not _pool:
4123+
_pool = self._octavia_driver_lib.get_pool(pool_id)
4124+
if not self._get_pool_admin_state(_pool) or not member_statuses:
40944125
pools[pool_id] = constants.OFFLINE
40954126
elif pools[pool_id] and all(constants.ERROR == member_status
40964127
for member_status in pools[pool_id]):
@@ -4115,8 +4146,10 @@ def _get_current_operating_statuses(self, ovn_lb):
41154146
# if we don't have local info we assume best option
41164147
listener_pools[i] = constants.ONLINE
41174148

4118-
_listener = self._octavia_driver_lib.get_listener(listener_id)
4119-
if not _listener.admin_state_up:
4149+
_listener = lb_listeners.get(listener_id)
4150+
if not _listener:
4151+
_listener = self._octavia_driver_lib.get_listener(listener_id)
4152+
if not self._get_listener_admin_state(_listener):
41204153
listeners[listener_id] = constants.OFFLINE
41214154
elif any(constants.ERROR == pool_status
41224155
for pool_status in listeners[listener_id]):
@@ -4134,7 +4167,6 @@ def _get_current_operating_statuses(self, ovn_lb):
41344167

41354168
# get LB status
41364169
lb_status = constants.ONLINE
4137-
_lb = self._octavia_driver_lib.get_loadbalancer(ovn_lb.name)
41384170
if not _lb.admin_state_up:
41394171
lb_status = constants.OFFLINE
41404172
elif any(constants.ERROR == status

ovn_octavia_provider/tests/functional/test_driver.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,22 @@ def test_member_no_subnet(self):
249249
pool_TCP_id = lb_data['pools'][0].pool_id
250250

251251
self._o_driver_lib.get_pool.return_value = lb_data['pools'][0]
252+
253+
if not hasattr(lb_data['model'], 'pools'):
254+
lb_data['model'].pools = []
255+
if not hasattr(lb_data['model'], 'listeners'):
256+
lb_data['model'].listeners = []
257+
258+
lb_data['model'].pools = [{
259+
'pool_id': pool.pool_id,
260+
'admin_state_up': pool.admin_state_up
261+
} for pool in lb_data['pools']]
262+
263+
lb_data['model'].listeners = [{
264+
'listener_id': listener.listener_id,
265+
'admin_state_up': listener.admin_state_up
266+
} for listener in lb_data['listeners']]
267+
252268
self._o_driver_lib.get_loadbalancer.return_value = lb_data['model']
253269

254270
# Test deleting a member without subnet

ovn_octavia_provider/tests/unit/test_helper.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8311,3 +8311,101 @@ def test__members_in_subnet_last_member_match(self):
83118311
})
83128312
result = self.helper._members_in_subnet(self.ovn_lb, 'subnet2')
83138313
self.assertTrue(result)
8314+
8315+
def test__get_pool_admin_state_with_object(self):
8316+
class MockPool:
8317+
def __init__(self, admin_state_up=True):
8318+
self.admin_state_up = admin_state_up
8319+
8320+
pool_obj = MockPool(admin_state_up=True)
8321+
result = self.helper._get_pool_admin_state(pool_obj)
8322+
self.assertTrue(result)
8323+
8324+
pool_obj_false = MockPool(admin_state_up=False)
8325+
result = self.helper._get_pool_admin_state(pool_obj_false)
8326+
self.assertFalse(result)
8327+
8328+
def test__get_pool_admin_state_with_dict(self):
8329+
pool_dict = {'admin_state_up': True}
8330+
result = self.helper._get_pool_admin_state(pool_dict)
8331+
self.assertTrue(result)
8332+
8333+
pool_dict_false = {'admin_state_up': False}
8334+
result = self.helper._get_pool_admin_state(pool_dict_false)
8335+
self.assertFalse(result)
8336+
8337+
pool_dict_no_key = {'other_key': 'value'}
8338+
result = self.helper._get_pool_admin_state(pool_dict_no_key)
8339+
self.assertTrue(result)
8340+
8341+
def test__get_pool_admin_state_with_other_type(self):
8342+
result = self.helper._get_pool_admin_state(None)
8343+
self.assertIsNone(result)
8344+
8345+
result = self.helper._get_pool_admin_state("some_string")
8346+
self.assertIsNone(result)
8347+
8348+
result = self.helper._get_pool_admin_state(123)
8349+
self.assertIsNone(result)
8350+
8351+
def test__get_listener_admin_state_with_object(self):
8352+
class MockListener:
8353+
def __init__(self, admin_state_up=True):
8354+
self.admin_state_up = admin_state_up
8355+
8356+
listener_obj = MockListener(admin_state_up=True)
8357+
result = self.helper._get_listener_admin_state(listener_obj)
8358+
self.assertTrue(result)
8359+
8360+
listener_obj_false = MockListener(admin_state_up=False)
8361+
result = self.helper._get_listener_admin_state(listener_obj_false)
8362+
self.assertFalse(result)
8363+
8364+
def test__get_listener_admin_state_with_dict(self):
8365+
listener_dict = {'admin_state_up': True}
8366+
result = self.helper._get_listener_admin_state(listener_dict)
8367+
self.assertTrue(result)
8368+
8369+
listener_dict_false = {'admin_state_up': False}
8370+
result = self.helper._get_listener_admin_state(listener_dict_false)
8371+
self.assertFalse(result)
8372+
8373+
listener_dict_no_key = {'other_key': 'value'}
8374+
result = self.helper._get_listener_admin_state(listener_dict_no_key)
8375+
self.assertTrue(result)
8376+
8377+
def test__get_listener_admin_state_with_other_type(self):
8378+
result = self.helper._get_listener_admin_state(None)
8379+
self.assertIsNone(result)
8380+
8381+
result = self.helper._get_listener_admin_state("some_string")
8382+
self.assertIsNone(result)
8383+
8384+
result = self.helper._get_listener_admin_state(456)
8385+
self.assertIsNone(result)
8386+
8387+
def test__get_pool_admin_state_edge_cases(self):
8388+
class MockPoolNone:
8389+
def __init__(self):
8390+
self.admin_state_up = None
8391+
8392+
pool_none = MockPoolNone()
8393+
result = self.helper._get_pool_admin_state(pool_none)
8394+
self.assertIsNone(result)
8395+
8396+
pool_dict_none = {'admin_state_up': None}
8397+
result = self.helper._get_pool_admin_state(pool_dict_none)
8398+
self.assertIsNone(result)
8399+
8400+
def test__get_listener_admin_state_edge_cases(self):
8401+
class MockListenerNone:
8402+
def __init__(self):
8403+
self.admin_state_up = None
8404+
8405+
listener_none = MockListenerNone()
8406+
result = self.helper._get_listener_admin_state(listener_none)
8407+
self.assertIsNone(result)
8408+
8409+
listener_dict_none = {'admin_state_up': None}
8410+
result = self.helper._get_listener_admin_state(listener_dict_none)
8411+
self.assertIsNone(result)

test-requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ coverage!=4.4,>=4.0 # Apache-2.0
55
flake8-import-order>=0.18.0,<0.19.0 # LGPLv3
66
oslotest>=3.2.0 # Apache-2.0
77
stestr>=1.0.0 # Apache-2.0
8-
pylint>=2.6.0,!=4.0.0,!=4.0.1 # GPLv2
8+
pylint>=2.6.0,<4.0.0 # GPLv2
99
testresources>=2.0.0 # Apache-2.0/BSD
1010
testscenarios>=0.4 # Apache-2.0/BSD
1111
WebTest>=2.0.27 # MIT
1212
testtools>=2.2.0 # MIT
13+
PyMySQL>=0.7.6 # MIT License
1314
neutron>=23.0.0.0b3 # Apache-2.0

tox.ini

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@ commands = false
6060
setenv = {[testenv:functional]setenv}
6161
{[testenv:dsvm]setenv}
6262
deps = {[testenv:functional]deps}
63+
passenv =
64+
{[testenv]passenv}
65+
OS_TEST_DBAPI_ADMIN_CONNECTION
6366
commands =
64-
stestr run --isolated {posargs}
67+
stestr run {posargs}
6568

6669
[testenv:cover]
6770
setenv =

0 commit comments

Comments
 (0)