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

Commit 4b5aa2a

Browse files
markvrFeng Honglin
authored andcommitted
Add extra options as files (#184)
* Added config for: EXTRA_DEFAULT_SETTINGS_FILE EXTRA_GLOBAL_SETTINGS_FILE EXTRA_FRONTEND_SETTINGS_FILE_XXX ADDITIONAL_BACKEND_SETTINGS_FILE_XXX * correct typo in filename * update readme * correct error in backend
1 parent ef61092 commit 4b5aa2a

5 files changed

Lines changed: 67 additions & 8 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ nosetests.xml
4040
.pydevproject
4141
.idea
4242
.DS_Store
43+
.vagrant/

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ Settings in this part is immutable, you have to redeploy HAProxy service to make
199199
|Environment Variable|Default|Description|
200200
|:-----:|:-----:|:----------|
201201
|ADDITIONAL_BACKEND_\<NAME\>| |add an additional backend with the name set in <NAME>. Possible values include:`balance source, server 127.0.0.1:8080`|
202+
|ADDITIONAL_BACKEND_FILE_\<NAME\>| add an additional backend with the name set in <NAME> and value of the contents of specified file.
202203
|ADDITIONAL_SERVICES| |list of additional services to balance (es: `prj1:web,prj2:sql`). Discovery will be based on `com.docker.compose.[project|service]` container labels. This environment variable only works on compose v2, and the referenced services must be on a network resolvable and accessible to this containers.|
203204
|BALANCE|roundrobin|load balancing algorithm to use. Possible values include: `roundrobin`, `static-rr`, `source`, `leastconn`. See:[HAProxy:balance](https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4-balance)|
204205
|CA_CERT_FILE| |the path of a ca-cert file. This allows you to mount your ca-cert file directly from a volume instead of from envvar. If set, `CA_CERT` envvar will be ignored. Possible value: `/cacerts/cert0.pem`|
@@ -207,8 +208,11 @@ Settings in this part is immutable, you have to redeploy HAProxy service to make
207208
|DEFAULT_SSL_CERT| |Default ssl cert, a pem file content with private key followed by public certificate, '\n'(two chars) as the line separator. should be formatted as one line - see [SSL Termination](#ssl-termination)|
208209
|EXTRA_BIND_SETTINGS| |comma-separated string(`<port>:<setting>`) of extra settings, and each part will be appended to the related port bind section in the configuration file. To escape comma, use `\,`. Possible value: `443:accept-proxy, 80:name http`|
209210
|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 `\,`|
211+
|EXTRA_DEFAULT_SETTINGS_FILE|File whose contents will be included in the DEFAULT section of the configuration file.|
210212
|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`|
213+
|EXTRA_DEFAULT_SETTINGS_FILE_\<PORT\>|File whose contents will be appended to the frontend section with the port number specified in the filename.|
211214
|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`|
215+
|EXTRA_GLOBAL_SETTINGS_FILE|File whose contents will be included in the GLOBAL section of the configuration file.|
212216
|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"|
213217
|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>"`|
214218
|FORCE_DEFAULT_BACKEND| True | set the default_service as a default backend. This is useful when you have more than one backend and you don't want your default_service as a default backend

haproxy/config.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import os
22
import re
3+
import logging
34

5+
logger = logging.getLogger("haproxy")
46

57
class RunningMode():
68
LegacyMode, ComposeMode, SwarmMode, CloudMode = range(4)
@@ -21,11 +23,24 @@ def parse_extra_frontend_settings(envvars):
2123
settings_dict = {}
2224
if isinstance(envvars, os._Environ) or isinstance(envvars, dict):
2325
frontend_settings_pattern = re.compile(r"^EXTRA_FRONTEND_SETTINGS_(\d{1,5})$")
26+
frontend_settings_file_pattern = re.compile(r"^EXTRA_FRONTEND_SETTINGS_FILE_(\d{1,5})$")
2427
for k, v in envvars.iteritems():
28+
settings = []
2529
match = frontend_settings_pattern.match(k)
30+
file_match = frontend_settings_file_pattern.match(k)
2631
if match:
2732
port = match.group(1)
28-
settings = [x.strip().replace("\,", ",") for x in re.split(r'(?<!\\),', v.strip())]
33+
settings.extend([x.strip().replace("\,", ",") for x in re.split(r'(?<!\\),', v.strip())])
34+
elif file_match:
35+
port = file_match.group(1)
36+
try:
37+
with open(v) as file:
38+
for line in file:
39+
settings.append(line.strip())
40+
except Exception as e:
41+
logger.info("Error reading %s at '%s', error %s" % (k, v, e))
42+
43+
if len(settings) > 0:
2944
if port in settings_dict:
3045
settings_dict[port].extend(settings)
3146
else:
@@ -36,12 +51,25 @@ def parse_extra_frontend_settings(envvars):
3651
def parse_additional_backend_settings(envvars):
3752
settings_dict = {}
3853
if isinstance(envvars, os._Environ) or isinstance(envvars, dict):
39-
frontend_settings_pattern = re.compile(r"^ADDITIONAL_BACKEND_(\w{1,9})$")
54+
additional_backend_pattern = re.compile(r"^ADDITIONAL_BACKEND_(\w{1,9})$")
55+
additional_backend_file_pattern = re.compile(r"^ADDITIONAL_BACKEND_FILE_(\w{1,9})$")
4056
for k, v in envvars.iteritems():
41-
match = frontend_settings_pattern.match(k)
57+
settings = []
58+
match = additional_backend_pattern.match(k)
59+
file_match = additional_backend_file_pattern.match(k)
4260
if match:
4361
server = match.group(1)
44-
settings = [x.strip().replace("\,", ",") for x in re.split(r'(?<!\\),', v.strip())]
62+
settings.extend([x.strip().replace("\,", ",") for x in re.split(r'(?<!\\),', v.strip())])
63+
elif file_match:
64+
server = file_match.group(1)
65+
try:
66+
with open(v) as file:
67+
for line in file:
68+
settings.append(line.strip())
69+
except Exception as e:
70+
logger.info("Error reading %s at '%s', error %s" % (k, v, e))
71+
72+
if len(settings) > 0:
4573
if server in settings_dict:
4674
settings_dict[server].extend(settings)
4775
else:
@@ -61,8 +89,10 @@ def parse_additional_backend_settings(envvars):
6189
DEFAULT_SSL_CERT = os.getenv("DEFAULT_SSL_CERT") or os.getenv("SSL_CERT")
6290
EXTRA_BIND_SETTINGS = parse_extra_bind_settings(os.getenv("EXTRA_BIND_SETTINGS"))
6391
EXTRA_DEFAULT_SETTINGS = os.getenv("EXTRA_DEFAULT_SETTINGS")
92+
EXTRA_DEFAULT_SETTINGS_FILE = os.getenv("EXTRA_DEFAULT_SETTINGS_FILE")
6493
EXTRA_FRONTEND_SETTINGS = parse_extra_frontend_settings(os.environ)
6594
EXTRA_GLOBAL_SETTINGS = os.getenv("EXTRA_GLOBAL_SETTINGS")
95+
EXTRA_GLOBAL_SETTINGS_FILE = os.getenv("EXTRA_GLOBAL_SETTINGS_FILE")
6696
EXTRA_SSL_CERT = os.getenv("EXTRA_SSL_CERTS")
6797
EXTRA_ROUTE_SETTINGS = os.getenv("EXTRA_ROUTE_SETTINGS", "")
6898
FORCE_DEFAULT_BACKEND = os.getenv("FORCE_DEFAULT_BACKEND", "True")

haproxy/haproxycfg.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,15 @@ def _config_global_section():
256256
statements.extend(ConfigHelper.config_ssl_bind_options(SSL_BIND_OPTIONS))
257257
statements.extend(ConfigHelper.config_ssl_bind_ciphers(SSL_BIND_CIPHERS))
258258
statements.extend(ConfigHelper.config_extra_settings(EXTRA_GLOBAL_SETTINGS))
259+
if EXTRA_GLOBAL_SETTINGS_FILE:
260+
try:
261+
with open(EXTRA_GLOBAL_SETTINGS_FILE) as file:
262+
for line in file:
263+
statements.append(line.strip())
264+
except Exception as e:
265+
logger.info("Error reading EXTRA_GLOBAL_SETTINGS_FILE at '%s', error %s" % (EXTRA_GLOBAL_SETTINGS_FILE, e))
259266
cfg["global"] = statements
267+
260268
return cfg
261269

262270
@staticmethod
@@ -285,7 +293,13 @@ def _config_defaults_section():
285293
statements.extend(ConfigHelper.config_option(OPTION))
286294
statements.extend(ConfigHelper.config_timeout(TIMEOUT))
287295
statements.extend(ConfigHelper.config_extra_settings(EXTRA_DEFAULT_SETTINGS))
288-
296+
if EXTRA_DEFAULT_SETTINGS_FILE:
297+
try:
298+
with open(EXTRA_DEFAULT_SETTINGS_FILE) as file:
299+
for line in file:
300+
statements.append(line.strip())
301+
except Exception as e:
302+
logger.info("Error reading EXTRA_DEFAULT_SETTINGS_FILE at '%s', error %s" % (EXTRA_DEFAULT_SETTINGS_FILE, e))
289303
cfg["defaults"] = statements
290304
return cfg
291305

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import unittest
2-
2+
import tempfile
3+
import time
34
from haproxy.config import parse_extra_bind_settings, parse_extra_frontend_settings
45

56

@@ -18,14 +19,23 @@ class ParseExtraFrontendSettings(unittest.TestCase):
1819
def test_parse_extra_frontend_settings(self):
1920
self.assertEqual({}, parse_extra_frontend_settings(""))
2021
self.assertEqual({}, parse_extra_frontend_settings({}))
21-
22+
tf = tempfile.NamedTemporaryFile();
23+
tf.write("reqadd file_header value99")
24+
tf.flush()
25+
2226
envvars = {"EXTRA_FRONTEND_SETTINGS_443": " reqadd header1 value1, reqadd header2 va\,lue2,"
2327
" reqadd header3 value3 ",
28+
"EXTRA_FRONTEND_SETTINGS_FILE_443": tf.name,
2429
"EXTRA_FRONTEND_SETTINGS_80": "reqadd header4",
2530
"EXTRA_FRONTEND_SETTINGS_8080": "",
2631
"EXTRA_FRONTEND_SETTINGS_ABC": "reqadd header5",
2732
"EXTRA_FRONTEND_SETTINGS_": "reqadd header6"}
28-
settings = {"443": ["reqadd header1 value1", "reqadd header2 va,lue2", "reqadd header3 value3"],
33+
settings = {"443": ["reqadd file_header value99","reqadd header1 value1", "reqadd header2 va,lue2", "reqadd header3 value3"],
2934
"80": ["reqadd header4"],
3035
"8080": [""]}
3136
self.assertEqual(settings, parse_extra_frontend_settings(envvars))
37+
38+
39+
40+
41+

0 commit comments

Comments
 (0)