Fix PING health-monitor with recent haproxy releases
haproxy 2.2.x requires an "insecure-fork-wanted" global option when using external-check. This commit also fixes a function that builds the list of the features available in haproxy based on its version. Story 2009953 Task 44900 Conflicts: octavia/common/jinja/haproxy/combined_listeners/jinja_cfg.py octavia/tests/unit/common/jinja/haproxy/combined_listeners/test_jinja_cfg.py Change-Id: I35c5976c6bdb8828e54bcde00052622a7b6bc96a (cherry picked from commit1ac7818128
) (cherry picked from commitd4d8d597d5
)
This commit is contained in:
parent
c0b6f5c9ef
commit
ad65672f1f
@ -802,6 +802,7 @@ AMP_NETNS_SVC_PREFIX = 'amphora-netns'
|
|||||||
HTTP_REUSE = 'has_http_reuse'
|
HTTP_REUSE = 'has_http_reuse'
|
||||||
SERVER_STATE_FILE = 'has_server_state_file'
|
SERVER_STATE_FILE = 'has_server_state_file'
|
||||||
POOL_ALPN = 'has_pool_alpn'
|
POOL_ALPN = 'has_pool_alpn'
|
||||||
|
INSECURE_FORK = 'requires_insecure_fork'
|
||||||
|
|
||||||
# TODO(johnsom) convert these to octavia_lib constants
|
# TODO(johnsom) convert these to octavia_lib constants
|
||||||
# once octavia is transitioned to use octavia_lib
|
# once octavia is transitioned to use octavia_lib
|
||||||
|
@ -17,6 +17,7 @@ import re
|
|||||||
|
|
||||||
import jinja2
|
import jinja2
|
||||||
from octavia_lib.common import constants as lib_consts
|
from octavia_lib.common import constants as lib_consts
|
||||||
|
from oslo_utils import versionutils
|
||||||
|
|
||||||
from octavia.common.config import cfg
|
from octavia.common.config import cfg
|
||||||
from octavia.common import constants
|
from octavia.common import constants
|
||||||
@ -97,12 +98,16 @@ class JinjaTemplater(object):
|
|||||||
# pair might be running an older amphora version.
|
# pair might be running an older amphora version.
|
||||||
|
|
||||||
feature_compatibility = {}
|
feature_compatibility = {}
|
||||||
|
version = ".".join(haproxy_versions)
|
||||||
# Is it newer than haproxy 1.5?
|
# Is it newer than haproxy 1.5?
|
||||||
if not (int(haproxy_versions[0]) < 2 and int(haproxy_versions[1]) < 6):
|
if versionutils.is_compatible("1.6.0", version, same_major=False):
|
||||||
feature_compatibility[constants.HTTP_REUSE] = True
|
feature_compatibility[constants.HTTP_REUSE] = True
|
||||||
feature_compatibility[constants.SERVER_STATE_FILE] = True
|
feature_compatibility[constants.SERVER_STATE_FILE] = True
|
||||||
if not (int(haproxy_versions[0]) < 2 and int(haproxy_versions[1]) < 9):
|
if versionutils.is_compatible("1.9.0", version, same_major=False):
|
||||||
feature_compatibility[constants.POOL_ALPN] = True
|
feature_compatibility[constants.POOL_ALPN] = True
|
||||||
|
# haproxy 2.2 requires insecure-fork-wanted for PING healthchecks
|
||||||
|
if versionutils.is_compatible("2.2.0", version, same_major=False):
|
||||||
|
feature_compatibility[constants.INSECURE_FORK] = True
|
||||||
|
|
||||||
return self.render_loadbalancer_obj(
|
return self.render_loadbalancer_obj(
|
||||||
host_amphora, listeners, tls_certs=tls_certs,
|
host_amphora, listeners, tls_certs=tls_certs,
|
||||||
@ -167,6 +172,8 @@ class JinjaTemplater(object):
|
|||||||
self.base_amp_path,
|
self.base_amp_path,
|
||||||
listeners[0].load_balancer.id) if feature_compatibility.get(
|
listeners[0].load_balancer.id) if feature_compatibility.get(
|
||||||
constants.SERVER_STATE_FILE) else ''
|
constants.SERVER_STATE_FILE) else ''
|
||||||
|
require_insecure_fork = feature_compatibility.get(
|
||||||
|
constants.INSECURE_FORK)
|
||||||
return self._get_template().render(
|
return self._get_template().render(
|
||||||
{'loadbalancer': loadbalancer,
|
{'loadbalancer': loadbalancer,
|
||||||
'stats_sock': socket_path,
|
'stats_sock': socket_path,
|
||||||
@ -176,7 +183,8 @@ class JinjaTemplater(object):
|
|||||||
'administrative_log_facility':
|
'administrative_log_facility':
|
||||||
CONF.amphora_agent.administrative_log_facility,
|
CONF.amphora_agent.administrative_log_facility,
|
||||||
'user_log_facility': CONF.amphora_agent.user_log_facility,
|
'user_log_facility': CONF.amphora_agent.user_log_facility,
|
||||||
'connection_logging': self.connection_logging},
|
'connection_logging': self.connection_logging,
|
||||||
|
'require_insecure_fork': require_insecure_fork},
|
||||||
constants=constants, lib_consts=lib_consts)
|
constants=constants, lib_consts=lib_consts)
|
||||||
|
|
||||||
def _transform_loadbalancer(self, host_amphora, loadbalancer, listeners,
|
def _transform_loadbalancer(self, host_amphora, loadbalancer, listeners,
|
||||||
|
@ -34,6 +34,9 @@ global
|
|||||||
found_ns.found == false %}
|
found_ns.found == false %}
|
||||||
{% set found_ns.found = true %}
|
{% set found_ns.found = true %}
|
||||||
external-check
|
external-check
|
||||||
|
{% if require_insecure_fork %}
|
||||||
|
insecure-fork-wanted
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
import copy
|
import copy
|
||||||
import os
|
import os
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_config import fixture as oslo_fixture
|
from oslo_config import fixture as oslo_fixture
|
||||||
@ -706,6 +707,36 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
self.assertEqual(sample_configs_combined.sample_base_expected_config(
|
self.assertEqual(sample_configs_combined.sample_base_expected_config(
|
||||||
backend=be, global_opts=go), rendered_obj)
|
backend=be, global_opts=go), rendered_obj)
|
||||||
|
|
||||||
|
def test_render_template_ping_monitor_http_insecure_fork(self):
|
||||||
|
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
|
||||||
|
" mode http\n"
|
||||||
|
" balance roundrobin\n"
|
||||||
|
" cookie SRV insert indirect nocache\n"
|
||||||
|
" timeout check 31s\n"
|
||||||
|
" option external-check\n"
|
||||||
|
" external-check command /var/lib/octavia/ping-wrapper.sh\n"
|
||||||
|
" fullconn {maxconn}\n"
|
||||||
|
" option allbackups\n"
|
||||||
|
" timeout connect 5000\n"
|
||||||
|
" timeout server 50000\n"
|
||||||
|
" server sample_member_id_1 10.0.0.99:82 "
|
||||||
|
"weight 13 check inter 30s fall 3 rise 2 "
|
||||||
|
"cookie sample_member_id_1\n"
|
||||||
|
" server sample_member_id_2 10.0.0.98:82 "
|
||||||
|
"weight 13 check inter 30s fall 3 rise 2 "
|
||||||
|
"cookie sample_member_id_2\n\n").format(
|
||||||
|
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
|
||||||
|
go = (f" maxconn {constants.HAPROXY_DEFAULT_MAXCONN}\n"
|
||||||
|
" external-check\n insecure-fork-wanted\n\n")
|
||||||
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
|
sample_configs_combined.sample_amphora_tuple(),
|
||||||
|
[sample_configs_combined.sample_listener_tuple(
|
||||||
|
proto='HTTP', monitor_proto='PING')],
|
||||||
|
feature_compatibility={
|
||||||
|
"requires_insecure_fork": True})
|
||||||
|
self.assertEqual(sample_configs_combined.sample_base_expected_config(
|
||||||
|
backend=be, global_opts=go), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_no_monitor_https(self):
|
def test_render_template_no_monitor_https(self):
|
||||||
fe = ("frontend sample_listener_id_1\n"
|
fe = ("frontend sample_listener_id_1\n"
|
||||||
" maxconn {maxconn}\n"
|
" maxconn {maxconn}\n"
|
||||||
@ -1672,3 +1703,109 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
sample_configs_combined.sample_base_expected_config(
|
sample_configs_combined.sample_base_expected_config(
|
||||||
frontend=fe, backend=be),
|
frontend=fe, backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
|
@mock.patch("octavia.common.jinja.haproxy.combined_listeners.jinja_cfg."
|
||||||
|
"JinjaTemplater.render_loadbalancer_obj")
|
||||||
|
def test_build_config(self, mock_render_loadbalancer_obj):
|
||||||
|
mock_amp = mock.Mock()
|
||||||
|
mock_listeners = mock.Mock()
|
||||||
|
mock_tls_certs = mock.Mock()
|
||||||
|
mock_socket_path = mock.Mock()
|
||||||
|
|
||||||
|
j_cfg = jinja_cfg.JinjaTemplater()
|
||||||
|
j_cfg.build_config(mock_amp, mock_listeners, mock_tls_certs,
|
||||||
|
haproxy_versions=("0", "7", "0"),
|
||||||
|
socket_path=mock_socket_path)
|
||||||
|
|
||||||
|
expected_fc = {}
|
||||||
|
mock_render_loadbalancer_obj.assert_called_once_with(
|
||||||
|
mock_amp, mock_listeners, tls_certs=mock_tls_certs,
|
||||||
|
socket_path=mock_socket_path,
|
||||||
|
feature_compatibility=expected_fc)
|
||||||
|
|
||||||
|
mock_render_loadbalancer_obj.reset_mock()
|
||||||
|
|
||||||
|
j_cfg.build_config(mock_amp, mock_listeners, mock_tls_certs,
|
||||||
|
haproxy_versions=("1", "6", "0"),
|
||||||
|
socket_path=mock_socket_path)
|
||||||
|
|
||||||
|
expected_fc = {
|
||||||
|
constants.HTTP_REUSE: True,
|
||||||
|
constants.SERVER_STATE_FILE: True
|
||||||
|
|
||||||
|
}
|
||||||
|
mock_render_loadbalancer_obj.assert_called_once_with(
|
||||||
|
mock_amp, mock_listeners, tls_certs=mock_tls_certs,
|
||||||
|
socket_path=mock_socket_path,
|
||||||
|
feature_compatibility=expected_fc)
|
||||||
|
|
||||||
|
mock_render_loadbalancer_obj.reset_mock()
|
||||||
|
|
||||||
|
j_cfg.build_config(mock_amp, mock_listeners, mock_tls_certs,
|
||||||
|
haproxy_versions=("1", "9", "0"),
|
||||||
|
socket_path=mock_socket_path)
|
||||||
|
|
||||||
|
expected_fc = {
|
||||||
|
constants.HTTP_REUSE: True,
|
||||||
|
constants.SERVER_STATE_FILE: True,
|
||||||
|
constants.POOL_ALPN: True
|
||||||
|
}
|
||||||
|
mock_render_loadbalancer_obj.assert_called_once_with(
|
||||||
|
mock_amp, mock_listeners, tls_certs=mock_tls_certs,
|
||||||
|
socket_path=mock_socket_path,
|
||||||
|
feature_compatibility=expected_fc)
|
||||||
|
|
||||||
|
mock_render_loadbalancer_obj.reset_mock()
|
||||||
|
|
||||||
|
j_cfg.build_config(mock_amp, mock_listeners, mock_tls_certs,
|
||||||
|
haproxy_versions=("2", "1", "1"),
|
||||||
|
socket_path=mock_socket_path)
|
||||||
|
|
||||||
|
expected_fc = {
|
||||||
|
constants.HTTP_REUSE: True,
|
||||||
|
constants.SERVER_STATE_FILE: True,
|
||||||
|
constants.POOL_ALPN: True
|
||||||
|
}
|
||||||
|
mock_render_loadbalancer_obj.assert_called_once_with(
|
||||||
|
mock_amp, mock_listeners, tls_certs=mock_tls_certs,
|
||||||
|
socket_path=mock_socket_path,
|
||||||
|
feature_compatibility=expected_fc)
|
||||||
|
|
||||||
|
mock_render_loadbalancer_obj.reset_mock()
|
||||||
|
|
||||||
|
j_cfg.build_config(mock_amp, mock_listeners, mock_tls_certs,
|
||||||
|
haproxy_versions=("2", "2", "1"),
|
||||||
|
socket_path=mock_socket_path)
|
||||||
|
|
||||||
|
expected_fc = {
|
||||||
|
constants.HTTP_REUSE: True,
|
||||||
|
constants.SERVER_STATE_FILE: True,
|
||||||
|
constants.POOL_ALPN: True,
|
||||||
|
constants.INSECURE_FORK: True
|
||||||
|
}
|
||||||
|
mock_render_loadbalancer_obj.assert_called_once_with(
|
||||||
|
mock_amp, mock_listeners, tls_certs=mock_tls_certs,
|
||||||
|
socket_path=mock_socket_path,
|
||||||
|
feature_compatibility=expected_fc)
|
||||||
|
|
||||||
|
mock_render_loadbalancer_obj.reset_mock()
|
||||||
|
|
||||||
|
j_cfg.build_config(mock_amp, mock_listeners, mock_tls_certs,
|
||||||
|
haproxy_versions=("2", "4", "0"),
|
||||||
|
socket_path=mock_socket_path)
|
||||||
|
|
||||||
|
mock_render_loadbalancer_obj.assert_called_once_with(
|
||||||
|
mock_amp, mock_listeners, tls_certs=mock_tls_certs,
|
||||||
|
socket_path=mock_socket_path,
|
||||||
|
feature_compatibility=expected_fc)
|
||||||
|
|
||||||
|
mock_render_loadbalancer_obj.reset_mock()
|
||||||
|
|
||||||
|
j_cfg.build_config(mock_amp, mock_listeners, mock_tls_certs,
|
||||||
|
haproxy_versions=("3", "1", "0"),
|
||||||
|
socket_path=mock_socket_path)
|
||||||
|
|
||||||
|
mock_render_loadbalancer_obj.assert_called_once_with(
|
||||||
|
mock_amp, mock_listeners, tls_certs=mock_tls_certs,
|
||||||
|
socket_path=mock_socket_path,
|
||||||
|
feature_compatibility=expected_fc)
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Fix PING health-monitors with recent haproxy releases (>=2.2), haproxy now
|
||||||
|
requires an additional "insecure-fork-wanted" option to authorize the
|
||||||
|
Octavia PING healthcheck.
|
Loading…
Reference in New Issue
Block a user