Merge lp:~sidnei/charms/precise/squid-reverseproxy/trunk into lp:charms/squid-reverseproxy
- Precise Pangolin (12.04)
- trunk
- Merge into trunk
Proposed by
Sidnei da Silva
Status: | Merged |
---|---|
Merged at revision: | 45 |
Proposed branch: | lp:~sidnei/charms/precise/squid-reverseproxy/trunk |
Merge into: | lp:charms/squid-reverseproxy |
Diff against target: |
405 lines (+193/-5) 6 files modified
README.md (+13/-0) config.yaml (+33/-3) hooks/hooks.py (+22/-1) hooks/tests/test_helpers.py (+93/-1) hooks/tests/test_nrpe_hooks.py (+22/-0) templates/main_config.template (+10/-0) |
To merge this branch: | bzr merge lp:~sidnei/charms/precise/squid-reverseproxy/trunk |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
David Lawson (community) | Approve | ||
Review via email: mp+198451@code.launchpad.net |
Commit message
- If there's a query string in the check path, use a GET instead of HEAD request
- If cache_size_mb is set to 0, only disable disk cache but still leave memory cache.
- Expose 'via' config setting, default to on.
Description of the change
- If there's a query string in the check path, use a GET instead of HEAD request
- If cache_size_mb is set to 0, only disable disk cache but still leave memory cache.
- Expose 'via' config setting, default to on.
To post a comment you must log in.
- 44. By Sidnei da Silva
-
Merge from alexlist's https support branch
- 45. By Sidnei da Silva
-
- Merge from trunk
Revision history for this message
David Lawson (deej) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'README.md' |
2 | --- README.md 2013-02-15 07:00:58 +0000 |
3 | +++ README.md 2013-12-10 20:23:01 +0000 |
4 | @@ -63,6 +63,19 @@ |
5 | The options that can be configured in config.yaml should be self-explanatory. |
6 | If not, please file a bug against this charm. |
7 | |
8 | +## HTTPS Reverse Proxying |
9 | + |
10 | +Assuming you have a squid3 deb compiled with --enable-ssl, you can setup a |
11 | +single https reverse proxy. |
12 | + |
13 | +An example of this would be: |
14 | + |
15 | + juju set squid-reverseproxy enable_https=true ssl_key="$(base64 < /path/to/cert.key)" ssl_cert="$(base64 < /path/to/cert.crt)" |
16 | + |
17 | +This should enable https access to the default website. |
18 | + |
19 | +A current implementation limitation is that it doesn't support multiple https vhosts. |
20 | + |
21 | ## Monitoring |
22 | |
23 | This charm provides relations that support monitoring via Nagios using |
24 | |
25 | === modified file 'config.yaml' |
26 | --- config.yaml 2013-10-29 16:56:23 +0000 |
27 | +++ config.yaml 2013-12-10 20:23:01 +0000 |
28 | @@ -5,8 +5,36 @@ |
29 | description: Squid listening port. |
30 | port_options: |
31 | type: string |
32 | - default: accel vhost |
33 | + default: 'accel vhost' |
34 | description: Squid listening port options |
35 | + enable_https: |
36 | + type: boolean |
37 | + default: false |
38 | + description: Enable https access for squid, requires a squid compiled with --enable-ssl, certificate and private key |
39 | + https_port: |
40 | + type: int |
41 | + default: 443 |
42 | + description: Squid https listening port |
43 | + https_options: |
44 | + type: string |
45 | + default: 'accel vhost' |
46 | + description: Options for https port |
47 | + ssl_keyfile: |
48 | + type: string |
49 | + default: '/etc/squid3/ssl/cert.key' |
50 | + description: File path to ssl key file inside deployed units |
51 | + ssl_certfile: |
52 | + type: string |
53 | + default: '/etc/squid3/ssl/cert.crt' |
54 | + description: File path to ssl cert file inside deployed units |
55 | + ssl_key: |
56 | + type: string |
57 | + default: '' |
58 | + description: Base64 encoded ssl key file |
59 | + ssl_cert: |
60 | + type: string |
61 | + default: '' |
62 | + description: Base64 encoded ssl cert file |
63 | log_format: |
64 | type: string |
65 | default: '%>a %ui %un [%tl] "%rm %ru HTTP/%rv" %>Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh' |
66 | @@ -22,11 +50,13 @@ |
67 | cache_mem_mb: |
68 | type: int |
69 | default: 256 |
70 | - description: Maximum size of in-memory object cache (MB). Should be smaller than cache_size_mb. |
71 | + description: > |
72 | + Maximum size of in-memory object cache (MB). Should be smaller than |
73 | + cache_size_mb. Set to zero to disable caching completely. |
74 | cache_size_mb: |
75 | type: int |
76 | default: 512 |
77 | - description: Maximum size of the on-disk object cache (MB). Set to zero to disable caching. |
78 | + description: Maximum size of the on-disk object cache (MB). Set to zero to disable disk caching. |
79 | cache_dir: |
80 | type: string |
81 | default: '/var/spool/squid3' |
82 | |
83 | === added directory 'exec.d' |
84 | === modified file 'hooks/hooks.py' |
85 | --- hooks/hooks.py 2013-10-29 17:37:20 +0000 |
86 | +++ hooks/hooks.py 2013-12-10 20:23:01 +0000 |
87 | @@ -256,6 +256,26 @@ |
88 | write_squid3_config('\n'.join( |
89 | (l.strip() for l in str(template).splitlines()))) |
90 | |
91 | + # If we have https, write out ssl key and cert file |
92 | + if config_data.get('enable_https'): |
93 | + from base64 import b64decode |
94 | + if config_data.get('ssl_key') is not None: |
95 | + ssl_keyfile = config_data['ssl_keyfile'] |
96 | + ssl_keyfile_dir = os.path.dirname(os.path.realpath(ssl_keyfile)) |
97 | + if not os.path.exists(ssl_keyfile_dir): |
98 | + os.makedirs(ssl_keyfile_dir) |
99 | + ssl_key = config_data['ssl_key'] |
100 | + with open(ssl_keyfile, 'w') as ssl_key_path: |
101 | + ssl_key_path.write(str(b64decode(ssl_key))) |
102 | + if config_data.get('ssl_cert') is not None: |
103 | + ssl_certfile = config_data['ssl_certfile'] |
104 | + ssl_certfile_dir = os.path.dirname(ssl_certfile) |
105 | + if not os.path.exists(ssl_certfile_dir): |
106 | + os.makedirs(ssl_certfile_dir) |
107 | + ssl_cert = config_data['ssl_cert'] |
108 | + with open(ssl_certfile, 'w') as ssl_cert_path: |
109 | + ssl_cert_path.write(str(b64decode(ssl_cert))) |
110 | + |
111 | |
112 | def write_squid3_config(contents): |
113 | with open(default_squid3_config, 'w') as squid3_config: |
114 | @@ -321,7 +341,8 @@ |
115 | for service in config_services: |
116 | path = service.get('nrpe_check_path') |
117 | if path is not None: |
118 | - command = 'check_http -I 127.0.0.1 -p 3128 --method=HEAD ' |
119 | + method = "GET" if "?" in path else "HEAD" |
120 | + command = 'check_http -I 127.0.0.1 -p 3128 --method=%s ' % method |
121 | service_name = service['service_name'] |
122 | if conf.get('x_balancer_name_allowed'): |
123 | command += ("-u http://localhost%s " |
124 | |
125 | === modified file 'hooks/tests/test_helpers.py' |
126 | --- hooks/tests/test_helpers.py 2013-10-29 16:56:23 +0000 |
127 | +++ hooks/tests/test_helpers.py 2013-12-10 20:23:01 +0000 |
128 | @@ -5,7 +5,7 @@ |
129 | from os.path import dirname |
130 | |
131 | from testtools import TestCase |
132 | -from testtools.matchers import AfterPreprocessing, Contains |
133 | +from testtools.matchers import AfterPreprocessing, Contains, Not |
134 | from mock import patch |
135 | |
136 | import hooks |
137 | @@ -27,6 +27,14 @@ |
138 | Contains(normalize_whitespace(chunk)))) |
139 | return side_effect |
140 | |
141 | + def _assert_not_contents(self, *expected): |
142 | + def side_effect(got): |
143 | + for chunk in expected: |
144 | + self.assertThat(got, AfterPreprocessing( |
145 | + normalize_whitespace, |
146 | + Not(Contains(normalize_whitespace(chunk))))) |
147 | + return side_effect |
148 | + |
149 | def _apply_patch(self, name): |
150 | p = patch(name) |
151 | mocked_name = p.start() |
152 | @@ -47,6 +55,7 @@ |
153 | self.config_get.return_value = Serializable({ |
154 | "refresh_patterns": "", |
155 | "cache_size_mb": 1024, |
156 | + "cache_mem_mb": 256, |
157 | "target_objs_per_dir": 1024, |
158 | "avg_obj_size_kb": 1024, |
159 | "via": "on", |
160 | @@ -66,6 +75,7 @@ |
161 | self.config_get.return_value = Serializable({ |
162 | "refresh_patterns": "", |
163 | "cache_size_mb": 1024, |
164 | + "cache_mem_mb": 256, |
165 | "target_objs_per_dir": 1024, |
166 | "avg_obj_size_kb": 1024, |
167 | "via": "off", |
168 | @@ -84,6 +94,7 @@ |
169 | {"http://www.ubuntu.com": |
170 | {"min": 0, "percent": 20, "max": 60}}), |
171 | "cache_size_mb": 1024, |
172 | + "cache_mem_mb": 256, |
173 | "target_objs_per_dir": 1024, |
174 | "avg_obj_size_kb": 1024, |
175 | }) |
176 | @@ -101,6 +112,7 @@ |
177 | {"http://www.ubuntu.com": |
178 | {"min": 0, "percent": 20, "max": 60}}), |
179 | "cache_size_mb": 1024, |
180 | + "cache_mem_mb": 256, |
181 | "target_objs_per_dir": 1024, |
182 | "avg_obj_size_kb": 1024, |
183 | }) |
184 | @@ -120,6 +132,7 @@ |
185 | "options": ["override-lastmod", |
186 | "reload-into-ims"]}}), |
187 | "cache_size_mb": 1024, |
188 | + "cache_mem_mb": 256, |
189 | "target_objs_per_dir": 1024, |
190 | "avg_obj_size_kb": 1024, |
191 | }) |
192 | @@ -141,6 +154,7 @@ |
193 | "options": ["override-lastmod", |
194 | "reload-into-ims"]}}), |
195 | "cache_size_mb": 1024, |
196 | + "cache_mem_mb": 256, |
197 | "target_objs_per_dir": 1024, |
198 | "avg_obj_size_kb": 1024, |
199 | }) |
200 | @@ -157,6 +171,7 @@ |
201 | self.config_get.return_value = Serializable({ |
202 | "refresh_patterns": "", |
203 | "cache_size_mb": 1024, |
204 | + "cache_mem_mb": 256, |
205 | "target_objs_per_dir": 1024, |
206 | "avg_obj_size_kb": 1024, |
207 | }) |
208 | @@ -191,6 +206,7 @@ |
209 | self.config_get.return_value = Serializable({ |
210 | "refresh_patterns": "", |
211 | "cache_size_mb": 1024, |
212 | + "cache_mem_mb": 256, |
213 | "target_objs_per_dir": 1024, |
214 | "avg_obj_size_kb": 1024, |
215 | }) |
216 | @@ -231,6 +247,7 @@ |
217 | self.config_get.return_value = Serializable({ |
218 | "refresh_patterns": "", |
219 | "cache_size_mb": 1024, |
220 | + "cache_mem_mb": 256, |
221 | "target_objs_per_dir": 1024, |
222 | "avg_obj_size_kb": 1024, |
223 | }) |
224 | @@ -252,6 +269,7 @@ |
225 | self.config_get.return_value = Serializable({ |
226 | "refresh_patterns": "", |
227 | "cache_size_mb": 1024, |
228 | + "cache_mem_mb": 256, |
229 | "target_objs_per_dir": 1024, |
230 | "avg_obj_size_kb": 1024, |
231 | "x_balancer_name_allowed": True, |
232 | @@ -279,6 +297,7 @@ |
233 | self.config_get.return_value = Serializable({ |
234 | "refresh_patterns": "", |
235 | "cache_size_mb": 1024, |
236 | + "cache_mem_mb": 256, |
237 | "target_objs_per_dir": 1024, |
238 | "avg_obj_size_kb": 1024, |
239 | "x_balancer_name_allowed": True, |
240 | @@ -326,6 +345,7 @@ |
241 | "enable_forward_proxy": True, |
242 | "refresh_patterns": "", |
243 | "cache_size_mb": 1024, |
244 | + "cache_mem_mb": 256, |
245 | "target_objs_per_dir": 1024, |
246 | "avg_obj_size_kb": 1024, |
247 | }) |
248 | @@ -376,10 +396,28 @@ |
249 | ) |
250 | hooks.construct_squid3_config() |
251 | |
252 | + def test_squid_config_disk_cache_disabled(self): |
253 | + self.config_get.return_value = Serializable({ |
254 | + "refresh_patterns": "", |
255 | + "cache_size_mb": 0, |
256 | + "cache_mem_mb": 256, |
257 | + "cache_dir": "/var/run/squid3", |
258 | + "target_objs_per_dir": 16, |
259 | + "avg_obj_size_kb": 4, |
260 | + }) |
261 | + self.get_reverse_sites.return_value = None |
262 | + self.write_squid3_config.side_effect = self._assert_not_contents( |
263 | + """ |
264 | + cache_dir aufs |
265 | + """, |
266 | + ) |
267 | + hooks.construct_squid3_config() |
268 | + |
269 | def test_squid_config_cache_disabled(self): |
270 | self.config_get.return_value = Serializable({ |
271 | "refresh_patterns": "", |
272 | "cache_size_mb": 0, |
273 | + "cache_mem_mb": 0, |
274 | "target_objs_per_dir": 1024, |
275 | "avg_obj_size_kb": 1024, |
276 | }) |
277 | @@ -391,6 +429,60 @@ |
278 | ) |
279 | hooks.construct_squid3_config() |
280 | |
281 | + self.write_squid3_config.side_effect = self._assert_not_contents( |
282 | + """ |
283 | + cache_mem |
284 | + """, |
285 | + ) |
286 | + hooks.construct_squid3_config() |
287 | + |
288 | + def test_no_https(self): |
289 | + self.config_get.return_value = Serializable({ |
290 | + "port": 3128, |
291 | + "port_options": "accel vhost", |
292 | + "enable_https": False, |
293 | + "refresh_patterns": "", |
294 | + "cache_size_mb": 0, |
295 | + "cache_mem_mb": 0, |
296 | + "target_objs_per_dir": 1024, |
297 | + "avg_obj_size_kb": 1024, |
298 | + }) |
299 | + self.get_reverse_sites.return_value = None |
300 | + self.write_squid3_config.side_effect = self._assert_contents( |
301 | + """ |
302 | + http_port 3128 accel vhost |
303 | + """, |
304 | + ) |
305 | + hooks.construct_squid3_config() |
306 | + |
307 | + self.write_squid3_config.side_effect = self._assert_not_contents( |
308 | + """ |
309 | + https_port |
310 | + """, |
311 | + ) |
312 | + hooks.construct_squid3_config() |
313 | + |
314 | + def test_with_https(self): |
315 | + self.config_get.return_value = Serializable({ |
316 | + "enable_https": True, |
317 | + "https_port": 443, |
318 | + "https_options": "accel vhost", |
319 | + "ssl_certfile": "/path/to/cert", |
320 | + "ssl_keyfile": "/path/to/key", |
321 | + "refresh_patterns": "", |
322 | + "cache_size_mb": 0, |
323 | + "cache_mem_mb": 0, |
324 | + "target_objs_per_dir": 1024, |
325 | + "avg_obj_size_kb": 1024, |
326 | + }) |
327 | + self.get_reverse_sites.return_value = None |
328 | + self.write_squid3_config.side_effect = self._assert_contents( |
329 | + """ |
330 | + https_port 443 accel vhost cert=/path/to/cert key=/path/to/key |
331 | + """, |
332 | + ) |
333 | + hooks.construct_squid3_config() |
334 | + |
335 | |
336 | class HelpersTest(TestCase): |
337 | def test_gets_config(self): |
338 | |
339 | === modified file 'hooks/tests/test_nrpe_hooks.py' |
340 | --- hooks/tests/test_nrpe_hooks.py 2013-08-22 02:22:04 +0000 |
341 | +++ hooks/tests/test_nrpe_hooks.py 2013-12-10 20:23:01 +0000 |
342 | @@ -255,6 +255,28 @@ |
343 | call().__enter__().write(expected)], |
344 | any_order=True) |
345 | |
346 | + def test_update_nrpe_with_services_GET_if_query_string_in_path(self): |
347 | + services = ('- {nrpe_check_path: "/?path=foo.jpg", ' |
348 | + 'service_name: foo_com}\n') |
349 | + config = { |
350 | + 'nagios_context': 'test', |
351 | + 'services': services, |
352 | + } |
353 | + self.patched['config'].return_value = Serializable(config) |
354 | + self.patched['exists'].return_value = True |
355 | + |
356 | + self.assertEqual(None, hooks.update_nrpe_checks()) |
357 | + |
358 | + self.check_call_counts(config=1, getpwnam=1, getgrnam=1, |
359 | + exists=5, open=4, listdir=2) |
360 | + expected = ('command[check_squid-foo_com]=/check_http ' |
361 | + '-I 127.0.0.1 -p 3128 --method=GET ' |
362 | + '-u http://foo_com/?path=foo.jpg\n') |
363 | + self.patched['open'].assert_has_calls( |
364 | + [call('/etc/nagios/nrpe.d/check_squid-foo_com.cfg', 'w'), |
365 | + call().__enter__().write(expected)], |
366 | + any_order=True) |
367 | + |
368 | def test_update_nrpe_restarts_service(self): |
369 | config = { |
370 | 'nagios_context': 'test', |
371 | |
372 | === modified file 'templates/main_config.template' |
373 | --- templates/main_config.template 2013-10-29 17:37:20 +0000 |
374 | +++ templates/main_config.template 2013-12-10 20:23:01 +0000 |
375 | @@ -1,4 +1,7 @@ |
376 | http_port {{ config.port }} {{ config.port_options }} |
377 | +{% if config.enable_https -%} |
378 | +https_port {{ config.https_port }} {{ config.https_options }} cert={{ config.ssl_certfile }} key={{ config.ssl_keyfile }} |
379 | +{% endif -%} |
380 | |
381 | acl manager proto cache_object |
382 | acl localhost src 127.0.0.1/32 |
383 | @@ -28,8 +31,12 @@ |
384 | |
385 | coredump_dir {{ config.cache_dir }} |
386 | maximum_object_size {{ config.max_obj_size_kb }} KB |
387 | + |
388 | {% if config.cache_size_mb > 0 -%} |
389 | cache_dir aufs {{ config.cache_dir }} {{ config.cache_size_mb }} {{ config.cache_l1 }} {{ config.cache_l2 }} |
390 | +{% endif -%} |
391 | + |
392 | +{% if config.cache_mem_mb > 0 -%} |
393 | cache_mem {{ config.cache_mem_mb }} MB |
394 | {% else -%} |
395 | cache deny all |
396 | @@ -39,6 +46,9 @@ |
397 | log_mime_hdrs on |
398 | |
399 | acl accel_ports myport {{ config.port }} |
400 | +{% if config.enable_https -%} |
401 | +acl accel_ports myport {{ config.https_port }} |
402 | +{% endif -%} |
403 | |
404 | {% for rp in refresh_patterns.keys() -%} |
405 | refresh_pattern {{ rp }} {{ refresh_patterns[rp]['min'] }} {{ refresh_patterns[rp]['percent'] }}% {{ refresh_patterns[rp]['max'] }} {{ ' '.join(refresh_patterns[rp]['options']) }} |