Fix memory consumption issues with default connection_limit

With 1.8.x releases, haproxy consumes a lot of memory when
using 1,000,000 as default connection_limit.

This commit introduces a new configuration option for the Amphora
provider: [haproxy_amphora].default_connection_limit (defaulted to
50,000). This value is used when creating a listener with -1 (which is
the default) as connection_limit, or when unsetting connection_limit in
a listener.
Updating an existing listener by setting connection_limit to -1 also
sets it to default_connection_limit.

The global connection_limit for a load balancer is the sum of the
connection_limit of the listeners, but it cannot be over
HAPROXY_MAX_MAXCONN (which is still 1,000,000).

Story: 2007794
Task: 40046

Change-Id: Ibc525d9a046a5ab7f090a942459d80a2df66ae2e
This commit is contained in:
Gregory Thiemonge 2020-06-10 21:11:23 +02:00
parent f68e3aba49
commit f4305e036c
10 changed files with 147 additions and 75 deletions

View File

@ -440,14 +440,16 @@ compute-id:
connection_limit:
description: |
The maximum number of connections permitted for this listener. Default
value is -1 which represents infinite connections.
value is -1 which represents infinite connections or a default value
defined by the provider driver.
in: body
required: true
type: integer
connection_limit-optional:
description: |
The maximum number of connections permitted for this listener. Default
value is -1 which represents infinite connections.
value is -1 which represents infinite connections or a default value
defined by the provider driver.
in: body
required: false
type: integer

View File

@ -275,6 +275,10 @@
# api_db_commit_retry_backoff = 1
# api_db_commit_retry_max = 5
# Default connection_limit for listeners, this value is used when setting "-1"
# or when unsetting "connection_limit" with the listener API.
# default_connection_limit = 50000
[controller_worker]
# workers = 1
# amp_active_retries = 30

View File

@ -413,6 +413,11 @@ haproxy_amphora_opts = [
cfg.IntOpt('api_db_commit_retry_max', default=5,
help=_('The maximum amount of time to wait between retry '
'attempts.')),
cfg.IntOpt('default_connection_limit',
default=constants.HAPROXY_DEFAULT_MAXCONN,
help=_('Default connection_limit for listeners, used when '
'setting "-1" or when unsetting connection_limit with '
'the listener API.')),
]
controller_worker_opts = [

View File

@ -636,6 +636,9 @@ NO_CHECK = 'no check'
# NO_CHECK = no health monitor is enabled
HAPROXY_MEMBER_STATUSES = (UP, DOWN, DRAIN, MAINT, NO_CHECK)
# Default number of concurrent connections in a HAProxy listener.
HAPROXY_DEFAULT_MAXCONN = 50000
# Current maximum number of conccurent connections in HAProxy.
# This is limited by the systemd "LimitNOFILE" and
# the sysctl fs.file-max fs.nr_open settings in the image

View File

@ -203,8 +203,8 @@ class JinjaTemplater(object):
if listener.connection_limit and listener.connection_limit > -1:
connection_limit_sum += listener.connection_limit
else:
# If *any* listener has no connection limit, global = MAX
connection_limit_sum = constants.HAPROXY_MAX_MAXCONN
connection_limit_sum += (
CONF.haproxy_amphora.default_connection_limit)
# If there's a limit between 0 and MAX, set it, otherwise just set MAX
if 0 < connection_limit_sum < constants.HAPROXY_MAX_MAXCONN:
ret_value['global_connection_limit'] = connection_limit_sum
@ -262,7 +262,8 @@ class JinjaTemplater(object):
if listener.connection_limit and listener.connection_limit > -1:
ret_value['connection_limit'] = listener.connection_limit
else:
ret_value['connection_limit'] = constants.HAPROXY_MAX_MAXCONN
ret_value['connection_limit'] = (
CONF.haproxy_amphora.default_connection_limit)
if listener.tls_certificate_id:
ret_value['crt_list_filename'] = os.path.join(

View File

@ -2607,7 +2607,7 @@ class TestLoadBalancerGraph(base.BaseAPITest):
'description': '',
'default_tls_container_ref': None,
'sni_container_refs': [],
'connection_limit': -1,
'connection_limit': constants.DEFAULT_CONNECTION_LIMIT,
'admin_state_up': True,
'provisioning_status': constants.PENDING_CREATE,
'operating_status': constants.OFFLINE,

View File

@ -49,7 +49,7 @@ class HAProxyCompatTestCase(base.TestCase):
"%ci\\ %cp\\ %t\\ %{{+Q}}r\\ %ST\\ %B\\ %U\\ "
"%[ssl_c_verify]\\ %{{+Q}}[ssl_c_s_dn]\\ %b\\ %s\\ %Tt\\ "
"%tsc\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
self.backend_without_external = (
"backend sample_pool_id_1:sample_listener_id_1\n"
" mode http\n"
@ -67,7 +67,7 @@ class HAProxyCompatTestCase(base.TestCase):
" 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").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
self.backend_with_external = (
"backend sample_pool_id_1:sample_listener_id_1\n"
" mode http\n"
@ -87,7 +87,7 @@ class HAProxyCompatTestCase(base.TestCase):
" 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").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
@mock.patch('subprocess.check_output')
def test_get_haproxy_versions(self, mock_process):

View File

@ -56,7 +56,7 @@ class TestHaproxyCfg(base.TestCase):
" mode http\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
crt_list=FAKE_CRT_LIST_FILENAME,
ciphers=constants.CIPHERS_OWASP_SUITE_B)
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
@ -76,7 +76,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
tls_tupe = {'cont_id_1':
sample_configs_combined.sample_tls_container_tuple(
id='tls_container_id',
@ -109,7 +109,7 @@ class TestHaproxyCfg(base.TestCase):
" mode http\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
crt_list=FAKE_CRT_LIST_FILENAME,
ciphers=constants.CIPHERS_OWASP_SUITE_B)
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
@ -129,7 +129,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -159,7 +159,7 @@ class TestHaproxyCfg(base.TestCase):
" mode http\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
crt_list=FAKE_CRT_LIST_FILENAME)
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
" mode http\n"
@ -178,7 +178,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -211,7 +211,7 @@ class TestHaproxyCfg(base.TestCase):
" mode http\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
crt_list=FAKE_CRT_LIST_FILENAME,
ciphers=constants.CIPHERS_OWASP_SUITE_B)
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
@ -231,7 +231,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
tls_tupe = {'cont_id_1':
sample_configs_combined.sample_tls_container_tuple(
id='tls_container_id',
@ -263,7 +263,7 @@ class TestHaproxyCfg(base.TestCase):
" mode http\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
crt_list=FAKE_CRT_LIST_FILENAME)
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
" mode http\n"
@ -282,7 +282,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -317,7 +317,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple()])
@ -345,7 +345,7 @@ class TestHaproxyCfg(base.TestCase):
"weight 13 check inter 30s fall 3 rise 2 "
"addr 192.168.1.1 port 9000 "
"cookie sample_member_id_2 backup\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -361,7 +361,7 @@ class TestHaproxyCfg(base.TestCase):
" mode http\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 2\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
" mode http\n"
" balance roundrobin\n"
@ -378,7 +378,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -396,7 +396,7 @@ class TestHaproxyCfg(base.TestCase):
" mode http\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
" mode http\n"
" balance roundrobin\n"
@ -413,7 +413,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -444,7 +444,7 @@ class TestHaproxyCfg(base.TestCase):
"weight 13 check inter 30s fall 3 rise 2 "
"addr 192.168.1.1 port 9000 "
"cookie sample_member_id_2\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -460,7 +460,7 @@ class TestHaproxyCfg(base.TestCase):
" mode tcp\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
lg = (" log-format 12345\\ sample_loadbalancer_id_1\\ %f\\ "
"%ci\\ %cp\\ %t\\ -\\ -\\ %B\\ %U\\ "
"%[ssl_c_verify]\\ %{+Q}[ssl_c_s_dn]\\ %b\\ %s\\ %Tt\\ "
@ -482,7 +482,7 @@ class TestHaproxyCfg(base.TestCase):
" server sample_member_id_2 10.0.0.98:82 "
"weight 13 check check-ssl verify none inter 30s fall 3 rise 2 "
"cookie sample_member_id_2\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(proto='HTTPS')])
@ -496,7 +496,7 @@ class TestHaproxyCfg(base.TestCase):
" mode tcp\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
lg = (" log-format 12345\\ sample_loadbalancer_id_1\\ %f\\ "
"%ci\\ %cp\\ %t\\ -\\ -\\ %B\\ %U\\ "
"%[ssl_c_verify]\\ %{+Q}[ssl_c_s_dn]\\ %b\\ %s\\ %Tt\\ "
@ -517,7 +517,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -538,7 +538,7 @@ class TestHaproxyCfg(base.TestCase):
"cookie sample_member_id_1\n"
" server sample_member_id_2 10.0.0.98:82 weight 13 "
"cookie sample_member_id_2\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(proto='HTTP',
@ -559,7 +559,7 @@ class TestHaproxyCfg(base.TestCase):
"cookie sample_member_id_1\n"
" server sample_member_id_2 10.0.0.98:82 weight 13 "
"cookie sample_member_id_2 disabled\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -585,9 +585,9 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
go = " maxconn {maxconn}\n external-check\n\n".format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -602,7 +602,7 @@ class TestHaproxyCfg(base.TestCase):
" mode tcp\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
lg = (" log-format 12345\\ sample_loadbalancer_id_1\\ %f\\ "
"%ci\\ %cp\\ %t\\ -\\ -\\ %B\\ %U\\ "
"%[ssl_c_verify]\\ %{+Q}[ssl_c_s_dn]\\ %b\\ %s\\ %Tt\\ "
@ -619,7 +619,7 @@ class TestHaproxyCfg(base.TestCase):
"cookie sample_member_id_1\n"
" server sample_member_id_2 10.0.0.98:82 weight 13 "
"cookie sample_member_id_2\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(proto='HTTPS',
@ -646,7 +646,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -661,7 +661,7 @@ class TestHaproxyCfg(base.TestCase):
" mode tcp\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
lg = (" log-format 12345\\ sample_loadbalancer_id_1\\ %f\\ "
"%ci\\ %cp\\ %t\\ -\\ -\\ %B\\ %U\\ "
"%[ssl_c_verify]\\ %{+Q}[ssl_c_s_dn]\\ %b\\ %s\\ %Tt\\ "
@ -675,7 +675,8 @@ class TestHaproxyCfg(base.TestCase):
" timeout server 50000\n"
" server sample_member_id_1 10.0.0.99:82 weight 13\n"
" server sample_member_id_2 10.0.0.98:82 "
"weight 13\n\n").format(maxconn=constants.HAPROXY_MAX_MAXCONN)
"weight 13\n\n").format(
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -693,7 +694,8 @@ class TestHaproxyCfg(base.TestCase):
" timeout server 50000\n"
" server sample_member_id_1 10.0.0.99:82 weight 13\n"
" server sample_member_id_2 10.0.0.98:82 "
"weight 13\n\n").format(maxconn=constants.HAPROXY_MAX_MAXCONN)
"weight 13\n\n").format(
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -718,7 +720,7 @@ class TestHaproxyCfg(base.TestCase):
"weight 13 check inter 30s fall 3 rise 2\n"
" server sample_member_id_2 10.0.0.98:82 "
"weight 13 check inter 30s fall 3 rise 2\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -745,7 +747,7 @@ class TestHaproxyCfg(base.TestCase):
"weight 13 check inter 30s fall 3 rise 2\n"
" server sample_member_id_2 10.0.0.98:82 "
"weight 13 check inter 30s fall 3 rise 2\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -765,7 +767,7 @@ class TestHaproxyCfg(base.TestCase):
" mode tcp\n"
" default_backend {pool_id}:{listener_id}\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
pool_id=sample_listener.default_pool.id,
listener_id=sample_listener.id)
lg = (" log-format 12345\\ sample_loadbalancer_id_1\\ %f\\ "
@ -784,7 +786,7 @@ class TestHaproxyCfg(base.TestCase):
"cookie sample_member_id_1\n"
" server sample_member_id_2 10.0.0.98:82 weight 13 "
"cookie sample_member_id_2\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
pool_id=sample_listener.default_pool.id,
listener_id=sample_listener.id)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
@ -852,7 +854,7 @@ class TestHaproxyCfg(base.TestCase):
"!sample_l7rule_id_2 sample_l7rule_id_3\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
" mode http\n"
" balance roundrobin\n"
@ -882,7 +884,7 @@ class TestHaproxyCfg(base.TestCase):
" timeout server 50000\n"
" server sample_member_id_3 10.0.0.97:82 weight 13 check "
"inter 30s fall 3 rise 2 cookie sample_member_id_3\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(l7=True)])
@ -908,7 +910,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -937,7 +939,7 @@ class TestHaproxyCfg(base.TestCase):
" 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_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
@ -963,7 +965,7 @@ class TestHaproxyCfg(base.TestCase):
" server sample_member_id_2 10.0.0.98:82 "
"weight 13 check inter 30s fall 3 rise 2 "
"cookie sample_member_id_2 send-proxy\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(be_proto='PROXY')])
@ -991,7 +993,7 @@ class TestHaproxyCfg(base.TestCase):
" server sample_member_id_2 10.0.0.98:82 weight 13 "
"check inter 30s fall 3 rise 2 cookie sample_member_id_2 "
"{opts}\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path +
" ciphers " + constants.CIPHERS_OWASP_SUITE_B +
" no-sslv3 no-tlsv10 no-tlsv11")
@ -1028,7 +1030,7 @@ class TestHaproxyCfg(base.TestCase):
" server sample_member_id_2 10.0.0.98:82 weight 13 "
"check inter 30s fall 3 rise 2 cookie sample_member_id_2 "
"{opts}\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path +
" ciphers " + constants.CIPHERS_OWASP_SUITE_B)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
@ -1065,7 +1067,7 @@ class TestHaproxyCfg(base.TestCase):
" server sample_member_id_2 10.0.0.98:82 weight 13 "
"check inter 30s fall 3 rise 2 cookie sample_member_id_2 "
"{opts}\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path +
" no-sslv3 no-tlsv10 no-tlsv11")
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
@ -1100,7 +1102,7 @@ class TestHaproxyCfg(base.TestCase):
" server sample_member_id_2 10.0.0.98:82 weight 13 "
"check inter 30s fall 3 rise 2 cookie sample_member_id_2 "
"{opts}\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path)
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
@ -1135,7 +1137,7 @@ class TestHaproxyCfg(base.TestCase):
" server sample_member_id_2 10.0.0.98:82 weight 13 "
"check inter 30s fall 3 rise 2 cookie sample_member_id_2 "
"{opts}\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
opts="%s %s %s %s %s %s" % (
"ssl", "crt", pool_client_cert,
"ca-file %s" % pool_ca_cert,
@ -1220,6 +1222,41 @@ class TestHaproxyCfg(base.TestCase):
in_amphora, in_listener.load_balancer, [in_listener], None, {})
self.assertEqual(sample_configs_combined.RET_LB, ret)
def test_transform_two_loadbalancers(self):
in_amphora = sample_configs_combined.sample_amphora_tuple()
in_listener1 = sample_configs_combined.sample_listener_tuple()
in_listener2 = sample_configs_combined.sample_listener_tuple()
ret = self.jinja_cfg._transform_loadbalancer(
in_amphora, in_listener1.load_balancer,
[in_listener1, in_listener2], None, {})
self.assertEqual(ret['global_connection_limit'],
constants.HAPROXY_DEFAULT_MAXCONN +
constants.HAPROXY_DEFAULT_MAXCONN)
def test_transform_many_loadbalancers(self):
in_amphora = sample_configs_combined.sample_amphora_tuple()
in_listeners = []
# Create many listeners, until the sum of connection_limits
# is greater than MAX_MAXCONN
connection_limit_sum = 0
while connection_limit_sum <= constants.HAPROXY_MAX_MAXCONN:
in_listener = (
sample_configs_combined.sample_listener_tuple())
connection_limit_sum += constants.HAPROXY_DEFAULT_MAXCONN
in_listeners.append(in_listener)
ret = self.jinja_cfg._transform_loadbalancer(
in_amphora, in_listeners[0].load_balancer,
in_listeners, None, {})
self.assertEqual(ret['global_connection_limit'],
constants.HAPROXY_MAX_MAXCONN)
self.assertLess(ret['global_connection_limit'],
connection_limit_sum)
def test_transform_amphora(self):
in_amphora = sample_configs_combined.sample_amphora_tuple()
ret = self.jinja_cfg._transform_amphora(in_amphora, {})
@ -1312,7 +1349,7 @@ class TestHaproxyCfg(base.TestCase):
" server sample_member_id_2 10.0.0.98:82 "
"weight 13 check inter 30s fall 3 rise 2 "
"cookie sample_member_id_2 send-proxy\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
pool_id=sample_proxy_listener.default_pool.id,
listener_id=sample_proxy_listener.id)
rendered_obj = j_cfg.build_config(
@ -1340,7 +1377,7 @@ class TestHaproxyCfg(base.TestCase):
" server sample_member_id_2 10.0.0.98:82 "
"weight 13 check inter 30s fall 3 rise 2 "
"cookie sample_member_id_2 send-proxy\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN,
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
pool_id=sample_proxy_listener.default_pool.id,
listener_id=sample_proxy_listener.id)
rendered_obj = j_cfg.build_config(
@ -1357,11 +1394,10 @@ class TestHaproxyCfg(base.TestCase):
base_amp_path='/var/lib/octavia',
base_crt_dir='/var/lib/octavia/certs')
fe = ("frontend sample_listener_id_1\n"
" maxconn 1000000\n"
" redirect scheme https if !{ ssl_fc }\n"
" bind 10.0.0.2:443 ciphers " +
constants.CIPHERS_OWASP_SUITE_B +
" no-sslv3 no-tlsv10 no-tlsv11\n"
" maxconn {maxconn}\n"
" redirect scheme https if !{{ ssl_fc }}\n"
" bind 10.0.0.2:443 ciphers {ciphers} "
"no-sslv3 no-tlsv10 no-tlsv11\n"
" mode http\n"
" acl sample_l7rule_id_1 path -m beg /api\n"
" use_backend sample_pool_id_2:sample_listener_id_1"
@ -1395,7 +1431,9 @@ class TestHaproxyCfg(base.TestCase):
"if sample_l7rule_id_7 !sample_l7rule_id_8 !sample_l7rule_id_9 "
"!sample_l7rule_id_10 sample_l7rule_id_11\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n")
" timeout client 50000\n".format(
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
ciphers=constants.CIPHERS_OWASP_SUITE_B))
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
" mode http\n"
" balance roundrobin\n"
@ -1403,7 +1441,7 @@ class TestHaproxyCfg(base.TestCase):
" timeout check 31s\n"
" option httpchk GET /index.html HTTP/1.0\\r\\n\n"
" http-check expect rstatus 418\n"
" fullconn 1000000\n"
" fullconn {maxconn}\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\n"
@ -1418,12 +1456,13 @@ class TestHaproxyCfg(base.TestCase):
" timeout check 31s\n"
" option httpchk GET /healthmon.html HTTP/1.0\\r\\n\n"
" http-check expect rstatus 418\n"
" fullconn 1000000\n"
" fullconn {maxconn}\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\n"
" server sample_member_id_3 10.0.0.97:82 weight 13 check "
"inter 30s fall 3 rise 2 cookie sample_member_id_3\n\n")
"inter 30s fall 3 rise 2 cookie sample_member_id_3\n\n".format(
maxconn=constants.HAPROXY_DEFAULT_MAXCONN))
sample_listener = sample_configs_combined.sample_listener_tuple(
proto=constants.PROTOCOL_TERMINATED_HTTPS, l7=True,
ssl_type_l7=True)

View File

@ -295,7 +295,7 @@ RET_LISTENER = {
'protocol': 'HTTP',
'protocol_mode': 'http',
'default_pool': RET_POOL_1,
'connection_limit': constants.HAPROXY_MAX_MAXCONN,
'connection_limit': constants.HAPROXY_DEFAULT_MAXCONN,
'user_log_format': '12345\\ sample_loadbalancer_id_1\\ %f\\ %ci\\ %cp\\ '
'%t\\ %{+Q}r\\ %ST\\ %B\\ %U\\ %[ssl_c_verify]\\ '
'%{+Q}[ssl_c_s_dn]\\ %b\\ %s\\ %Tt\\ %tsc',
@ -315,7 +315,7 @@ RET_LISTENER_L7 = {
'protocol': 'HTTP',
'protocol_mode': 'http',
'default_pool': RET_POOL_1,
'connection_limit': constants.HAPROXY_MAX_MAXCONN,
'connection_limit': constants.HAPROXY_DEFAULT_MAXCONN,
'user_log_format': '12345\\ sample_loadbalancer_id_1\\ %f\\ %ci\\ %cp\\ '
'%t\\ %{+Q}r\\ %ST\\ %B\\ %U\\ %[ssl_c_verify]\\ '
'%{+Q}[ssl_c_s_dn]\\ %b\\ %s\\ %Tt\\ %tsc',
@ -337,7 +337,7 @@ RET_LISTENER_TLS = {
'protocol': 'TERMINATED_HTTPS',
'protocol_mode': 'http',
'default_pool': RET_POOL_1,
'connection_limit': constants.HAPROXY_MAX_MAXCONN,
'connection_limit': constants.HAPROXY_DEFAULT_MAXCONN,
'tls_certificate_id': 'cont_id_1',
'default_tls_path': '/etc/ssl/sample_loadbalancer_id_1/fakeCN.pem',
'default_tls_container': RET_DEF_TLS_CONT,
@ -351,7 +351,7 @@ RET_LISTENER_TLS_SNI = {
'protocol_port': '443',
'protocol': 'TERMINATED_HTTPS',
'default_pool': RET_POOL_1,
'connection_limit': constants.HAPROXY_MAX_MAXCONN,
'connection_limit': constants.HAPROXY_DEFAULT_MAXCONN,
'tls_certificate_id': 'cont_id_1',
'default_tls_path': '/etc/ssl/sample_loadbalancer_id_1/fakeCN.pem',
'default_tls_container': RET_DEF_TLS_CONT,
@ -383,7 +383,7 @@ RET_LB = {
'peer_port': 1024,
'topology': 'SINGLE',
'enabled': True,
'global_connection_limit': constants.HAPROXY_MAX_MAXCONN,
'global_connection_limit': constants.HAPROXY_DEFAULT_MAXCONN,
'amphorae': [sample_amphora_tuple()]}
RET_LB_L7 = {
@ -394,7 +394,7 @@ RET_LB_L7 = {
'peer_port': 1024,
'topology': 'SINGLE',
'enabled': True,
'global_connection_limit': constants.HAPROXY_MAX_MAXCONN,
'global_connection_limit': constants.HAPROXY_DEFAULT_MAXCONN,
'amphorae': [sample_amphora_tuple()]}
UDP_SOURCE_IP_BODY = {
@ -590,7 +590,7 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
be_proto=None, monitor_ip_port=False,
monitor_proto=None, monitor_expected_codes=None,
backup_member=False, disabled_member=False,
connection_limit=-1,
connection_limit=constants.DEFAULT_CONNECTION_LIMIT,
timeout_client_data=50000,
timeout_member_connect=5000,
timeout_member_data=50000,
@ -1095,7 +1095,7 @@ def sample_base_expected_config(frontend=None, logging=None, backend=None,
" default_backend sample_pool_id_1:sample_listener_id_1"
"\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
if logging is None:
logging = (" log-format 12345\\ sample_loadbalancer_id_1\\ %f\\ "
"%ci\\ %cp\\ %t\\ %{+Q}r\\ %ST\\ %B\\ %U\\ "
@ -1117,13 +1117,13 @@ def sample_base_expected_config(frontend=None, logging=None, backend=None,
"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_MAX_MAXCONN)
"\n").format(maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
if peers is None:
peers = "\n\n"
if global_opts is None:
global_opts = " maxconn {maxconn}\n\n".format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_DEFAULT_MAXCONN)
if defaults is None:
defaults = ("defaults\n"
" log global\n"

View File

@ -0,0 +1,18 @@
---
features:
- |
Add a new configuration option to define the default connection_limit for
new listeners that use the Amphora provider. The option is
[haproxy_amphora].default_connection_limit and its default value is 50,000.
This value is used when creating or setting a listener with -1 as
connection_limit parameter, or when unsetting connection_limit parameter.
fixes:
- |
With haproxy 1.8.x releases, haproxy consumes much more memory in the
amphorae because of pre-allocated data structures. This amount of memory
depends on the maxconn parameters in its configuration file (which is
related to the connection_limit parameter in the Octavia API).
In the Amphora provider, the default connection_limit value -1 is
now converted to a maxconn of 50,000. It was previously 1,000,000 but that
value triggered some memory allocation issues when quickly performing
multiple configuration updates in a load balancer.