Merge lp:~sidnei/charms/precise/squid-reverseproxy/trunk into lp:charms/squid-reverseproxy

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
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
=== modified file 'README.md'
--- README.md 2013-02-15 07:00:58 +0000
+++ README.md 2013-12-10 20:23:01 +0000
@@ -63,6 +63,19 @@
63The options that can be configured in config.yaml should be self-explanatory.63The options that can be configured in config.yaml should be self-explanatory.
64If not, please file a bug against this charm.64If not, please file a bug against this charm.
6565
66## HTTPS Reverse Proxying
67
68Assuming you have a squid3 deb compiled with --enable-ssl, you can setup a
69single https reverse proxy.
70
71An example of this would be:
72
73 juju set squid-reverseproxy enable_https=true ssl_key="$(base64 < /path/to/cert.key)" ssl_cert="$(base64 < /path/to/cert.crt)"
74
75This should enable https access to the default website.
76
77A current implementation limitation is that it doesn't support multiple https vhosts.
78
66## Monitoring79## Monitoring
6780
68This charm provides relations that support monitoring via Nagios using 81This charm provides relations that support monitoring via Nagios using
6982
=== modified file 'config.yaml'
--- config.yaml 2013-10-29 16:56:23 +0000
+++ config.yaml 2013-12-10 20:23:01 +0000
@@ -5,8 +5,36 @@
5 description: Squid listening port.5 description: Squid listening port.
6 port_options:6 port_options:
7 type: string7 type: string
8 default: accel vhost8 default: 'accel vhost'
9 description: Squid listening port options9 description: Squid listening port options
10 enable_https:
11 type: boolean
12 default: false
13 description: Enable https access for squid, requires a squid compiled with --enable-ssl, certificate and private key
14 https_port:
15 type: int
16 default: 443
17 description: Squid https listening port
18 https_options:
19 type: string
20 default: 'accel vhost'
21 description: Options for https port
22 ssl_keyfile:
23 type: string
24 default: '/etc/squid3/ssl/cert.key'
25 description: File path to ssl key file inside deployed units
26 ssl_certfile:
27 type: string
28 default: '/etc/squid3/ssl/cert.crt'
29 description: File path to ssl cert file inside deployed units
30 ssl_key:
31 type: string
32 default: ''
33 description: Base64 encoded ssl key file
34 ssl_cert:
35 type: string
36 default: ''
37 description: Base64 encoded ssl cert file
10 log_format:38 log_format:
11 type: string39 type: string
12 default: '%>a %ui %un [%tl] "%rm %ru HTTP/%rv" %>Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh'40 default: '%>a %ui %un [%tl] "%rm %ru HTTP/%rv" %>Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh'
@@ -22,11 +50,13 @@
22 cache_mem_mb:50 cache_mem_mb:
23 type: int51 type: int
24 default: 25652 default: 256
25 description: Maximum size of in-memory object cache (MB). Should be smaller than cache_size_mb.53 description: >
54 Maximum size of in-memory object cache (MB). Should be smaller than
55 cache_size_mb. Set to zero to disable caching completely.
26 cache_size_mb:56 cache_size_mb:
27 type: int57 type: int
28 default: 51258 default: 512
29 description: Maximum size of the on-disk object cache (MB). Set to zero to disable caching.59 description: Maximum size of the on-disk object cache (MB). Set to zero to disable disk caching.
30 cache_dir:60 cache_dir:
31 type: string61 type: string
32 default: '/var/spool/squid3'62 default: '/var/spool/squid3'
3363
=== added directory 'exec.d'
=== modified file 'hooks/hooks.py'
--- hooks/hooks.py 2013-10-29 17:37:20 +0000
+++ hooks/hooks.py 2013-12-10 20:23:01 +0000
@@ -256,6 +256,26 @@
256 write_squid3_config('\n'.join(256 write_squid3_config('\n'.join(
257 (l.strip() for l in str(template).splitlines())))257 (l.strip() for l in str(template).splitlines())))
258258
259 # If we have https, write out ssl key and cert file
260 if config_data.get('enable_https'):
261 from base64 import b64decode
262 if config_data.get('ssl_key') is not None:
263 ssl_keyfile = config_data['ssl_keyfile']
264 ssl_keyfile_dir = os.path.dirname(os.path.realpath(ssl_keyfile))
265 if not os.path.exists(ssl_keyfile_dir):
266 os.makedirs(ssl_keyfile_dir)
267 ssl_key = config_data['ssl_key']
268 with open(ssl_keyfile, 'w') as ssl_key_path:
269 ssl_key_path.write(str(b64decode(ssl_key)))
270 if config_data.get('ssl_cert') is not None:
271 ssl_certfile = config_data['ssl_certfile']
272 ssl_certfile_dir = os.path.dirname(ssl_certfile)
273 if not os.path.exists(ssl_certfile_dir):
274 os.makedirs(ssl_certfile_dir)
275 ssl_cert = config_data['ssl_cert']
276 with open(ssl_certfile, 'w') as ssl_cert_path:
277 ssl_cert_path.write(str(b64decode(ssl_cert)))
278
259279
260def write_squid3_config(contents):280def write_squid3_config(contents):
261 with open(default_squid3_config, 'w') as squid3_config:281 with open(default_squid3_config, 'w') as squid3_config:
@@ -321,7 +341,8 @@
321 for service in config_services:341 for service in config_services:
322 path = service.get('nrpe_check_path')342 path = service.get('nrpe_check_path')
323 if path is not None:343 if path is not None:
324 command = 'check_http -I 127.0.0.1 -p 3128 --method=HEAD '344 method = "GET" if "?" in path else "HEAD"
345 command = 'check_http -I 127.0.0.1 -p 3128 --method=%s ' % method
325 service_name = service['service_name']346 service_name = service['service_name']
326 if conf.get('x_balancer_name_allowed'):347 if conf.get('x_balancer_name_allowed'):
327 command += ("-u http://localhost%s "348 command += ("-u http://localhost%s "
328349
=== modified file 'hooks/tests/test_helpers.py'
--- hooks/tests/test_helpers.py 2013-10-29 16:56:23 +0000
+++ hooks/tests/test_helpers.py 2013-12-10 20:23:01 +0000
@@ -5,7 +5,7 @@
5from os.path import dirname5from os.path import dirname
66
7from testtools import TestCase7from testtools import TestCase
8from testtools.matchers import AfterPreprocessing, Contains8from testtools.matchers import AfterPreprocessing, Contains, Not
9from mock import patch9from mock import patch
1010
11import hooks11import hooks
@@ -27,6 +27,14 @@
27 Contains(normalize_whitespace(chunk))))27 Contains(normalize_whitespace(chunk))))
28 return side_effect28 return side_effect
2929
30 def _assert_not_contents(self, *expected):
31 def side_effect(got):
32 for chunk in expected:
33 self.assertThat(got, AfterPreprocessing(
34 normalize_whitespace,
35 Not(Contains(normalize_whitespace(chunk)))))
36 return side_effect
37
30 def _apply_patch(self, name):38 def _apply_patch(self, name):
31 p = patch(name)39 p = patch(name)
32 mocked_name = p.start()40 mocked_name = p.start()
@@ -47,6 +55,7 @@
47 self.config_get.return_value = Serializable({55 self.config_get.return_value = Serializable({
48 "refresh_patterns": "",56 "refresh_patterns": "",
49 "cache_size_mb": 1024,57 "cache_size_mb": 1024,
58 "cache_mem_mb": 256,
50 "target_objs_per_dir": 1024,59 "target_objs_per_dir": 1024,
51 "avg_obj_size_kb": 1024,60 "avg_obj_size_kb": 1024,
52 "via": "on",61 "via": "on",
@@ -66,6 +75,7 @@
66 self.config_get.return_value = Serializable({75 self.config_get.return_value = Serializable({
67 "refresh_patterns": "",76 "refresh_patterns": "",
68 "cache_size_mb": 1024,77 "cache_size_mb": 1024,
78 "cache_mem_mb": 256,
69 "target_objs_per_dir": 1024,79 "target_objs_per_dir": 1024,
70 "avg_obj_size_kb": 1024,80 "avg_obj_size_kb": 1024,
71 "via": "off",81 "via": "off",
@@ -84,6 +94,7 @@
84 {"http://www.ubuntu.com":94 {"http://www.ubuntu.com":
85 {"min": 0, "percent": 20, "max": 60}}),95 {"min": 0, "percent": 20, "max": 60}}),
86 "cache_size_mb": 1024,96 "cache_size_mb": 1024,
97 "cache_mem_mb": 256,
87 "target_objs_per_dir": 1024,98 "target_objs_per_dir": 1024,
88 "avg_obj_size_kb": 1024,99 "avg_obj_size_kb": 1024,
89 })100 })
@@ -101,6 +112,7 @@
101 {"http://www.ubuntu.com":112 {"http://www.ubuntu.com":
102 {"min": 0, "percent": 20, "max": 60}}),113 {"min": 0, "percent": 20, "max": 60}}),
103 "cache_size_mb": 1024,114 "cache_size_mb": 1024,
115 "cache_mem_mb": 256,
104 "target_objs_per_dir": 1024,116 "target_objs_per_dir": 1024,
105 "avg_obj_size_kb": 1024,117 "avg_obj_size_kb": 1024,
106 })118 })
@@ -120,6 +132,7 @@
120 "options": ["override-lastmod",132 "options": ["override-lastmod",
121 "reload-into-ims"]}}),133 "reload-into-ims"]}}),
122 "cache_size_mb": 1024,134 "cache_size_mb": 1024,
135 "cache_mem_mb": 256,
123 "target_objs_per_dir": 1024,136 "target_objs_per_dir": 1024,
124 "avg_obj_size_kb": 1024,137 "avg_obj_size_kb": 1024,
125 })138 })
@@ -141,6 +154,7 @@
141 "options": ["override-lastmod",154 "options": ["override-lastmod",
142 "reload-into-ims"]}}),155 "reload-into-ims"]}}),
143 "cache_size_mb": 1024,156 "cache_size_mb": 1024,
157 "cache_mem_mb": 256,
144 "target_objs_per_dir": 1024,158 "target_objs_per_dir": 1024,
145 "avg_obj_size_kb": 1024,159 "avg_obj_size_kb": 1024,
146 })160 })
@@ -157,6 +171,7 @@
157 self.config_get.return_value = Serializable({171 self.config_get.return_value = Serializable({
158 "refresh_patterns": "",172 "refresh_patterns": "",
159 "cache_size_mb": 1024,173 "cache_size_mb": 1024,
174 "cache_mem_mb": 256,
160 "target_objs_per_dir": 1024,175 "target_objs_per_dir": 1024,
161 "avg_obj_size_kb": 1024,176 "avg_obj_size_kb": 1024,
162 })177 })
@@ -191,6 +206,7 @@
191 self.config_get.return_value = Serializable({206 self.config_get.return_value = Serializable({
192 "refresh_patterns": "",207 "refresh_patterns": "",
193 "cache_size_mb": 1024,208 "cache_size_mb": 1024,
209 "cache_mem_mb": 256,
194 "target_objs_per_dir": 1024,210 "target_objs_per_dir": 1024,
195 "avg_obj_size_kb": 1024,211 "avg_obj_size_kb": 1024,
196 })212 })
@@ -231,6 +247,7 @@
231 self.config_get.return_value = Serializable({247 self.config_get.return_value = Serializable({
232 "refresh_patterns": "",248 "refresh_patterns": "",
233 "cache_size_mb": 1024,249 "cache_size_mb": 1024,
250 "cache_mem_mb": 256,
234 "target_objs_per_dir": 1024,251 "target_objs_per_dir": 1024,
235 "avg_obj_size_kb": 1024,252 "avg_obj_size_kb": 1024,
236 })253 })
@@ -252,6 +269,7 @@
252 self.config_get.return_value = Serializable({269 self.config_get.return_value = Serializable({
253 "refresh_patterns": "",270 "refresh_patterns": "",
254 "cache_size_mb": 1024,271 "cache_size_mb": 1024,
272 "cache_mem_mb": 256,
255 "target_objs_per_dir": 1024,273 "target_objs_per_dir": 1024,
256 "avg_obj_size_kb": 1024,274 "avg_obj_size_kb": 1024,
257 "x_balancer_name_allowed": True,275 "x_balancer_name_allowed": True,
@@ -279,6 +297,7 @@
279 self.config_get.return_value = Serializable({297 self.config_get.return_value = Serializable({
280 "refresh_patterns": "",298 "refresh_patterns": "",
281 "cache_size_mb": 1024,299 "cache_size_mb": 1024,
300 "cache_mem_mb": 256,
282 "target_objs_per_dir": 1024,301 "target_objs_per_dir": 1024,
283 "avg_obj_size_kb": 1024,302 "avg_obj_size_kb": 1024,
284 "x_balancer_name_allowed": True,303 "x_balancer_name_allowed": True,
@@ -326,6 +345,7 @@
326 "enable_forward_proxy": True,345 "enable_forward_proxy": True,
327 "refresh_patterns": "",346 "refresh_patterns": "",
328 "cache_size_mb": 1024,347 "cache_size_mb": 1024,
348 "cache_mem_mb": 256,
329 "target_objs_per_dir": 1024,349 "target_objs_per_dir": 1024,
330 "avg_obj_size_kb": 1024,350 "avg_obj_size_kb": 1024,
331 })351 })
@@ -376,10 +396,28 @@
376 )396 )
377 hooks.construct_squid3_config()397 hooks.construct_squid3_config()
378398
399 def test_squid_config_disk_cache_disabled(self):
400 self.config_get.return_value = Serializable({
401 "refresh_patterns": "",
402 "cache_size_mb": 0,
403 "cache_mem_mb": 256,
404 "cache_dir": "/var/run/squid3",
405 "target_objs_per_dir": 16,
406 "avg_obj_size_kb": 4,
407 })
408 self.get_reverse_sites.return_value = None
409 self.write_squid3_config.side_effect = self._assert_not_contents(
410 """
411 cache_dir aufs
412 """,
413 )
414 hooks.construct_squid3_config()
415
379 def test_squid_config_cache_disabled(self):416 def test_squid_config_cache_disabled(self):
380 self.config_get.return_value = Serializable({417 self.config_get.return_value = Serializable({
381 "refresh_patterns": "",418 "refresh_patterns": "",
382 "cache_size_mb": 0,419 "cache_size_mb": 0,
420 "cache_mem_mb": 0,
383 "target_objs_per_dir": 1024,421 "target_objs_per_dir": 1024,
384 "avg_obj_size_kb": 1024,422 "avg_obj_size_kb": 1024,
385 })423 })
@@ -391,6 +429,60 @@
391 )429 )
392 hooks.construct_squid3_config()430 hooks.construct_squid3_config()
393431
432 self.write_squid3_config.side_effect = self._assert_not_contents(
433 """
434 cache_mem
435 """,
436 )
437 hooks.construct_squid3_config()
438
439 def test_no_https(self):
440 self.config_get.return_value = Serializable({
441 "port": 3128,
442 "port_options": "accel vhost",
443 "enable_https": False,
444 "refresh_patterns": "",
445 "cache_size_mb": 0,
446 "cache_mem_mb": 0,
447 "target_objs_per_dir": 1024,
448 "avg_obj_size_kb": 1024,
449 })
450 self.get_reverse_sites.return_value = None
451 self.write_squid3_config.side_effect = self._assert_contents(
452 """
453 http_port 3128 accel vhost
454 """,
455 )
456 hooks.construct_squid3_config()
457
458 self.write_squid3_config.side_effect = self._assert_not_contents(
459 """
460 https_port
461 """,
462 )
463 hooks.construct_squid3_config()
464
465 def test_with_https(self):
466 self.config_get.return_value = Serializable({
467 "enable_https": True,
468 "https_port": 443,
469 "https_options": "accel vhost",
470 "ssl_certfile": "/path/to/cert",
471 "ssl_keyfile": "/path/to/key",
472 "refresh_patterns": "",
473 "cache_size_mb": 0,
474 "cache_mem_mb": 0,
475 "target_objs_per_dir": 1024,
476 "avg_obj_size_kb": 1024,
477 })
478 self.get_reverse_sites.return_value = None
479 self.write_squid3_config.side_effect = self._assert_contents(
480 """
481 https_port 443 accel vhost cert=/path/to/cert key=/path/to/key
482 """,
483 )
484 hooks.construct_squid3_config()
485
394486
395class HelpersTest(TestCase):487class HelpersTest(TestCase):
396 def test_gets_config(self):488 def test_gets_config(self):
397489
=== modified file 'hooks/tests/test_nrpe_hooks.py'
--- hooks/tests/test_nrpe_hooks.py 2013-08-22 02:22:04 +0000
+++ hooks/tests/test_nrpe_hooks.py 2013-12-10 20:23:01 +0000
@@ -255,6 +255,28 @@
255 call().__enter__().write(expected)],255 call().__enter__().write(expected)],
256 any_order=True)256 any_order=True)
257257
258 def test_update_nrpe_with_services_GET_if_query_string_in_path(self):
259 services = ('- {nrpe_check_path: "/?path=foo.jpg", '
260 'service_name: foo_com}\n')
261 config = {
262 'nagios_context': 'test',
263 'services': services,
264 }
265 self.patched['config'].return_value = Serializable(config)
266 self.patched['exists'].return_value = True
267
268 self.assertEqual(None, hooks.update_nrpe_checks())
269
270 self.check_call_counts(config=1, getpwnam=1, getgrnam=1,
271 exists=5, open=4, listdir=2)
272 expected = ('command[check_squid-foo_com]=/check_http '
273 '-I 127.0.0.1 -p 3128 --method=GET '
274 '-u http://foo_com/?path=foo.jpg\n')
275 self.patched['open'].assert_has_calls(
276 [call('/etc/nagios/nrpe.d/check_squid-foo_com.cfg', 'w'),
277 call().__enter__().write(expected)],
278 any_order=True)
279
258 def test_update_nrpe_restarts_service(self):280 def test_update_nrpe_restarts_service(self):
259 config = {281 config = {
260 'nagios_context': 'test',282 'nagios_context': 'test',
261283
=== modified file 'templates/main_config.template'
--- templates/main_config.template 2013-10-29 17:37:20 +0000
+++ templates/main_config.template 2013-12-10 20:23:01 +0000
@@ -1,4 +1,7 @@
1http_port {{ config.port }} {{ config.port_options }}1http_port {{ config.port }} {{ config.port_options }}
2{% if config.enable_https -%}
3https_port {{ config.https_port }} {{ config.https_options }} cert={{ config.ssl_certfile }} key={{ config.ssl_keyfile }}
4{% endif -%}
25
3acl manager proto cache_object6acl manager proto cache_object
4acl localhost src 127.0.0.1/327acl localhost src 127.0.0.1/32
@@ -28,8 +31,12 @@
2831
29coredump_dir {{ config.cache_dir }}32coredump_dir {{ config.cache_dir }}
30maximum_object_size {{ config.max_obj_size_kb }} KB33maximum_object_size {{ config.max_obj_size_kb }} KB
34
31{% if config.cache_size_mb > 0 -%}35{% if config.cache_size_mb > 0 -%}
32cache_dir aufs {{ config.cache_dir }} {{ config.cache_size_mb }} {{ config.cache_l1 }} {{ config.cache_l2 }}36cache_dir aufs {{ config.cache_dir }} {{ config.cache_size_mb }} {{ config.cache_l1 }} {{ config.cache_l2 }}
37{% endif -%}
38
39{% if config.cache_mem_mb > 0 -%}
33cache_mem {{ config.cache_mem_mb }} MB40cache_mem {{ config.cache_mem_mb }} MB
34{% else -%}41{% else -%}
35cache deny all42cache deny all
@@ -39,6 +46,9 @@
39log_mime_hdrs on46log_mime_hdrs on
4047
41acl accel_ports myport {{ config.port }}48acl accel_ports myport {{ config.port }}
49{% if config.enable_https -%}
50acl accel_ports myport {{ config.https_port }}
51{% endif -%}
4252
43{% for rp in refresh_patterns.keys() -%}53{% for rp in refresh_patterns.keys() -%}
44refresh_pattern {{ rp }} {{ refresh_patterns[rp]['min'] }} {{ refresh_patterns[rp]['percent'] }}% {{ refresh_patterns[rp]['max'] }} {{ ' '.join(refresh_patterns[rp]['options']) }}54refresh_pattern {{ rp }} {{ refresh_patterns[rp]['min'] }} {{ refresh_patterns[rp]['percent'] }}% {{ refresh_patterns[rp]['max'] }} {{ ' '.join(refresh_patterns[rp]['options']) }}

Subscribers

People subscribed via source and target branches