Merge "Fix health monitor API handling of None updates"
This commit is contained in:
commit
b2d40c1120
|
@ -285,14 +285,13 @@ class HealthMonitorController(base.BaseController):
|
||||||
raise exceptions.InvalidOption(
|
raise exceptions.InvalidOption(
|
||||||
value=consts.EXPECTED_CODES, option='health monitors of '
|
value=consts.EXPECTED_CODES, option='health monitors of '
|
||||||
'type {}'.format(db_hm.type))
|
'type {}'.format(db_hm.type))
|
||||||
else:
|
if health_monitor.delay is None:
|
||||||
# For HTTP health monitor these cannot be null/None
|
raise exceptions.InvalidOption(value=None, option=consts.DELAY)
|
||||||
if health_monitor.http_method is None:
|
if health_monitor.max_retries is None:
|
||||||
health_monitor.http_method = wtypes.Unset
|
raise exceptions.InvalidOption(value=None,
|
||||||
if health_monitor.url_path is None:
|
option=consts.MAX_RETRIES)
|
||||||
health_monitor.url_path = wtypes.Unset
|
if health_monitor.timeout is None:
|
||||||
if health_monitor.expected_codes is None:
|
raise exceptions.InvalidOption(value=None, option=consts.TIMEOUT)
|
||||||
health_monitor.expected_codes = wtypes.Unset
|
|
||||||
|
|
||||||
if health_monitor.domain_name and not (
|
if health_monitor.domain_name and not (
|
||||||
db_hm.http_version or health_monitor.http_version):
|
db_hm.http_version or health_monitor.http_version):
|
||||||
|
@ -308,6 +307,29 @@ class HealthMonitorController(base.BaseController):
|
||||||
value='http_version %s' % http_version,
|
value='http_version %s' % http_version,
|
||||||
option='health monitors HTTP 1.1 domain name health check')
|
option='health monitors HTTP 1.1 domain name health check')
|
||||||
|
|
||||||
|
def _set_default_on_none(self, health_monitor):
|
||||||
|
"""Reset settings to their default values if None/null was passed in
|
||||||
|
|
||||||
|
A None/null value can be passed in to clear a value. PUT values
|
||||||
|
that were not provided by the user have a type of wtypes.UnsetType.
|
||||||
|
If the user is attempting to clear values, they should either
|
||||||
|
be set to None (for example in the name field) or they should be
|
||||||
|
reset to their default values.
|
||||||
|
This method is intended to handle those values that need to be set
|
||||||
|
back to a default value.
|
||||||
|
"""
|
||||||
|
if health_monitor.http_method is None:
|
||||||
|
health_monitor.http_method = (
|
||||||
|
consts.HEALTH_MONITOR_HTTP_DEFAULT_METHOD)
|
||||||
|
if health_monitor.url_path is None:
|
||||||
|
health_monitor.url_path = (
|
||||||
|
consts.HEALTH_MONITOR_DEFAULT_URL_PATH)
|
||||||
|
if health_monitor.expected_codes is None:
|
||||||
|
health_monitor.expected_codes = (
|
||||||
|
consts.HEALTH_MONITOR_DEFAULT_EXPECTED_CODES)
|
||||||
|
if health_monitor.max_retries_down is None:
|
||||||
|
health_monitor.max_retries_down = consts.DEFAULT_MAX_RETRIES_DOWN
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(hm_types.HealthMonitorRootResponse, wtypes.text,
|
@wsme_pecan.wsexpose(hm_types.HealthMonitorRootResponse, wtypes.text,
|
||||||
body=hm_types.HealthMonitorRootPUT, status_code=200)
|
body=hm_types.HealthMonitorRootPUT, status_code=200)
|
||||||
def put(self, id, health_monitor_):
|
def put(self, id, health_monitor_):
|
||||||
|
@ -327,6 +349,9 @@ class HealthMonitorController(base.BaseController):
|
||||||
if (pool.protocol == consts.PROTOCOL_UDP and
|
if (pool.protocol == consts.PROTOCOL_UDP and
|
||||||
db_hm.type == consts.HEALTH_MONITOR_UDP_CONNECT):
|
db_hm.type == consts.HEALTH_MONITOR_UDP_CONNECT):
|
||||||
self._validate_healthmonitor_request_for_udp(health_monitor)
|
self._validate_healthmonitor_request_for_udp(health_monitor)
|
||||||
|
|
||||||
|
self._set_default_on_none(health_monitor)
|
||||||
|
|
||||||
# Load the driver early as it also provides validation
|
# Load the driver early as it also provides validation
|
||||||
driver = driver_factory.get_driver(provider)
|
driver = driver_factory.get_driver(provider)
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,8 @@ class HealthMonitorPOST(BaseHealthMonitorType):
|
||||||
timeout = wtypes.wsattr(wtypes.IntegerType(minimum=0), mandatory=True)
|
timeout = wtypes.wsattr(wtypes.IntegerType(minimum=0), mandatory=True)
|
||||||
max_retries_down = wtypes.wsattr(
|
max_retries_down = wtypes.wsattr(
|
||||||
wtypes.IntegerType(minimum=constants.MIN_HM_RETRIES,
|
wtypes.IntegerType(minimum=constants.MIN_HM_RETRIES,
|
||||||
maximum=constants.MAX_HM_RETRIES), default=3)
|
maximum=constants.MAX_HM_RETRIES),
|
||||||
|
default=constants.DEFAULT_MAX_RETRIES_DOWN)
|
||||||
max_retries = wtypes.wsattr(
|
max_retries = wtypes.wsattr(
|
||||||
wtypes.IntegerType(minimum=constants.MIN_HM_RETRIES,
|
wtypes.IntegerType(minimum=constants.MIN_HM_RETRIES,
|
||||||
maximum=constants.MAX_HM_RETRIES),
|
maximum=constants.MAX_HM_RETRIES),
|
||||||
|
@ -152,7 +153,8 @@ class HealthMonitorSingleCreate(BaseHealthMonitorType):
|
||||||
timeout = wtypes.wsattr(wtypes.IntegerType(minimum=0), mandatory=True)
|
timeout = wtypes.wsattr(wtypes.IntegerType(minimum=0), mandatory=True)
|
||||||
max_retries_down = wtypes.wsattr(
|
max_retries_down = wtypes.wsattr(
|
||||||
wtypes.IntegerType(minimum=constants.MIN_HM_RETRIES,
|
wtypes.IntegerType(minimum=constants.MIN_HM_RETRIES,
|
||||||
maximum=constants.MAX_HM_RETRIES), default=3)
|
maximum=constants.MAX_HM_RETRIES),
|
||||||
|
default=constants.DEFAULT_MAX_RETRIES_DOWN)
|
||||||
max_retries = wtypes.wsattr(
|
max_retries = wtypes.wsattr(
|
||||||
wtypes.IntegerType(minimum=constants.MIN_HM_RETRIES,
|
wtypes.IntegerType(minimum=constants.MIN_HM_RETRIES,
|
||||||
maximum=constants.MAX_HM_RETRIES),
|
maximum=constants.MAX_HM_RETRIES),
|
||||||
|
|
|
@ -193,11 +193,14 @@ HEALTH_MONITOR_DEFAULT_URL_PATH = '/'
|
||||||
TYPE = 'type'
|
TYPE = 'type'
|
||||||
URL_PATH = 'url_path'
|
URL_PATH = 'url_path'
|
||||||
HTTP_METHOD = 'http_method'
|
HTTP_METHOD = 'http_method'
|
||||||
|
HTTP_VERSION = 'http_version'
|
||||||
EXPECTED_CODES = 'expected_codes'
|
EXPECTED_CODES = 'expected_codes'
|
||||||
DELAY = 'delay'
|
DELAY = 'delay'
|
||||||
TIMEOUT = 'timeout'
|
TIMEOUT = 'timeout'
|
||||||
MAX_RETRIES = 'max_retries'
|
MAX_RETRIES = 'max_retries'
|
||||||
|
MAX_RETRIES_DOWN = 'max_retries_down'
|
||||||
RISE_THRESHOLD = 'rise_threshold'
|
RISE_THRESHOLD = 'rise_threshold'
|
||||||
|
DOMAIN_NAME = 'domain_name'
|
||||||
|
|
||||||
UPDATE_STATS = 'UPDATE_STATS'
|
UPDATE_STATS = 'UPDATE_STATS'
|
||||||
UPDATE_HEALTH = 'UPDATE_HEALTH'
|
UPDATE_HEALTH = 'UPDATE_HEALTH'
|
||||||
|
@ -212,6 +215,7 @@ MIN_CONNECTION_LIMIT = -1
|
||||||
MIN_WEIGHT = 0
|
MIN_WEIGHT = 0
|
||||||
MAX_WEIGHT = 256
|
MAX_WEIGHT = 256
|
||||||
|
|
||||||
|
DEFAULT_MAX_RETRIES_DOWN = 3
|
||||||
MIN_HM_RETRIES = 1
|
MIN_HM_RETRIES = 1
|
||||||
MAX_HM_RETRIES = 10
|
MAX_HM_RETRIES = 10
|
||||||
|
|
||||||
|
|
|
@ -1519,6 +1519,42 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||||
self.put(self.HM_PATH.format(healthmonitor_id=api_hm.get('id')),
|
self.put(self.HM_PATH.format(healthmonitor_id=api_hm.get('id')),
|
||||||
self._build_body(new_hm), status=400)
|
self._build_body(new_hm), status=400)
|
||||||
|
|
||||||
|
def test_update_delay_none(self):
|
||||||
|
api_hm = self.create_health_monitor(self.pool_with_listener_id,
|
||||||
|
constants.HEALTH_MONITOR_HTTP,
|
||||||
|
1, 1, 1, 1).get(self.root_tag)
|
||||||
|
new_hm = {constants.DELAY: None}
|
||||||
|
self.set_lb_status(self.lb_id)
|
||||||
|
expect_error_msg = ("None is not a valid option for %s" %
|
||||||
|
constants.DELAY)
|
||||||
|
res = self.put(self.HM_PATH.format(healthmonitor_id=api_hm.get('id')),
|
||||||
|
self._build_body(new_hm), status=400)
|
||||||
|
self.assertEqual(expect_error_msg, res.json['faultstring'])
|
||||||
|
|
||||||
|
def test_update_max_retries_none(self):
|
||||||
|
api_hm = self.create_health_monitor(self.pool_with_listener_id,
|
||||||
|
constants.HEALTH_MONITOR_HTTP,
|
||||||
|
1, 1, 1, 1).get(self.root_tag)
|
||||||
|
new_hm = {constants.MAX_RETRIES: None}
|
||||||
|
self.set_lb_status(self.lb_id)
|
||||||
|
expect_error_msg = ("None is not a valid option for %s" %
|
||||||
|
constants.MAX_RETRIES)
|
||||||
|
res = self.put(self.HM_PATH.format(healthmonitor_id=api_hm.get('id')),
|
||||||
|
self._build_body(new_hm), status=400)
|
||||||
|
self.assertEqual(expect_error_msg, res.json['faultstring'])
|
||||||
|
|
||||||
|
def test_update_timeout_none(self):
|
||||||
|
api_hm = self.create_health_monitor(self.pool_with_listener_id,
|
||||||
|
constants.HEALTH_MONITOR_HTTP,
|
||||||
|
1, 1, 1, 1).get(self.root_tag)
|
||||||
|
new_hm = {constants.TIMEOUT: None}
|
||||||
|
self.set_lb_status(self.lb_id)
|
||||||
|
expect_error_msg = ("None is not a valid option for %s" %
|
||||||
|
constants.TIMEOUT)
|
||||||
|
res = self.put(self.HM_PATH.format(healthmonitor_id=api_hm.get('id')),
|
||||||
|
self._build_body(new_hm), status=400)
|
||||||
|
self.assertEqual(expect_error_msg, res.json['faultstring'])
|
||||||
|
|
||||||
@mock.patch('octavia.api.drivers.utils.call_provider')
|
@mock.patch('octavia.api.drivers.utils.call_provider')
|
||||||
def test_update_with_bad_provider(self, mock_provider):
|
def test_update_with_bad_provider(self, mock_provider):
|
||||||
api_hm = self.create_health_monitor(
|
api_hm = self.create_health_monitor(
|
||||||
|
@ -1631,6 +1667,31 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||||
'domain_name'], constants.DOMAIN_NAME_REGEX)
|
'domain_name'], constants.DOMAIN_NAME_REGEX)
|
||||||
self.assertEqual(expect_error_msg, response.json['faultstring'])
|
self.assertEqual(expect_error_msg, response.json['faultstring'])
|
||||||
|
|
||||||
|
def test_update_unset_defaults(self):
|
||||||
|
api_hm = self.create_health_monitor(
|
||||||
|
self.pool_with_listener_id, constants.HEALTH_MONITOR_HTTP,
|
||||||
|
1, 1, 1, 1, name='test', domain_name='test.example.com',
|
||||||
|
expected_codes='400', http_method='HEAD', http_version='1.1',
|
||||||
|
url_path='/test').get(self.root_tag)
|
||||||
|
new_hm = {constants.DOMAIN_NAME: None, constants.EXPECTED_CODES: None,
|
||||||
|
constants.HTTP_METHOD: None, constants.HTTP_VERSION: None,
|
||||||
|
constants.MAX_RETRIES_DOWN: None, 'name': None,
|
||||||
|
constants.URL_PATH: None}
|
||||||
|
self.set_lb_status(self.lb_id)
|
||||||
|
res = self.put(self.HM_PATH.format(healthmonitor_id=api_hm.get('id')),
|
||||||
|
self._build_body(new_hm)).json.get(self.root_tag)
|
||||||
|
self.assertIsNone(res[constants.DOMAIN_NAME])
|
||||||
|
self.assertEqual(constants.HEALTH_MONITOR_DEFAULT_EXPECTED_CODES,
|
||||||
|
res[constants.EXPECTED_CODES])
|
||||||
|
self.assertEqual(constants.HEALTH_MONITOR_HTTP_DEFAULT_METHOD,
|
||||||
|
res[constants.HTTP_METHOD])
|
||||||
|
self.assertIsNone(res[constants.HTTP_VERSION])
|
||||||
|
self.assertEqual(constants.DEFAULT_MAX_RETRIES_DOWN,
|
||||||
|
res[constants.MAX_RETRIES_DOWN])
|
||||||
|
self.assertEqual('', res['name'])
|
||||||
|
self.assertEqual(constants.HEALTH_MONITOR_DEFAULT_URL_PATH,
|
||||||
|
res[constants.URL_PATH])
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
api_hm = self.create_health_monitor(
|
api_hm = self.create_health_monitor(
|
||||||
self.pool_with_listener_id,
|
self.pool_with_listener_id,
|
||||||
|
|
Loading…
Reference in New Issue