Skip to content

Commit 72f59a3

Browse files
committed
Fix error in agent-agent with empty UDP pools in IPv4+IPv6 LBs
With dual stack LBs (IPv4+IPv6) and UDP pools, the amphora-agent triggered an exception when a pool contained only IPv4 or only IPv6 members. This commit fixes this issue. Closes-Bug: #2028751 Change-Id: I7141258bfee69606a6749cd17e524b7932359d7a
1 parent 12d8e0d commit 72f59a3

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

octavia/amphorae/backends/utils/keepalivedlvs_query.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,8 @@ def get_lvs_listeners_stats():
460460
status = constants.OPEN
461461
# Get scur
462462
for listener_ipport in listener_ipports:
463+
if listener_ipport not in scur_res:
464+
continue
463465
for m in scur_res[listener_ipport]['Members']:
464466
for item in m:
465467
if item[0] == 'ActiveConn':

octavia/tests/unit/amphorae/backends/utils/test_keepalivedlvs_query.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,37 @@
190190
" # Member %(member_id5)s is disabled\n\n"
191191
"}")
192192

193+
CFG_FILE_TEMPLATE_mixed_no_ipv6_member = (
194+
"# Configuration for Listener %(listener_id)s\n\n"
195+
"net_namespace %(ns_name)s\n\n"
196+
"virtual_server_group ipv4-group {\n"
197+
" 10.0.0.37 7777\n"
198+
"}\n\n"
199+
"virtual_server group ipv4-group {\n"
200+
" lb_algo rr\n"
201+
" lvs_method NAT\n"
202+
" protocol udp\n\n\n"
203+
" # Configuration for Pool %(pool_id)s\n"
204+
" # Configuration for Member %(member_id1)s\n"
205+
" real_server 10.0.0.25 2222 {\n"
206+
" weight 3\n"
207+
" MISC_CHECK {\n\n"
208+
" misc_path \"/usr/bin/check_script.sh\"\n\n"
209+
" misc_timeout 5\n\n"
210+
" }\n\n"
211+
" }\n\n"
212+
" # Member %(member_id2)s is disabled\n\n"
213+
"}\n"
214+
"virtual_server_group ipv6-group {\n"
215+
" fd79:35e2:9963:0:f816:3eff:fe6d:7a2a 7777\n"
216+
"}\n\n"
217+
"virtual_server group ipv6-group {\n"
218+
" lb_algo rr\n"
219+
" lvs_method NAT\n"
220+
" protocol udp\n\n\n"
221+
" # Configuration for Pool %(pool_id)s\n"
222+
"}")
223+
193224
CFG_FILE_TEMPLATE_DISABLED_LISTENER = (
194225
"# Listener %(listener_id)s is disabled \n\n"
195226
"net_namespace %(ns_name)s\n\n"
@@ -233,6 +264,7 @@ def setUp(self):
233264
self.member_id4_v6 = uuidutils.generate_uuid()
234265
self.member_id5_v6 = uuidutils.generate_uuid()
235266
self.listener_id_mixed = uuidutils.generate_uuid()
267+
self.listener_id_mixed_no_ipv6_member = uuidutils.generate_uuid()
236268
self.pool_id_mixed = uuidutils.generate_uuid()
237269
self.disabled_listener_id = uuidutils.generate_uuid()
238270
cfg_content_v4 = CFG_FILE_TEMPLATE_v4 % {
@@ -264,6 +296,15 @@ def setUp(self):
264296
'member_id4': self.member_id4_v6,
265297
'member_id5': self.member_id5_v6
266298
}
299+
cfg_content_mixed_no_ipv6_member = (
300+
CFG_FILE_TEMPLATE_mixed_no_ipv6_member % {
301+
'listener_id': self.listener_id_mixed,
302+
'ns_name': constants.AMPHORA_NAMESPACE,
303+
'pool_id': self.pool_id_mixed,
304+
'member_id1': self.member_id1_v4,
305+
'member_id2': self.member_id2_v4
306+
}
307+
)
267308
cfg_content_disabled_listener = (
268309
CFG_FILE_TEMPLATE_DISABLED_LISTENER % {
269310
'listener_id': self.listener_id_v6,
@@ -277,6 +318,10 @@ def setUp(self):
277318
self.useFixture(test_utils.OpenFixture(
278319
util.keepalived_lvs_cfg_path(self.listener_id_mixed),
279320
cfg_content_mixed))
321+
self.useFixture(test_utils.OpenFixture(
322+
util.keepalived_lvs_cfg_path(
323+
self.listener_id_mixed_no_ipv6_member),
324+
cfg_content_mixed_no_ipv6_member))
280325
self.useFixture(test_utils.OpenFixture(
281326
util.keepalived_lvs_cfg_path(self.disabled_listener_id),
282327
cfg_content_disabled_listener))
@@ -629,6 +674,29 @@ def test_get_lvs_listeners_stats(
629674
res = lvs_query.get_lvs_listeners_stats()
630675
self.assertEqual({}, res)
631676

677+
# listener for both ipv4 and ipv6, but no member in the ipv6 pool
678+
mock_is_running.return_value = True
679+
mock_get_listener.return_value = [
680+
self.listener_id_mixed_no_ipv6_member]
681+
output_list = list()
682+
output_list.append(IPVSADM_OUTPUT_TEMPLATE % {
683+
"listener_ipport": "10.0.0.37:7777",
684+
"member1_ipport": "10.0.0.25:2222",
685+
"member2_ipport": "10.0.0.35:3333"})
686+
output_list.append(IPVSADM_STATS_OUTPUT_TEMPLATE % {
687+
"listener_ipport": "10.0.0.37:7777",
688+
"member1_ipport": "10.0.0.25:2222",
689+
"member2_ipport": "10.0.0.35:3333"})
690+
mock_check_output.side_effect = output_list
691+
res = lvs_query.get_lvs_listeners_stats()
692+
# We can check the expected result reference the stats sample,
693+
# that means this func can compute the stats info of single listener.
694+
expected = {self.listener_id_mixed_no_ipv6_member: {
695+
'status': constants.OPEN,
696+
'stats': {'bin': 6387472, 'stot': 5, 'bout': 7490,
697+
'ereq': 0, 'scur': 0}}}
698+
self.assertEqual(expected, res)
699+
632700
@mock.patch('subprocess.check_output')
633701
@mock.patch("octavia.amphorae.backends.agent.api_server.util."
634702
"is_lvs_listener_running", return_value=True)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
fixes:
3+
- |
4+
Fixed a bug in the amphora-agent, an exception was triggered when a LB with
5+
both IPv4 and IPv6 VIPs and with a UDP pool had only IPv4 members or
6+
only IPv6 members.

0 commit comments

Comments
 (0)