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

Commit 4f856dd

Browse files
author
Feng Honglin
committed
Merge pull request #62 from docker/staging
1.4.1
2 parents d031529 + 2530556 commit 4f856dd

8 files changed

Lines changed: 96 additions & 20 deletions

File tree

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Similar to using legacy links, here list some differences that you need to notic
8787
- DO not overwrite `HOSTNAME` environment variable in `dockercloud/haproxy container`.
8888
- As it is the case on Docker Cloud, auto reconfiguration is supported when the linked services scales or/and the linked container starts/stops.
8989

90-
##### example of docker-compose.yml running in linux:
90+
##### example of docker-compose.yml running on Linux or Docker for Mac (beta):
9191

9292
version: '2'
9393
services:
@@ -102,7 +102,7 @@ Similar to using legacy links, here list some differences that you need to notic
102102
ports:
103103
- 80:80
104104

105-
##### example of docker-compose.yml running in Mac OS
105+
##### example of docker-compose.yml running on Mac OS
106106

107107
version: '2'
108108
services:
@@ -185,6 +185,7 @@ Settings in this part is immutable, you have to redeploy HAProxy service to make
185185
|MONITOR_URI| |the exact URI which we want to intercept to return HAProxy's health status instead of forwarding the request.See: http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4-monitor-uri. Possible value: `/ping`|
186186
|OPTION|redispatch|comma-separated list of HAProxy `option` entries to the `default` section.|
187187
|RSYSLOG_DESTINATION|127.0.0.1|the rsyslog destination to where HAProxy logs are sent|
188+
|SKIP_FORWARDED_PROTO||If set to any value, HAProxy will not add an X-Forwarded- headers. This can be used when combining HAProxy with another load balancer|
188189
|SSL_BIND_CIPHERS| |explicitly set which SSL ciphers will be used for the SSL server. This sets the HAProxy `ssl-default-bind-ciphers` configuration setting.|
189190
|SSL_BIND_OPTIONS|no-sslv3|explicitly set which SSL bind options will be used for the SSL server. This sets the HAProxy `ssl-default-bind-options` configuration setting. The default will allow only TLSv1.0+ to be used on the SSL server.|
190191
|STATS_AUTH|stats:stats|username and password required to access the Haproxy stats.|

haproxy/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def parse_extra_frontend_settings(envvars):
5353
MONITOR_URI = os.getenv("MONITOR_URI")
5454
OPTION = os.getenv("OPTION", "redispatch, httplog, dontlognull, forwardfor")
5555
RSYSLOG_DESTINATION = os.getenv("RSYSLOG_DESTINATION", "127.0.0.1")
56+
SKIP_FORWARDED_PROTO = os.getenv("SKIP_FORWARDED_PROTO")
5657
SSL_BIND_CIPHERS = os.getenv("SSL_BIND_CIPHERS")
5758
SSL_BIND_OPTIONS = os.getenv("SSL_BIND_OPTIONS")
5859
STATS_AUTH = os.getenv("STATS_AUTH", "stats:stats")

haproxy/eventhandler.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
import logging
3+
import time
34

45
import dockercloud
56
from compose.cli.docker_client import docker_client
@@ -52,12 +53,23 @@ def on_user_reload(signum, frame):
5253
run_haproxy("User reload")
5354

5455

56+
def on_cloud_error(e):
57+
if isinstance(e, KeyboardInterrupt):
58+
exit(0)
59+
60+
5561
def listen_dockercloud_events():
5662
events = dockercloud.Events()
5763
events.on_open(on_websocket_open)
5864
events.on_close(on_websocket_close)
5965
events.on_message(on_cloud_event)
60-
events.run_forever()
66+
events.on_error(on_cloud_error)
67+
while True:
68+
try:
69+
events.run_forever()
70+
except dockercloud.AuthError as e:
71+
logger.info("Auth error: %s, retry in 1 hour" % e)
72+
time.sleep(3600)
6173

6274

6375
def listen_docker_events():

haproxy/haproxycfg.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,14 @@ def _initialize(link_mode):
6464
@staticmethod
6565
def _init_cloud_links():
6666
haproxy_container = fetch_remote_obj(HAPROXY_CONTAINER_URI)
67-
links = CloudLinkHelper.get_cloud_links(haproxy_container)
68-
Haproxy.cls_linked_services = CloudLinkHelper.get_linked_services(links)
69-
logger.info("Linked service: %s", ", ".join(CloudLinkHelper.get_service_links_str(links)))
70-
logger.info("Linked container: %s", ", ".join(CloudLinkHelper.get_container_links_str(links)))
71-
return links
67+
if haproxy_container:
68+
links = CloudLinkHelper.get_cloud_links(haproxy_container)
69+
Haproxy.cls_linked_services = CloudLinkHelper.get_linked_services(links)
70+
logger.info("Linked service: %s", ", ".join(CloudLinkHelper.get_service_links_str(links)))
71+
logger.info("Linked container: %s", ", ".join(CloudLinkHelper.get_container_links_str(links)))
72+
return links
73+
else:
74+
return {}
7275

7376
@staticmethod
7477
def _init_new_links():

haproxy/helper/frontend_helper.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from collections import OrderedDict
22

3-
from haproxy.config import EXTRA_BIND_SETTINGS, EXTRA_FRONTEND_SETTINGS, MONITOR_URI, MONITOR_PORT, MAXCONN
3+
from haproxy.config import EXTRA_BIND_SETTINGS, EXTRA_FRONTEND_SETTINGS, MONITOR_URI, MONITOR_PORT, MAXCONN, SKIP_FORWARDED_PROTO
44

55

66
def check_require_default_route(routes, routes_added):
@@ -95,11 +95,12 @@ def config_common_part(port, ssl_bind_string, vhosts):
9595
bind_string, ssl = get_bind_string(port, ssl_bind_string, vhosts)
9696
frontend_section.append("bind :%s" % bind_string)
9797

98-
# add x-forwarded-porto header
99-
if ssl:
100-
frontend_section.append("reqadd X-Forwarded-Proto:\ https")
101-
else:
102-
frontend_section.append("reqadd X-Forwarded-Proto:\ http")
98+
# add x-forwarded-porto header if not skipped
99+
if not SKIP_FORWARDED_PROTO:
100+
if ssl:
101+
frontend_section.append("reqadd X-Forwarded-Proto:\ https")
102+
else:
103+
frontend_section.append("reqadd X-Forwarded-Proto:\ http")
103104

104105
# add maxconn
105106
frontend_section.append("maxconn %s" % MAXCONN)
@@ -135,8 +136,13 @@ def get_bind_string(port, ssl_bind_string, vhosts):
135136
def config_default_frontend(ssl_bind_string):
136137
cfg = OrderedDict()
137138
monitor_uri_configured = False
138-
frontend = [("bind :80 %s" % EXTRA_BIND_SETTINGS.get('80', "")).strip(),
139-
"reqadd X-Forwarded-Proto:\ http", "maxconn %s" % MAXCONN]
139+
frontend = [("bind :80 %s" % EXTRA_BIND_SETTINGS.get('80', "")).strip()]
140+
141+
# add x-forwarded-porto header if not skipped
142+
if not SKIP_FORWARDED_PROTO:
143+
frontend.append("reqadd X-Forwarded-Proto:\ http")
144+
145+
frontend.append("maxconn %s" % MAXCONN)
140146

141147
if MONITOR_URI and MONITOR_PORT == '80':
142148
frontend.append("monitor-uri %s" % MONITOR_URI)
@@ -149,8 +155,13 @@ def config_default_frontend(ssl_bind_string):
149155
cfg["frontend default_port_80"] = frontend
150156

151157
if ssl_bind_string:
152-
ssl_frontend = [("bind :443 %s %s" % (ssl_bind_string, EXTRA_BIND_SETTINGS.get('443', ""))).strip(),
153-
"reqadd X-Forwarded-Proto:\ https", "maxconn %s" % MAXCONN]
158+
ssl_frontend = [("bind :443 %s %s" % (ssl_bind_string, EXTRA_BIND_SETTINGS.get('443', ""))).strip()]
159+
160+
# add x-forwarded-porto header if not skipped
161+
if not SKIP_FORWARDED_PROTO:
162+
ssl_frontend.append("reqadd X-Forwarded-Proto:\ https")
163+
164+
ssl_frontend.append("maxconn %s" % MAXCONN)
154165

155166
if MONITOR_URI and (MONITOR_PORT == '443'):
156167
ssl_frontend.append("monitor-uri %s" % MONITOR_URI)

haproxy/utils.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,27 @@
77

88
logger = logging.getLogger("haproxy")
99

10+
invalid_auth_headers = set()
11+
1012

1113
def fetch_remote_obj(uri):
1214
if not uri:
1315
return None
1416

17+
auth_header = str(dockercloud.auth.get_auth_header())
1518
while True:
1619
try:
20+
if auth_header in invalid_auth_headers:
21+
logger.info("Using know invalid credentials")
22+
return None
1723
obj = dockercloud.Utils.fetch_by_resource_uri(uri)
1824
return obj
25+
except dockercloud.AuthError as e:
26+
invalid_auth_headers.add(auth_header)
27+
logger.info(e)
28+
return None
1929
except Exception as e:
20-
logger.error(e)
30+
logger.info(e)
2131
time.sleep(config.API_RETRY)
2232

2333

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ requests==2.7.0
1111
six==1.9.0
1212
websocket-client==0.37.0
1313
docker-compose==1.6.0
14-
python-dockercloud==1.0.4
14+
python-dockercloud==1.0.5
1515
gevent==1.1.1

tests/unit/helper/test_frontend_helper.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ def setUp(self):
1717
frontend_helper.EXTRA_BIND_SETTINGS = {"8888": "name http", "4443": "accept-proxy"}
1818
frontend_helper.MAXCONN = "55555"
1919
frontend_helper.EXTRA_FRONTEND_SETTINGS = {}
20+
frontend_helper.SKIP_FORWARDED_PROTO = None
2021

2122
def tearDown(self):
2223
frontend_helper.MONITOR_PORT = self.monitor_port
2324
frontend_helper.MONITOR_URI = self.monitor_uri
2425
frontend_helper.EXTRA_BIND_SETTINGS = self.extra_bind_settings
2526
frontend_helper.MAXCONN = self.maxconn
2627
frontend_helper.EXTRA_FRONTEND_SETTINGS = {}
28+
frontend_helper.SKIP_FORWARDED_PROTO = None
2729

2830
def test_config_frontend_with_virtual_host_without_monitoring_uri_added(self):
2931
vhosts = [{'service_alias': 'web-a', 'path': '', 'host': 'a.com', 'scheme': 'http', 'port': '80'}]
@@ -185,6 +187,27 @@ def test_config_common_part_with_extra_frontend_sttings(self, mock_get_bind_stri
185187
self.assertFalse(monitor_uri_configured)
186188
frontend_helper.EXTRA_FRONTEND_SETTINGS = {}
187189

190+
@mock.patch("haproxy.helper.frontend_helper.get_bind_string")
191+
def test_config_common_part_without_forwarded_headers(self, mock_get_bind_string):
192+
mock_get_bind_string.return_value = ("80", False)
193+
frontend_helper.SKIP_FORWARDED_PROTO = 'true'
194+
frontend_section, monitor_uri_configured = config_common_part("80", "ssl crt /certs/", [])
195+
self.assertEqual(["bind :80",
196+
"maxconn 55555",
197+
"acl is_websocket hdr(Upgrade) -i WebSocket"],
198+
frontend_section)
199+
200+
@mock.patch("haproxy.helper.frontend_helper.get_bind_string")
201+
def test_config_common_part_without_forwarded_headers_with_ssl(self, mock_get_bind_string):
202+
mock_get_bind_string.return_value = ("9999 ssl crt /certs/", True)
203+
frontend_helper.SKIP_FORWARDED_PROTO = 'true'
204+
frontend_section, monitor_uri_configured = config_common_part("9999", "ssl crt /certs/", [])
205+
self.assertEqual(["bind :9999 ssl crt /certs/",
206+
'maxconn 55555',
207+
"monitor-uri %s" % frontend_helper.MONITOR_URI,
208+
"acl is_websocket hdr(Upgrade) -i WebSocket"],
209+
frontend_section)
210+
188211
def test_get_bind_string(self):
189212
vhosts = [{'service_alias': 'web-a', 'path': '', 'host': 'a.com', 'scheme': 'http', 'port': '80'},
190213
{'service_alias': 'web-b', 'path': '', 'host': 'a.com', 'scheme': 'http', 'port': '8888'},
@@ -277,6 +300,21 @@ def test_config_default_front(self):
277300
'default_backend default_service'])]), cfg)
278301
self.assertTrue(monitor_uri_configured)
279302

303+
frontend_helper.SKIP_FORWARDED_PROTO = 'true'
304+
cfg, monitor_uri_configured = config_default_frontend("ssl crt /certs/")
305+
self.assertEqual(OrderedDict([('frontend default_port_80',
306+
['bind :80',
307+
'maxconn 55555',
308+
'reqadd header1 value1',
309+
'default_backend default_service']),
310+
('frontend default_port_443',
311+
['bind :443 ssl crt /certs/ accept-proxy',
312+
'maxconn 55555',
313+
'monitor-uri /ping',
314+
'reqadd header2 value2',
315+
'default_backend default_service'])]), cfg)
316+
self.assertTrue(monitor_uri_configured)
317+
280318
def test_config_common_part_with_monitor_uri(self):
281319
self.assertEqual(OrderedDict(), config_monitor_frontend(True))
282320
self.assertEqual(OrderedDict([('frontend monitor', ['bind :9999', 'monitor-uri /ping'])]),

0 commit comments

Comments
 (0)