From 294e0fc1288feabea7f412015e40b3609dfdb313 Mon Sep 17 00:00:00 2001 From: Michael Johnson Date: Fri, 6 Jul 2018 10:29:52 -0700 Subject: [PATCH] Fixes unlimited listener connection limit When using the Octavia/amphora driver, unspecified or unlimited (-1) settings would lead to a 2000 connection limit in HAproxy. This patch updates that to be 1,000,000 connections. 1,000,000 was selected to amphora memory usage at a reasonable level. Change-Id: Iddeb62412bb71b69cf1e9198be6131c59a3051b0 Story: 1635416 Task: 5159 --- .../post-install.d/20-haproxy-tune-kernel | 7 +- .../api_server/templates/systemd.conf.j2 | 1 + octavia/common/constants.py | 5 + octavia/common/jinja/haproxy/jinja_cfg.py | 5 + .../api_server/test_haproxy_compatibility.py | 20 +- .../common/jinja/haproxy/test_jinja_cfg.py | 218 +++++++++++++----- .../common/sample_configs/sample_configs.py | 29 +-- ...ted-connection-limit-48079688de033c1a.yaml | 7 + 8 files changed, 205 insertions(+), 87 deletions(-) create mode 100644 releasenotes/notes/fix-unlimited-connection-limit-48079688de033c1a.yaml diff --git a/elements/haproxy-octavia/post-install.d/20-haproxy-tune-kernel b/elements/haproxy-octavia/post-install.d/20-haproxy-tune-kernel index b531fa3412..6474266080 100755 --- a/elements/haproxy-octavia/post-install.d/20-haproxy-tune-kernel +++ b/elements/haproxy-octavia/post-install.d/20-haproxy-tune-kernel @@ -12,11 +12,12 @@ sysctl-write-value net.ipv4.tcp_tw_reuse 1 sysctl-write-value net.core.somaxconn 65534 sysctl-write-value net.ipv4.tcp_synack_retries 3 sysctl-write-value net.core.netdev_max_backlog 100000 -sysctl-write-value fs.file-max 1048576 +# This should allow HAProxy maxconn to be 1,000,000 +sysctl-write-value fs.file-max 2097152 +sysctl-write-value fs.nr_open 2097152 # It's ok for these to fail if conntrack module isn't loaded -sysctl-write-value net.netfilter.nf_conntrack_max 131072 || true -sysctl-write-value net.ipv4.netfilter.ip_conntrack_max 1524288 || true +sysctl-write-value net.netfilter.nf_conntrack_buckets 125000 || true sysctl-write-value net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait 5 || true sysctl-write-value net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait 5 || true diff --git a/octavia/amphorae/backends/agent/api_server/templates/systemd.conf.j2 b/octavia/amphorae/backends/agent/api_server/templates/systemd.conf.j2 index 7088176836..9a835cdc41 100644 --- a/octavia/amphorae/backends/agent/api_server/templates/systemd.conf.j2 +++ b/octavia/amphorae/backends/agent/api_server/templates/systemd.conf.j2 @@ -30,6 +30,7 @@ Type=notify KillMode=mixed Restart=always +LimitNOFILE=2097152 [Install] WantedBy=multi-user.target diff --git a/octavia/common/constants.py b/octavia/common/constants.py index 8d0d78c602..7983a13904 100644 --- a/octavia/common/constants.py +++ b/octavia/common/constants.py @@ -401,6 +401,11 @@ NO_CHECK = 'no check' # NO_CHECK = no health monitor is enabled HAPROXY_MEMBER_STATUSES = (UP, DOWN, DRAIN, MAINT, NO_CHECK) +# 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 +HAPROXY_MAX_MAXCONN = 1000000 + # Quota Constants QUOTA_UNLIMITED = -1 MIN_QUOTA = QUOTA_UNLIMITED diff --git a/octavia/common/jinja/haproxy/jinja_cfg.py b/octavia/common/jinja/haproxy/jinja_cfg.py index 5c2437585e..5d734c7835 100644 --- a/octavia/common/jinja/haproxy/jinja_cfg.py +++ b/octavia/common/jinja/haproxy/jinja_cfg.py @@ -158,6 +158,9 @@ class JinjaTemplater(object): # the global value trivial. if listener.connection_limit and listener.connection_limit > -1: ret_value['global_connection_limit'] = listener.connection_limit + else: + ret_value['global_connection_limit'] = ( + constants.HAPROXY_MAX_MAXCONN) return ret_value def _transform_amphora(self, amphora): @@ -205,6 +208,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 if listener.tls_certificate_id: ret_value['default_tls_path'] = '%s.pem' % ( os.path.join(self.base_crt_dir, diff --git a/octavia/tests/unit/amphorae/backends/agent/api_server/test_haproxy_compatibility.py b/octavia/tests/unit/amphorae/backends/agent/api_server/test_haproxy_compatibility.py index 8546d13519..77415ce17a 100644 --- a/octavia/tests/unit/amphorae/backends/agent/api_server/test_haproxy_compatibility.py +++ b/octavia/tests/unit/amphorae/backends/agent/api_server/test_haproxy_compatibility.py @@ -15,6 +15,7 @@ import mock from octavia.amphorae.backends.agent.api_server import haproxy_compatibility +from octavia.common import constants import octavia.tests.unit.base as base from octavia.tests.unit.common.sample_configs import sample_configs @@ -32,18 +33,19 @@ class HAProxyCompatTestCase(base.TestCase): " log /dev/log local1 notice\n" " stats socket /var/lib/octavia/sample_listener_id_1.sock" " mode 0666 level user\n" - " maxconn 98\n\n" + " maxconn {maxconn}\n\n" "defaults\n" " log global\n" " retries 3\n" " option redispatch\n\n\n\n" "frontend sample_listener_id_1\n" " option httplog\n" - " maxconn 98\n" + " maxconn {maxconn}\n" " bind 10.0.0.2:80\n" " mode http\n" " default_backend sample_pool_id_1\n" - " timeout client 50000\n\n") + " timeout client 50000\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) self.backend_without_external = ( "backend sample_pool_id_1\n" " mode http\n" @@ -52,14 +54,16 @@ class HAProxyCompatTestCase(base.TestCase): " timeout check 31\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\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") + "check inter 30s fall 3 rise 2 cookie " + "sample_member_id_2\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) self.backend_with_external = ( "backend sample_pool_id_1\n" " mode http\n" @@ -70,14 +74,16 @@ class HAProxyCompatTestCase(base.TestCase): " http-check expect rstatus 418\n" " option external-check\n" " external-check command /var/lib/octavia/ping-wrapper.sh\n" - " fullconn 98\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") + "check inter 30s fall 3 rise 2 cookie " + "sample_member_id_2\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) @mock.patch('subprocess.check_output') def test_get_haproxy_versions(self, mock_process): diff --git a/octavia/tests/unit/common/jinja/haproxy/test_jinja_cfg.py b/octavia/tests/unit/common/jinja/haproxy/test_jinja_cfg.py index e2d2aa6752..afcded7d7d 100644 --- a/octavia/tests/unit/common/jinja/haproxy/test_jinja_cfg.py +++ b/octavia/tests/unit/common/jinja/haproxy/test_jinja_cfg.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +from octavia.common import constants from octavia.common.jinja.haproxy import jinja_cfg from octavia.tests.unit import base from octavia.tests.unit.common.sample_configs import sample_configs @@ -32,15 +33,16 @@ class TestHaproxyCfg(base.TestCase): def test_render_template_tls(self): fe = ("frontend sample_listener_id_1\n" " option httplog\n" - " maxconn 98\n" - " redirect scheme https if !{ ssl_fc }\n" + " maxconn {maxconn}\n" + " redirect scheme https if !{{ ssl_fc }}\n" " bind 10.0.0.2:443 " "ssl crt /var/lib/octavia/certs/" "sample_listener_id_1/tls_container_id.pem " "crt /var/lib/octavia/certs/sample_listener_id_1\n" " mode http\n" " default_backend sample_pool_id_1\n" - " timeout client 50000\n\n") + " timeout client 50000\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) be = ("backend sample_pool_id_1\n" " mode http\n" " balance roundrobin\n" @@ -48,7 +50,7 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -57,7 +59,8 @@ class TestHaproxyCfg(base.TestCase): "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") + "sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) tls_tupe = sample_configs.sample_tls_container_tuple( id='tls_container_id', certificate='imaCert1', private_key='imaPrivateKey1', @@ -75,14 +78,15 @@ class TestHaproxyCfg(base.TestCase): def test_render_template_tls_no_sni(self): fe = ("frontend sample_listener_id_1\n" " option httplog\n" - " maxconn 98\n" - " redirect scheme https if !{ ssl_fc }\n" + " maxconn {maxconn}\n" + " redirect scheme https if !{{ ssl_fc }}\n" " bind 10.0.0.2:443 " "ssl crt /var/lib/octavia/certs/" "sample_listener_id_1/tls_container_id.pem\n" " mode http\n" " default_backend sample_pool_id_1\n" - " timeout client 50000\n\n") + " timeout client 50000\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) be = ("backend sample_pool_id_1\n" " mode http\n" " balance roundrobin\n" @@ -90,7 +94,7 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -99,7 +103,8 @@ class TestHaproxyCfg(base.TestCase): "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") + "cookie sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple( @@ -122,7 +127,7 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -131,7 +136,8 @@ class TestHaproxyCfg(base.TestCase): "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") + "cookie sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple()) @@ -147,7 +153,7 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -158,7 +164,8 @@ class TestHaproxyCfg(base.TestCase): " server sample_member_id_2 10.0.0.98:82 " "weight 13 check inter 30s fall 3 rise 2 " "addr 192.168.1.1 port 9000 " - "cookie sample_member_id_2 backup\n\n") + "cookie sample_member_id_2 backup\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(monitor_ip_port=True, @@ -170,11 +177,12 @@ class TestHaproxyCfg(base.TestCase): def test_render_template_custom_timeouts(self): fe = ("frontend sample_listener_id_1\n" " option httplog\n" - " maxconn 98\n" + " maxconn {maxconn}\n" " bind 10.0.0.2:80\n" " mode http\n" " default_backend sample_pool_id_1\n" - " timeout client 2\n\n") + " timeout client 2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) be = ("backend sample_pool_id_1\n" " mode http\n" " balance roundrobin\n" @@ -182,14 +190,16 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 1\n" " timeout server 3\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") + "check inter 30s fall 3 rise 2 cookie " + "sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(timeout_member_connect=1, @@ -203,11 +213,12 @@ class TestHaproxyCfg(base.TestCase): def test_render_template_null_timeouts(self): fe = ("frontend sample_listener_id_1\n" " option httplog\n" - " maxconn 98\n" + " maxconn {maxconn}\n" " bind 10.0.0.2:80\n" " mode http\n" " default_backend sample_pool_id_1\n" - " timeout client 50000\n\n") + " timeout client 50000\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) be = ("backend sample_pool_id_1\n" " mode http\n" " balance roundrobin\n" @@ -215,14 +226,16 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\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") + "check inter 30s fall 3 rise 2 cookie " + "sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(timeout_member_connect=None, @@ -241,7 +254,7 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -252,7 +265,8 @@ class TestHaproxyCfg(base.TestCase): " server sample_member_id_2 10.0.0.98:82 " "weight 13 check inter 30s fall 3 rise 2 " "addr 192.168.1.1 port 9000 " - "cookie sample_member_id_2\n\n") + "cookie sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(monitor_ip_port=True)) @@ -263,11 +277,12 @@ class TestHaproxyCfg(base.TestCase): def test_render_template_https_real_monitor(self): fe = ("frontend sample_listener_id_1\n" " option tcplog\n" - " maxconn 98\n" + " maxconn {maxconn}\n" " bind 10.0.0.2:443\n" " mode tcp\n" " default_backend sample_pool_id_1\n" - " timeout client 50000\n\n") + " timeout client 50000\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) be = ("backend sample_pool_id_1\n" " mode tcp\n" " balance roundrobin\n" @@ -275,7 +290,7 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -284,7 +299,8 @@ class TestHaproxyCfg(base.TestCase): "cookie sample_member_id_1\n" " 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") + "cookie sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(proto='HTTPS')) @@ -294,18 +310,19 @@ class TestHaproxyCfg(base.TestCase): def test_render_template_https_hello_monitor(self): fe = ("frontend sample_listener_id_1\n" " option tcplog\n" - " maxconn 98\n" + " maxconn {maxconn}\n" " bind 10.0.0.2:443\n" " mode tcp\n" " default_backend sample_pool_id_1\n" - " timeout client 50000\n\n") + " timeout client 50000\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) be = ("backend sample_pool_id_1\n" " mode tcp\n" " balance roundrobin\n" " cookie SRV insert indirect nocache\n" " timeout check 31s\n" " option ssl-hello-chk\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -314,7 +331,8 @@ class TestHaproxyCfg(base.TestCase): "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") + "cookie sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple( @@ -327,14 +345,15 @@ class TestHaproxyCfg(base.TestCase): " mode http\n" " balance roundrobin\n" " cookie SRV insert indirect nocache\n" - " fullconn 98\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 " "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") + "cookie sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(proto='HTTP', monitor=False)) @@ -346,14 +365,15 @@ class TestHaproxyCfg(base.TestCase): " mode http\n" " balance roundrobin\n" " cookie SRV insert indirect nocache\n" - " fullconn 98\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 " "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") + "cookie sample_member_id_2 disabled\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(proto='HTTP', monitor=False, @@ -369,7 +389,7 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option external-check\n" " external-check command /var/lib/octavia/ping-wrapper.sh\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -378,8 +398,10 @@ class TestHaproxyCfg(base.TestCase): "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") - go = " maxconn 98\n external-check\n\n" + "cookie sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) + go = " maxconn {maxconn}\n external-check\n\n".format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(proto='HTTP', @@ -390,23 +412,25 @@ class TestHaproxyCfg(base.TestCase): def test_render_template_no_monitor_https(self): fe = ("frontend sample_listener_id_1\n" " option tcplog\n" - " maxconn 98\n" + " maxconn {maxconn}\n" " bind 10.0.0.2:443\n" " mode tcp\n" " default_backend sample_pool_id_1\n" - " timeout client 50000\n\n") + " timeout client 50000\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) be = ("backend sample_pool_id_1\n" " mode tcp\n" " balance roundrobin\n" " cookie SRV insert indirect nocache\n" - " fullconn 98\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 " "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") + "cookie sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(proto='HTTPS', monitor=False)) @@ -416,20 +440,22 @@ class TestHaproxyCfg(base.TestCase): def test_render_template_no_persistence_https(self): fe = ("frontend sample_listener_id_1\n" " option tcplog\n" - " maxconn 98\n" + " maxconn {maxconn}\n" " bind 10.0.0.2:443\n" " mode tcp\n" " default_backend sample_pool_id_1\n" - " timeout client 50000\n\n") + " timeout client 50000\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) be = ("backend sample_pool_id_1\n" " mode tcp\n" " balance roundrobin\n" - " fullconn 98\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\n" - " server sample_member_id_2 10.0.0.98:82 weight 13\n\n") + " server sample_member_id_2 10.0.0.98:82 " + "weight 13\n\n").format(maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(proto='HTTPS', monitor=False, @@ -441,12 +467,13 @@ class TestHaproxyCfg(base.TestCase): be = ("backend sample_pool_id_1\n" " mode http\n" " balance roundrobin\n" - " fullconn 98\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\n" - " server sample_member_id_2 10.0.0.98:82 weight 13\n\n") + " server sample_member_id_2 10.0.0.98:82 " + "weight 13\n\n").format(maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(proto='HTTP', monitor=False, @@ -463,14 +490,15 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\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\n" " server sample_member_id_2 10.0.0.98:82 " - "weight 13 check inter 30s fall 3 rise 2\n\n") + "weight 13 check inter 30s fall 3 rise 2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple( @@ -489,14 +517,15 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\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\n" " server sample_member_id_2 10.0.0.98:82 " - "weight 13 check inter 30s fall 3 rise 2\n\n") + "weight 13 check inter 30s fall 3 rise 2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple( @@ -506,10 +535,66 @@ class TestHaproxyCfg(base.TestCase): sample_configs.sample_base_expected_config(backend=be), rendered_obj) + def test_render_template_unlimited_connections(self): + fe = ("frontend sample_listener_id_1\n" + " option tcplog\n" + " maxconn {maxconn}\n" + " bind 10.0.0.2:443\n" + " mode tcp\n" + " default_backend sample_pool_id_1\n" + " timeout client 50000\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) + be = ("backend sample_pool_id_1\n" + " mode tcp\n" + " balance roundrobin\n" + " cookie SRV insert indirect nocache\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 " + "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) + rendered_obj = self.jinja_cfg.render_loadbalancer_obj( + sample_configs.sample_amphora_tuple(), + sample_configs.sample_listener_tuple(proto='HTTPS', monitor=False)) + self.assertEqual(sample_configs.sample_base_expected_config( + frontend=fe, backend=be), rendered_obj) + + def test_render_template_limited_connections(self): + fe = ("frontend sample_listener_id_1\n" + " option tcplog\n" + " maxconn 2014\n" + " bind 10.0.0.2:443\n" + " mode tcp\n" + " default_backend sample_pool_id_1\n" + " timeout client 50000\n\n") + be = ("backend sample_pool_id_1\n" + " mode tcp\n" + " balance roundrobin\n" + " cookie SRV insert indirect nocache\n" + " fullconn 2014\n" + " option allbackups\n" + " timeout connect 5000\n" + " timeout server 50000\n" + " server sample_member_id_1 10.0.0.99:82 weight 13 " + "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") + g_opts = " maxconn 2014\n\n" + rendered_obj = self.jinja_cfg.render_loadbalancer_obj( + sample_configs.sample_amphora_tuple(), + sample_configs.sample_listener_tuple(proto='HTTPS', monitor=False, + connection_limit=2014)) + self.assertEqual(sample_configs.sample_base_expected_config( + frontend=fe, backend=be, global_opts=g_opts), rendered_obj) + def test_render_template_l7policies(self): fe = ("frontend sample_listener_id_1\n" " option httplog\n" - " maxconn 98\n" + " maxconn {maxconn}\n" " bind 10.0.0.2:80\n" " mode http\n" " acl sample_l7rule_id_1 path -m beg /api\n" @@ -526,7 +611,8 @@ class TestHaproxyCfg(base.TestCase): " http-request deny if sample_l7rule_id_4 " "sample_l7rule_id_5\n" " default_backend sample_pool_id_1\n" - " timeout client 50000\n\n") + " timeout client 50000\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) be = ("backend sample_pool_id_1\n" " mode http\n" " balance roundrobin\n" @@ -534,7 +620,7 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -550,12 +636,13 @@ class TestHaproxyCfg(base.TestCase): " timeout check 31s\n" " option httpchk GET /healthmon.html\n" " http-check expect rstatus 418\n" - " fullconn 98\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_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple(l7=True)) @@ -571,7 +658,7 @@ class TestHaproxyCfg(base.TestCase): " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" " option forwardfor\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -580,7 +667,8 @@ class TestHaproxyCfg(base.TestCase): "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") + "cookie sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple( @@ -599,7 +687,7 @@ class TestHaproxyCfg(base.TestCase): " http-check expect rstatus 418\n" " option forwardfor\n" " http-request set-header X-Forwarded-Port %[dst_port]\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -608,7 +696,8 @@ class TestHaproxyCfg(base.TestCase): "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") + "cookie sample_member_id_2\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple( @@ -624,7 +713,7 @@ class TestHaproxyCfg(base.TestCase): " balance roundrobin\n" " cookie SRV insert indirect nocache\n" " timeout check 31s\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -633,7 +722,8 @@ class TestHaproxyCfg(base.TestCase): "cookie sample_member_id_1 send-proxy\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 send-proxy\n\n") + "cookie sample_member_id_2 send-proxy\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) rendered_obj = self.jinja_cfg.render_loadbalancer_obj( sample_configs.sample_amphora_tuple(), sample_configs.sample_listener_tuple( diff --git a/octavia/tests/unit/common/sample_configs/sample_configs.py b/octavia/tests/unit/common/sample_configs/sample_configs.py index 406ef0ca82..61a9cf0d0a 100644 --- a/octavia/tests/unit/common/sample_configs/sample_configs.py +++ b/octavia/tests/unit/common/sample_configs/sample_configs.py @@ -238,7 +238,7 @@ RET_LISTENER = { 'protocol': 'HTTP', 'protocol_mode': 'http', 'default_pool': RET_POOL_1, - 'connection_limit': 98, + 'connection_limit': constants.HAPROXY_MAX_MAXCONN, 'amphorae': [sample_amphora_tuple()], 'peer_port': 1024, 'topology': 'SINGLE', @@ -258,7 +258,7 @@ RET_LISTENER_L7 = { 'protocol': 'HTTP', 'protocol_mode': 'http', 'default_pool': RET_POOL_1, - 'connection_limit': 98, + 'connection_limit': constants.HAPROXY_MAX_MAXCONN, 'amphorae': [sample_amphora_tuple()], 'peer_port': 1024, 'topology': 'SINGLE', @@ -279,7 +279,7 @@ RET_LISTENER_TLS = { 'protocol': 'TERMINATED_HTTPS', 'protocol_mode': 'http', 'default_pool': RET_POOL_1, - 'connection_limit': 98, + 'connection_limit': constants.HAPROXY_MAX_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, @@ -294,7 +294,7 @@ RET_LISTENER_TLS_SNI = { 'protocol': 'http', 'protocol': 'TERMINATED_HTTPS', 'default_pool': RET_POOL_1, - 'connection_limit': 98, + 'connection_limit': constants.HAPROXY_MAX_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, @@ -325,7 +325,7 @@ RET_LB = { 'listener': RET_LISTENER, 'topology': 'SINGLE', 'enabled': True, - 'global_connection_limit': 98} + 'global_connection_limit': constants.HAPROXY_MAX_MAXCONN} RET_LB_L7 = { 'host_amphora': RET_AMPHORA, @@ -334,7 +334,7 @@ RET_LB_L7 = { 'listener': RET_LISTENER_L7, 'topology': 'SINGLE', 'enabled': True, - 'global_connection_limit': 98} + 'global_connection_limit': constants.HAPROXY_MAX_MAXCONN} def sample_loadbalancer_tuple(proto=None, monitor=True, persistence=True, @@ -406,7 +406,7 @@ def sample_listener_tuple(proto=None, monitor=True, persistence=True, l7=False, enabled=True, insert_headers=None, be_proto=None, monitor_ip_port=False, monitor_proto=None, backup_member=False, - disabled_member=False, + disabled_member=False, connection_limit=-1, timeout_client_data=50000, timeout_member_connect=5000, timeout_member_data=50000, @@ -467,7 +467,7 @@ def sample_listener_tuple(proto=None, monitor=True, persistence=True, persistence_type=persistence_type, persistence_cookie=persistence_cookie, monitor_ip_port=monitor_ip_port, monitor_proto=monitor_proto), - connection_limit=98, + connection_limit=connection_limit, tls_certificate_id='cont_id_1' if tls else '', sni_container_ids=['cont_id_2', 'cont_id_3'] if sni else [], default_tls_container=sample_tls_container_tuple( @@ -716,11 +716,12 @@ def sample_base_expected_config(frontend=None, backend=None, if frontend is None: frontend = ("frontend sample_listener_id_1\n" " option httplog\n" - " maxconn 98\n" + " maxconn {maxconn}\n" " bind 10.0.0.2:80\n" " mode http\n" " default_backend sample_pool_id_1\n" - " timeout client 50000\n\n") + " timeout client 50000\n\n").format( + maxconn=constants.HAPROXY_MAX_MAXCONN) if backend is None: backend = ("backend sample_pool_id_1\n" " mode http\n" @@ -729,7 +730,7 @@ def sample_base_expected_config(frontend=None, backend=None, " timeout check 31s\n" " option httpchk GET /index.html\n" " http-check expect rstatus 418\n" - " fullconn 98\n" + " fullconn {maxconn}\n" " option allbackups\n" " timeout connect 5000\n" " timeout server 50000\n" @@ -737,11 +738,13 @@ def sample_base_expected_config(frontend=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") + "\n").format(maxconn=constants.HAPROXY_MAX_MAXCONN) + if peers is None: peers = "\n\n" if global_opts is None: - global_opts = " maxconn 98\n\n" + global_opts = " maxconn {maxconn}\n\n".format( + maxconn=constants.HAPROXY_MAX_MAXCONN) if defaults is None: defaults = ("defaults\n" " log global\n" diff --git a/releasenotes/notes/fix-unlimited-connection-limit-48079688de033c1a.yaml b/releasenotes/notes/fix-unlimited-connection-limit-48079688de033c1a.yaml new file mode 100644 index 0000000000..23a01b930e --- /dev/null +++ b/releasenotes/notes/fix-unlimited-connection-limit-48079688de033c1a.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixes a bug where unspecified or unlimited listener connection limit + settings would lead to a 2000 connection limit when using the + amphora/octavia driver. This was the compiled in connection limit + in some HAproxy packages.