Support HTTP and TCP checks in UDP healthmonitor
This patch introduces 2 macros in lvs. 1. Support HTTP GET, allow users create HTTP healthmonitor for udp pool. 2. Support TCP check, allow users create TCP healthmonitor for udp pool. Co-Authored-By: Adam Harwell <flux.adam@gmail.com> Change-Id: I61c7d8d4df54710a92b8c055be84bba29bf3d7e6 Story: 2003200 Task: 23356 Story: 2003199 Task: 23355
This commit is contained in:
parent
4b2a38d93c
commit
6e61991833
@ -573,13 +573,13 @@ recreated.
|
||||
|
||||
.. _valid_protocol:
|
||||
|
||||
Protocol Combinations
|
||||
=====================
|
||||
Protocol Combinations (Listener/Pool)
|
||||
=====================================
|
||||
|
||||
The listener and pool can be associated through the listener's
|
||||
``default_pool_id`` or l7policy's ``redirect_pool_id``. Both listener and pool
|
||||
must set the protocol parameter. But the association between the listener and
|
||||
the pool isn't arbitrarily and has some constraints at the protocol aspect.
|
||||
must set the protocol parameter, but the association between the listener and
|
||||
the pool isn't arbitrary and has some constraints on the protocol aspect.
|
||||
|
||||
Valid protocol combinations
|
||||
---------------------------
|
||||
@ -621,3 +621,44 @@ The pool protocol of PROXY will use the listener protocol as the pool protocol
|
||||
but will wrap that protocol in the proxy protocol. In the case of listener
|
||||
protocol TERMINATED_HTTPS, a pool protocol of PROXY will be HTTP wrapped in the
|
||||
proxy protocol.
|
||||
|
||||
Protocol Combinations (Pool/Health Monitor)
|
||||
===========================================
|
||||
|
||||
Pools and health monitors are also related with regard to protocol. Pools set
|
||||
the protocol parameter for the real member connections, and the health monitor
|
||||
sets a type for health checks. Health check types are limited based on the
|
||||
protocol of the pool.
|
||||
|
||||
Valid protocol combinations
|
||||
---------------------------
|
||||
|
||||
.. |Health Monitor| replace:: |2| |2| Health Monitor
|
||||
.. |UDPCONNECT| replace:: UDP-CONNECT
|
||||
.. |4Y| replace:: |2| |2| Y
|
||||
.. |4N| replace:: |2| |2| N
|
||||
.. |5Y| replace:: |2| |2| |1| Y
|
||||
.. |5N| replace:: |2| |2| |1| N
|
||||
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
|| |Health Monitor| || HTTP || HTTPS || PING || TCP || TLS-HELLO || |UDPCONNECT| |
|
||||
|| Pool || || || || || || |
|
||||
+===================+=======+========+=======+======+============+===============+
|
||||
| HTTP | |2Y| | |2Y| | |1Y| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
| HTTPS | |2Y| | |2Y| | |1Y| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
| PROXY | |2Y| | |2Y| | |1Y| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
| TCP | |2Y| | |2Y| | |1Y| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
| UDP | |2Y| | |2N| | |1N| | |1Y| | |4N| | |5Y| |
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
|
||||
"Y" means the combination is valid and "N" means invalid.
|
||||
|
||||
These combinations are mostly as you'd expect for all non-UDP pool protocols:
|
||||
non-UDP pools can have health monitors with any check type besides UDP-CONNECT.
|
||||
For UDP pools however, things are a little more complicated. UDP Pools support
|
||||
UDP-CONNECT but also HTTP and TCP checks. HTTPS checks are technically feasible
|
||||
but have not yet been implemented.
|
||||
|
@ -37,7 +37,7 @@ CONFIG_COMMENT_REGEX = re.compile(
|
||||
DISABLED_MEMBER_COMMENT_REGEX = re.compile(
|
||||
r"#\sMember\s(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}) is disabled")
|
||||
|
||||
CHECKER_REGEX = re.compile(r"MISC_CHECK")
|
||||
CHECKER_REGEX = re.compile(r"(MISC_CHECK|HTTP_GET|TCP_CHECK)")
|
||||
|
||||
|
||||
def read_kernel_file(ns_name, file_path):
|
||||
|
@ -109,8 +109,10 @@ class RootController(object):
|
||||
# Availability Zones
|
||||
self._add_a_version(versions, 'v2.14', 'v2', 'SUPPORTED',
|
||||
'2019-11-10T00:00:00Z', host_url)
|
||||
|
||||
# TLS version and cipher options
|
||||
self._add_a_version(versions, 'v2.15', 'v2', 'CURRENT',
|
||||
self._add_a_version(versions, 'v2.15', 'v2', 'SUPPORTED',
|
||||
'2020-03-10T00:00:00Z', host_url)
|
||||
# Additional UDP Healthcheck Types (HTTP/TCP)
|
||||
self._add_a_version(versions, 'v2.16', 'v2', 'CURRENT',
|
||||
'2020-03-15T00:00:00Z', host_url)
|
||||
return {'versions': versions}
|
||||
|
@ -165,31 +165,28 @@ class HealthMonitorController(base.BaseController):
|
||||
raise exceptions.InvalidOption(value='', option='')
|
||||
|
||||
def _validate_healthmonitor_request_for_udp(self, request):
|
||||
invalid_fields = (request.http_method or request.url_path or
|
||||
request.expected_codes)
|
||||
is_invalid = (hasattr(request, 'type') and
|
||||
(request.type != consts.HEALTH_MONITOR_UDP_CONNECT or
|
||||
invalid_fields))
|
||||
if is_invalid:
|
||||
if request.type not in (
|
||||
consts.HEALTH_MONITOR_UDP_CONNECT,
|
||||
consts.HEALTH_MONITOR_TCP,
|
||||
consts.HEALTH_MONITOR_HTTP):
|
||||
raise exceptions.ValidationException(detail=_(
|
||||
"The associated pool protocol is %(pool_protocol)s, so only "
|
||||
"a %(type)s health monitor is supported.") % {
|
||||
"a %(types)s health monitor is supported.") % {
|
||||
'pool_protocol': consts.PROTOCOL_UDP,
|
||||
'type': consts.HEALTH_MONITOR_UDP_CONNECT})
|
||||
# if the logic arrives here, that means the validation of request above
|
||||
# is OK. type is UDP-CONNECT, then here we check the healthmonitor
|
||||
# delay value is matched.
|
||||
if request.delay:
|
||||
conf_set = (CONF.api_settings.
|
||||
udp_connect_min_interval_health_monitor)
|
||||
if conf_set < 0:
|
||||
return
|
||||
if request.delay < conf_set:
|
||||
'types': '/'.join((consts.HEALTH_MONITOR_UDP_CONNECT,
|
||||
consts.HEALTH_MONITOR_TCP,
|
||||
consts.HEALTH_MONITOR_HTTP))})
|
||||
# check the delay value if the HM type is UDP-CONNECT
|
||||
hm_is_type_udp = (
|
||||
request.type == consts.HEALTH_MONITOR_UDP_CONNECT)
|
||||
conf_min_delay = (
|
||||
CONF.api_settings.udp_connect_min_interval_health_monitor)
|
||||
if hm_is_type_udp and request.delay < conf_min_delay:
|
||||
raise exceptions.ValidationException(detail=_(
|
||||
"The request delay value %(delay)s should be larger than "
|
||||
"%(conf_set)s for %(type)s health monitor type.") % {
|
||||
"%(conf_min_delay)s for %(type)s health monitor type.") % {
|
||||
'delay': request.delay,
|
||||
'conf_set': conf_set,
|
||||
'conf_min_delay': conf_min_delay,
|
||||
'type': consts.HEALTH_MONITOR_UDP_CONNECT})
|
||||
|
||||
@wsme_pecan.wsexpose(hm_types.HealthMonitorRootResponse,
|
||||
@ -348,6 +345,7 @@ class HealthMonitorController(base.BaseController):
|
||||
# Validate health monitor update options for UDP-CONNECT type.
|
||||
if (pool.protocol == consts.PROTOCOL_UDP and
|
||||
db_hm.type == consts.HEALTH_MONITOR_UDP_CONNECT):
|
||||
health_monitor.type = db_hm.type
|
||||
self._validate_healthmonitor_request_for_udp(health_monitor)
|
||||
|
||||
self._set_default_on_none(health_monitor)
|
||||
|
@ -287,12 +287,21 @@ class PoolsController(base.BaseController):
|
||||
resource=data_models.HealthMonitor._name())
|
||||
|
||||
# Now possibly create a healthmonitor
|
||||
new_hm = None
|
||||
if hm:
|
||||
hm['pool_id'] = db_pool.id
|
||||
hm['project_id'] = db_pool.project_id
|
||||
hm[constants.POOL_ID] = db_pool.id
|
||||
hm[constants.PROJECT_ID] = db_pool.project_id
|
||||
new_hm = health_monitor.HealthMonitorController()._graph_create(
|
||||
lock_session, hm)
|
||||
if db_pool.protocol == constants.PROTOCOL_UDP:
|
||||
health_monitor.HealthMonitorController(
|
||||
)._validate_healthmonitor_request_for_udp(new_hm)
|
||||
else:
|
||||
if new_hm.type == constants.HEALTH_MONITOR_UDP_CONNECT:
|
||||
raise exceptions.ValidationException(detail=_(
|
||||
"The %(type)s type is only supported for pools of "
|
||||
"type %(protocol)s.") % {
|
||||
'type': new_hm.type,
|
||||
'protocol': constants.PROTOCOL_UDP})
|
||||
db_pool.health_monitor = new_hm
|
||||
|
||||
# Now check quotas for members
|
||||
|
@ -398,7 +398,7 @@ class JinjaTemplater(object):
|
||||
"""
|
||||
codes = None
|
||||
if monitor.expected_codes:
|
||||
codes = '|'.join(self._expand_expected_codes(
|
||||
codes = '|'.join(octavia_utils.expand_expected_codes(
|
||||
monitor.expected_codes))
|
||||
return {
|
||||
'id': monitor.id,
|
||||
@ -479,25 +479,3 @@ class JinjaTemplater(object):
|
||||
# Spaces next
|
||||
value = re.sub(' ', '\\ ', value)
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def _expand_expected_codes(codes):
|
||||
"""Expand the expected code string in set of codes.
|
||||
|
||||
200-204 -> 200, 201, 202, 204
|
||||
200, 203 -> 200, 203
|
||||
"""
|
||||
|
||||
retval = set()
|
||||
for code in codes.replace(',', ' ').split(' '):
|
||||
code = code.strip()
|
||||
|
||||
if not code:
|
||||
continue
|
||||
if '-' in code:
|
||||
low, hi = code.split('-')[:2]
|
||||
retval.update(
|
||||
str(i) for i in range(int(low), int(hi) + 1))
|
||||
else:
|
||||
retval.add(code)
|
||||
return sorted(retval)
|
||||
|
@ -382,7 +382,7 @@ class JinjaTemplater(object):
|
||||
"""
|
||||
codes = None
|
||||
if monitor.expected_codes:
|
||||
codes = '|'.join(self._expand_expected_codes(
|
||||
codes = '|'.join(octavia_utils.expand_expected_codes(
|
||||
monitor.expected_codes))
|
||||
return {
|
||||
'id': monitor.id,
|
||||
@ -463,25 +463,3 @@ class JinjaTemplater(object):
|
||||
# Spaces next
|
||||
value = re.sub(' ', '\\ ', value)
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def _expand_expected_codes(codes):
|
||||
"""Expand the expected code string in set of codes.
|
||||
|
||||
200-204 -> 200, 201, 202, 204
|
||||
200, 203 -> 200, 203
|
||||
"""
|
||||
|
||||
retval = set()
|
||||
for code in codes.replace(',', ' ').split(' '):
|
||||
code = code.strip()
|
||||
|
||||
if not code:
|
||||
continue
|
||||
if '-' in code:
|
||||
low, hi = code.split('-')[:2]
|
||||
retval.update(
|
||||
str(i) for i in range(int(low), int(hi) + 1))
|
||||
else:
|
||||
retval.add(code)
|
||||
return sorted(retval)
|
||||
|
@ -18,6 +18,7 @@ import jinja2
|
||||
|
||||
from octavia.common.config import cfg
|
||||
from octavia.common import constants
|
||||
from octavia.common import utils as octavia_utils
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -194,7 +195,7 @@ class LvsJinjaTemplater(object):
|
||||
|
||||
be processed by the templating system
|
||||
"""
|
||||
return {
|
||||
return_val = {
|
||||
'id': monitor.id,
|
||||
'type': monitor.type,
|
||||
'delay': monitor.delay,
|
||||
@ -206,3 +207,16 @@ class LvsJinjaTemplater(object):
|
||||
constants.HEALTH_MONITOR_UDP_CONNECT else
|
||||
None)
|
||||
}
|
||||
if monitor.type == constants.HEALTH_MONITOR_HTTP:
|
||||
return_val.update({
|
||||
'rise_threshold': monitor.rise_threshold,
|
||||
'url_path': monitor.url_path,
|
||||
'http_method': (monitor.http_method
|
||||
if monitor.http_method ==
|
||||
constants.HEALTH_MONITOR_HTTP_METHOD_GET else
|
||||
None),
|
||||
'expected_codes': (sorted(list(
|
||||
octavia_utils.expand_expected_codes(
|
||||
monitor.expected_codes)))
|
||||
if monitor.expected_codes else [])})
|
||||
return return_val
|
||||
|
@ -29,10 +29,40 @@ MISC_CHECK {
|
||||
}
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro http_url_macro(health_monitor, health_monitor_status_code) %}
|
||||
url {
|
||||
path {{ health_monitor.url_path }}
|
||||
status_code {{ health_monitor_status_code }}
|
||||
}
|
||||
{% endmacro -%}
|
||||
|
||||
{%- macro http_get_macro(pool, member, health_monitor) -%}
|
||||
HTTP_GET {
|
||||
{% for status_code in health_monitor.expected_codes %}
|
||||
{{ http_url_macro(health_monitor, status_code) -}}
|
||||
{% endfor %}
|
||||
connect_ip {{ member.monitor_address|default(member.address, true) }}
|
||||
connect_port {{ member.monitor_port|default(member.protocol_port, true) }}
|
||||
connect_timeout {{ health_monitor.timeout }}
|
||||
}
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro tcp_check_macro(pool, member, health_monitor) -%}
|
||||
TCP_CHECK {
|
||||
connect_ip {{ member.monitor_address|default(member.address, true) }}
|
||||
connect_port {{ member.monitor_port|default(member.protocol_port, true) }}
|
||||
connect_timeout {{ health_monitor.timeout }}
|
||||
}
|
||||
{%- endmacro -%}
|
||||
|
||||
{% macro health_monitor_rs_macro(constants, pool, member) %}
|
||||
{% if pool.health_monitor and pool.health_monitor.enabled %}
|
||||
{% if pool.health_monitor.type == constants.HEALTH_MONITOR_UDP_CONNECT %}
|
||||
{{ misc_check_macro(pool, member, pool.health_monitor) -}}
|
||||
{% elif pool.health_monitor.type == constants.HEALTH_MONITOR_HTTP and pool.health_monitor.http_method == constants.HEALTH_MONITOR_HTTP_METHOD_GET %}
|
||||
{{ http_get_macro(pool, member, pool.health_monitor) -}}
|
||||
{% elif pool.health_monitor.type == constants.HEALTH_MONITOR_TCP %}
|
||||
{{ tcp_check_macro(pool, member, pool.health_monitor) -}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
@ -54,10 +84,8 @@ MISC_CHECK {
|
||||
|
||||
{% macro health_monitor_vs_macro(default_pool) %}
|
||||
{% if default_pool and default_pool.health_monitor and default_pool.health_monitor.enabled %}
|
||||
{% if default_pool.health_monitor.delay %}
|
||||
delay_loop {{ default_pool.health_monitor.delay }}
|
||||
delay_before_retry {{ default_pool.health_monitor.delay }}
|
||||
{% endif %}
|
||||
{% if default_pool.health_monitor.fall_threshold %}
|
||||
retry {{ default_pool.health_monitor.fall_threshold }}
|
||||
{% endif %}
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import re
|
||||
import socket
|
||||
|
||||
import netaddr
|
||||
@ -120,6 +121,26 @@ def b(s):
|
||||
return s.encode('utf-8')
|
||||
|
||||
|
||||
def expand_expected_codes(codes):
|
||||
"""Expand the expected code string in set of codes.
|
||||
|
||||
200-204 -> 200, 201, 202, 204
|
||||
200, 203 -> 200, 203
|
||||
"""
|
||||
retval = set()
|
||||
codes = re.split(', *', codes)
|
||||
for code in codes:
|
||||
if not code:
|
||||
continue
|
||||
if '-' in code:
|
||||
low, hi = code.split('-')[:2]
|
||||
retval.update(
|
||||
str(i) for i in range(int(low), int(hi) + 1))
|
||||
else:
|
||||
retval.add(code)
|
||||
return retval
|
||||
|
||||
|
||||
class exception_logger(object):
|
||||
"""Wrap a function and log raised exception
|
||||
|
||||
|
@ -45,7 +45,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
|
||||
def test_api_versions(self):
|
||||
versions = self._get_versions_with_config()
|
||||
version_ids = tuple(v.get('id') for v in versions)
|
||||
self.assertEqual(16, len(version_ids))
|
||||
self.assertEqual(17, len(version_ids))
|
||||
self.assertIn('v2.0', version_ids)
|
||||
self.assertIn('v2.1', version_ids)
|
||||
self.assertIn('v2.2', version_ids)
|
||||
@ -62,6 +62,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
|
||||
self.assertIn('v2.13', version_ids)
|
||||
self.assertIn('v2.14', version_ids)
|
||||
self.assertIn('v2.15', version_ids)
|
||||
self.assertIn('v2.16', version_ids)
|
||||
|
||||
# Each version should have a 'self' 'href' to the API version URL
|
||||
# [{u'rel': u'self', u'href': u'http://localhost/v2'}]
|
||||
|
@ -801,7 +801,8 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
self.assertEqual('/', api_hm.get('url_path'))
|
||||
self.assertEqual('200', api_hm.get('expected_codes'))
|
||||
|
||||
def test_create_udp_case(self):
|
||||
def test_create_udp_case_with_udp_connect_type(self):
|
||||
# create with UDP-CONNECT type
|
||||
api_hm = self.create_health_monitor(
|
||||
self.udp_pool_with_listener_id,
|
||||
constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
@ -826,6 +827,56 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
self.assertIsNone(api_hm.get('url_path'))
|
||||
self.assertIsNone(api_hm.get('expected_codes'))
|
||||
|
||||
def test_create_udp_case_with_tcp_type(self):
|
||||
# create with TCP type
|
||||
api_hm = self.create_health_monitor(
|
||||
self.udp_pool_with_listener_id, constants.HEALTH_MONITOR_TCP,
|
||||
3, 1, 1, 1).get(self.root_tag)
|
||||
self.assert_correct_status(
|
||||
lb_id=self.udp_lb_id, listener_id=self.udp_listener_id,
|
||||
pool_id=self.udp_pool_with_listener_id, hm_id=api_hm.get('id'),
|
||||
lb_prov_status=constants.PENDING_UPDATE,
|
||||
listener_prov_status=constants.PENDING_UPDATE,
|
||||
pool_prov_status=constants.PENDING_UPDATE,
|
||||
hm_prov_status=constants.PENDING_CREATE,
|
||||
hm_op_status=constants.OFFLINE)
|
||||
self.set_lb_status(self.udp_lb_id)
|
||||
self.assertEqual(constants.HEALTH_MONITOR_TCP, api_hm.get('type'))
|
||||
self.assertEqual(3, api_hm.get('delay'))
|
||||
self.assertEqual(1, api_hm.get('timeout'))
|
||||
self.assertEqual(1, api_hm.get('max_retries_down'))
|
||||
self.assertEqual(1, api_hm.get('max_retries'))
|
||||
self.assertIsNone(api_hm.get('http_method'))
|
||||
self.assertIsNone(api_hm.get('url_path'))
|
||||
self.assertIsNone(api_hm.get('expected_codes'))
|
||||
|
||||
def test_create_udp_case_with_http_type(self):
|
||||
# create with HTTP type
|
||||
api_hm = self.create_health_monitor(
|
||||
self.udp_pool_with_listener_id, constants.HEALTH_MONITOR_HTTP,
|
||||
3, 1, 1, 1, url_path='/test.html',
|
||||
http_method=constants.HEALTH_MONITOR_HTTP_METHOD_GET,
|
||||
expected_codes='200-201').get(self.root_tag)
|
||||
self.assert_correct_status(
|
||||
lb_id=self.udp_lb_id, listener_id=self.udp_listener_id,
|
||||
pool_id=self.udp_pool_with_listener_id, hm_id=api_hm.get('id'),
|
||||
lb_prov_status=constants.PENDING_UPDATE,
|
||||
listener_prov_status=constants.PENDING_UPDATE,
|
||||
pool_prov_status=constants.PENDING_UPDATE,
|
||||
hm_prov_status=constants.PENDING_CREATE,
|
||||
hm_op_status=constants.OFFLINE)
|
||||
self.set_lb_status(self.udp_lb_id)
|
||||
self.assertEqual(constants.HEALTH_MONITOR_HTTP, api_hm.get('type'))
|
||||
self.assertEqual(3, api_hm.get('delay'))
|
||||
self.assertEqual(1, api_hm.get('timeout'))
|
||||
self.assertEqual(1, api_hm.get('max_retries_down'))
|
||||
self.assertEqual(1, api_hm.get('max_retries'))
|
||||
self.assertEqual(3, api_hm.get('delay'))
|
||||
self.assertEqual(constants.HEALTH_MONITOR_HTTP_METHOD_GET,
|
||||
api_hm.get('http_method'))
|
||||
self.assertEqual('/test.html', api_hm.get('url_path'))
|
||||
self.assertEqual('200-201', api_hm.get('expected_codes'))
|
||||
|
||||
def test_udp_case_when_udp_connect_min_interval_health_monitor_set(self):
|
||||
# negative case first
|
||||
req_dict = {'pool_id': self.udp_pool_with_listener_id,
|
||||
@ -867,13 +918,15 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
'max_retries_down': 1,
|
||||
'max_retries': 1}
|
||||
expect_error_msg = ("Validation failure: The associated pool protocol "
|
||||
"is %(pool_protocol)s, so only a %(type)s health "
|
||||
"is %(pool_protocol)s, so only a %(types)s health "
|
||||
"monitor is supported.") % {
|
||||
'pool_protocol': constants.PROTOCOL_UDP,
|
||||
'type': constants.HEALTH_MONITOR_UDP_CONNECT}
|
||||
'types': '/'.join([constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
constants.HEALTH_MONITOR_TCP,
|
||||
constants.HEALTH_MONITOR_HTTP])}
|
||||
|
||||
# Not allowed types, url_path, expected_codes specified.
|
||||
update_req = {'type': constants.HEALTH_MONITOR_TCP}
|
||||
# Not allowed types specified.
|
||||
update_req = {'type': constants.HEALTH_MONITOR_TLS_HELLO}
|
||||
req_dict.update(update_req)
|
||||
res = self.post(self.HMS_PATH, self._build_body(req_dict), status=400,
|
||||
expect_errors=True)
|
||||
@ -882,22 +935,6 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
lb_id=self.udp_lb_id, listener_id=self.udp_listener_id,
|
||||
pool_id=self.udp_pool_with_listener_id)
|
||||
|
||||
update_req = {'type': constants.HEALTH_MONITOR_UDP_CONNECT}
|
||||
req_dict.update(update_req)
|
||||
for req in [{'http_method':
|
||||
constants.HEALTH_MONITOR_HTTP_METHOD_GET},
|
||||
{'url_path': constants.HEALTH_MONITOR_DEFAULT_URL_PATH},
|
||||
{'expected_codes':
|
||||
constants.HEALTH_MONITOR_DEFAULT_EXPECTED_CODES}]:
|
||||
req_dict.update(req)
|
||||
res = self.post(self.HMS_PATH, self._build_body(req_dict),
|
||||
status=400,
|
||||
expect_errors=True)
|
||||
self.assertEqual(expect_error_msg, res.json['faultstring'])
|
||||
self.assert_correct_status(
|
||||
lb_id=self.udp_lb_id, listener_id=self.udp_listener_id,
|
||||
pool_id=self.udp_pool_with_listener_id)
|
||||
|
||||
# Hit error during create with a non-UDP pool
|
||||
req_dict = {'pool_id': self.pool_with_listener_id,
|
||||
'delay': 1,
|
||||
@ -1458,10 +1495,10 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
def test_update_udp_case(self):
|
||||
api_hm = self.create_health_monitor(
|
||||
self.udp_pool_with_listener_id,
|
||||
constants.HEALTH_MONITOR_UDP_CONNECT, 3, 1, 1, 1).get(
|
||||
constants.HEALTH_MONITOR_TCP, 3, 1, 1, 1).get(
|
||||
self.root_tag)
|
||||
self.set_lb_status(self.udp_lb_id)
|
||||
new_hm = {'max_retries': 2}
|
||||
new_hm = {'timeout': 2}
|
||||
self.put(
|
||||
self.HM_PATH.format(healthmonitor_id=api_hm.get('id')),
|
||||
self._build_body(new_hm))
|
||||
|
@ -2724,10 +2724,27 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
expected_member.update(create_member)
|
||||
return create_member, expected_member
|
||||
|
||||
def _get_hm_bodies(self):
|
||||
def _get_hm_bodies(self, hm_type=constants.HEALTH_MONITOR_PING,
|
||||
delay=1):
|
||||
if hm_type == constants.HEALTH_MONITOR_UDP_CONNECT:
|
||||
create_hm = {
|
||||
'type': constants.HEALTH_MONITOR_PING,
|
||||
'delay': 1,
|
||||
'type': constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
'delay': delay,
|
||||
'timeout': 1,
|
||||
'max_retries_down': 1,
|
||||
'max_retries': 1
|
||||
}
|
||||
expected_hm = {
|
||||
'admin_state_up': True,
|
||||
'project_id': self._project_id,
|
||||
'provisioning_status': constants.PENDING_CREATE,
|
||||
'operating_status': constants.OFFLINE,
|
||||
'tags': []
|
||||
}
|
||||
elif hm_type == constants.HEALTH_MONITOR_HTTP:
|
||||
create_hm = {
|
||||
'type': constants.HEALTH_MONITOR_HTTP,
|
||||
'delay': delay,
|
||||
'timeout': 1,
|
||||
'max_retries_down': 1,
|
||||
'max_retries': 1
|
||||
@ -2742,6 +2759,21 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
'operating_status': constants.OFFLINE,
|
||||
'tags': []
|
||||
}
|
||||
else:
|
||||
create_hm = {
|
||||
'type': constants.HEALTH_MONITOR_PING,
|
||||
'delay': delay,
|
||||
'timeout': 1,
|
||||
'max_retries_down': 1,
|
||||
'max_retries': 1
|
||||
}
|
||||
expected_hm = {
|
||||
'admin_state_up': True,
|
||||
'project_id': self._project_id,
|
||||
'provisioning_status': constants.PENDING_CREATE,
|
||||
'operating_status': constants.OFFLINE,
|
||||
'tags': []
|
||||
}
|
||||
expected_hm.update(create_hm)
|
||||
return create_hm, expected_hm
|
||||
|
||||
@ -2899,6 +2931,47 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
def test_with_one_listener_one_hm_udp(self):
|
||||
create_hm, expected_hm = self._get_hm_bodies(
|
||||
hm_type=constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
delay=3)
|
||||
create_pool, expected_pool = self._get_pool_bodies(
|
||||
create_hm=create_hm,
|
||||
expected_hm=expected_hm,
|
||||
protocol=constants.PROTOCOL_UDP)
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_default_pool_name=create_pool['name'],
|
||||
create_protocol=constants.PROTOCOL_UDP)
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
def test_with_one_listener_one_hm_udp_validation_failure(self):
|
||||
create_hm, expected_hm = self._get_hm_bodies(
|
||||
hm_type=constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
delay=1)
|
||||
create_pool, expected_pool = self._get_pool_bodies(
|
||||
create_hm=create_hm,
|
||||
expected_hm=expected_hm,
|
||||
protocol=constants.PROTOCOL_UDP)
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_default_pool_name=create_pool['name'],
|
||||
create_protocol=constants.PROTOCOL_UDP)
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body, status=400,
|
||||
expect_errors=True)
|
||||
error_text = response.json.get('faultstring')
|
||||
self.assertIn('request delay value 1 should be larger', error_text)
|
||||
|
||||
def test_with_one_listener_allowed_cidrs(self):
|
||||
allowed_cidrs = ['10.0.1.0/24', '172.16.0.0/16']
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
|
@ -1086,35 +1086,6 @@ class TestHaproxyCfg(base.TestCase):
|
||||
self.assertEqual(self.jinja_cfg._escape_haproxy_config_string(
|
||||
'string\\ with\\ all'), 'string\\\\\\ with\\\\\\ all')
|
||||
|
||||
def test_expand_expected_codes(self):
|
||||
exp_codes = ''
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
[])
|
||||
exp_codes = '200'
|
||||
self.assertEqual(
|
||||
self.jinja_cfg._expand_expected_codes(exp_codes), ['200'])
|
||||
exp_codes = '200, 201'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201'])
|
||||
exp_codes = '200, 201,202'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201', '202'])
|
||||
exp_codes = '200-202'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201', '202'])
|
||||
exp_codes = '200-202, 205'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201', '202', '205'])
|
||||
exp_codes = '200, 201-203'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201', '202', '203'])
|
||||
exp_codes = '200, 201-203, 205'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201', '202', '203', '205'])
|
||||
exp_codes = '201-200, 205'
|
||||
self.assertEqual(
|
||||
self.jinja_cfg._expand_expected_codes(exp_codes), ['205'])
|
||||
|
||||
def test_render_template_no_log(self):
|
||||
j_cfg = jinja_cfg.JinjaTemplater(
|
||||
base_amp_path='/var/lib/octavia',
|
||||
|
@ -981,35 +981,6 @@ class TestHaproxyCfg(base.TestCase):
|
||||
self.assertEqual(self.jinja_cfg._escape_haproxy_config_string(
|
||||
'string\\ with\\ all'), 'string\\\\\\ with\\\\\\ all')
|
||||
|
||||
def test_expand_expected_codes(self):
|
||||
exp_codes = ''
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
[])
|
||||
exp_codes = '200'
|
||||
self.assertEqual(
|
||||
self.jinja_cfg._expand_expected_codes(exp_codes), ['200'])
|
||||
exp_codes = '200, 201'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201'])
|
||||
exp_codes = '200, 201,202'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201', '202'])
|
||||
exp_codes = '200-202'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201', '202'])
|
||||
exp_codes = '200-202, 205'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201', '202', '205'])
|
||||
exp_codes = '200, 201-203'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201', '202', '203'])
|
||||
exp_codes = '200, 201-203, 205'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
['200', '201', '202', '203', '205'])
|
||||
exp_codes = '201-200, 205'
|
||||
self.assertEqual(
|
||||
self.jinja_cfg._expand_expected_codes(exp_codes), ['205'])
|
||||
|
||||
def test_render_template_no_log(self):
|
||||
j_cfg = jinja_cfg.JinjaTemplater(
|
||||
base_amp_path='/var/lib/octavia',
|
||||
|
@ -297,3 +297,107 @@ 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_udp_listener_with_http_health_monitor(self):
|
||||
exp = ("# Configuration for Loadbalancer sample_loadbalancer_id_1\n"
|
||||
"# Configuration for Listener sample_listener_id_1\n\n"
|
||||
"net_namespace amphora-haproxy\n\n"
|
||||
"virtual_server 10.0.0.2 80 {\n"
|
||||
" lb_algo rr\n"
|
||||
" lb_kind NAT\n"
|
||||
" protocol UDP\n"
|
||||
" delay_loop 30\n"
|
||||
" delay_before_retry 30\n"
|
||||
" retry 3\n\n\n"
|
||||
" # Configuration for Pool sample_pool_id_1\n"
|
||||
" # Configuration for HealthMonitor sample_monitor_id_1\n"
|
||||
" # Configuration for Member sample_member_id_1\n"
|
||||
" real_server 10.0.0.99 82 {\n"
|
||||
" weight 13\n"
|
||||
" uthreshold 98\n"
|
||||
" HTTP_GET {\n"
|
||||
" url {\n"
|
||||
" path /index.html\n"
|
||||
" status_code 200\n"
|
||||
" }\n"
|
||||
" url {\n"
|
||||
" path /index.html\n"
|
||||
" status_code 201\n"
|
||||
" }\n"
|
||||
" connect_ip 10.0.0.99\n"
|
||||
" connect_port 82\n"
|
||||
" connect_timeout 31\n"
|
||||
" }\n"
|
||||
" }\n\n"
|
||||
" # Configuration for Member sample_member_id_2\n"
|
||||
" real_server 10.0.0.98 82 {\n"
|
||||
" weight 13\n"
|
||||
" uthreshold 98\n"
|
||||
" HTTP_GET {\n"
|
||||
" url {\n"
|
||||
" path /index.html\n"
|
||||
" status_code 200\n"
|
||||
" }\n"
|
||||
" url {\n"
|
||||
" path /index.html\n"
|
||||
" status_code 201\n"
|
||||
" }\n"
|
||||
" connect_ip 10.0.0.98\n"
|
||||
" connect_port 82\n"
|
||||
" connect_timeout 31\n"
|
||||
" }\n"
|
||||
" }\n\n"
|
||||
"}\n\n")
|
||||
|
||||
listener = sample_configs_combined.sample_listener_tuple(
|
||||
proto=constants.PROTOCOL_UDP,
|
||||
monitor_proto=constants.HEALTH_MONITOR_HTTP,
|
||||
connection_limit=98,
|
||||
persistence=False,
|
||||
monitor_expected_codes='200-201')
|
||||
|
||||
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(listener)
|
||||
self.assertEqual(exp, rendered_obj)
|
||||
|
||||
def test_render_template_udp_listener_with_tcp_health_monitor(self):
|
||||
exp = ("# Configuration for Loadbalancer sample_loadbalancer_id_1\n"
|
||||
"# Configuration for Listener sample_listener_id_1\n\n"
|
||||
"net_namespace amphora-haproxy\n\n"
|
||||
"virtual_server 10.0.0.2 80 {\n"
|
||||
" lb_algo rr\n"
|
||||
" lb_kind NAT\n"
|
||||
" protocol UDP\n"
|
||||
" delay_loop 30\n"
|
||||
" delay_before_retry 30\n"
|
||||
" retry 3\n\n\n"
|
||||
" # Configuration for Pool sample_pool_id_1\n"
|
||||
" # Configuration for HealthMonitor sample_monitor_id_1\n"
|
||||
" # Configuration for Member sample_member_id_1\n"
|
||||
" real_server 10.0.0.99 82 {\n"
|
||||
" weight 13\n"
|
||||
" uthreshold 98\n"
|
||||
" TCP_CHECK {\n"
|
||||
" connect_ip 10.0.0.99\n"
|
||||
" connect_port 82\n"
|
||||
" connect_timeout 31\n"
|
||||
" }\n"
|
||||
" }\n\n"
|
||||
" # Configuration for Member sample_member_id_2\n"
|
||||
" real_server 10.0.0.98 82 {\n"
|
||||
" weight 13\n"
|
||||
" uthreshold 98\n"
|
||||
" TCP_CHECK {\n"
|
||||
" connect_ip 10.0.0.98\n"
|
||||
" connect_port 82\n"
|
||||
" connect_timeout 31\n"
|
||||
" }\n"
|
||||
" }\n\n"
|
||||
"}\n\n")
|
||||
listener = sample_configs_combined.sample_listener_tuple(
|
||||
proto=constants.PROTOCOL_UDP,
|
||||
monitor_proto=constants.HEALTH_MONITOR_TCP,
|
||||
connection_limit=98,
|
||||
persistence=False)
|
||||
|
||||
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(listener)
|
||||
self.assertEqual(exp, rendered_obj)
|
||||
|
@ -588,8 +588,9 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
||||
tls=False, sni=False, peer_port=None, topology=None,
|
||||
l7=False, enabled=True, insert_headers=None,
|
||||
be_proto=None, monitor_ip_port=False,
|
||||
monitor_proto=None, backup_member=False,
|
||||
disabled_member=False, connection_limit=-1,
|
||||
monitor_proto=None, monitor_expected_codes=None,
|
||||
backup_member=False, disabled_member=False,
|
||||
connection_limit=-1,
|
||||
timeout_client_data=50000,
|
||||
timeout_member_connect=5000,
|
||||
timeout_member_data=50000,
|
||||
@ -686,6 +687,7 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
||||
persistence_granularity=persistence_granularity,
|
||||
monitor_ip_port=monitor_ip_port,
|
||||
monitor_proto=monitor_proto,
|
||||
monitor_expected_codes=monitor_expected_codes,
|
||||
pool_cert=pool_cert,
|
||||
pool_ca_cert=pool_ca_cert,
|
||||
pool_crl=pool_crl,
|
||||
@ -769,6 +771,7 @@ def sample_pool_tuple(listener_id=None, proto=None, monitor=True,
|
||||
persistence_cookie=None, persistence_timeout=None,
|
||||
persistence_granularity=None, sample_pool=1,
|
||||
monitor_ip_port=False, monitor_proto=None,
|
||||
monitor_expected_codes=None,
|
||||
backup_member=False, disabled_member=False,
|
||||
has_http_reuse=True, pool_cert=False, pool_ca_cert=False,
|
||||
pool_crl=False, tls_enabled=False,
|
||||
@ -806,7 +809,9 @@ def sample_pool_tuple(listener_id=None, proto=None, monitor=True,
|
||||
enabled=not disabled_member)]
|
||||
if monitor is True:
|
||||
mon = sample_health_monitor_tuple(
|
||||
proto=monitor_proto, host_http_check=hm_host_http_check)
|
||||
proto=monitor_proto,
|
||||
host_http_check=hm_host_http_check,
|
||||
expected_codes=monitor_expected_codes)
|
||||
elif sample_pool == 2:
|
||||
id = 'sample_pool_id_2'
|
||||
members = [sample_member_tuple('sample_member_id_3', '10.0.0.97',
|
||||
@ -814,7 +819,8 @@ def sample_pool_tuple(listener_id=None, proto=None, monitor=True,
|
||||
if monitor is True:
|
||||
mon = sample_health_monitor_tuple(
|
||||
proto=monitor_proto, sample_hm=2,
|
||||
host_http_check=hm_host_http_check)
|
||||
host_http_check=hm_host_http_check,
|
||||
expected_codes=monitor_expected_codes)
|
||||
return in_pool(
|
||||
id=id,
|
||||
protocol=proto,
|
||||
@ -872,7 +878,7 @@ def sample_session_persistence_tuple(persistence_type=None,
|
||||
|
||||
|
||||
def sample_health_monitor_tuple(proto='HTTP', sample_hm=1,
|
||||
host_http_check=False,
|
||||
host_http_check=False, expected_codes=None,
|
||||
provisioning_status=constants.ACTIVE):
|
||||
proto = 'HTTP' if proto == 'TERMINATED_HTTPS' else proto
|
||||
monitor = collections.namedtuple(
|
||||
@ -904,6 +910,8 @@ def sample_health_monitor_tuple(proto='HTTP', sample_hm=1,
|
||||
kwargs.update({'http_version': 1.1, 'domain_name': 'testlab.com'})
|
||||
else:
|
||||
kwargs.update({'http_version': 1.0, 'domain_name': None})
|
||||
if expected_codes:
|
||||
kwargs.update({'expected_codes': expected_codes})
|
||||
if proto == constants.HEALTH_MONITOR_UDP_CONNECT:
|
||||
kwargs['check_script_path'] = (CONF.haproxy_amphora.base_path +
|
||||
'lvs/check/' + 'udp_check.sh')
|
||||
|
@ -611,8 +611,9 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
||||
tls=False, sni=False, peer_port=None, topology=None,
|
||||
l7=False, enabled=True, insert_headers=None,
|
||||
be_proto=None, monitor_ip_port=False,
|
||||
monitor_proto=None, backup_member=False,
|
||||
disabled_member=False, connection_limit=-1,
|
||||
monitor_proto=None, monitor_expected_codes=None,
|
||||
backup_member=False, disabled_member=False,
|
||||
connection_limit=-1,
|
||||
timeout_client_data=50000,
|
||||
timeout_member_connect=5000,
|
||||
timeout_member_data=50000,
|
||||
@ -697,6 +698,7 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
||||
persistence_granularity=persistence_granularity,
|
||||
monitor_ip_port=monitor_ip_port,
|
||||
monitor_proto=monitor_proto,
|
||||
monitor_expected_codes=monitor_expected_codes,
|
||||
pool_cert=pool_cert,
|
||||
pool_ca_cert=pool_ca_cert,
|
||||
pool_crl=pool_crl,
|
||||
@ -778,7 +780,8 @@ def sample_pool_tuple(proto=None, monitor=True, persistence=True,
|
||||
persistence_type=None, persistence_cookie=None,
|
||||
persistence_timeout=None, persistence_granularity=None,
|
||||
sample_pool=1, monitor_ip_port=False,
|
||||
monitor_proto=None, backup_member=False,
|
||||
monitor_proto=None, monitor_expected_codes=None,
|
||||
backup_member=False,
|
||||
disabled_member=False, has_http_reuse=True,
|
||||
pool_cert=False, pool_ca_cert=False, pool_crl=False,
|
||||
tls_enabled=False, hm_host_http_check=False,
|
||||
@ -811,7 +814,9 @@ def sample_pool_tuple(proto=None, monitor=True, persistence=True,
|
||||
enabled=not disabled_member)]
|
||||
if monitor is True:
|
||||
mon = sample_health_monitor_tuple(
|
||||
proto=monitor_proto, host_http_check=hm_host_http_check)
|
||||
proto=monitor_proto,
|
||||
host_http_check=hm_host_http_check,
|
||||
expected_codes=monitor_expected_codes)
|
||||
elif sample_pool == 2:
|
||||
id = 'sample_pool_id_2'
|
||||
members = [sample_member_tuple('sample_member_id_3', '10.0.0.97',
|
||||
@ -819,7 +824,8 @@ def sample_pool_tuple(proto=None, monitor=True, persistence=True,
|
||||
if monitor is True:
|
||||
mon = sample_health_monitor_tuple(
|
||||
proto=monitor_proto, sample_hm=2,
|
||||
host_http_check=hm_host_http_check)
|
||||
host_http_check=hm_host_http_check,
|
||||
expected_codes=monitor_expected_codes)
|
||||
|
||||
return in_pool(
|
||||
id=id,
|
||||
@ -877,7 +883,7 @@ def sample_session_persistence_tuple(persistence_type=None,
|
||||
|
||||
|
||||
def sample_health_monitor_tuple(proto='HTTP', sample_hm=1,
|
||||
host_http_check=False,
|
||||
host_http_check=False, expected_codes=None,
|
||||
provisioning_status=constants.ACTIVE):
|
||||
proto = 'HTTP' if proto == 'TERMINATED_HTTPS' else proto
|
||||
monitor = collections.namedtuple(
|
||||
@ -909,6 +915,8 @@ def sample_health_monitor_tuple(proto='HTTP', sample_hm=1,
|
||||
kwargs.update({'http_version': 1.1, 'domain_name': 'testlab.com'})
|
||||
else:
|
||||
kwargs.update({'http_version': 1.0, 'domain_name': None})
|
||||
if expected_codes:
|
||||
kwargs.update({'expected_codes': expected_codes})
|
||||
if proto == constants.HEALTH_MONITOR_UDP_CONNECT:
|
||||
kwargs['check_script_path'] = (CONF.haproxy_amphora.base_path +
|
||||
'lvs/check/' + 'udp_check.sh')
|
||||
|
@ -60,3 +60,32 @@ class TestConfig(base.TestCase):
|
||||
utils.ip_netmask_to_cidr('10.0.0.1', '255.255.240.0'))
|
||||
self.assertEqual('10.0.0.0/30', utils.ip_netmask_to_cidr(
|
||||
'10.0.0.1', '255.255.255.252'))
|
||||
|
||||
def test_expand_expected_codes(self):
|
||||
exp_codes = ''
|
||||
self.assertEqual(utils.expand_expected_codes(exp_codes),
|
||||
set())
|
||||
exp_codes = '200'
|
||||
self.assertEqual(utils.expand_expected_codes(exp_codes),
|
||||
{'200'})
|
||||
exp_codes = '200, 201'
|
||||
self.assertEqual(utils.expand_expected_codes(exp_codes),
|
||||
{'200', '201'})
|
||||
exp_codes = '200, 201,202'
|
||||
self.assertEqual(utils.expand_expected_codes(exp_codes),
|
||||
{'200', '201', '202'})
|
||||
exp_codes = '200-202'
|
||||
self.assertEqual(utils.expand_expected_codes(exp_codes),
|
||||
{'200', '201', '202'})
|
||||
exp_codes = '200-202, 205'
|
||||
self.assertEqual(utils.expand_expected_codes(exp_codes),
|
||||
{'200', '201', '202', '205'})
|
||||
exp_codes = '200, 201-203'
|
||||
self.assertEqual(utils.expand_expected_codes(exp_codes),
|
||||
{'200', '201', '202', '203'})
|
||||
exp_codes = '200, 201-203, 205'
|
||||
self.assertEqual(utils.expand_expected_codes(exp_codes),
|
||||
{'200', '201', '202', '203', '205'})
|
||||
exp_codes = '201-200, 205'
|
||||
self.assertEqual(utils.expand_expected_codes(exp_codes),
|
||||
{'205'})
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Two new types of healthmonitoring are now valid for UDP listeners. Both
|
||||
``HTTP`` and ``TCP`` check types can now be used.
|
Loading…
Reference in New Issue
Block a user