diff --git a/api-ref/source/parameters.yaml b/api-ref/source/parameters.yaml index b8887895d9..859d5df7d8 100644 --- a/api-ref/source/parameters.yaml +++ b/api-ref/source/parameters.yaml @@ -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 diff --git a/etc/octavia.conf b/etc/octavia.conf index f666446197..de797b0e7b 100644 --- a/etc/octavia.conf +++ b/etc/octavia.conf @@ -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 diff --git a/octavia/common/config.py b/octavia/common/config.py index c253128215..6b9bafc8b8 100644 --- a/octavia/common/config.py +++ b/octavia/common/config.py @@ -415,6 +415,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 = [ diff --git a/octavia/common/constants.py b/octavia/common/constants.py index 41e7429079..a2cc7330c0 100644 --- a/octavia/common/constants.py +++ b/octavia/common/constants.py @@ -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 diff --git a/octavia/common/jinja/haproxy/combined_listeners/jinja_cfg.py b/octavia/common/jinja/haproxy/combined_listeners/jinja_cfg.py index 46365f7d76..ec167179a0 100644 --- a/octavia/common/jinja/haproxy/combined_listeners/jinja_cfg.py +++ b/octavia/common/jinja/haproxy/combined_listeners/jinja_cfg.py @@ -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( diff --git a/octavia/tests/functional/api/v2/test_load_balancer.py b/octavia/tests/functional/api/v2/test_load_balancer.py index 61adbe2b2c..4912f0e414 100644 --- a/octavia/tests/functional/api/v2/test_load_balancer.py +++ b/octavia/tests/functional/api/v2/test_load_balancer.py @@ -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, 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 91d9592a1e..80c872e832 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 @@ -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): diff --git a/octavia/tests/unit/common/jinja/haproxy/combined_listeners/test_jinja_cfg.py b/octavia/tests/unit/common/jinja/haproxy/combined_listeners/test_jinja_cfg.py index c9cd52fc0f..e521645ff3 100644 --- a/octavia/tests/unit/common/jinja/haproxy/combined_listeners/test_jinja_cfg.py +++ b/octavia/tests/unit/common/jinja/haproxy/combined_listeners/test_jinja_cfg.py @@ -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) diff --git a/octavia/tests/unit/common/sample_configs/sample_configs_combined.py b/octavia/tests/unit/common/sample_configs/sample_configs_combined.py index 926056edf1..4359638636 100644 --- a/octavia/tests/unit/common/sample_configs/sample_configs_combined.py +++ b/octavia/tests/unit/common/sample_configs/sample_configs_combined.py @@ -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" diff --git a/releasenotes/notes/new-default_connection_limit-config-option-3ed9f0ed6ec2b514.yaml b/releasenotes/notes/new-default_connection_limit-config-option-3ed9f0ed6ec2b514.yaml new file mode 100644 index 0000000000..41837df966 --- /dev/null +++ b/releasenotes/notes/new-default_connection_limit-config-option-3ed9f0ed6ec2b514.yaml @@ -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.