Merge ~hloeung/content-cache-charm:master into content-cache-charm:master

Proposed by Haw Loeung
Status: Merged
Approved by: Haw Loeung
Approved revision: 539437892786c3e687ea2f7a9bc999e0fba1c12d
Merged at revision: 67f7f1384a4c1f788d2117dc31c377cc29a2051e
Proposed branch: ~hloeung/content-cache-charm:master
Merge into: content-cache-charm:master
Prerequisite: ~hloeung/content-cache-charm:haproxy-config
Diff against target: 392 lines (+317/-3)
5 files modified
config.yaml (+6/-0)
lib/haproxy.py (+9/-2)
reactive/content_cache.py (+6/-1)
tests/unit/files/content_cache_rendered_haproxy_test_output_load_balancing_algorithm.txt (+267/-0)
tests/unit/test_content_cache.py (+29/-0)
Reviewer Review Type Date Requested Status
Joel Sing (community) +1 Approve
Barry Price Approve
Review via email: mp+390519@code.launchpad.net

Commit message

Allow overriding default load balancing algorithm used by HAProxy - LP:1891263

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
Barry Price (barryprice) wrote :

We could consider adding safety checks to handle a typo or just a plain wrong setting via the haproxy_load_balancing_algorithm config item. If someone sets it to e.g. "xyzzy", will haproxy start? Should it?

On the other hand, if an operator is determined to break things, there's only so much the charms can do to prevent this. Other than that, LGTM - approving on that basis.

review: Approve
Revision history for this message
Joel Sing (jsing) wrote :

LGTM, minor comments inline.

review: Approve (+1)
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 67f7f1384a4c1f788d2117dc31c377cc29a2051e

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/config.yaml b/config.yaml
index 12560a6..e634fe2 100644
--- a/config.yaml
+++ b/config.yaml
@@ -45,6 +45,12 @@ options:
45 description: >45 description: >
46 Tune HAProxy's hard-stop-after to prevent lingering HAProxy processes46 Tune HAProxy's hard-stop-after to prevent lingering HAProxy processes
47 (LP:1874386).47 (LP:1874386).
48 haproxy_load_balancing_algorithm:
49 default: "leastconn"
50 type: string
51 description: >
52 Change the load balancing algorithm used by HAProxy for the
53 backends.
48 haproxy_processes:54 haproxy_processes:
49 default: 055 default: 0
50 type: int56 type: int
diff --git a/lib/haproxy.py b/lib/haproxy.py
index c3f3a76..cdb5721 100644
--- a/lib/haproxy.py
+++ b/lib/haproxy.py
@@ -11,15 +11,21 @@ from lib import utils
1111
1212
13HAPROXY_BASE_PATH = '/etc/haproxy'13HAPROXY_BASE_PATH = '/etc/haproxy'
14HAPROXY_LOAD_BALANCING_ALGORITHM = 'leastconn'
14INDENT = ' ' * 415INDENT = ' ' * 4
15TLS_CIPHER_SUITES = 'ECDHE+AESGCM:ECDHE+AES256:ECDHE+AES128:!SSLv3:!TLSv1'16TLS_CIPHER_SUITES = 'ECDHE+AESGCM:ECDHE+AES256:ECDHE+AES128:!SSLv3:!TLSv1'
1617
1718
18class HAProxyConf:19class HAProxyConf:
19 def __init__(self, conf_path=HAPROXY_BASE_PATH, max_connections=0, hard_stop_after='5m'):20 def __init__(
21 self, conf_path=HAPROXY_BASE_PATH, max_connections=0, hard_stop_after='5m', load_balancing_algorithm=None
22 ):
20 self._conf_path = conf_path23 self._conf_path = conf_path
21 self.max_connections = int(max_connections)24 self.max_connections = int(max_connections)
22 self.hard_stop_after = hard_stop_after25 self.hard_stop_after = hard_stop_after
26 self.load_balancing_algorithm = HAPROXY_LOAD_BALANCING_ALGORITHM
27 if load_balancing_algorithm:
28 self.load_balancing_algorithm = load_balancing_algorithm
2329
24 @property30 @property
25 def conf_path(self):31 def conf_path(self):
@@ -212,7 +218,7 @@ listen {name}
212backend backend-{name}218backend backend-{name}
213{options}{indent}{httpchk}219{options}{indent}{httpchk}
214{indent}http-request set-header Host {site_name}220{indent}http-request set-header Host {site_name}
215{indent}balance leastconn221{indent}balance {load_balancing_algorithm}
216{backends}222{backends}
217"""223"""
218 rendered_output = []224 rendered_output = []
@@ -293,6 +299,7 @@ backend backend-{name}
293 site=site,299 site=site,
294 site_name=site_name,300 site_name=site_name,
295 httpchk=httpchk,301 httpchk=httpchk,
302 load_balancing_algorithm=self.load_balancing_algorithm,
296 backends='\n'.join(backend_confs),303 backends='\n'.join(backend_confs),
297 options=options,304 options=options,
298 indent=INDENT,305 indent=INDENT,
diff --git a/reactive/content_cache.py b/reactive/content_cache.py
index 5b15f8a..5d4460b 100644
--- a/reactive/content_cache.py
+++ b/reactive/content_cache.py
@@ -208,7 +208,12 @@ def configure_haproxy(): # NOQA: C901 LP#1825084
208208
209 max_connections = config.get('max_connections', 0)209 max_connections = config.get('max_connections', 0)
210 hard_stop_after = config.get('haproxy_hard_stop_after')210 hard_stop_after = config.get('haproxy_hard_stop_after')
211 haproxy = HAProxy.HAProxyConf(max_connections=max_connections, hard_stop_after=hard_stop_after)211 load_balancing_algorithm = config.get('haproxy_load_balancing_algorithm')
212 haproxy = HAProxy.HAProxyConf(
213 max_connections=max_connections,
214 hard_stop_after=hard_stop_after,
215 load_balancing_algorithm=load_balancing_algorithm,
216 )
212 sites_secrets = secrets_from_config(config.get('sites_secrets'))217 sites_secrets = secrets_from_config(config.get('sites_secrets'))
213 blacklist_ports = [int(x.strip()) for x in config.get('blacklist_ports', '').split(',') if x.strip()]218 blacklist_ports = [int(x.strip()) for x in config.get('blacklist_ports', '').split(',') if x.strip()]
214 sites = sites_from_config(config.get('sites'), sites_secrets, blacklist_ports=blacklist_ports)219 sites = sites_from_config(config.get('sites'), sites_secrets, blacklist_ports=blacklist_ports)
diff --git a/tests/unit/files/content_cache_rendered_haproxy_test_output_load_balancing_algorithm.txt b/tests/unit/files/content_cache_rendered_haproxy_test_output_load_balancing_algorithm.txt
215new file mode 100644220new file mode 100644
index 0000000..b0c6370
--- /dev/null
+++ b/tests/unit/files/content_cache_rendered_haproxy_test_output_load_balancing_algorithm.txt
@@ -0,0 +1,267 @@
1global
2 nbthread 4
3 maxconn 106496
4 log /dev/log local0
5 log /dev/log local1 notice
6 chroot /var/lib/haproxy
7 stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
8 stats timeout 30s
9 user haproxy
10 group haproxy
11 daemon
12
13 # LP#1874386: Work around lingering HAProxy processes as per LP:1874386
14 # and kill them off.
15 hard-stop-after 15m
16
17 # Default SSL material locations
18 ca-base /etc/ssl/certs
19 crt-base /etc/ssl/private
20
21 # Default ciphers to use on SSL-enabled listening sockets.
22 # For more information, see ciphers(1SSL). This list is from:
23 # https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
24 # An alternative list with additional directives can be obtained from
25 # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
26 ssl-default-bind-ciphers ECDHE+AESGCM:ECDHE+AES256:ECDHE+AES128:!SSLv3:!TLSv1
27 ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
28 # We'll eventually disable DHE (LP#1825321), but for now, bump DH params
29 tune.ssl.default-dh-param 2048
30
31 # Increase the SSL/TLS session cache from the default 20k. But
32 # rather than hardcode values, let's just set it to match
33 # global_max_connections (which by default is calculated using
34 # num. of CPU cores and num. of configured sites). Each entry
35 # requires ~200 bytes so on a host with say 32 CPUs, 10 sites,
36 # each with 2000 max conns will only consume around 122 Mbytes
37 # (32 * 10 * 2000 * 200), which is not much.
38 tune.ssl.cachesize 106496
39
40defaults
41 log global
42 maxconn 8192
43 mode http
44 option httplog
45 option dontlognull
46 timeout connect 5s
47 timeout client 50s
48 timeout server 50s
49 errorfile 400 /etc/haproxy/errors/400.http
50 errorfile 403 /etc/haproxy/errors/403.http
51 errorfile 408 /etc/haproxy/errors/408.http
52 errorfile 500 /etc/haproxy/errors/500.http
53 errorfile 502 /etc/haproxy/errors/502.http
54 errorfile 503 /etc/haproxy/errors/503.http
55 errorfile 504 /etc/haproxy/errors/504.http
56
57resolvers dns
58 nameserver dns1 127.0.0.53:53
59 resolve_retries 3
60 timeout resolve 3s
61 timeout retry 3s
62 accepted_payload_size 8192
63
64listen stats
65 bind 127.0.0.1:10000
66 acl allowed_cidr src 127.0.0.0/8
67 http-request deny unless allowed_cidr
68
69 mode http
70 stats enable
71 stats uri /
72 stats realm Haproxy\ Statistics
73 stats auth haproxy:biometricsarenotsecret
74 stats refresh 3
75
76
77listen combined-80
78 bind 0.0.0.0:80
79 bind :::80
80 redirect scheme https code 301 if { hdr(Host) -i site2.local } !{ ssl_fc }
81 use_backend backend-cached-site1-local if { hdr(Host) -i site1.local }
82 use_backend backend-cached-site3-local if { hdr(Host) -i site3.local }
83 use_backend backend-cached-site4-local if { hdr(Host) -i site4.local }
84 use_backend backend-cached-site5 if { hdr(Host) -i site5.local }
85 use_backend backend-cached-site6-local if { hdr(Host) -i site6.local }
86 use_backend backend-cached-site9-local if { hdr(Host) -i site9.local }
87 default_backend backend-cached-site3-local
88
89listen site1-local
90 bind 127.0.0.1:8080
91 default_backend backend-site1-local
92
93listen cached-site2-local
94 bind 0.0.0.0:443 ssl crt /etc/haproxy/site2-bundle.crt alpn h2,http/1.1
95 bind :::443 ssl crt /etc/haproxy/site2-bundle.crt alpn h2,http/1.1
96 default_backend backend-cached-site2-local
97
98listen site2-local
99 bind 127.0.0.1:8081
100 default_backend backend-site2-local
101
102listen site3-local
103 bind 127.0.0.1:8082
104 default_backend backend-site3-local
105
106listen site5
107 bind 127.0.0.1:8083
108 default_backend backend-site5
109
110listen site5-2
111 bind 127.0.0.1:8084
112 default_backend backend-site5-2
113
114listen site6-local
115 bind 127.0.0.1:8085
116 default_backend backend-site6-local
117
118listen combined-444
119 bind 0.0.0.0:444 ssl crt /etc/haproxy/site7-bundle.crt crt /etc/haproxy/site8-bundle.crt alpn h2,http/1.1
120 bind :::444 ssl crt /etc/haproxy/site7-bundle.crt crt /etc/haproxy/site8-bundle.crt alpn h2,http/1.1
121 use_backend backend-cached-site7-local if { hdr(Host) -i site7.local }
122 use_backend backend-cached-site8-local if { hdr(Host) -i site8.local }
123
124listen site7-local
125 bind 127.0.0.1:8086
126 default_backend backend-site7-local
127
128listen site8-local
129 bind 127.0.0.1:8087
130 default_backend backend-site8-local
131
132listen site8-local-2
133 bind 127.0.0.1:8088
134 default_backend backend-site8-local-2
135
136listen site9-local
137 bind 127.0.0.1:8089
138 default_backend backend-site9-local
139
140backend backend-cached-site1-local
141 option forwardfor
142 option httpchk HEAD /?token=1861920000_f3e404e205ed44749e942d481f7a7bec57c5e78a HTTP/1.0\r\nHost:\ site1.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
143 http-request set-header Host site1.local
144 balance roundrobin
145 server server_1 127.0.0.1:6080 check inter 2s rise 2 fall 60 maxconn 2048
146
147backend backend-site1-local
148 option httpchk HEAD / HTTP/1.0\r\nHost:\ site1.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
149 http-request set-header Host site1.local
150 balance roundrobin
151 server server_1 127.0.1.10:80 check inter 5s rise 2 fall 5 maxconn 2048
152 server server_2 127.0.1.11:80 check inter 5s rise 2 fall 5 maxconn 2048
153 server server_3 127.0.1.12:80 check inter 5s rise 2 fall 5 maxconn 2048
154
155backend backend-cached-site2-local
156 option forwardfor
157 option httpchk GET /check/ HTTP/1.0\r\nHost:\ site2.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
158 http-request set-header Host site2.local
159 balance roundrobin
160 server server_1 127.0.0.1:6081 check inter 2s rise 2 fall 60 maxconn 2048
161
162backend backend-site2-local
163 option httpchk GET /check/ HTTP/1.0\r\nHost:\ site2.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
164 http-request set-header Host site2.local
165 balance roundrobin
166 server server_1 127.0.1.10:443 check inter 5s rise 2 fall 5 maxconn 1024 ssl sni str(site2.local) check-sni site2.local verify required ca-file ca-certificates.crt
167 server server_2 127.0.1.11:443 check inter 5s rise 2 fall 5 maxconn 1024 ssl sni str(site2.local) check-sni site2.local verify required ca-file ca-certificates.crt
168 server server_3 127.0.1.12:443 check inter 5s rise 2 fall 5 maxconn 1024 ssl sni str(site2.local) check-sni site2.local verify required ca-file ca-certificates.crt
169
170backend backend-cached-site3-local
171 option forwardfor
172 option httpchk HEAD / HTTP/1.0\r\nHost:\ site3.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
173 http-request set-header Host site3.local
174 balance roundrobin
175 server server_1 127.0.0.1:6082 check inter 2s rise 2 fall 60 maxconn 4096
176
177backend backend-site3-local
178 option httpchk HEAD / HTTP/1.0\r\nHost:\ site3.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
179 http-request set-header Host site3.local
180 balance roundrobin
181 server server_1 127.0.1.10:80 check inter 5s rise 2 fall 5 maxconn 2048
182 server server_2 127.0.1.11:80 check inter 5s rise 2 fall 5 maxconn 2048
183 server server_3 127.0.1.12:80 check inter 5s rise 2 fall 5 maxconn 2048
184
185backend backend-cached-site4-local
186 option forwardfor
187 option httpchk HEAD / HTTP/1.0\r\nHost:\ site4.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
188 http-request set-header Host site4.local
189 balance roundrobin
190 server server_1 127.0.0.1:6083 check inter 2s rise 2 fall 60 maxconn 2048
191
192backend backend-cached-site5
193 option forwardfor
194 option httpchk HEAD / HTTP/1.0\r\nHost:\ site5.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
195 http-request set-header Host site5.local
196 balance roundrobin
197 server server_1 127.0.0.1:6084 check inter 2s rise 2 fall 60 maxconn 2048
198
199backend backend-site5
200 option httpchk HEAD / HTTP/1.0\r\nHost:\ site5.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
201 http-request set-header Host site5.local
202 balance roundrobin
203 server server_1 127.0.1.10:80 check inter 5s rise 2 fall 5 maxconn 2048
204
205backend backend-site5-2
206 option httpchk HEAD / HTTP/1.0\r\nHost:\ site5.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
207 http-request set-header Host site5.local
208 balance roundrobin
209 server server_1 127.0.1.11:80 check inter 5s rise 2 fall 5 maxconn 2048
210
211backend backend-cached-site6-local
212 option forwardfor
213 option httpchk HEAD / HTTP/1.0\r\nHost:\ site6.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
214 http-request set-header Host site6.local
215 balance roundrobin
216 server server_1 127.0.0.1:6085 check inter 2s rise 2 fall 60 maxconn 2048
217
218backend backend-site6-local
219 option httpchk HEAD / HTTP/1.0\r\nHost:\ site6.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
220 http-request set-header Host site6.local
221 balance roundrobin
222 server server_1 127.0.1.10:443 check inter 5s rise 2 fall 5 maxconn 2048 ssl sni str(site6.local) check-sni site6.local verify required ca-file ca-certificates.crt
223
224backend backend-cached-site7-local
225 option forwardfor
226 option httpchk HEAD / HTTP/1.0\r\nHost:\ site7.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
227 http-request set-header Host site7.local
228 balance roundrobin
229 server server_1 127.0.0.1:6086 check inter 2s rise 2 fall 60 maxconn 2048
230
231backend backend-site7-local
232 option httpchk HEAD / HTTP/1.0\r\nHost:\ site7.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
233 http-request set-header Host site7.local
234 balance roundrobin
235 server server_1 127.0.1.10:80 check inter 5s rise 2 fall 5 maxconn 2048
236
237backend backend-cached-site8-local
238 option forwardfor
239 option httpchk HEAD / HTTP/1.0\r\nHost:\ site8.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
240 http-request set-header Host site8.local
241 balance roundrobin
242 server server_1 127.0.0.1:6087 check inter 2s rise 2 fall 60 maxconn 2048
243
244backend backend-site8-local
245 option httpchk HEAD / HTTP/1.0\r\nHost:\ site8.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
246 http-request set-header Host site8.local
247 balance roundrobin
248 server server_1 127.0.1.10:80 check inter 5s rise 2 fall 5 maxconn 2048
249
250backend backend-site8-local-2
251 option httpchk HEAD / HTTP/1.0\r\nHost:\ auth.site8.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
252 http-request set-header Host auth.site8.local
253 balance roundrobin
254 server server_1 127.0.1.10:443 check inter 5s rise 2 fall 5 maxconn 2048 ssl sni str(auth.site8.local) check-sni auth.site8.local verify required ca-file ca-certificates.crt
255
256backend backend-cached-site9-local
257 option forwardfor
258 option httpchk HEAD / HTTP/1.0\r\nHost:\ site9.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
259 http-request set-header Host site9.local
260 balance roundrobin
261 server server_1 127.0.0.1:6088 check inter 2s rise 2 fall 60 maxconn 2048
262
263backend backend-site9-local
264 option httpchk HEAD / HTTP/1.0\r\nHost:\ site9.local\r\nUser-Agent:\ haproxy/httpchk\r\nCache-Control:\ no-cache
265 http-request set-header Host site9.local
266 balance roundrobin
267 server server_1 127.0.1.15:80 check inter 1m rise 2 fall 5 maxconn 2048
diff --git a/tests/unit/test_content_cache.py b/tests/unit/test_content_cache.py
index 3b62cbb..561cd53 100644
--- a/tests/unit/test_content_cache.py
+++ b/tests/unit/test_content_cache.py
@@ -485,6 +485,35 @@ site1.local:
485 @freezegun.freeze_time("2019-03-22", tz_offset=0)485 @freezegun.freeze_time("2019-03-22", tz_offset=0)
486 @mock.patch('charmhelpers.core.hookenv.opened_ports')486 @mock.patch('charmhelpers.core.hookenv.opened_ports')
487 @mock.patch('charms.reactive.set_flag')487 @mock.patch('charms.reactive.set_flag')
488 @mock.patch('reactive.content_cache.update_logrotate')
489 def test_configure_haproxy_sites_load_balancing_algorithm(self, logrotation, set_flag, opened_ports):
490 with open('tests/unit/files/config_test_config.txt', 'r', encoding='utf-8') as f:
491 config = f.read()
492 self.mock_config.return_value = {
493 'haproxy_hard_stop_after': '15m',
494 'haproxy_load_balancing_algorithm': 'roundrobin',
495 'max_connections': 8192,
496 'sites': config,
497 }
498
499 with mock.patch('lib.haproxy.HAProxyConf.conf_file', new_callable=mock.PropertyMock) as mock_conf_file:
500 mock_conf_file.return_value = os.path.join(self.tmpdir, 'haproxy.cfg')
501 opened_ports.return_value = ['443/tcp']
502 content_cache.configure_haproxy()
503
504 with open(
505 'tests/unit/files/content_cache_rendered_haproxy_test_output_load_balancing_algorithm.txt',
506 'r',
507 encoding='utf-8',
508 ) as f:
509 want = f.read()
510 with open(os.path.join(self.tmpdir, 'haproxy.cfg'), 'r', encoding='utf-8') as f:
511 got = f.read()
512 self.assertEqual(got, want)
513
514 @freezegun.freeze_time("2019-03-22", tz_offset=0)
515 @mock.patch('charmhelpers.core.hookenv.opened_ports')
516 @mock.patch('charms.reactive.set_flag')
488 @mock.patch('lib.utils.package_version')517 @mock.patch('lib.utils.package_version')
489 @mock.patch('reactive.content_cache.update_logrotate')518 @mock.patch('reactive.content_cache.update_logrotate')
490 def test_configure_haproxy_processes_and_threads(self, logrotation, package_version, set_flag, opened_ports):519 def test_configure_haproxy_processes_and_threads(self, logrotation, package_version, set_flag, opened_ports):

Subscribers

People subscribed via source and target branches