7ab75bfd95
Result of running: $ codespell -w octavia Change-Id: I85354ddafc61f2ab064330ae4b630366dfed0cbb
792 lines
34 KiB
Python
792 lines
34 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
from unittest import mock
|
|
|
|
from oslo_utils import uuidutils
|
|
|
|
from octavia.amphorae.backends.agent.api_server import util
|
|
from octavia.amphorae.backends.utils import keepalivedlvs_query as lvs_query
|
|
from octavia.common import constants
|
|
from octavia.tests.common import utils as test_utils
|
|
from octavia.tests.unit import base
|
|
|
|
# Kernal_file_sample which is in /proc/net/ip_vs
|
|
# The realservers and the listened ports are
|
|
# 10.0.0.25:2222, 10.0.0.35:3333.
|
|
# Realserver 10.0.0.45:4444 is not listed because healthcheck failed.
|
|
# The virtual server and the listened port is
|
|
# 10.0.0.37:7777.
|
|
KERNAL_FILE_SAMPLE_V4 = (
|
|
"IP Virtual Server version 1.2.1 (size=4096)\n"
|
|
"Prot LocalAddress:Port Scheduler Flags\n"
|
|
" -> RemoteAddress:Port Forward Weight ActiveConn InActConn\n"
|
|
"UDP 0A000025:1E61 rr\n"
|
|
" -> 0A000023:0D05 Masq 2 0 0\n"
|
|
" -> 0A000019:08AE Masq 3 0 0")
|
|
# Kernal_file_sample which is in /proc/net/ip_vs
|
|
# The realservers and the listened ports are
|
|
# [fd79:35e2:9963:0:f816:3eff:feca:b7bf]:2222,
|
|
# [fd79:35e2:9963:0:f816:3eff:fe9d:94df]:3333.
|
|
# Readlserver [fd79:35e2:9963:0:f816:3eff:fe9d:8f3f]:4444 is not listed
|
|
# because healthcheck failed.
|
|
# The virtual server and the listened port is
|
|
# [fd79:35e2:9963:0:f816:3eff:fe6d:7a2a]:7777.
|
|
KERNAL_FILE_SAMPLE_V6 = (
|
|
"IP Virtual Server version 1.2.1 (size=4096)\n"
|
|
"Prot LocalAddress:Port Scheduler Flags\n"
|
|
" -> RemoteAddress:Port Forward Weight ActiveConn InActConn\n"
|
|
"UDP [fd79:35e2:9963:0000:f816:3eff:fe6d:7a2a]:1E61 rr\n"
|
|
" -> [fd79:35e2:9963:0000:f816:3eff:feca:b7bf]:08AE "
|
|
"Masq 3 0 0\n"
|
|
" -> [fd79:35e2:9963:0000:f816:3eff:fe9d:94df]:0D05 "
|
|
"Masq 2 0 0\n"
|
|
" -> [fd79:35e2::8f3f]:115C "
|
|
"Masq 2 0 0")
|
|
|
|
KERNEL_FILE_SAMPLE_MIXED = (
|
|
"IP Virtual Server version 1.2.1 (size=4096)\n"
|
|
"Prot LocalAddress:Port Scheduler Flags\n"
|
|
" -> RemoteAddress:Port Forward Weight ActiveConn InActConn\n"
|
|
"UDP [fd79:35e2:9963:0000:f816:3eff:fe6d:7a2a]:1E61 rr\n"
|
|
" -> [fd79:35e2:9963:0000:f816:3eff:feca:b7bf]:08AE "
|
|
"Masq 3 0 0\n"
|
|
" -> [fd79:35e2:9963:0000:f816:3eff:fe9d:94df]:0D05 "
|
|
"Masq 2 0 0\n"
|
|
" -> [fd79:35e2::8f3f]:115C "
|
|
"Masq 2 0 0\n"
|
|
"UDP 0A000025:1E61 rr\n"
|
|
" -> 0A000023:0D05 Masq 2 0 0\n"
|
|
" -> 0A000019:08AE Masq 3 0 0\n"
|
|
"UDP 0A000025:FF12 rr\n"
|
|
" -> 0A000023:12AB Masq 2 0 0\n"
|
|
" -> 0A000019:BF2E Masq 3 0 0")
|
|
|
|
CFG_FILE_TEMPLATE_v4 = (
|
|
"# Configuration for Listener %(listener_id)s\n\n"
|
|
"net_namespace %(ns_name)s\n\n"
|
|
"virtual_server_group ipv4-group {\n"
|
|
" 10.0.0.37 7777\n"
|
|
"}\n\n"
|
|
"virtual_server group ipv4-group {\n"
|
|
" lb_algo rr\n"
|
|
" lb_kind NAT\n"
|
|
" protocol udp\n\n\n"
|
|
" # Configuration for Pool %(pool_id)s\n"
|
|
" # Configuration for Member %(member_id1)s\n"
|
|
" real_server 10.0.0.25 2222 {\n"
|
|
" weight 3\n"
|
|
" persistence_timeout 5\n"
|
|
" persistence_granularity 255.0.0.0\n\n"
|
|
" MISC_CHECK {\n\n"
|
|
" misc_path \"/usr/bin/check_script.sh\"\n\n"
|
|
" misc_timeout 5\n\n"
|
|
" }\n\n"
|
|
" }\n\n"
|
|
" # Configuration for Member %(member_id2)s\n"
|
|
" real_server 10.0.0.35 3333 {\n"
|
|
" weight 2\n"
|
|
" persistence_timeout 5\n"
|
|
" persistence_granularity 255.0.0.0\n\n"
|
|
" MISC_CHECK {\n\n"
|
|
" misc_path \"/usr/bin/check_script.sh\"\n\n"
|
|
" misc_timeout 5\n\n"
|
|
" }\n\n"
|
|
" }\n\n"
|
|
" # Configuration for Member %(member_id3)s\n"
|
|
" real_server 10.0.0.45 4444 {\n"
|
|
" weight 2\n"
|
|
" persistence_timeout 5\n"
|
|
" persistence_granularity 255.0.0.0\n\n"
|
|
" MISC_CHECK {\n\n"
|
|
" misc_path \"/usr/bin/check_script.sh\"\n\n"
|
|
" misc_timeout 5\n\n"
|
|
" }\n\n"
|
|
" }\n\n"
|
|
" # Member %(member_id4)s is disabled\n\n"
|
|
"}")
|
|
|
|
CFG_FILE_TEMPLATE_v6 = (
|
|
"# Configuration for Listener %(listener_id)s\n\n"
|
|
"net_namespace %(ns_name)s\n\n"
|
|
"virtual_server_group ipv6-group {\n"
|
|
" fd79:35e2:9963:0:f816:3eff:fe6d:7a2a 7777\n"
|
|
"}\n\n"
|
|
"virtual_server group ipv6-group {\n"
|
|
" lb_algo rr\n"
|
|
" lb_kind NAT\n"
|
|
" protocol udp\n\n\n"
|
|
" # Configuration for Pool %(pool_id)s\n"
|
|
" # Configuration for Member %(member_id1)s\n"
|
|
" real_server fd79:35e2:9963:0:f816:3eff:feca:b7bf 2222 {\n"
|
|
" weight 3\n"
|
|
" MISC_CHECK {\n\n"
|
|
" misc_path \"/usr/bin/check_script.sh\"\n\n"
|
|
" misc_timeout 5\n\n"
|
|
" }\n\n"
|
|
" }\n\n"
|
|
" # Configuration for Member %(member_id2)s\n"
|
|
" real_server fd79:35e2:9963:0:f816:3eff:fe9d:94df 3333 {\n"
|
|
" weight 2\n"
|
|
" MISC_CHECK {\n\n"
|
|
" misc_path \"/usr/bin/check_script.sh\"\n\n"
|
|
" misc_timeout 5\n\n"
|
|
" }\n\n"
|
|
" }\n\n"
|
|
" # Configuration for Member %(member_id3)s\n"
|
|
" real_server fd79:35e2:9963:0:f816:3eff:fe9d:8f3f 4444 {\n"
|
|
" weight 2\n"
|
|
" MISC_CHECK {\n\n"
|
|
" misc_path \"/usr/bin/check_script.sh\"\n\n"
|
|
" misc_timeout 5\n\n"
|
|
" }\n\n"
|
|
" }\n\n"
|
|
" # Member %(member_id4)s is disabled\n\n"
|
|
" # Configuration for Member %(member_id5)s\n"
|
|
" real_server fd79:35e2:0:0:0:0:0:8f3f 4444 {\n"
|
|
" weight 2\n"
|
|
" MISC_CHECK {\n\n"
|
|
" misc_path \"/usr/bin/check_script.sh\"\n\n"
|
|
" misc_timeout 5\n\n"
|
|
" }\n\n"
|
|
" }\n\n"
|
|
"}")
|
|
|
|
CFG_FILE_TEMPLATE_mixed = (
|
|
"# Configuration for Listener %(listener_id)s\n\n"
|
|
"net_namespace %(ns_name)s\n\n"
|
|
"virtual_server_group ipv4-group {\n"
|
|
" 10.0.0.37 7777\n"
|
|
"}\n\n"
|
|
"virtual_server group ipv4-group {\n"
|
|
" lb_algo rr\n"
|
|
" lb_kind NAT\n"
|
|
" protocol udp\n\n\n"
|
|
" # Configuration for Pool %(pool_id)s\n"
|
|
" # Configuration for Member %(member_id1)s\n"
|
|
" real_server 10.0.0.25 2222 {\n"
|
|
" weight 3\n"
|
|
" MISC_CHECK {\n\n"
|
|
" misc_path \"/usr/bin/check_script.sh\"\n\n"
|
|
" misc_timeout 5\n\n"
|
|
" }\n\n"
|
|
" }\n\n"
|
|
" # Member %(member_id2)s is disabled\n\n"
|
|
"}\n"
|
|
"virtual_server_group ipv6-group {\n"
|
|
" fd79:35e2:9963:0:f816:3eff:fe6d:7a2a 7777\n"
|
|
"}\n\n"
|
|
"virtual_server group ipv6-group {\n"
|
|
" lb_algo rr\n"
|
|
" lb_kind NAT\n"
|
|
" protocol udp\n\n\n"
|
|
" # Configuration for Pool %(pool_id)s\n"
|
|
" # Configuration for Member %(member_id3)s\n"
|
|
" real_server fd79:35e2:9963:0:f816:3eff:feca:b7bf 2222 {\n"
|
|
" weight 3\n"
|
|
" MISC_CHECK {\n\n"
|
|
" misc_path \"/usr/bin/check_script.sh\"\n\n"
|
|
" misc_timeout 5\n\n"
|
|
" }\n\n"
|
|
" }\n\n"
|
|
" # Configuration for Member %(member_id4)s\n"
|
|
" real_server fd79:35e2:9963:0:f816:3eff:fe9d:94df 3333 {\n"
|
|
" weight 2\n"
|
|
" MISC_CHECK {\n\n"
|
|
" misc_path \"/usr/bin/check_script.sh\"\n\n"
|
|
" misc_timeout 5\n\n"
|
|
" }\n\n"
|
|
" }\n\n"
|
|
" # Member %(member_id5)s is disabled\n\n"
|
|
"}")
|
|
|
|
CFG_FILE_TEMPLATE_mixed_no_ipv6_member = (
|
|
"# Configuration for Listener %(listener_id)s\n\n"
|
|
"net_namespace %(ns_name)s\n\n"
|
|
"virtual_server_group ipv4-group {\n"
|
|
" 10.0.0.37 7777\n"
|
|
"}\n\n"
|
|
"virtual_server group ipv4-group {\n"
|
|
" lb_algo rr\n"
|
|
" lvs_method NAT\n"
|
|
" protocol udp\n\n\n"
|
|
" # Configuration for Pool %(pool_id)s\n"
|
|
" # Configuration for Member %(member_id1)s\n"
|
|
" real_server 10.0.0.25 2222 {\n"
|
|
" weight 3\n"
|
|
" MISC_CHECK {\n\n"
|
|
" misc_path \"/usr/bin/check_script.sh\"\n\n"
|
|
" misc_timeout 5\n\n"
|
|
" }\n\n"
|
|
" }\n\n"
|
|
" # Member %(member_id2)s is disabled\n\n"
|
|
"}\n"
|
|
"virtual_server_group ipv6-group {\n"
|
|
" fd79:35e2:9963:0:f816:3eff:fe6d:7a2a 7777\n"
|
|
"}\n\n"
|
|
"virtual_server group ipv6-group {\n"
|
|
" lb_algo rr\n"
|
|
" lvs_method NAT\n"
|
|
" protocol udp\n\n\n"
|
|
" # Configuration for Pool %(pool_id)s\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"
|
|
" -> RemoteAddress:Port Forward Weight ActiveConn InActConn\n"
|
|
"UDP %(listener_ipport)s rr\n"
|
|
" -> %(member1_ipport)s Masq 3 0 0\n"
|
|
" -> %(member2_ipport)s Masq 2 0 0")
|
|
|
|
IPVSADM_STATS_OUTPUT_TEMPLATE = (
|
|
"IP Virtual Server version 1.2.1 (size=4096)\n"
|
|
"Prot LocalAddress:Port Conns InPkts OutPkts "
|
|
"InBytes OutBytes\n"
|
|
" -> RemoteAddress:Port\n"
|
|
"UDP %(listener_ipport)s 5 4264 5"
|
|
" 6387472 7490\n"
|
|
" -> %(member1_ipport)s 2 1706 2"
|
|
" 2555588 2996\n"
|
|
" -> %(member2_ipport)s 3 2558 3"
|
|
" 3831884 4494")
|
|
|
|
|
|
class LvsQueryTestCase(base.TestCase):
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.listener_id_v4 = uuidutils.generate_uuid()
|
|
self.pool_id_v4 = uuidutils.generate_uuid()
|
|
self.member_id1_v4 = uuidutils.generate_uuid()
|
|
self.member_id2_v4 = uuidutils.generate_uuid()
|
|
self.member_id3_v4 = uuidutils.generate_uuid()
|
|
self.member_id4_v4 = uuidutils.generate_uuid()
|
|
self.listener_id_v6 = uuidutils.generate_uuid()
|
|
self.pool_id_v6 = uuidutils.generate_uuid()
|
|
self.member_id1_v6 = uuidutils.generate_uuid()
|
|
self.member_id2_v6 = uuidutils.generate_uuid()
|
|
self.member_id3_v6 = uuidutils.generate_uuid()
|
|
self.member_id4_v6 = uuidutils.generate_uuid()
|
|
self.member_id5_v6 = uuidutils.generate_uuid()
|
|
self.listener_id_mixed = uuidutils.generate_uuid()
|
|
self.listener_id_mixed_no_ipv6_member = uuidutils.generate_uuid()
|
|
self.pool_id_mixed = 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,
|
|
'pool_id': self.pool_id_v4,
|
|
'member_id1': self.member_id1_v4,
|
|
'member_id2': self.member_id2_v4,
|
|
'member_id3': self.member_id3_v4,
|
|
'member_id4': self.member_id4_v4,
|
|
}
|
|
cfg_content_v6 = CFG_FILE_TEMPLATE_v6 % {
|
|
'listener_id': self.listener_id_v6,
|
|
'ns_name': constants.AMPHORA_NAMESPACE,
|
|
'pool_id': self.pool_id_v6,
|
|
'member_id1': self.member_id1_v6,
|
|
'member_id2': self.member_id2_v6,
|
|
'member_id3': self.member_id3_v6,
|
|
'member_id4': self.member_id4_v6,
|
|
'member_id5': self.member_id5_v6
|
|
}
|
|
cfg_content_mixed = CFG_FILE_TEMPLATE_mixed % {
|
|
'listener_id': self.listener_id_mixed,
|
|
'ns_name': constants.AMPHORA_NAMESPACE,
|
|
'pool_id': self.pool_id_mixed,
|
|
'member_id1': self.member_id1_v4,
|
|
'member_id2': self.member_id2_v4,
|
|
'member_id3': self.member_id3_v6,
|
|
'member_id4': self.member_id4_v6,
|
|
'member_id5': self.member_id5_v6
|
|
}
|
|
cfg_content_mixed_no_ipv6_member = (
|
|
CFG_FILE_TEMPLATE_mixed_no_ipv6_member % {
|
|
'listener_id': self.listener_id_mixed,
|
|
'ns_name': constants.AMPHORA_NAMESPACE,
|
|
'pool_id': self.pool_id_mixed,
|
|
'member_id1': self.member_id1_v4,
|
|
'member_id2': self.member_id2_v4
|
|
}
|
|
)
|
|
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.listener_id_mixed),
|
|
cfg_content_mixed))
|
|
self.useFixture(test_utils.OpenFixture(
|
|
util.keepalived_lvs_cfg_path(
|
|
self.listener_id_mixed_no_ipv6_member),
|
|
cfg_content_mixed_no_ipv6_member))
|
|
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):
|
|
# Ipv4 resolver
|
|
input_listener_ip_port = ['10.0.0.37:7777']
|
|
target_ns = constants.AMPHORA_NAMESPACE
|
|
mock_check_output.return_value = KERNAL_FILE_SAMPLE_V4
|
|
result = lvs_query.get_listener_realserver_mapping(
|
|
target_ns, input_listener_ip_port,
|
|
health_monitor_enabled=True)
|
|
expected = {'10.0.0.25:2222': {'status': 'UP',
|
|
'Forward': 'Masq',
|
|
'Weight': '3',
|
|
'ActiveConn': '0',
|
|
'InActConn': '0'},
|
|
'10.0.0.35:3333': {'status': 'UP',
|
|
'Forward': 'Masq',
|
|
'Weight': '2',
|
|
'ActiveConn': '0',
|
|
'InActConn': '0'}}
|
|
self.assertEqual(expected, result)
|
|
|
|
# Ipv6 resolver
|
|
input_listener_ip_port = [
|
|
'[fd79:35e2:9963:0:f816:3eff:fe6d:7a2a]:7777']
|
|
mock_check_output.return_value = KERNAL_FILE_SAMPLE_V6
|
|
result = lvs_query.get_listener_realserver_mapping(
|
|
target_ns, input_listener_ip_port,
|
|
health_monitor_enabled=True)
|
|
expected = {'[fd79:35e2:9963:0:f816:3eff:feca:b7bf]:2222':
|
|
{'status': constants.UP,
|
|
'Forward': 'Masq',
|
|
'Weight': '3',
|
|
'ActiveConn': '0',
|
|
'InActConn': '0'},
|
|
'[fd79:35e2:9963:0:f816:3eff:fe9d:94df]:3333':
|
|
{'status': constants.UP,
|
|
'Forward': 'Masq',
|
|
'Weight': '2',
|
|
'ActiveConn': '0',
|
|
'InActConn': '0'},
|
|
'[fd79:35e2::8f3f]:4444':
|
|
{'status': constants.UP,
|
|
'Forward': 'Masq',
|
|
'Weight': '2',
|
|
'ActiveConn': '0',
|
|
'InActConn': '0'}}
|
|
self.assertEqual(expected, result)
|
|
|
|
# mixed resolver
|
|
input_listener_ip_port = [
|
|
'[fd79:35e2:9963:0:f816:3eff:fe6d:7a2a]:7777',
|
|
'10.0.0.37:7777']
|
|
mock_check_output.return_value = KERNEL_FILE_SAMPLE_MIXED
|
|
result = lvs_query.get_listener_realserver_mapping(
|
|
target_ns, input_listener_ip_port,
|
|
health_monitor_enabled=True)
|
|
expected = {'[fd79:35e2:9963:0:f816:3eff:feca:b7bf]:2222':
|
|
{'status': constants.UP,
|
|
'Forward': 'Masq',
|
|
'Weight': '3',
|
|
'ActiveConn': '0',
|
|
'InActConn': '0'},
|
|
'[fd79:35e2:9963:0:f816:3eff:fe9d:94df]:3333':
|
|
{'status': constants.UP,
|
|
'Forward': 'Masq',
|
|
'Weight': '2',
|
|
'ActiveConn': '0',
|
|
'InActConn': '0'},
|
|
'[fd79:35e2::8f3f]:4444':
|
|
{'status': constants.UP,
|
|
'Forward': 'Masq',
|
|
'Weight': '2',
|
|
'ActiveConn': '0',
|
|
'InActConn': '0'},
|
|
'10.0.0.25:2222': {'status': 'UP',
|
|
'Forward': 'Masq',
|
|
'Weight': '3',
|
|
'ActiveConn': '0',
|
|
'InActConn': '0'},
|
|
'10.0.0.35:3333': {'status': 'UP',
|
|
'Forward': 'Masq',
|
|
'Weight': '2',
|
|
'ActiveConn': '0',
|
|
'InActConn': '0'}}
|
|
self.assertEqual(expected, result)
|
|
|
|
# negetive cases
|
|
mock_check_output.return_value = KERNAL_FILE_SAMPLE_V4
|
|
for listener_ip_port in ['10.0.0.37:7776', '10.0.0.31:7777']:
|
|
result = lvs_query.get_listener_realserver_mapping(
|
|
target_ns, [listener_ip_port],
|
|
health_monitor_enabled=True)
|
|
self.assertEqual({}, result)
|
|
|
|
mock_check_output.return_value = KERNAL_FILE_SAMPLE_V6
|
|
for listener_ip_port in [
|
|
'[fd79:35e2:9963:0:f816:3eff:fe6d:7a2a]:7776',
|
|
'[fd79:35e2:9973:0:f816:3eff:fe6d:7a2a]:7777']:
|
|
result = lvs_query.get_listener_realserver_mapping(
|
|
target_ns, [listener_ip_port],
|
|
health_monitor_enabled=True)
|
|
self.assertEqual({}, result)
|
|
|
|
def test_get_lvs_listener_resource_ipports_nsname(self):
|
|
# ipv4
|
|
res = lvs_query.get_lvs_listener_resource_ipports_nsname(
|
|
self.listener_id_v4)
|
|
expected = {'Listener': {'id': self.listener_id_v4,
|
|
'ipports': ['10.0.0.37:7777']},
|
|
'Pool': {'id': self.pool_id_v4},
|
|
'Members': [{'id': self.member_id1_v4,
|
|
'ipport': '10.0.0.25:2222'},
|
|
{'id': self.member_id2_v4,
|
|
'ipport': '10.0.0.35:3333'},
|
|
{'id': self.member_id3_v4,
|
|
'ipport': '10.0.0.45:4444'},
|
|
{'id': self.member_id4_v4,
|
|
'ipport': None}]}
|
|
self.assertEqual((expected, constants.AMPHORA_NAMESPACE), res)
|
|
|
|
# ipv6
|
|
res = lvs_query.get_lvs_listener_resource_ipports_nsname(
|
|
self.listener_id_v6)
|
|
expected = {'Listener': {
|
|
'id': self.listener_id_v6,
|
|
'ipports': ['[fd79:35e2:9963:0:f816:3eff:fe6d:7a2a]:7777']},
|
|
'Pool': {'id': self.pool_id_v6},
|
|
'Members': [
|
|
{'id': self.member_id1_v6,
|
|
'ipport': '[fd79:35e2:9963:0:f816:3eff:feca:b7bf]:2222'},
|
|
{'id': self.member_id2_v6,
|
|
'ipport': '[fd79:35e2:9963:0:f816:3eff:fe9d:94df]:3333'},
|
|
{'id': self.member_id3_v6,
|
|
'ipport': '[fd79:35e2:9963:0:f816:3eff:fe9d:8f3f]:4444'},
|
|
{'id': self.member_id5_v6,
|
|
'ipport': '[fd79:35e2::8f3f]:4444'},
|
|
{'id': self.member_id4_v6,
|
|
'ipport': None}]}
|
|
self.assertEqual((expected, constants.AMPHORA_NAMESPACE), res)
|
|
|
|
# disabled
|
|
res = lvs_query.get_lvs_listener_resource_ipports_nsname(
|
|
self.disabled_listener_id)
|
|
self.assertEqual((None, constants.AMPHORA_NAMESPACE), res)
|
|
|
|
# multi-vip/mixed
|
|
res = lvs_query.get_lvs_listener_resource_ipports_nsname(
|
|
self.listener_id_mixed)
|
|
expected = {'Listener': {
|
|
'id': self.listener_id_mixed,
|
|
'ipports': [
|
|
'10.0.0.37:7777',
|
|
'[fd79:35e2:9963:0:f816:3eff:fe6d:7a2a]:7777']},
|
|
'Pool': {'id': self.pool_id_mixed},
|
|
'Members': [
|
|
{'id': self.member_id1_v4,
|
|
'ipport': '10.0.0.25:2222'},
|
|
{'id': self.member_id3_v6,
|
|
'ipport': '[fd79:35e2:9963:0:f816:3eff:feca:b7bf]:2222'},
|
|
{'id': self.member_id4_v6,
|
|
'ipport': '[fd79:35e2:9963:0:f816:3eff:fe9d:94df]:3333'},
|
|
{'id': self.member_id2_v4,
|
|
'ipport': None},
|
|
{'id': self.member_id5_v6,
|
|
'ipport': None}]}
|
|
self.assertEqual((expected, constants.AMPHORA_NAMESPACE), res)
|
|
|
|
@mock.patch('os.stat')
|
|
@mock.patch('subprocess.check_output')
|
|
def test_get_lvs_listener_pool_status(self, mock_check_output,
|
|
mock_os_stat):
|
|
mock_os_stat.side_effect = (
|
|
mock.Mock(st_mtime=1234),
|
|
mock.Mock(st_mtime=1234),
|
|
)
|
|
|
|
# test with ipv4 and ipv6
|
|
mock_check_output.return_value = KERNAL_FILE_SAMPLE_V4
|
|
res = lvs_query.get_lvs_listener_pool_status(self.listener_id_v4)
|
|
expected = {
|
|
'lvs':
|
|
{'uuid': self.pool_id_v4,
|
|
'status': constants.UP,
|
|
'members': {self.member_id1_v4: constants.UP,
|
|
self.member_id2_v4: constants.UP,
|
|
self.member_id3_v4: constants.DOWN,
|
|
self.member_id4_v4: constants.MAINT}}}
|
|
self.assertEqual(expected, res)
|
|
|
|
mock_os_stat.side_effect = (
|
|
mock.Mock(st_mtime=1234),
|
|
mock.Mock(st_mtime=1234),
|
|
)
|
|
|
|
mock_check_output.return_value = KERNAL_FILE_SAMPLE_V6
|
|
res = lvs_query.get_lvs_listener_pool_status(self.listener_id_v6)
|
|
expected = {
|
|
'lvs':
|
|
{'uuid': self.pool_id_v6,
|
|
'status': constants.UP,
|
|
'members': {self.member_id1_v6: constants.UP,
|
|
self.member_id2_v6: constants.UP,
|
|
self.member_id3_v6: constants.DOWN,
|
|
self.member_id4_v6: constants.MAINT,
|
|
self.member_id5_v6: constants.UP}}}
|
|
self.assertEqual(expected, res)
|
|
|
|
@mock.patch('os.stat')
|
|
@mock.patch('subprocess.check_output')
|
|
def test_get_lvs_listener_pool_status_restarting(self, mock_check_output,
|
|
mock_os_stat):
|
|
mock_os_stat.side_effect = (
|
|
mock.Mock(st_mtime=1234), # config file
|
|
mock.Mock(st_mtime=1220), # pid file
|
|
)
|
|
|
|
# test with ipv4 and ipv6
|
|
mock_check_output.return_value = KERNAL_FILE_SAMPLE_V4
|
|
res = lvs_query.get_lvs_listener_pool_status(self.listener_id_v4)
|
|
expected = {
|
|
'lvs':
|
|
{'uuid': self.pool_id_v4,
|
|
'status': constants.UP,
|
|
'members': {self.member_id1_v4: constants.UP,
|
|
self.member_id2_v4: constants.UP,
|
|
self.member_id3_v4: constants.RESTARTING,
|
|
self.member_id4_v4: constants.MAINT}}}
|
|
self.assertEqual(expected, res)
|
|
|
|
@mock.patch('octavia.amphorae.backends.utils.keepalivedlvs_query.'
|
|
'get_lvs_listener_resource_ipports_nsname')
|
|
def test_get_lvs_listener_pool_status_when_no_pool(
|
|
self, mock_get_resource_ipports):
|
|
# Just test with ipv4, ipv6 tests is same.
|
|
# the returned resource_ipport_mapping doesn't contains the 'Pool'
|
|
# resource, that means the listener doesn't have a pool resource, it
|
|
# isn't usable at this moment, then the pool status will
|
|
# return nothing.
|
|
mock_get_resource_ipports.return_value = (
|
|
{
|
|
'Listener': {
|
|
'id': self.listener_id_v4,
|
|
'ipports': ['10.0.0.37:7777']}},
|
|
constants.AMPHORA_NAMESPACE)
|
|
res = lvs_query.get_lvs_listener_pool_status(self.listener_id_v4)
|
|
self.assertEqual({}, res)
|
|
|
|
@mock.patch('octavia.amphorae.backends.utils.keepalivedlvs_query.'
|
|
'get_lvs_listener_resource_ipports_nsname')
|
|
def test_get_lvs_listener_pool_status_when_no_members(
|
|
self, mock_get_resource_ipports):
|
|
# Just test with ipv4, ipv6 tests is same.
|
|
# the returned resource_ipport_mapping doesn't contains the 'Members'
|
|
# resources, that means the pool of listener doesn't have a enabled
|
|
# pool resource, so the pool is not usable, then the pool status will
|
|
# return UP.
|
|
mock_get_resource_ipports.return_value = (
|
|
{
|
|
'Listener': {'id': self.listener_id_v4,
|
|
'ipports': ['10.0.0.37:7777']},
|
|
'Pool': {'id': self.pool_id_v4}},
|
|
constants.AMPHORA_NAMESPACE)
|
|
res = lvs_query.get_lvs_listener_pool_status(self.listener_id_v4)
|
|
expected = {'lvs': {
|
|
'uuid': self.pool_id_v4,
|
|
'status': constants.UP,
|
|
'members': {}
|
|
}}
|
|
self.assertEqual(expected, res)
|
|
|
|
@mock.patch('os.stat')
|
|
@mock.patch('octavia.amphorae.backends.utils.keepalivedlvs_query.'
|
|
'get_listener_realserver_mapping')
|
|
def test_get_lvs_listener_pool_status_when_not_get_realserver_result(
|
|
self, mock_get_mapping, mock_os_stat):
|
|
# This will hit if the kernel lvs file (/proc/net/ip_vs)
|
|
# lose its content. So at this moment, even though we configure the
|
|
# pool and member into udp keepalived config file, we have to set
|
|
# ths status of pool and its members to DOWN.
|
|
mock_os_stat.side_effect = (
|
|
mock.Mock(st_mtime=1234),
|
|
mock.Mock(st_mtime=1234),
|
|
)
|
|
mock_get_mapping.return_value = {}
|
|
res = lvs_query.get_lvs_listener_pool_status(self.listener_id_v4)
|
|
expected = {
|
|
'lvs':
|
|
{'uuid': self.pool_id_v4,
|
|
'status': constants.DOWN,
|
|
'members': {self.member_id1_v4: constants.DOWN,
|
|
self.member_id2_v4: constants.DOWN,
|
|
self.member_id3_v4: constants.DOWN,
|
|
self.member_id4_v4: constants.MAINT}}}
|
|
self.assertEqual(expected, res)
|
|
|
|
@mock.patch('subprocess.check_output')
|
|
def test_get_ipvsadm_info(self, mock_check_output):
|
|
for ip_list in [["10.0.0.37:7777", "10.0.0.25:2222", "10.0.0.35:3333"],
|
|
["[fd79:35e2:9963:0:f816:3eff:fe6d:7a2a]:7777",
|
|
"[fd79:35e2:9963:0:f816:3eff:feca:b7bf]:2222",
|
|
"[fd79:35e2:9963:0:f816:3eff:fe9d:94df]:3333"]]:
|
|
mock_check_output.return_value = IPVSADM_OUTPUT_TEMPLATE % {
|
|
"listener_ipport": ip_list[0],
|
|
"member1_ipport": ip_list[1],
|
|
"member2_ipport": ip_list[2]}
|
|
res = lvs_query.get_ipvsadm_info(constants.AMPHORA_NAMESPACE)
|
|
# This expected result can reference on IPVSADM_OUTPUT_TEMPLATE,
|
|
# that means the function can get every element of the virtual
|
|
# server and the real servers.
|
|
expected = {
|
|
ip_list[0]: {
|
|
'Listener': [('Prot', 'UDP'),
|
|
('LocalAddress:Port', ip_list[0]),
|
|
('Scheduler', 'rr')],
|
|
'Members': [[('RemoteAddress:Port', ip_list[1]),
|
|
('Forward', 'Masq'), ('Weight', '3'),
|
|
('ActiveConn', '0'), ('InActConn', '0')],
|
|
[('RemoteAddress:Port', ip_list[2]),
|
|
('Forward', 'Masq'), ('Weight', '2'),
|
|
('ActiveConn', '0'), ('InActConn', '0')]]}}
|
|
self.assertEqual(expected, res)
|
|
|
|
# ipvsadm stats
|
|
mock_check_output.return_value = IPVSADM_STATS_OUTPUT_TEMPLATE % {
|
|
"listener_ipport": ip_list[0],
|
|
"member1_ipport": ip_list[1],
|
|
"member2_ipport": ip_list[2]}
|
|
res = lvs_query.get_ipvsadm_info(constants.AMPHORA_NAMESPACE,
|
|
is_stats_cmd=True)
|
|
expected = {
|
|
ip_list[0]:
|
|
{'Listener': [('Prot', 'UDP'),
|
|
('LocalAddress:Port', ip_list[0]),
|
|
('Conns', '5'),
|
|
('InPkts', '4264'),
|
|
('OutPkts', '5'),
|
|
('InBytes', '6387472'),
|
|
('OutBytes', '7490')],
|
|
'Members': [[('RemoteAddress:Port', ip_list[1]),
|
|
('Conns', '2'),
|
|
('InPkts', '1706'),
|
|
('OutPkts', '2'),
|
|
('InBytes', '2555588'),
|
|
('OutBytes', '2996')],
|
|
[('RemoteAddress:Port', ip_list[2]),
|
|
('Conns', '3'),
|
|
('InPkts', '2558'),
|
|
('OutPkts', '3'),
|
|
('InBytes', '3831884'),
|
|
('OutBytes', '4494')]]}}
|
|
self.assertEqual(expected, res)
|
|
|
|
@mock.patch('subprocess.check_output')
|
|
@mock.patch("octavia.amphorae.backends.agent.api_server.util."
|
|
"is_lvs_listener_running", return_value=True)
|
|
@mock.patch("octavia.amphorae.backends.agent.api_server.util."
|
|
"get_lvs_listeners")
|
|
def test_get_lvs_listeners_stats(
|
|
self, mock_get_listener, mock_is_running, mock_check_output):
|
|
# The ipv6 test is same with ipv4, so just test ipv4 here
|
|
mock_get_listener.return_value = [self.listener_id_v4]
|
|
output_list = list()
|
|
output_list.append(IPVSADM_OUTPUT_TEMPLATE % {
|
|
"listener_ipport": "10.0.0.37:7777",
|
|
"member1_ipport": "10.0.0.25:2222",
|
|
"member2_ipport": "10.0.0.35:3333"})
|
|
output_list.append(IPVSADM_STATS_OUTPUT_TEMPLATE % {
|
|
"listener_ipport": "10.0.0.37:7777",
|
|
"member1_ipport": "10.0.0.25:2222",
|
|
"member2_ipport": "10.0.0.35:3333"})
|
|
mock_check_output.side_effect = output_list
|
|
res = lvs_query.get_lvs_listeners_stats()
|
|
# We can check the expected result reference the stats sample,
|
|
# that means this func can compute the stats info of single listener.
|
|
expected = {self.listener_id_v4: {
|
|
'status': constants.OPEN,
|
|
'stats': {'bin': 6387472, 'stot': 5, 'bout': 7490,
|
|
'ereq': 0, 'scur': 0}}}
|
|
self.assertEqual(expected, res)
|
|
|
|
# if no udp listener need to be collected.
|
|
# Then this function will return nothing.
|
|
mock_is_running.return_value = False
|
|
res = lvs_query.get_lvs_listeners_stats()
|
|
self.assertEqual({}, res)
|
|
|
|
# listener for both ipv4 and ipv6, but no member in the ipv6 pool
|
|
mock_is_running.return_value = True
|
|
mock_get_listener.return_value = [
|
|
self.listener_id_mixed_no_ipv6_member]
|
|
output_list = list()
|
|
output_list.append(IPVSADM_OUTPUT_TEMPLATE % {
|
|
"listener_ipport": "10.0.0.37:7777",
|
|
"member1_ipport": "10.0.0.25:2222",
|
|
"member2_ipport": "10.0.0.35:3333"})
|
|
output_list.append(IPVSADM_STATS_OUTPUT_TEMPLATE % {
|
|
"listener_ipport": "10.0.0.37:7777",
|
|
"member1_ipport": "10.0.0.25:2222",
|
|
"member2_ipport": "10.0.0.35:3333"})
|
|
mock_check_output.side_effect = output_list
|
|
res = lvs_query.get_lvs_listeners_stats()
|
|
# We can check the expected result reference the stats sample,
|
|
# that means this func can compute the stats info of single listener.
|
|
expected = {self.listener_id_mixed_no_ipv6_member: {
|
|
'status': constants.OPEN,
|
|
'stats': {'bin': 6387472, 'stot': 5, 'bout': 7490,
|
|
'ereq': 0, 'scur': 0}}}
|
|
self.assertEqual(expected, res)
|
|
|
|
@mock.patch('subprocess.check_output')
|
|
@mock.patch("octavia.amphorae.backends.agent.api_server.util."
|
|
"is_lvs_listener_running", return_value=True)
|
|
@mock.patch("octavia.amphorae.backends.agent.api_server.util."
|
|
"get_lvs_listeners")
|
|
def test_get_lvs_listeners_stats_missing_listener(
|
|
self, mock_get_listener, mock_is_running, mock_check_output):
|
|
# The ipv6 test is same with ipv4, so just test ipv4 here
|
|
mock_get_listener.return_value = [self.listener_id_v4]
|
|
output_list = list()
|
|
output_list.append(IPVSADM_OUTPUT_TEMPLATE % {
|
|
"listener_ipport": "10.0.0.37:7778",
|
|
"member1_ipport": "10.0.0.25:2222",
|
|
"member2_ipport": "10.0.0.35:3333"})
|
|
output_list.append(IPVSADM_STATS_OUTPUT_TEMPLATE % {
|
|
"listener_ipport": "10.0.0.37:7778",
|
|
"member1_ipport": "10.0.0.25:2222",
|
|
"member2_ipport": "10.0.0.35:3333"})
|
|
mock_check_output.side_effect = output_list
|
|
res = lvs_query.get_lvs_listeners_stats()
|
|
expected = {self.listener_id_v4: {
|
|
'status': constants.OPEN,
|
|
'stats': {'bin': 0, 'stot': 0, 'bout': 0,
|
|
'ereq': 0, 'scur': 0}}}
|
|
self.assertEqual(expected, res)
|
|
|
|
@mock.patch('subprocess.check_output')
|
|
@mock.patch("octavia.amphorae.backends.agent.api_server.util."
|
|
"is_lvs_listener_running", return_value=True)
|
|
@mock.patch("octavia.amphorae.backends.agent.api_server.util."
|
|
"get_lvs_listeners")
|
|
def test_get_lvs_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_lvs_listeners_stats()
|
|
self.assertEqual({}, res)
|