Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.

Commit 42672c5

Browse files
committed
add "EXTRA_ROUTE_SETTINGS" to allow modifying server clause in the backend section
1 parent eb26d47 commit 42672c5

11 files changed

Lines changed: 81 additions & 36 deletions

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ Settings in this part is immutable, you have to redeploy HAProxy service to make
176176
|EXTRA_DEFAULT_SETTINGS| |comma-separated string of extra settings, and each part will be appended to DEFAULT section in the configuration file. To escape comma, use `\,`|
177177
|EXTRA_FRONTEND_SETTINGS_\<PORT\>| |comma-separated string of extra settings, and each part will be appended frontend section with the port number specified in the name of the envvar. To escape comma, use `\,`. E.g. `EXTRA_FRONTEND_SETTINGS_80=balance source, maxconn 2000`|
178178
|EXTRA_GLOBAL_SETTINGS| |comma-separated string of extra settings, and each part will be appended to GLOBAL section in the configuration file. To escape comma, use `\,`. Possible value: `tune.ssl.cachesize 20000, tune.ssl.default-dh-param 2048`|
179+
|EXTRA_ROUTE_SETTINGS| |a string which is append to the each backend route after the health check, can be over written in the linked services. Possible value: "send-proxy"|
179180
|EXTRA_SSL_CERTS| |list of extra certificate names separated by comma, eg. `CERT1, CERT2, CERT3`. You also need to specify each certificate as separate env variables like so: `CERT1="<cert-body1>"`, `CERT2="<cert-body2>"`, `CERT3="<cert-body3>"`|
180181
|HEALTH_CHECK|check|set health check on each backend route, possible value: "check inter 2000 rise 2 fall 3". See:[HAProxy:check](https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#5.2-check)|
181182
|HTTP_BASIC_AUTH| |a comma-separated list of credentials(`<user>:<pass>`) for HTTP basic auth, which applies to all the backend routes. To escape comma, use `\,`. *Attention:* DO NOT rely on this for authentication in production|
@@ -203,6 +204,7 @@ Settings here can overwrite the settings in HAProxy, which are only applied to t
203204
|COOKIE|sticky session option. Possible value `SRV insert indirect nocache`. See:[HAProxy:cookie](http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4-cookie)|
204205
|DEFAULT_SSL_CERT|similar to SSL_CERT, but stores the pem file at `/certs/cert0.pem` as the default ssl certs. If multiple `DEFAULT_SSL_CERT` are specified in linked services and HAProxy, the behavior is undefined|
205206
|EXCLUDE_PORTS|comma separated port numbers(e.g. 3306, 3307). By default, HAProxy will add all the ports exposed by the application services to the backend routes. You can exclude the ports that you don't want to be routed, like database port|
207+
|EXTRA_ROUTE_SETTINGS| |a string which is append to the each backend route after the health check,possible value: "send-proxy"|
206208
|EXTRA_SETTINGS|comma-separated string of extra settings, and each part will be appended to either related backend section or listen session in the configuration file. To escape comma, use `\,`. Possible value: `balance source`|
207209
|FORCE_SSL|if set(any value) together with ssl termination enabled. HAProxy will redirect HTTP request to HTTPS request.
208210
|GZIP_COMPRESSION_TYPE|enable gzip compression. The value of this envvar is a list of MIME types that will be compressed, possible value: `text/html text/plain text/css`|

haproxy/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def parse_extra_frontend_settings(envvars):
4343
EXTRA_FRONTEND_SETTINGS = parse_extra_frontend_settings(os.environ)
4444
EXTRA_GLOBAL_SETTINGS = os.getenv("EXTRA_GLOBAL_SETTINGS")
4545
EXTRA_SSL_CERT = os.getenv("EXTRA_SSL_CERTS")
46+
EXTRA_ROUTE_SETTINGS=os.getenv("EXTRA_ROUTE_SETTINGS", "")
4647
HAPROXY_CONTAINER_URI = os.getenv("DOCKERCLOUD_CONTAINER_API_URI")
4748
HAPROXY_SERVICE_URI = os.getenv("DOCKERCLOUD_SERVICE_API_URI")
4849
HEALTH_CHECK = os.getenv("HEALTH_CHECK", "check inter 2000 rise 2 fall 3")

haproxy/helper/backend_helper.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import re
22

3-
from haproxy.config import HEALTH_CHECK, HTTP_BASIC_AUTH
3+
from haproxy.config import HEALTH_CHECK, HTTP_BASIC_AUTH, EXTRA_ROUTE_SETTINGS
44
from haproxy.utils import get_service_attribute
55

66

@@ -14,12 +14,14 @@ def get_backend_section(details, routes, vhosts, service_alias, routes_added):
1414
backend.extend(backend_settings)
1515

1616
route_health_check = get_route_health_check(details, service_alias, HEALTH_CHECK)
17-
backend_routes = get_backend_routes(route_health_check, is_sticky, routes, routes_added, service_alias)
17+
extra_route_settings = get_extra_route_settings(details, service_alias, EXTRA_ROUTE_SETTINGS)
18+
route_setting = " ".join([route_health_check, extra_route_settings]).strip()
19+
backend_routes = get_backend_routes(route_setting, is_sticky, routes, routes_added, service_alias)
1820
backend.extend(backend_routes)
1921
return backend
2022

2123

22-
def get_backend_routes(route_health_check, is_sticky, routes, routes_added, service_alias):
24+
def get_backend_routes(route_setting, is_sticky, routes, routes_added, service_alias):
2325
backend_routes = []
2426
for _service_alias, routes in routes.iteritems():
2527
if not service_alias or _service_alias == service_alias:
@@ -35,8 +37,8 @@ def get_backend_routes(route_health_check, is_sticky, routes, routes_added, serv
3537
if is_sticky:
3638
backend_route.append("cookie %s" % route["container_name"])
3739

38-
if route_health_check:
39-
backend_route.append(route_health_check)
40+
if route_setting:
41+
backend_route.append(route_setting)
4042

4143
backend_routes.append(" ".join(backend_route))
4244

@@ -49,6 +51,12 @@ def get_route_health_check(details, service_alias, default_health_check):
4951
return health_check
5052

5153

54+
def get_extra_route_settings(details, service_alias, default_extra_route_settings):
55+
extra_route_settings = get_service_attribute(details, "extra_route_settings", service_alias)
56+
extra_route_settings = extra_route_settings if extra_route_settings else default_extra_route_settings
57+
return extra_route_settings
58+
59+
5260
def get_websocket_setting(vhosts, service_alias):
5361
websocket_setting = []
5462
for v in vhosts:
@@ -159,4 +167,4 @@ def get_basic_auth_setting(basic_auth):
159167
if basic_auth:
160168
setting.append("acl need_auth http_auth(haproxy_userlist)")
161169
setting.append("http-request auth realm haproxy_basic_auth if !need_auth")
162-
return setting
170+
return setting

haproxy/helper/frontend_helper.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from collections import OrderedDict
22

3-
from haproxy.config import EXTRA_BIND_SETTINGS, EXTRA_FRONTEND_SETTINGS, MONITOR_URI, MONITOR_PORT, MAXCONN, SKIP_FORWARDED_PROTO
3+
from haproxy.config import EXTRA_BIND_SETTINGS, EXTRA_FRONTEND_SETTINGS, MONITOR_URI, MONITOR_PORT, MAXCONN, \
4+
SKIP_FORWARDED_PROTO
45

56

67
def check_require_default_route(routes, routes_added):

haproxy/helper/tcp_helper.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import re
22

3-
from haproxy.config import HEALTH_CHECK
3+
from haproxy.config import HEALTH_CHECK, EXTRA_ROUTE_SETTINGS
44
from haproxy.utils import get_service_attribute
55

66

@@ -41,7 +41,9 @@ def get_tcp_routes(details, routes, port, port_num):
4141
addresses_added.append(address)
4242
tcp_route = ["server %s %s" % (route["container_name"], address)]
4343
health_check = get_healthcheck_string(details, _service_alias)
44-
tcp_route.append(health_check)
44+
extra_route_settings = get_extra_route_settings_string(details, _service_alias)
45+
route_setting = " ".join([health_check, extra_route_settings]).strip()
46+
tcp_route.append(route_setting)
4547
tcp_routes.append(" ".join(tcp_route))
4648
routes_added.append(route)
4749

@@ -54,6 +56,12 @@ def get_healthcheck_string(details, service_alias):
5456
return health_check
5557

5658

59+
def get_extra_route_settings_string(details, service_alias):
60+
extra_route_settings = get_service_attribute(details, "extra_route_settings", service_alias)
61+
extra_route_settings = extra_route_settings if extra_route_settings else EXTRA_ROUTE_SETTINGS
62+
return extra_route_settings
63+
64+
5765
def get_service_aliases_given_tcp_port(details, service_aliases, tcp_port):
5866
services = []
5967
for service_alias in service_aliases:

haproxy/parser/base_parser.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,7 @@ def parse_option(value):
184184
@staticmethod
185185
def parse_extra_settings(value):
186186
return value
187+
188+
@staticmethod
189+
def parse_extra_route_settings(value):
190+
return value

tests/unit/helper/test_backend_helper.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,45 +10,45 @@ def test_get_backend_routes(self):
1010
'WEB': [{'container_name': 'WEB_2', 'proto': 'tcp', 'port': '8080', 'addr': '10.7.0.4'},
1111
{'container_name': 'WEB_1', 'proto': 'tcp', 'port': '8080', 'addr': '10.7.0.5'}]}
1212
self.assertEqual(["server HW_1 10.7.0.3:80 check", "server HW_2 10.7.0.2:80 check"],
13-
get_backend_routes(route_health_check="check", is_sticky=False,
13+
get_backend_routes(route_setting="check", is_sticky=False,
1414
routes=routes, routes_added=[], service_alias="HW"))
1515
self.assertEqual(["server WEB_1 10.7.0.5:8080", "server WEB_2 10.7.0.4:8080"],
16-
get_backend_routes(route_health_check="", is_sticky=False,
16+
get_backend_routes(route_setting="", is_sticky=False,
1717
routes=routes, routes_added=[], service_alias="WEB"))
1818
self.assertEqual(["server WEB_1 10.7.0.5:8080 cookie WEB_1", "server WEB_2 10.7.0.4:8080 cookie WEB_2"],
19-
get_backend_routes(route_health_check="", is_sticky=True,
19+
get_backend_routes(route_setting="", is_sticky=True,
2020
routes=routes, routes_added=[], service_alias="WEB"))
2121
self.assertEqual([],
22-
get_backend_routes(route_health_check="", is_sticky=False,
22+
get_backend_routes(route_setting="", is_sticky=False,
2323
routes={}, routes_added=[], service_alias="WEB"))
2424
self.assertEqual(["server WEB_2 10.7.0.4:8080"],
25-
get_backend_routes(route_health_check="", is_sticky=False,
25+
get_backend_routes(route_setting="", is_sticky=False,
2626
routes=routes, routes_added=[
2727
{'container_name': 'WEB_1', 'proto': 'tcp', 'port': '8080', 'addr': '10.7.0.5'}],
2828
service_alias="WEB"))
2929
self.assertEqual(["server WEB_2 10.7.0.4:8080 cookie WEB_2"],
30-
get_backend_routes(route_health_check="", is_sticky=True,
30+
get_backend_routes(route_setting="", is_sticky=True,
3131
routes=routes, routes_added=[
3232
{'container_name': 'WEB_1', 'proto': 'tcp', 'port': '8080', 'addr': '10.7.0.5'}],
3333
service_alias="WEB"))
3434
self.assertEqual(["server WEB_1 10.7.0.5:8080", "server WEB_2 10.7.0.4:8080"],
35-
get_backend_routes(route_health_check="", is_sticky=False,
35+
get_backend_routes(route_setting="", is_sticky=False,
3636
routes=routes, routes_added=[
3737
{'container_name': 'WEB_3', 'proto': 'tcp', 'port': '8080', 'addr': '10.7.0.5'}],
3838
service_alias="WEB"))
3939
self.assertEqual([],
40-
get_backend_routes(route_health_check="", is_sticky=False,
40+
get_backend_routes(route_setting="", is_sticky=False,
4141
routes=routes, routes_added=[
4242
{'container_name': 'WEB_2', 'proto': 'tcp', 'port': '8080', 'addr': '10.7.0.4'},
4343
{'container_name': 'WEB_1', 'proto': 'tcp', 'port': '8080', 'addr': '10.7.0.5'}],
4444
service_alias="WEB"))
4545
self.assertEqual(["server HW_1 10.7.0.3:80 check", "server HW_2 10.7.0.2:80 check"],
46-
get_backend_routes(route_health_check="check", is_sticky=False,
46+
get_backend_routes(route_setting="check", is_sticky=False,
4747
routes=routes, routes_added=[
4848
{'container_name': 'WEB_3', 'proto': 'tcp', 'port': '8080', 'addr': '10.7.0.5'}],
4949
service_alias="HW"))
5050
self.assertEqual([],
51-
get_backend_routes(route_health_check="", is_sticky=False,
51+
get_backend_routes(route_setting="", is_sticky=False,
5252
routes=routes, routes_added=[], service_alias="HELLO"))
5353

5454
def test_get_route_health(self):
@@ -59,9 +59,20 @@ def test_get_route_health(self):
5959

6060
self.assertEqual("health_check_web_a", get_route_health_check(details, 'web-a', default_health_check))
6161
self.assertEqual(default_health_check, get_route_health_check(details, 'web-b', default_health_check))
62-
self.assertEqual(default_health_check, get_route_health_check(details, 'web-b', default_health_check))
62+
self.assertEqual(default_health_check, get_route_health_check(details, 'web-c', default_health_check))
6363
self.assertEqual(default_health_check, get_route_health_check(details, 'web-d', default_health_check))
6464

65+
def test_get_extra_route_settings(self):
66+
details = {'web-a': {'extra_route_settings': 'extra_route_settings_web_a'},
67+
'web-b': {'extra_route_settings': ''},
68+
'web-c': {}}
69+
default_route_settings = 'default_routsettings'
70+
71+
self.assertEqual("extra_route_settings_web_a", get_extra_route_settings(details, 'web-a', default_route_settings))
72+
self.assertEqual(default_route_settings, get_extra_route_settings(details, 'web-b', default_route_settings))
73+
self.assertEqual(default_route_settings, get_extra_route_settings(details, 'web-c', default_route_settings))
74+
self.assertEqual(default_route_settings, get_extra_route_settings(details, 'web-d', default_route_settings))
75+
6576
def test_get_websocket_setting(self):
6677
vhosts = [{'service_alias': 'web-a', 'path': '', 'host': 'a.com', 'scheme': 'http', 'port': '8080'},
6778
{'service_alias': 'web-a', 'path': '', 'host': 'ws.a.com', 'scheme': 'ws', 'port': '8080'},

tests/unit/helper/test_tcp_helper.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,16 @@ def test_get_healthcheck_string(self):
9292
'WEB': {'tcp_ports': ['22'], 'health_check': 'checked'}}
9393
self.assertEqual(HEALTH_CHECK, get_healthcheck_string(details, "HW"))
9494
self.assertEqual("checked", get_healthcheck_string(details, "WEB"))
95-
self.assertEqual(HEALTH_CHECK, get_healthcheck_string(details, "NOT_EXIT"))
96-
self.assertEqual(HEALTH_CHECK, get_healthcheck_string({}, "NOT_EXIT"))
95+
self.assertEqual(HEALTH_CHECK, get_healthcheck_string(details, "NOT_EXIST"))
96+
self.assertEqual(HEALTH_CHECK, get_healthcheck_string({}, "NOT_EXIST"))
97+
98+
def test_get_extra_route_settings_string(self):
99+
details = {'HW': {'tcp_ports': ['22']},
100+
'WEB': {'tcp_ports': ['22'], 'extra_route_settings': 'extra settings'}}
101+
self.assertEqual(EXTRA_ROUTE_SETTINGS, get_extra_route_settings_string(details, "HW"))
102+
self.assertEqual("extra settings", get_extra_route_settings_string(details, "WEB"))
103+
self.assertEqual(EXTRA_ROUTE_SETTINGS, get_extra_route_settings_string(details, "NOT_EXIST"))
104+
self.assertEqual(EXTRA_ROUTE_SETTINGS, get_extra_route_settings_string({}, "NOT_EXIST"))
97105

98106
def test_get_service_aliases_given_tcp_port(self):
99107
details = {'HW': {'tcp_ports': ['22', '33']},

0 commit comments

Comments
 (0)