Fix operational status for disabled UDP listeners

Disabled UDP listeners appeared as ONLINE, as the heartbeat message
always showed listeners as OPEN, even if disabled.

This commit fixes the configuration file for UDP listeners, previously
enabling or disabling a UDP listener created the same config file. Now
disabling a UDP listener explicitly adds a comment in the file.

Based on this comment, the heartbeat message doesn't include status
updates for disabled UDP listeners.

Conflicts:
  octavia/tests/unit/common/jinja/lvs/test_lvs_jinja_cfg.py

Story: 2007979
Task: 40605

Change-Id: I400dde533f78bc14ee568bfd9714eafac97e8a39
(cherry picked from commit bb4f50f798)
(cherry picked from commit 8fe7cff8dc)
This commit is contained in:
Gregory Thiemonge 2020-08-05 08:14:24 +02:00 committed by Michael Johnson
parent 6ba8dc62b6
commit 1c8adf8084
5 changed files with 75 additions and 3 deletions

View File

@ -35,8 +35,8 @@ V6_VS_REGEX = re.compile(r"virtual_server\s([\w*:]+\b)\s(\d{1,5})")
V6_RS_REGEX = re.compile(r"real_server\s([\w*:]+\b)\s(\d{1,5})")
CONFIG_COMMENT_REGEX = re.compile(
r"#\sConfiguration\sfor\s(\w+)\s(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})")
DISABLED_MEMBER_COMMENT_REGEX = re.compile(
r"#\sMember\s(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}) is disabled")
DISABLED_CONFIG_COMMENT_REGEX = re.compile(
r"#\s(\w+)\s(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}) is disabled")
CHECKER_REGEX = re.compile(r"MISC_CHECK")
@ -152,6 +152,14 @@ def get_udp_listener_resource_ipports_nsname(listener_id):
listener_ip_port = V6_VS_REGEX.findall(cfg)
listener_ip_port = listener_ip_port[0] if listener_ip_port else []
disabled_resource_ids = DISABLED_CONFIG_COMMENT_REGEX.findall(cfg)
listener_disabled = any(True
for resource in disabled_resource_ids
if resource[0] == 'Listener')
if listener_disabled:
return None, ns_name
if not listener_ip_port:
# If not get listener_ip_port from the lvs config file,
# that means the udp listener's default pool have no enabled member
@ -181,7 +189,11 @@ def get_udp_listener_resource_ipports_nsname(listener_id):
elif resource_type == 'Members':
resource_ipport_mapping[resource_type].append(value)
disabled_member_ids = DISABLED_MEMBER_COMMENT_REGEX.findall(cfg)
disabled_member_ids = [
resource[1]
for resource in disabled_resource_ids
if resource[0] == 'Member'
]
resource_type = 'Members'
for member_id in disabled_member_ids:
@ -363,6 +375,10 @@ def get_udp_listeners_stats():
(resource_ipport_mapping,
ns_name) = get_udp_listener_resource_ipports_nsname(check_listener_id)
# Listener is disabled, we don't need to send an update
if resource_ipport_mapping is None:
continue
# Since we found the keepalived running, acknowledge the listener
# in the heartbeat. If this listener has a pool and members,
# the stats will be updated later in the code flow.

View File

@ -14,7 +14,11 @@
#
#}
# Configuration for Loadbalancer {{ loadbalancer.id }}
{% if loadbalancer.listener.enabled %}
# Configuration for Listener {{ udp_listener_id }}
{% else %}
# Listener {{ udp_listener_id }} is disabled
{% endif %}
{% block global_definitions %}{% endblock global_definitions %}

View File

@ -126,6 +126,11 @@ CFG_FILE_TEMPLATE_v6 = (
" # Member %(member_id4)s is disabled\n\n"
"}")
CFG_FILE_TEMPLATE_DISABLED_LISTENER = (
"# Listener %(listener_id)s is disabled \n\n"
"net_namespace %(ns_name)s\n\n"
)
IPVSADM_OUTPUT_TEMPLATE = (
"IP Virtual Server version 1.2.1 (size=4096)\n"
"Prot LocalAddress:Port Scheduler Flags\n"
@ -162,6 +167,7 @@ class LvsQueryTestCase(base.TestCase):
self.member_id2_v6 = uuidutils.generate_uuid()
self.member_id3_v6 = uuidutils.generate_uuid()
self.member_id4_v6 = uuidutils.generate_uuid()
self.disabled_listener_id = uuidutils.generate_uuid()
cfg_content_v4 = CFG_FILE_TEMPLATE_v4 % {
'listener_id': self.listener_id_v4,
'ns_name': constants.AMPHORA_NAMESPACE,
@ -180,10 +186,19 @@ class LvsQueryTestCase(base.TestCase):
'member_id3': self.member_id3_v6,
'member_id4': self.member_id4_v6
}
cfg_content_disabled_listener = (
CFG_FILE_TEMPLATE_DISABLED_LISTENER % {
'listener_id': self.listener_id_v6,
'ns_name': constants.AMPHORA_NAMESPACE,
}
)
self.useFixture(test_utils.OpenFixture(
util.keepalived_lvs_cfg_path(self.listener_id_v4), cfg_content_v4))
self.useFixture(test_utils.OpenFixture(
util.keepalived_lvs_cfg_path(self.listener_id_v6), cfg_content_v6))
self.useFixture(test_utils.OpenFixture(
util.keepalived_lvs_cfg_path(self.disabled_listener_id),
cfg_content_disabled_listener))
@mock.patch('subprocess.check_output')
def test_get_listener_realserver_mapping(self, mock_check_output):
@ -278,6 +293,11 @@ class LvsQueryTestCase(base.TestCase):
'ipport': None}]}
self.assertEqual((expected, constants.AMPHORA_NAMESPACE), res)
# disabled
res = lvs_query.get_udp_listener_resource_ipports_nsname(
self.disabled_listener_id)
self.assertEqual((None, constants.AMPHORA_NAMESPACE), res)
@mock.patch('subprocess.check_output')
def test_get_udp_listener_pool_status(self, mock_check_output):
# test with ipv4 and ipv6
@ -456,3 +476,14 @@ class LvsQueryTestCase(base.TestCase):
mock_is_running.return_value = False
res = lvs_query.get_udp_listeners_stats()
self.assertEqual({}, res)
@mock.patch('subprocess.check_output')
@mock.patch("octavia.amphorae.backends.agent.api_server.util."
"is_udp_listener_running", return_value=True)
@mock.patch("octavia.amphorae.backends.agent.api_server.util."
"get_udp_listeners")
def test_get_udp_listeners_stats_disabled_listener(
self, mock_get_listener, mock_is_running, mock_check_output):
mock_get_listener.return_value = [self.disabled_listener_id]
res = lvs_query.get_udp_listeners_stats()
self.assertEqual({}, res)

View File

@ -297,3 +297,18 @@ class TestLvsCfg(base.TestCase):
ret = self.udp_jinja_cfg._transform_listener(in_listener)
sample_configs_combined.RET_UDP_LISTENER.pop('connection_limit')
self.assertEqual(sample_configs_combined.RET_UDP_LISTENER, ret)
def test_render_template_disabled_udp_listener(self):
exp = ("# Configuration for Loadbalancer sample_loadbalancer_id_1\n"
"# Listener sample_listener_id_1 is disabled\n\n"
"net_namespace amphora-haproxy\n\n")
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_listener_tuple(
enabled=False,
proto=constants.PROTOCOL_UDP,
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
persistence_timeout=33,
persistence_granularity='255.255.0.0',
monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT,
connection_limit=98))
self.assertEqual(exp, rendered_obj)

View File

@ -0,0 +1,6 @@
---
fixes:
- |
Fix operational status for disabled UDP listeners. The operating status of
disabled UDP listeners is now OFFLINE instead of ONLINE, the behavior is now
similary to the behavior of HTTP/HTTPS/TCP/... listeners.