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

Proposed by Haw Loeung
Status: Merged
Approved by: Haw Loeung
Approved revision: 08cf92089609e1bdb3250d2931783b13d51e88ea
Merged at revision: 61cc22b969fc5555ec7e0d5c37f0fca78ce6b9f8
Proposed branch: ~hloeung/content-cache-charm:rate-limiting
Merge into: content-cache-charm:master
Diff against target: 460 lines (+293/-2)
14 files modified
lib/haproxy.py (+21/-1)
reactive/content_cache.py (+2/-0)
tests/unit/files/config_test_config.txt (+6/-1)
tests/unit/files/content_cache_rendered_haproxy_test_output.txt (+3/-0)
tests/unit/files/content_cache_rendered_haproxy_test_output_auto_maxconns.txt (+3/-0)
tests/unit/files/content_cache_rendered_haproxy_test_output_load_balancing_algorithm.txt (+3/-0)
tests/unit/files/content_cache_rendered_haproxy_test_output_processes_and_threads.txt (+3/-0)
tests/unit/files/content_cache_rendered_haproxy_test_output_processes_and_threads_haproxy2.txt (+3/-0)
tests/unit/files/content_cache_rendered_haproxy_test_output_rate_limiting.txt (+95/-0)
tests/unit/files/content_cache_rendered_haproxy_test_output_rate_limiting_missing_condition.txt (+92/-0)
tests/unit/files/haproxy_config_rendered_backends_stanzas_test_output.txt (+3/-0)
tests/unit/files/haproxy_config_rendered_test_output.txt (+3/-0)
tests/unit/files/haproxy_config_rendered_test_output2.txt (+3/-0)
tests/unit/test_content_cache.py (+53/-0)
Reviewer Review Type Date Requested Status
James Simpson Approve
Canonical IS Reviewers Pending
Review via email: mp+441030@code.launchpad.net

Commit message

Add support for rate limiting on source IP and more - LP:1918439

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
James Simpson (jsimpso) wrote :

LGTM

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

Change successfully merged at revision 61cc22b969fc5555ec7e0d5c37f0fca78ce6b9f8

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/haproxy.py b/lib/haproxy.py
2index d666169..fa5c940 100644
3--- a/lib/haproxy.py
4+++ b/lib/haproxy.py
5@@ -227,7 +227,7 @@ listen {name}
6 backend_stanza = """
7 backend backend-{name}
8 {indent}{httpchk}
9-{indent}http-request set-header Host {site_name}
10+{ratelimit}{indent}http-request set-header Host {site_name}
11 {options}{indent}balance {load_balancing_algorithm}
12 {backends}
13 """
14@@ -314,6 +314,25 @@ backend backend-{name}
15 )
16 )
17
18+ ratelimit = ''
19+ if loc_conf.get('rate-limit'):
20+ loc_rl = loc_conf.get('rate-limit')
21+ condition = loc_rl.get('condition')
22+ sticky = loc_rl.get('sticky-table')
23+ track = loc_rl.get('track')
24+
25+ if condition and sticky and track:
26+ rlconf = []
27+ # https://www.haproxy.com/blog/four-examples-of-haproxy-rate-limiting/
28+ rlconf.append('{indent}stick-table {sticky}'.format(sticky=sticky, indent=INDENT))
29+ rlconf.append('{indent}http-request track-sc0 {track}'.format(track=track, indent=INDENT))
30+ rlconf.append(
31+ '{indent}http-request deny deny_status 429 if {condition}'.format(
32+ condition=condition, indent=INDENT
33+ )
34+ )
35+ ratelimit = '\n'.join(rlconf + [''])
36+
37 opts = []
38 for option in loc_conf.get('backend-options', []):
39 # retry-on only available from HAProxy 2.1.
40@@ -344,6 +363,7 @@ backend backend-{name}
41 load_balancing_algorithm=self.load_balancing_algorithm,
42 backends='\n'.join(backend_confs),
43 options=options,
44+ ratelimit=ratelimit,
45 indent=INDENT,
46 )
47
48diff --git a/reactive/content_cache.py b/reactive/content_cache.py
49index 4ddeb7a..d811b14 100644
50--- a/reactive/content_cache.py
51+++ b/reactive/content_cache.py
52@@ -322,6 +322,8 @@ def configure_haproxy(): # NOQA: C901 LP#1825084
53 # the X-F-F header in case it's spoofed.
54 new_cached_loc_conf['backend-options'].insert(0, 'http-request set-header X-Forwarded-For %[src]')
55
56+ new_cached_loc_conf['rate-limit'] = loc_conf.get('rate-limit', '')
57+
58 # No backends
59 if not site_conf['locations'][location].get('backends'):
60 if not new_conf[cached_site]['locations']:
61diff --git a/tests/unit/files/config_test_config.txt b/tests/unit/files/config_test_config.txt
62index 32ea46c..6c591e0 100644
63--- a/tests/unit/files/config_test_config.txt
64+++ b/tests/unit/files/config_test_config.txt
65@@ -113,7 +113,7 @@ site8.local:
66 cache-valid: ['200 1h', '401 15m']
67 site-name: auth.site8.local
68
69-# Test 9: Custom backend-inter-time
70+# Test 9: Custom backend-inter-time and rate limiting
71 site9.local:
72 locations:
73 /:
74@@ -124,6 +124,11 @@ site9.local:
75 cache-validity: ['200 1h', '401 30m']
76 extra-configs:
77 - proxy_force_ranges off
78+ # https://www.haproxy.com/blog/four-examples-of-haproxy-rate-limiting/
79+ rate-limit:
80+ condition: "{ sc_http_req_rate(0) gt 20 }"
81+ sticky-table: "type ip size 1m expire 30s store http_req_rate(10s)"
82+ track: "src"
83 /private/content:
84 extra-configs:
85 - root /srv/example1.com/content/
86diff --git a/tests/unit/files/content_cache_rendered_haproxy_test_output.txt b/tests/unit/files/content_cache_rendered_haproxy_test_output.txt
87index f06fc0e..7d7d726 100644
88--- a/tests/unit/files/content_cache_rendered_haproxy_test_output.txt
89+++ b/tests/unit/files/content_cache_rendered_haproxy_test_output.txt
90@@ -297,6 +297,9 @@ backend backend-site8-local-2
91
92 backend backend-cached-site9-local
93 option httpchk GET /_status/content-cache-check HTTP/1.1\r\nHost:\ site9.local\r\nUser-Agent:\ haproxy/httpchk
94+ stick-table type ip size 1m expire 30s store http_req_rate(10s)
95+ http-request track-sc0 src
96+ http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
97 http-request set-header Host site9.local
98 http-request set-header X-Forwarded-For %[src]
99 balance leastconn
100diff --git a/tests/unit/files/content_cache_rendered_haproxy_test_output_auto_maxconns.txt b/tests/unit/files/content_cache_rendered_haproxy_test_output_auto_maxconns.txt
101index 4435e25..93e026a 100644
102--- a/tests/unit/files/content_cache_rendered_haproxy_test_output_auto_maxconns.txt
103+++ b/tests/unit/files/content_cache_rendered_haproxy_test_output_auto_maxconns.txt
104@@ -297,6 +297,9 @@ backend backend-site8-local-2
105
106 backend backend-cached-site9-local
107 option httpchk GET /_status/content-cache-check HTTP/1.1\r\nHost:\ site9.local\r\nUser-Agent:\ haproxy/httpchk
108+ stick-table type ip size 1m expire 30s store http_req_rate(10s)
109+ http-request track-sc0 src
110+ http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
111 http-request set-header Host site9.local
112 http-request set-header X-Forwarded-For %[src]
113 balance leastconn
114diff --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
115index e3a0956..2cd7279 100644
116--- a/tests/unit/files/content_cache_rendered_haproxy_test_output_load_balancing_algorithm.txt
117+++ b/tests/unit/files/content_cache_rendered_haproxy_test_output_load_balancing_algorithm.txt
118@@ -297,6 +297,9 @@ backend backend-site8-local-2
119
120 backend backend-cached-site9-local
121 option httpchk GET /_status/content-cache-check HTTP/1.1\r\nHost:\ site9.local\r\nUser-Agent:\ haproxy/httpchk
122+ stick-table type ip size 1m expire 30s store http_req_rate(10s)
123+ http-request track-sc0 src
124+ http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
125 http-request set-header Host site9.local
126 http-request set-header X-Forwarded-For %[src]
127 balance roundrobin
128diff --git a/tests/unit/files/content_cache_rendered_haproxy_test_output_processes_and_threads.txt b/tests/unit/files/content_cache_rendered_haproxy_test_output_processes_and_threads.txt
129index fc0c096..450faaa 100644
130--- a/tests/unit/files/content_cache_rendered_haproxy_test_output_processes_and_threads.txt
131+++ b/tests/unit/files/content_cache_rendered_haproxy_test_output_processes_and_threads.txt
132@@ -298,6 +298,9 @@ backend backend-site8-local-2
133
134 backend backend-cached-site9-local
135 option httpchk GET /_status/content-cache-check HTTP/1.1\r\nHost:\ site9.local\r\nUser-Agent:\ haproxy/httpchk
136+ stick-table type ip size 1m expire 30s store http_req_rate(10s)
137+ http-request track-sc0 src
138+ http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
139 http-request set-header Host site9.local
140 http-request set-header X-Forwarded-For %[src]
141 balance leastconn
142diff --git a/tests/unit/files/content_cache_rendered_haproxy_test_output_processes_and_threads_haproxy2.txt b/tests/unit/files/content_cache_rendered_haproxy_test_output_processes_and_threads_haproxy2.txt
143index 1943512..8905d99 100644
144--- a/tests/unit/files/content_cache_rendered_haproxy_test_output_processes_and_threads_haproxy2.txt
145+++ b/tests/unit/files/content_cache_rendered_haproxy_test_output_processes_and_threads_haproxy2.txt
146@@ -306,6 +306,9 @@ backend backend-site8-local-2
147
148 backend backend-cached-site9-local
149 option httpchk GET /_status/content-cache-check HTTP/1.1\r\nHost:\ site9.local\r\nUser-Agent:\ haproxy/httpchk
150+ stick-table type ip size 1m expire 30s store http_req_rate(10s)
151+ http-request track-sc0 src
152+ http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
153 http-request set-header Host site9.local
154 http-request set-header X-Forwarded-For %[src]
155 balance leastconn
156diff --git a/tests/unit/files/content_cache_rendered_haproxy_test_output_rate_limiting.txt b/tests/unit/files/content_cache_rendered_haproxy_test_output_rate_limiting.txt
157new file mode 100644
158index 0000000..fa3404d
159--- /dev/null
160+++ b/tests/unit/files/content_cache_rendered_haproxy_test_output_rate_limiting.txt
161@@ -0,0 +1,95 @@
162+global
163+ nbthread 4
164+ maxconn 8192
165+ log /dev/log local0
166+ log /dev/log local1 notice
167+ chroot /var/lib/haproxy
168+ stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
169+ stats timeout 30s
170+ server-state-file /run/haproxy/saved-server-state
171+ user haproxy
172+ group haproxy
173+ daemon
174+
175+ # LP#1874386: Work around lingering HAProxy processes as per LP:1874386
176+ # and kill them off.
177+ hard-stop-after 15m
178+
179+ # Default SSL material locations
180+ ca-base /etc/ssl/certs
181+ crt-base /etc/ssl/private
182+
183+ # Default ciphers to use on SSL-enabled listening sockets.
184+ # For more information, see ciphers(1SSL). This list is from:
185+ # https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
186+ # An alternative list with additional directives can be obtained from
187+ # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
188+ ssl-default-bind-ciphers ECDHE+AESGCM:ECDHE+AES256:ECDHE+AES128:!SSLv3:!TLSv1
189+ ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
190+ # We'll eventually disable DHE (LP#1825321), but for now, bump DH params
191+ tune.ssl.default-dh-param 2048
192+
193+ # Increase the SSL/TLS session cache from the default 20k. But
194+ # rather than hardcode values, let's just set it to match
195+ # global_max_connections (which by default is calculated using
196+ # num. of CPU cores and num. of configured sites). Each entry
197+ # requires ~200 bytes so on a host with say 32 CPUs, 10 sites,
198+ # each with 2000 max conns will only consume around 122 Mbytes
199+ # (32 * 10 * 2000 * 200), which is not much.
200+ tune.ssl.cachesize 8192
201+
202+defaults
203+ log global
204+ maxconn 8192
205+ mode http
206+ option dontlognull
207+ timeout connect 5s
208+ timeout client 50s
209+ timeout server 50s
210+ errorfile 400 /etc/haproxy/errors/400.http
211+ errorfile 403 /etc/haproxy/errors/403.http
212+ errorfile 408 /etc/haproxy/errors/408.http
213+ errorfile 500 /etc/haproxy/errors/500.http
214+ errorfile 502 /etc/haproxy/errors/502.http
215+ errorfile 503 /etc/haproxy/errors/503.http
216+ errorfile 504 /etc/haproxy/errors/504.http
217+ load-server-state-from-file global
218+ unique-id-format %{+X}o\ %ci:%cp_%fi:%fp_%Ts_%rt:%pid
219+ unique-id-header X-Cache-Request-ID
220+ log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r %ID"
221+
222+resolvers dns
223+ nameserver dns1 127.0.0.53:53
224+ resolve_retries 3
225+ timeout resolve 3s
226+ timeout retry 3s
227+ accepted_payload_size 8192
228+
229+listen stats
230+ bind 127.0.0.1:10000
231+ acl allowed_cidr src 127.0.0.0/8
232+ http-request deny unless allowed_cidr
233+
234+ mode http
235+ stats enable
236+ stats uri /
237+ stats realm Haproxy\ Statistics
238+ stats auth haproxy:biometricsarenotsecret
239+ stats refresh 3
240+
241+
242+listen cached-site1-local
243+ bind 0.0.0.0:80
244+ bind :::80
245+ capture request header X-Cache-Request-ID len 60
246+ default_backend backend-cached-site1-local
247+
248+backend backend-cached-site1-local
249+ option httpchk GET /_status/content-cache-check HTTP/1.1\r\nHost:\ site1.local\r\nUser-Agent:\ haproxy/httpchk
250+ stick-table type ip size 1m expire 30s store http_req_rate(10s)
251+ http-request track-sc0 src
252+ http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
253+ http-request set-header Host site1.local
254+ http-request set-header X-Forwarded-For %[src]
255+ balance leastconn
256+ server server_1 127.0.0.1:6080 check inter 2s rise 2 fall 60 maxconn 200
257diff --git a/tests/unit/files/content_cache_rendered_haproxy_test_output_rate_limiting_missing_condition.txt b/tests/unit/files/content_cache_rendered_haproxy_test_output_rate_limiting_missing_condition.txt
258new file mode 100644
259index 0000000..037cd9f
260--- /dev/null
261+++ b/tests/unit/files/content_cache_rendered_haproxy_test_output_rate_limiting_missing_condition.txt
262@@ -0,0 +1,92 @@
263+global
264+ nbthread 4
265+ maxconn 8192
266+ log /dev/log local0
267+ log /dev/log local1 notice
268+ chroot /var/lib/haproxy
269+ stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
270+ stats timeout 30s
271+ server-state-file /run/haproxy/saved-server-state
272+ user haproxy
273+ group haproxy
274+ daemon
275+
276+ # LP#1874386: Work around lingering HAProxy processes as per LP:1874386
277+ # and kill them off.
278+ hard-stop-after 15m
279+
280+ # Default SSL material locations
281+ ca-base /etc/ssl/certs
282+ crt-base /etc/ssl/private
283+
284+ # Default ciphers to use on SSL-enabled listening sockets.
285+ # For more information, see ciphers(1SSL). This list is from:
286+ # https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
287+ # An alternative list with additional directives can be obtained from
288+ # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
289+ ssl-default-bind-ciphers ECDHE+AESGCM:ECDHE+AES256:ECDHE+AES128:!SSLv3:!TLSv1
290+ ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
291+ # We'll eventually disable DHE (LP#1825321), but for now, bump DH params
292+ tune.ssl.default-dh-param 2048
293+
294+ # Increase the SSL/TLS session cache from the default 20k. But
295+ # rather than hardcode values, let's just set it to match
296+ # global_max_connections (which by default is calculated using
297+ # num. of CPU cores and num. of configured sites). Each entry
298+ # requires ~200 bytes so on a host with say 32 CPUs, 10 sites,
299+ # each with 2000 max conns will only consume around 122 Mbytes
300+ # (32 * 10 * 2000 * 200), which is not much.
301+ tune.ssl.cachesize 8192
302+
303+defaults
304+ log global
305+ maxconn 8192
306+ mode http
307+ option dontlognull
308+ timeout connect 5s
309+ timeout client 50s
310+ timeout server 50s
311+ errorfile 400 /etc/haproxy/errors/400.http
312+ errorfile 403 /etc/haproxy/errors/403.http
313+ errorfile 408 /etc/haproxy/errors/408.http
314+ errorfile 500 /etc/haproxy/errors/500.http
315+ errorfile 502 /etc/haproxy/errors/502.http
316+ errorfile 503 /etc/haproxy/errors/503.http
317+ errorfile 504 /etc/haproxy/errors/504.http
318+ load-server-state-from-file global
319+ unique-id-format %{+X}o\ %ci:%cp_%fi:%fp_%Ts_%rt:%pid
320+ unique-id-header X-Cache-Request-ID
321+ log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r %ID"
322+
323+resolvers dns
324+ nameserver dns1 127.0.0.53:53
325+ resolve_retries 3
326+ timeout resolve 3s
327+ timeout retry 3s
328+ accepted_payload_size 8192
329+
330+listen stats
331+ bind 127.0.0.1:10000
332+ acl allowed_cidr src 127.0.0.0/8
333+ http-request deny unless allowed_cidr
334+
335+ mode http
336+ stats enable
337+ stats uri /
338+ stats realm Haproxy\ Statistics
339+ stats auth haproxy:biometricsarenotsecret
340+ stats refresh 3
341+
342+
343+listen cached-site1-local
344+ bind 0.0.0.0:80
345+ bind :::80
346+ capture request header X-Cache-Request-ID len 60
347+ default_backend backend-cached-site1-local
348+
349+backend backend-cached-site1-local
350+ option httpchk GET /_status/content-cache-check HTTP/1.1\r\nHost:\ site1.local\r\nUser-Agent:\ haproxy/httpchk
351+ http-request set-header Host site1.local
352+ http-request set-header X-Forwarded-For %[src]
353+ balance leastconn
354+ server server_1 127.0.0.1:6080 check inter 2s rise 2 fall 60 maxconn 200
355diff --git a/tests/unit/files/haproxy_config_rendered_backends_stanzas_test_output.txt b/tests/unit/files/haproxy_config_rendered_backends_stanzas_test_output.txt
356index bdb8064..565c469 100644
357--- a/tests/unit/files/haproxy_config_rendered_backends_stanzas_test_output.txt
358+++ b/tests/unit/files/haproxy_config_rendered_backends_stanzas_test_output.txt
359@@ -63,6 +63,9 @@ backend backend-site8-local-2
360
361 backend backend-site9-local
362 option httpchk HEAD / HTTP/1.1\r\nHost:\ site9.local\r\nUser-Agent:\ haproxy/httpchk
363+ stick-table type ip size 1m expire 30s store http_req_rate(10s)
364+ http-request track-sc0 src
365+ http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
366 http-request set-header Host site9.local
367 balance leastconn
368 server server_1 127.0.1.15:80 check inter 1m rise 2 fall 5 maxconn 200
369diff --git a/tests/unit/files/haproxy_config_rendered_test_output.txt b/tests/unit/files/haproxy_config_rendered_test_output.txt
370index 4f3e3a7..5020ee0 100644
371--- a/tests/unit/files/haproxy_config_rendered_test_output.txt
372+++ b/tests/unit/files/haproxy_config_rendered_test_output.txt
373@@ -172,6 +172,9 @@ backend backend-site8-local-2
374
375 backend backend-site9-local
376 option httpchk HEAD / HTTP/1.1\r\nHost:\ site9.local\r\nUser-Agent:\ haproxy/httpchk
377+ stick-table type ip size 1m expire 30s store http_req_rate(10s)
378+ http-request track-sc0 src
379+ http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
380 http-request set-header Host site9.local
381 balance leastconn
382 server server_1 127.0.1.15:80 check inter 1m rise 2 fall 5 maxconn 200
383diff --git a/tests/unit/files/haproxy_config_rendered_test_output2.txt b/tests/unit/files/haproxy_config_rendered_test_output2.txt
384index 0020879..4071e23 100644
385--- a/tests/unit/files/haproxy_config_rendered_test_output2.txt
386+++ b/tests/unit/files/haproxy_config_rendered_test_output2.txt
387@@ -172,6 +172,9 @@ backend backend-site8-local-2
388
389 backend backend-site9-local
390 option httpchk HEAD / HTTP/1.1\r\nHost:\ site9.local\r\nUser-Agent:\ haproxy/httpchk
391+ stick-table type ip size 1m expire 30s store http_req_rate(10s)
392+ http-request track-sc0 src
393+ http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
394 http-request set-header Host site9.local
395 balance leastconn
396 server server_1 127.0.1.15:80 check inter 1m rise 2 fall 5 maxconn 200
397diff --git a/tests/unit/test_content_cache.py b/tests/unit/test_content_cache.py
398index f5f32a2..41e098c 100644
399--- a/tests/unit/test_content_cache.py
400+++ b/tests/unit/test_content_cache.py
401@@ -685,6 +685,59 @@ site1.local:
402 @mock.patch('charms.reactive.set_flag')
403 @mock.patch('lib.haproxy.HAProxyConf.save_server_state')
404 @mock.patch('reactive.content_cache.update_logrotate')
405+ def test_configure_haproxy_sites_rate_limiting(self, logrotation, save_s_state, set_flag, opened_ports):
406+ config = '''
407+site1.local:
408+ locations:
409+ /:
410+ rate-limit:
411+ condition: "{ sc_http_req_rate(0) gt 20 }"
412+ sticky-table: "type ip size 1m expire 30s store http_req_rate(10s)"
413+ track: "src"
414+'''
415+ self.mock_config.return_value = {'haproxy_hard_stop_after': '15m', 'max_connections': 8192, 'sites': config}
416+ with mock.patch('lib.haproxy.HAProxyConf.conf_file', new_callable=mock.PropertyMock) as mock_conf_file:
417+ mock_conf_file.return_value = os.path.join(self.tmpdir, 'haproxy.cfg')
418+ opened_ports.return_value = ['443/tcp']
419+ content_cache.configure_haproxy()
420+
421+ with open(
422+ 'tests/unit/files/content_cache_rendered_haproxy_test_output_rate_limiting.txt', 'r', encoding='utf-8'
423+ ) as f:
424+ want = f.read()
425+ with open(os.path.join(self.tmpdir, 'haproxy.cfg'), 'r', encoding='utf-8') as f:
426+ got = f.read()
427+ self.assertEqual(got, want)
428+
429+ # Missing 'condition'
430+ config = '''
431+site1.local:
432+ locations:
433+ /:
434+ rate-limit:
435+ sticky-table: "type ip size 1m expire 30s store http_req_rate(10s)"
436+'''
437+ self.mock_config.return_value = {'haproxy_hard_stop_after': '15m', 'max_connections': 8192, 'sites': config}
438+ with mock.patch('lib.haproxy.HAProxyConf.conf_file', new_callable=mock.PropertyMock) as mock_conf_file:
439+ mock_conf_file.return_value = os.path.join(self.tmpdir, 'haproxy.cfg')
440+ opened_ports.return_value = ['443/tcp']
441+ content_cache.configure_haproxy()
442+
443+ with open(
444+ 'tests/unit/files/content_cache_rendered_haproxy_test_output_rate_limiting_missing_condition.txt',
445+ 'r',
446+ encoding='utf-8',
447+ ) as f:
448+ want = f.read()
449+ with open(os.path.join(self.tmpdir, 'haproxy.cfg'), 'r', encoding='utf-8') as f:
450+ got = f.read()
451+ self.assertEqual(got, want)
452+
453+ @freezegun.freeze_time("2019-03-22", tz_offset=0)
454+ @mock.patch('charmhelpers.core.hookenv.opened_ports')
455+ @mock.patch('charms.reactive.set_flag')
456+ @mock.patch('lib.haproxy.HAProxyConf.save_server_state')
457+ @mock.patch('reactive.content_cache.update_logrotate')
458 def test_configure_haproxy_processes_and_threads(self, logrotation, save_server_state, set_flag, opened_ports):
459 with open('tests/unit/files/config_test_config.txt', 'r', encoding='utf-8') as f:
460 ngx_config = f.read()

Subscribers

People subscribed via source and target branches