Merge ~hloeung/content-cache-charm:add-haproxy-v2 into content-cache-charm:master
- Git
- lp:~hloeung/content-cache-charm
- add-haproxy-v2
- Merge into master
Proposed by
Haw Loeung
Status: | Merged |
---|---|
Approved by: | Haw Loeung |
Approved revision: | d63023e1646c17171c11c8962d77739d858d7105 |
Merged at revision: | 16f2684a0ce7bf2bb03dc31d968e951f18161865 |
Proposed branch: | ~hloeung/content-cache-charm:add-haproxy-v2 |
Merge into: | content-cache-charm:master |
Diff against target: |
491 lines (+385/-5) 10 files modified
layer.yaml (+1/-0) lib/haproxy.py (+100/-0) reactive/content_cache.py (+8/-1) templates/haproxy_cfg.tmpl (+46/-0) tests/unit/files/config_test_config.txt (+23/-0) tests/unit/files/haproxy_config_rendered_backends_stanzas_test_output.txt (+24/-0) tests/unit/files/haproxy_config_rendered_listen_stanzas_test_output.txt (+12/-0) tests/unit/files/haproxy_config_rendered_test_output.txt (+75/-0) tests/unit/test_content_cache.py (+24/-4) tests/unit/test_haproxy.py (+72/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Joel Sing (community) | +1 | Approve | |
Haw Loeung | Pending | ||
Canonical IS Reviewers | Pending | ||
Review via email: mp+364417@code.launchpad.net |
This proposal supersedes a proposal from 2019-03-11.
Commit message
Add HAProxy configuration generation and service start/restart
Description of the change
To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : Posted in a previous version of this proposal | # |
Revision history for this message
Joel Sing (jsing) wrote : Posted in a previous version of this proposal | # |
Generally looks good - handful of mostly minor things to address.
review:
Needs Fixing
Revision history for this message
Haw Loeung (hloeung) : Posted in a previous version of this proposal | # |
Revision history for this message
Haw Loeung (hloeung) wrote : Posted in a previous version of this proposal | # |
New MP with fixes and this as a pre-req - https:/
Revision history for this message
Haw Loeung (hloeung) : Posted in a previous version of this proposal | # |
review:
Needs Resubmitting
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
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Change successfully merged at revision 16f2684a0ce7bf2
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/layer.yaml b/layer.yaml |
2 | index 253b93a..d102da7 100644 |
3 | --- a/layer.yaml |
4 | +++ b/layer.yaml |
5 | @@ -9,3 +9,4 @@ options: |
6 | packages: |
7 | - haproxy |
8 | - nginx |
9 | + - python3-jinja2 |
10 | diff --git a/lib/haproxy.py b/lib/haproxy.py |
11 | new file mode 100644 |
12 | index 0000000..a64f3af |
13 | --- /dev/null |
14 | +++ b/lib/haproxy.py |
15 | @@ -0,0 +1,100 @@ |
16 | +import os |
17 | + |
18 | +import jinja2 |
19 | + |
20 | + |
21 | +HAPROXY_BASE_PATH = '/etc/haproxy' |
22 | +INDENT = ' '*4 |
23 | + |
24 | + |
25 | +class HAProxyConf: |
26 | + |
27 | + def __init__(self, conf_path=HAPROXY_BASE_PATH): |
28 | + self._conf_path = conf_path |
29 | + |
30 | + @property |
31 | + def conf_path(self): |
32 | + return self._conf_path |
33 | + |
34 | + @property |
35 | + def conf_file(self): |
36 | + return os.path.join(self._conf_path, 'haproxy.cfg') |
37 | + |
38 | + def _generate_stanza_name(self, name): |
39 | + return name.replace('.', '-')[0:32] |
40 | + |
41 | + def render_stanza_listen(self, config): |
42 | + listen_stanza = """ |
43 | +listen {name} |
44 | +{indent}bind 0.0.0.0:{port}{tls} |
45 | +{indent}default_backend cached-{name} |
46 | +""" |
47 | + rendered_output = [] |
48 | + for site in config.keys(): |
49 | + default_port = 80 |
50 | + tls_config = '' |
51 | + |
52 | + tls_cert_bundle_path = config[site].get('tls-cert-bundle-path') |
53 | + if tls_cert_bundle_path: |
54 | + default_port = 443 |
55 | + tls_config = ' ssl crt {}'.format(tls_cert_bundle_path) |
56 | + |
57 | + port = config[site].get('port', default_port) |
58 | + |
59 | + output = listen_stanza.format(name=self._generate_stanza_name(site), |
60 | + port=port, tls=tls_config, indent=INDENT) |
61 | + rendered_output.append(output) |
62 | + |
63 | + return rendered_output |
64 | + |
65 | + def render_stanza_backend(self, config): |
66 | + backend_stanza = """ |
67 | +backend cached-{name} |
68 | +{indent}option httpchk HEAD / HTTP/1.0\\r\\nHost:\\ {site}\\r\\nUser-Agent:\\ haproxy/httpchk |
69 | +{indent}http-request set-header Host {site} |
70 | +{indent}balance leastconn |
71 | +{backends} |
72 | +""" |
73 | + rendered_output = [] |
74 | + for site in config.keys(): |
75 | + tls_config = '' |
76 | + if config[site].get('backend-tls'): |
77 | + tls_config = ' ssl sni str({site}) check-sni {site} verify required ca-file ca-certificates.crt' \ |
78 | + .format(site=site) |
79 | + backends = [] |
80 | + count = 0 |
81 | + for backend in config[site]['backends']: |
82 | + count += 1 |
83 | + name = 'server_{}'.format(count) |
84 | + backends.append('{indent}server {name} {backend} check inter 5000 rise 2 fall 5 maxconn 16{tls}' |
85 | + .format(name=name, backend=backend, tls=tls_config, indent=INDENT)) |
86 | + |
87 | + output = backend_stanza.format(name=self._generate_stanza_name(site), |
88 | + site=site, backends='\n'.join(backends), indent=INDENT) |
89 | + |
90 | + rendered_output.append(output) |
91 | + |
92 | + return rendered_output |
93 | + |
94 | + def render(self, config, num_procs): |
95 | + base = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) |
96 | + env = jinja2.Environment(loader=jinja2.FileSystemLoader(base)) |
97 | + template = env.get_template('templates/haproxy_cfg.tmpl') |
98 | + return template.render({ |
99 | + 'listen': self.render_stanza_listen(config), |
100 | + 'backend': self.render_stanza_backend(config), |
101 | + 'num_procs': num_procs, |
102 | + }) |
103 | + |
104 | + def write(self, content): |
105 | + # Check if contents changed |
106 | + try: |
107 | + with open(self.conf_file, 'r', encoding='utf-8') as f: |
108 | + current = f.read() |
109 | + except FileNotFoundError: |
110 | + current = '' |
111 | + if content == current: |
112 | + return False |
113 | + with open(self.conf_file, 'w', encoding='utf-8') as f: |
114 | + f.write(content) |
115 | + return True |
116 | diff --git a/reactive/content_cache.py b/reactive/content_cache.py |
117 | index d620521..78f6933 100644 |
118 | --- a/reactive/content_cache.py |
119 | +++ b/reactive/content_cache.py |
120 | @@ -1,9 +1,12 @@ |
121 | +import multiprocessing |
122 | import yaml |
123 | |
124 | from charms import reactive |
125 | from charms.layer import status |
126 | from charmhelpers.core import hookenv, host |
127 | + |
128 | from lib import nginx |
129 | +from lib import haproxy as HAProxy |
130 | |
131 | |
132 | @reactive.hook('upgrade-charm') |
133 | @@ -81,6 +84,10 @@ def configure_haproxy(): |
134 | reactive.clear_flag('content_cache.active') |
135 | return |
136 | |
137 | - # TODO: Configure up and start/restart HAProxy |
138 | + haproxy = HAProxy.HAProxyConf() |
139 | + num_procs = multiprocessing.cpu_count() |
140 | + conf = yaml.safe_load(config.get('sites')) |
141 | + if haproxy.write(haproxy.render(conf, num_procs)): |
142 | + service_start_or_restart('haproxy') |
143 | |
144 | reactive.set_flag('content_cache.haproxy.configured') |
145 | diff --git a/templates/haproxy_cfg.tmpl b/templates/haproxy_cfg.tmpl |
146 | new file mode 100644 |
147 | index 0000000..e6d367f |
148 | --- /dev/null |
149 | +++ b/templates/haproxy_cfg.tmpl |
150 | @@ -0,0 +1,46 @@ |
151 | +global |
152 | + nbproc {{num_procs}} |
153 | + log /dev/log local0 |
154 | + log /dev/log local1 notice |
155 | + chroot /var/lib/haproxy |
156 | + stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners |
157 | + stats timeout 30s |
158 | + user haproxy |
159 | + group haproxy |
160 | + daemon |
161 | + |
162 | + # Default SSL material locations |
163 | + ca-base /etc/ssl/certs |
164 | + crt-base /etc/ssl/private |
165 | + |
166 | + # Default ciphers to use on SSL-enabled listening sockets. |
167 | + # For more information, see ciphers(1SSL). This list is from: |
168 | + # https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ |
169 | + # An alternative list with additional directives can be obtained from |
170 | + # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy |
171 | + ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS |
172 | + ssl-default-bind-options no-sslv3 |
173 | + |
174 | +defaults |
175 | + log global |
176 | + mode http |
177 | + option httplog |
178 | + option dontlognull |
179 | + timeout connect 5000 |
180 | + timeout client 50000 |
181 | + timeout server 50000 |
182 | + errorfile 400 /etc/haproxy/errors/400.http |
183 | + errorfile 403 /etc/haproxy/errors/403.http |
184 | + errorfile 408 /etc/haproxy/errors/408.http |
185 | + errorfile 500 /etc/haproxy/errors/500.http |
186 | + errorfile 502 /etc/haproxy/errors/502.http |
187 | + errorfile 503 /etc/haproxy/errors/503.http |
188 | + errorfile 504 /etc/haproxy/errors/504.http |
189 | + |
190 | +{% for stanza in listen -%} |
191 | +{{stanza}} |
192 | +{%- endfor -%} |
193 | + |
194 | +{% for stanza in backend -%} |
195 | +{{stanza}} |
196 | +{%- endfor -%} |
197 | diff --git a/tests/unit/files/config_test_config.txt b/tests/unit/files/config_test_config.txt |
198 | new file mode 100644 |
199 | index 0000000..b27ec91 |
200 | --- /dev/null |
201 | +++ b/tests/unit/files/config_test_config.txt |
202 | @@ -0,0 +1,23 @@ |
203 | +# Test 1: The basic port and backends (HTTP) |
204 | +site1.local: |
205 | + port: 80 |
206 | + backends: |
207 | + - 127.0.1.10:80 |
208 | + - 127.0.1.11:80 |
209 | + - 127.0.1.12:80 |
210 | + |
211 | +# Test 2: TLS/SSL as well as backends (HTTPS) |
212 | +site2.local: |
213 | + tls-cert-bundle-path: /etc/haproxy/some-bundle.crt |
214 | + backend-tls: True |
215 | + backends: |
216 | + - 127.0.1.10:443 |
217 | + - 127.0.1.11:443 |
218 | + - 127.0.1.12:443 |
219 | + |
220 | +# Test 3: No port, just backends (HTTP) |
221 | +site3.local: |
222 | + backends: |
223 | + - 127.0.1.10:80 |
224 | + - 127.0.1.11:80 |
225 | + - 127.0.1.12:80 |
226 | diff --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 |
227 | new file mode 100644 |
228 | index 0000000..6b76e4e |
229 | --- /dev/null |
230 | +++ b/tests/unit/files/haproxy_config_rendered_backends_stanzas_test_output.txt |
231 | @@ -0,0 +1,24 @@ |
232 | + |
233 | +backend cached-site1-local |
234 | + option httpchk HEAD / HTTP/1.0\r\nHost:\ site1.local\r\nUser-Agent:\ haproxy/httpchk |
235 | + http-request set-header Host site1.local |
236 | + balance leastconn |
237 | + server server_1 127.0.1.10:80 check inter 5000 rise 2 fall 5 maxconn 16 |
238 | + server server_2 127.0.1.11:80 check inter 5000 rise 2 fall 5 maxconn 16 |
239 | + server server_3 127.0.1.12:80 check inter 5000 rise 2 fall 5 maxconn 16 |
240 | + |
241 | +backend cached-site2-local |
242 | + option httpchk HEAD / HTTP/1.0\r\nHost:\ site2.local\r\nUser-Agent:\ haproxy/httpchk |
243 | + http-request set-header Host site2.local |
244 | + balance leastconn |
245 | + server server_1 127.0.1.10:443 check inter 5000 rise 2 fall 5 maxconn 16 ssl sni str(site2.local) check-sni site2.local verify required ca-file ca-certificates.crt |
246 | + server server_2 127.0.1.11:443 check inter 5000 rise 2 fall 5 maxconn 16 ssl sni str(site2.local) check-sni site2.local verify required ca-file ca-certificates.crt |
247 | + server server_3 127.0.1.12:443 check inter 5000 rise 2 fall 5 maxconn 16 ssl sni str(site2.local) check-sni site2.local verify required ca-file ca-certificates.crt |
248 | + |
249 | +backend cached-site3-local |
250 | + option httpchk HEAD / HTTP/1.0\r\nHost:\ site3.local\r\nUser-Agent:\ haproxy/httpchk |
251 | + http-request set-header Host site3.local |
252 | + balance leastconn |
253 | + server server_1 127.0.1.10:80 check inter 5000 rise 2 fall 5 maxconn 16 |
254 | + server server_2 127.0.1.11:80 check inter 5000 rise 2 fall 5 maxconn 16 |
255 | + server server_3 127.0.1.12:80 check inter 5000 rise 2 fall 5 maxconn 16 |
256 | diff --git a/tests/unit/files/haproxy_config_rendered_listen_stanzas_test_output.txt b/tests/unit/files/haproxy_config_rendered_listen_stanzas_test_output.txt |
257 | new file mode 100644 |
258 | index 0000000..e60ae6c |
259 | --- /dev/null |
260 | +++ b/tests/unit/files/haproxy_config_rendered_listen_stanzas_test_output.txt |
261 | @@ -0,0 +1,12 @@ |
262 | + |
263 | +listen site1-local |
264 | + bind 0.0.0.0:80 |
265 | + default_backend cached-site1-local |
266 | + |
267 | +listen site2-local |
268 | + bind 0.0.0.0:443 ssl crt /etc/haproxy/some-bundle.crt |
269 | + default_backend cached-site2-local |
270 | + |
271 | +listen site3-local |
272 | + bind 0.0.0.0:80 |
273 | + default_backend cached-site3-local |
274 | diff --git a/tests/unit/files/haproxy_config_rendered_test_output.txt b/tests/unit/files/haproxy_config_rendered_test_output.txt |
275 | new file mode 100644 |
276 | index 0000000..71954ac |
277 | --- /dev/null |
278 | +++ b/tests/unit/files/haproxy_config_rendered_test_output.txt |
279 | @@ -0,0 +1,75 @@ |
280 | +global |
281 | + nbproc 4 |
282 | + log /dev/log local0 |
283 | + log /dev/log local1 notice |
284 | + chroot /var/lib/haproxy |
285 | + stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners |
286 | + stats timeout 30s |
287 | + user haproxy |
288 | + group haproxy |
289 | + daemon |
290 | + |
291 | + # Default SSL material locations |
292 | + ca-base /etc/ssl/certs |
293 | + crt-base /etc/ssl/private |
294 | + |
295 | + # Default ciphers to use on SSL-enabled listening sockets. |
296 | + # For more information, see ciphers(1SSL). This list is from: |
297 | + # https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ |
298 | + # An alternative list with additional directives can be obtained from |
299 | + # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy |
300 | + ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS |
301 | + ssl-default-bind-options no-sslv3 |
302 | + |
303 | +defaults |
304 | + log global |
305 | + mode http |
306 | + option httplog |
307 | + option dontlognull |
308 | + timeout connect 5000 |
309 | + timeout client 50000 |
310 | + timeout server 50000 |
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 | + |
319 | + |
320 | +listen site1-local |
321 | + bind 0.0.0.0:80 |
322 | + default_backend cached-site1-local |
323 | + |
324 | +listen site2-local |
325 | + bind 0.0.0.0:443 ssl crt /etc/haproxy/some-bundle.crt |
326 | + default_backend cached-site2-local |
327 | + |
328 | +listen site3-local |
329 | + bind 0.0.0.0:80 |
330 | + default_backend cached-site3-local |
331 | + |
332 | +backend cached-site1-local |
333 | + option httpchk HEAD / HTTP/1.0\r\nHost:\ site1.local\r\nUser-Agent:\ haproxy/httpchk |
334 | + http-request set-header Host site1.local |
335 | + balance leastconn |
336 | + server server_1 127.0.1.10:80 check inter 5000 rise 2 fall 5 maxconn 16 |
337 | + server server_2 127.0.1.11:80 check inter 5000 rise 2 fall 5 maxconn 16 |
338 | + server server_3 127.0.1.12:80 check inter 5000 rise 2 fall 5 maxconn 16 |
339 | + |
340 | +backend cached-site2-local |
341 | + option httpchk HEAD / HTTP/1.0\r\nHost:\ site2.local\r\nUser-Agent:\ haproxy/httpchk |
342 | + http-request set-header Host site2.local |
343 | + balance leastconn |
344 | + server server_1 127.0.1.10:443 check inter 5000 rise 2 fall 5 maxconn 16 ssl sni str(site2.local) check-sni site2.local verify required ca-file ca-certificates.crt |
345 | + server server_2 127.0.1.11:443 check inter 5000 rise 2 fall 5 maxconn 16 ssl sni str(site2.local) check-sni site2.local verify required ca-file ca-certificates.crt |
346 | + server server_3 127.0.1.12:443 check inter 5000 rise 2 fall 5 maxconn 16 ssl sni str(site2.local) check-sni site2.local verify required ca-file ca-certificates.crt |
347 | + |
348 | +backend cached-site3-local |
349 | + option httpchk HEAD / HTTP/1.0\r\nHost:\ site3.local\r\nUser-Agent:\ haproxy/httpchk |
350 | + http-request set-header Host site3.local |
351 | + balance leastconn |
352 | + server server_1 127.0.1.10:80 check inter 5000 rise 2 fall 5 maxconn 16 |
353 | + server server_2 127.0.1.11:80 check inter 5000 rise 2 fall 5 maxconn 16 |
354 | + server server_3 127.0.1.12:80 check inter 5000 rise 2 fall 5 maxconn 16 |
355 | diff --git a/tests/unit/test_content_cache.py b/tests/unit/test_content_cache.py |
356 | index 2366df8..618e3cd 100644 |
357 | --- a/tests/unit/test_content_cache.py |
358 | +++ b/tests/unit/test_content_cache.py |
359 | @@ -5,12 +5,13 @@ import tempfile |
360 | import unittest |
361 | from unittest import mock |
362 | |
363 | -# Add path to where our reactive layer lives and import. |
364 | -sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))) |
365 | # We also need to mock up charms.layer so we can run unit tests without having |
366 | # to build the charm and pull in layers such as layer-status. |
367 | sys.modules['charms.layer'] = mock.MagicMock() |
368 | + |
369 | from charms.layer import status # NOQA: E402 |
370 | +# Add path to where our reactive layer lives and import. |
371 | +sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))) |
372 | from reactive import content_cache # NOQA: E402 |
373 | |
374 | |
375 | @@ -41,6 +42,11 @@ class TestCharm(unittest.TestCase): |
376 | self.addCleanup(patcher.stop) |
377 | self.mock_config.return_value = {} |
378 | |
379 | + patcher = mock.patch('multiprocessing.cpu_count') |
380 | + self.mock_cpu_count = patcher.start() |
381 | + self.addCleanup(patcher.stop) |
382 | + self.mock_cpu_count.return_value = 4 |
383 | + |
384 | @mock.patch('charms.reactive.clear_flag') |
385 | def test_hook_upgrade_charm_flags(self, clear_flag): |
386 | '''Test correct flags set via upgrade-charm hook''' |
387 | @@ -142,10 +148,24 @@ class TestCharm(unittest.TestCase): |
388 | |
389 | @mock.patch('reactive.content_cache.service_start_or_restart') |
390 | def test_configure_haproxy_sites(self, service_start_or_restart): |
391 | - with open('tests/unit/files/nginx_config_test_config.txt', 'r', encoding='utf-8') as f: |
392 | + with open('tests/unit/files/config_test_config.txt', 'r', encoding='utf-8') as f: |
393 | ngx_config = f.read() |
394 | self.mock_config.return_value = {'sites': ngx_config} |
395 | - content_cache.configure_haproxy() |
396 | + |
397 | + with open('tests/unit/files/haproxy_config_rendered_test_output.txt', 'r', encoding='utf-8') as f: |
398 | + expected = f.read() |
399 | + with mock.patch('lib.haproxy.HAProxyConf.conf_file', new_callable=mock.PropertyMock) as mock_conf_file: |
400 | + mock_conf_file.return_value = os.path.join(self.tmpdir, 'haproxy.cfg') |
401 | + content_cache.configure_haproxy() |
402 | + with open(os.path.join(self.tmpdir, 'haproxy.cfg'), 'r', encoding='utf-8') as f: |
403 | + current = f.read() |
404 | + self.assertEqual(expected, current) |
405 | + self.assertFalse(service_start_or_restart.assert_called_with('haproxy')) |
406 | + |
407 | + # Again, this time should be no change so no need to restart HAProxy |
408 | + service_start_or_restart.reset_mock() |
409 | + content_cache.configure_haproxy() |
410 | + self.assertFalse(service_start_or_restart.assert_not_called()) |
411 | |
412 | |
413 | if __name__ == '__main__': |
414 | diff --git a/tests/unit/test_haproxy.py b/tests/unit/test_haproxy.py |
415 | new file mode 100644 |
416 | index 0000000..19025a3 |
417 | --- /dev/null |
418 | +++ b/tests/unit/test_haproxy.py |
419 | @@ -0,0 +1,72 @@ |
420 | +import os |
421 | +import shutil |
422 | +import sys |
423 | +import tempfile |
424 | +import unittest |
425 | +import yaml |
426 | + |
427 | +sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))) |
428 | +from lib import haproxy as HAProxy # NOQA: E402 |
429 | + |
430 | + |
431 | +class TestLibHAProxy(unittest.TestCase): |
432 | + def setUp(self): |
433 | + self.maxDiff = None |
434 | + self.tmpdir = tempfile.mkdtemp(prefix='charm-unittests-') |
435 | + self.addCleanup(shutil.rmtree, self.tmpdir) |
436 | + self.charm_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) |
437 | + with open('tests/unit/files/config_test_config.txt', 'r', encoding='utf-8') as f: |
438 | + self.site_config = yaml.safe_load(f.read()) |
439 | + |
440 | + def test_haproxy_config_path(self): |
441 | + conf_path = '/etc/haproxy' |
442 | + haproxy = HAProxy.HAProxyConf() |
443 | + self.assertEqual(haproxy.conf_path, conf_path) |
444 | + |
445 | + def test_haproxy_config_file(self): |
446 | + conf_file = '/etc/haproxy/haproxy.cfg' |
447 | + haproxy = HAProxy.HAProxyConf() |
448 | + self.assertEqual(haproxy.conf_file, conf_file) |
449 | + |
450 | + def test_haproxy_config_generate_stanza_names(self): |
451 | + haproxy = HAProxy.HAProxyConf(self.tmpdir) |
452 | + self.assertEqual(haproxy._generate_stanza_name('site1'), 'site1') |
453 | + self.assertEqual(haproxy._generate_stanza_name('site1.local'), 'site1-local') |
454 | + self.assertEqual(haproxy._generate_stanza_name('site1-canonical-com-canonical-com'), |
455 | + 'site1-canonical-com-canonical-co') |
456 | + |
457 | + def test_haproxy_config_rendered_listen_stanzas(self): |
458 | + haproxy = HAProxy.HAProxyConf(self.tmpdir) |
459 | + config = self.site_config |
460 | + with open('tests/unit/files/haproxy_config_rendered_listen_stanzas_test_output.txt', 'r', |
461 | + encoding='utf-8') as f: |
462 | + expected = f.read() |
463 | + self.assertEqual(''.join(haproxy.render_stanza_listen(config)), expected) |
464 | + |
465 | + def test_haproxy_config_rendered_backend_stanzas(self): |
466 | + haproxy = HAProxy.HAProxyConf(self.tmpdir) |
467 | + config = self.site_config |
468 | + with open('tests/unit/files/haproxy_config_rendered_backends_stanzas_test_output.txt', 'r', |
469 | + encoding='utf-8') as f: |
470 | + expected = f.read() |
471 | + self.assertEqual(''.join(haproxy.render_stanza_backend(config)), expected) |
472 | + |
473 | + def test_haproxy_config_rendered_full_config(self): |
474 | + haproxy = HAProxy.HAProxyConf(self.tmpdir) |
475 | + config = self.site_config |
476 | + num_procs = 4 |
477 | + self.assertTrue(haproxy.write(haproxy.render(config, num_procs))) |
478 | + with open(haproxy.conf_file, 'r') as f: |
479 | + new_conf = f.read() |
480 | + with open('tests/unit/files/haproxy_config_rendered_test_output.txt', 'r') as f: |
481 | + expected = f.read() |
482 | + self.assertEqual(new_conf, expected) |
483 | + |
484 | + def test_haproxy_config_write(self): |
485 | + haproxy = HAProxy.HAProxyConf(self.tmpdir) |
486 | + with open('tests/unit/files/haproxy_config_rendered_test_output.txt', 'r', encoding='utf-8') as f: |
487 | + conf = f.read() |
488 | + self.assertTrue(haproxy.write(conf)) |
489 | + # Write again with same contents, this time it should return 'False' |
490 | + # as there should be no change. |
491 | + self.assertFalse(haproxy.write(conf)) |
This merge proposal is being monitored by mergebot. Change the status to Approved to merge.