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
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']) }}

Subscribers

People subscribed via source and target branches