diff options
| author | Viacheslav Hletenko <v.gletenko@vyos.io> | 2026-06-23 18:45:17 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-06-23 18:45:17 +0300 |
| commit | 105c2470df751f9bff280255506640e63204e3bb (patch) | |
| tree | 18e25c127bf66f6316e91cc8646718ff6f34a9a1 | |
| parent | 4e74f21299c77a35115a61908a2c84e390e1f0d1 (diff) | |
| parent | 4f550fc5184f7d583f5976e801e9cae4d06e0cb6 (diff) | |
| download | vyos-1x-105c2470df751f9bff280255506640e63204e3bb.tar.gz vyos-1x-105c2470df751f9bff280255506640e63204e3bb.zip | |
Merge pull request #5226 from indrajitr/haproxy-websocket
haproxy: T8931: Improve WebSocket support for HAProxy
| -rw-r--r-- | data/templates/load-balancing/haproxy.cfg.j2 | 7 | ||||
| -rw-r--r-- | interface-definitions/include/haproxy/timeout-tunnel.xml.i | 14 | ||||
| -rw-r--r-- | interface-definitions/include/haproxy/timeout.xml.i | 1 | ||||
| -rw-r--r-- | interface-definitions/load-balancing_haproxy.xml.in | 10 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_load-balancing_haproxy.py | 33 | ||||
| -rw-r--r-- | src/conf_mode/load-balancing_haproxy.py | 7 |
6 files changed, 71 insertions, 1 deletions
diff --git a/data/templates/load-balancing/haproxy.cfg.j2 b/data/templates/load-balancing/haproxy.cfg.j2 index 79fb5e369..438796cee 100644 --- a/data/templates/load-balancing/haproxy.cfg.j2 +++ b/data/templates/load-balancing/haproxy.cfg.j2 @@ -42,6 +42,7 @@ defaults timeout connect {{ timeout.connect }}s timeout client {{ timeout.client }}s timeout server {{ timeout.server }}s + timeout tunnel {{ timeout.tunnel }}s errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http @@ -205,6 +206,9 @@ backend {{ back }} option forwardfor http-request set-header X-Forwarded-Port %[dst_port] http-request add-header X-Forwarded-Proto https if { ssl_fc } +{% if back_config.http_server_close is vyos_defined %} + option http-server-close +{% endif %} {% endif %} {% if back_config.logging is vyos_defined %} {% for facility, facility_config in back_config.logging.facility.items() %} @@ -285,5 +289,8 @@ backend {{ back }} {% if back_config.timeout.server is vyos_defined %} timeout server {{ back_config.timeout.server }}s {% endif %} +{% if back_config.timeout.tunnel is vyos_defined %} + timeout tunnel {{ back_config.timeout.tunnel }}s +{% endif %} {% endfor %} {% endif %} diff --git a/interface-definitions/include/haproxy/timeout-tunnel.xml.i b/interface-definitions/include/haproxy/timeout-tunnel.xml.i new file mode 100644 index 000000000..ea6be1505 --- /dev/null +++ b/interface-definitions/include/haproxy/timeout-tunnel.xml.i @@ -0,0 +1,14 @@ +<!-- include start from haproxy/timeout-tunnel.xml.i --> +<leafNode name="tunnel"> + <properties> + <help>Set the maximum inactivity time on the client and server side for tunnels</help> + <valueHelp> + <format>u32:1-86400</format> + <description>Tunnel timeout in seconds</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-86400"/> + </constraint> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/haproxy/timeout.xml.i b/interface-definitions/include/haproxy/timeout.xml.i index a3a5a8a3e..a84e32001 100644 --- a/interface-definitions/include/haproxy/timeout.xml.i +++ b/interface-definitions/include/haproxy/timeout.xml.i @@ -7,6 +7,7 @@ #include <include/haproxy/timeout-check.xml.i> #include <include/haproxy/timeout-connect.xml.i> #include <include/haproxy/timeout-server.xml.i> + #include <include/haproxy/timeout-tunnel.xml.i> </children> </node> <!-- include end --> diff --git a/interface-definitions/load-balancing_haproxy.xml.in b/interface-definitions/load-balancing_haproxy.xml.in index f3baf86ca..8111d7506 100644 --- a/interface-definitions/load-balancing_haproxy.xml.in +++ b/interface-definitions/load-balancing_haproxy.xml.in @@ -225,6 +225,12 @@ </constraint> </properties> </leafNode> + <leafNode name="http-server-close"> + <properties> + <help>Enable HTTP/1.x connection closing on the server side</help> + <valueless/> + </properties> + </leafNode> #include <include/haproxy/rule-backend.xml.i> <tagNode name="server"> <properties> @@ -399,6 +405,10 @@ <leafNode name="server"> <defaultValue>50</defaultValue> </leafNode> + #include <include/haproxy/timeout-tunnel.xml.i> + <leafNode name="tunnel"> + <defaultValue>300</defaultValue> + </leafNode> </children> </node> #include <include/interface/vrf.xml.i> diff --git a/smoketest/scripts/cli/test_load-balancing_haproxy.py b/smoketest/scripts/cli/test_load-balancing_haproxy.py index 9cb031276..118d42773 100755 --- a/smoketest/scripts/cli/test_load-balancing_haproxy.py +++ b/smoketest/scripts/cli/test_load-balancing_haproxy.py @@ -335,6 +335,34 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase): with self.assertRaises(ConfigSessionError) as e: self.cli_commit() + def test_reverse_proxy_backend_websocket(self): + t_tunnel = '3600' + opt_server_close = 'http-server-close' + + # Setup base + self.configure_pki() + self.base_config() + + # Set minimal backend websocket configuration + self.cli_set(base_path + ['backend', haproxy_backend_name, opt_server_close]) + self.cli_set(base_path + ['backend', haproxy_backend_name, 'timeout', 'tunnel', t_tunnel]) + self.cli_set(base_path + ['backend', haproxy_backend_name, 'ssl', 'no-verify']) + + self.cli_commit() + + # Ensure 'http-server-close' is not used in tcp mode, to test config validation + self.cli_set(base_path + ['backend', haproxy_backend_name, 'mode', 'tcp']) + with self.assertRaises(ConfigSessionError) as e: + self.cli_commit() + + config = read_file(HAPROXY_CONF) + self.assertIn(f'option {opt_server_close}', config) + self.assertIn(f'timeout tunnel {t_tunnel}s', config) + self.assertIn('option forwardfor', config) + self.assertIn(' http-request set-header X-Forwarded-Port %[dst_port]', config) + self.assertIn('http-request add-header X-Forwarded-Proto https if { ssl_fc }', config) + self.assertIn(f'server {haproxy_backend_name} 192.0.2.11:9090 send-proxy ssl verify none', config) + def test_reverse_proxy_backend_http_check(self): # Setup base self.base_config() @@ -619,10 +647,12 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase): t_default_client = '50' t_default_connect = '10' t_default_server ='50' + t_default_tunnel ='300' t_check = '4' t_client = '300' t_connect = '12' t_server ='120' + t_tunnel ='600' t_front_client = '600' self.base_config() @@ -633,6 +663,7 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase): f'timeout connect {t_default_connect}s', f'timeout client {t_default_client}s', f'timeout server {t_default_server}s', + f'timeout tunnel {t_default_tunnel}s' ) # Check default timeout options config = read_file(HAPROXY_CONF) @@ -644,6 +675,7 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['timeout', 'client', t_client]) self.cli_set(base_path + ['timeout', 'connect', t_connect]) self.cli_set(base_path + ['timeout', 'server', t_server]) + self.cli_set(base_path + ['timeout', 'tunnel', t_tunnel]) self.cli_set(base_path + ['service', haproxy_service_name, 'timeout', 'client', t_front_client]) self.cli_commit() @@ -654,6 +686,7 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase): f'timeout connect {t_connect}s', f'timeout client {t_client}s', f'timeout server {t_server}s', + f'timeout tunnel {t_tunnel}s', f'timeout client {t_front_client}s', ) diff --git a/src/conf_mode/load-balancing_haproxy.py b/src/conf_mode/load-balancing_haproxy.py index 0f31880ba..f95d05151 100644 --- a/src/conf_mode/load-balancing_haproxy.py +++ b/src/conf_mode/load-balancing_haproxy.py @@ -149,7 +149,12 @@ def verify(lb): for group in ['service', 'backend']: for config_name, config in lb[group].items(): if 'http_response_headers' in config and config['mode'] != 'http': - raise ConfigError(f'{group} {config_name} must be set to http mode to use http_response_headers!') + raise ConfigError(f'{group} {config_name} must be set to http mode to use http-response headers!') + + # Check if http-server-close is configured in any backend where mode != http + for config_name, config in lb['backend'].items(): + if 'http_server_close' in config and config['mode'] != 'http': + raise ConfigError(f'backend {config_name} must be set to http mode to use http-server-close!') def generate(lb): |
