Merge lp:~bloodearnest/charms/precise/squid-reverseproxy/metrics into lp:charms/squid-reverseproxy
- Precise Pangolin (12.04)
- metrics
- Merge into trunk
Proposed by
Simon Davy
Status: | Merged |
---|---|
Merged at revision: | 46 |
Proposed branch: | lp:~bloodearnest/charms/precise/squid-reverseproxy/metrics |
Merge into: | lp:charms/squid-reverseproxy |
Diff against target: |
626 lines (+444/-17) 10 files modified
.bzrignore (+1/-1) Makefile (+4/-0) config.yaml (+61/-5) files/squid_metrics.py (+99/-0) hooks/hooks.py (+76/-9) hooks/tests/test_config_changed_hooks.py (+1/-0) hooks/tests/test_metrics.py (+191/-0) templates/main_config.template (+2/-2) templates/metrics_cronjob.template (+3/-0) templates/squid_metrics_ini.template (+6/-0) |
To merge this branch: | bzr merge lp:~bloodearnest/charms/precise/squid-reverseproxy/metrics |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tom Haddon | Approve | ||
Review via email: mp+217138@code.launchpad.net |
Commit message
Add support for sending cache metrics to statsd
Description of the change
Add support for sending cache metrics to statsd.
Sets up a configurable cron job to gather metrics from squid via snmp and pipe them to statsd.
The snmp names of exported metrics can be set in the 'metrics' config, which has a set of defaults.
Also does a small refactor if jinja templating code as it's used in multiple places now.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2013-08-22 02:22:04 +0000 |
3 | +++ .bzrignore 2014-04-24 20:39:21 +0000 |
4 | @@ -6,5 +6,5 @@ |
5 | *.key |
6 | lib/* |
7 | *.pyc |
8 | -exec.d |
9 | +exec.d/* |
10 | build/charm-helpers |
11 | |
12 | === modified file 'Makefile' |
13 | --- Makefile 2013-10-29 17:37:20 +0000 |
14 | +++ Makefile 2014-04-24 20:39:21 +0000 |
15 | @@ -9,6 +9,10 @@ |
16 | |
17 | build: test lint proof |
18 | |
19 | +dev: |
20 | + mkdir -p exec.d |
21 | + bzr branch lp:~canonical-sysadmins/basenode/trunk exec.d/basenode |
22 | + |
23 | revision: |
24 | @test -f revision || echo 0 > revision |
25 | |
26 | |
27 | === modified file 'config.yaml' |
28 | --- config.yaml 2013-12-13 11:07:25 +0000 |
29 | +++ config.yaml 2014-04-24 20:39:21 +0000 |
30 | @@ -76,13 +76,17 @@ |
31 | snmp_community: |
32 | type: string |
33 | default: '' |
34 | - description: SNMP community string for monitoring the service. |
35 | + description: SNMP community string for monitoring the service. Required for metrics to be enabled. |
36 | snmp_allowed_ips: |
37 | # would like to use "regex" here, but it doesn't appear to work |
38 | type: string |
39 | default: '' |
40 | description: Single, or json-formatted list of, IP (with optional subnet mask) allowed to query SNMP. |
41 | # validator: '[0-9a-zA-z]{6,32}' |
42 | + snmp_port: |
43 | + type: int |
44 | + default: 3401 |
45 | + description: Port for snmp service |
46 | nagios_context: |
47 | default: "juju" |
48 | type: string |
49 | @@ -104,10 +108,10 @@ |
50 | description: > |
51 | The parameters to pass to the nrpe plugin check_http. String will be formatted with config data |
52 | nagios_service_type: |
53 | - default: "generic" |
54 | - type: string |
55 | - description: > |
56 | - What service this component forms part of, e.g. supermassive-squid-cluster. Used by nrpe. |
57 | + default: "generic" |
58 | + type: string |
59 | + description: > |
60 | + What service this component forms part of, e.g. supermassive-squid-cluster. Used by nrpe. |
61 | package_status: |
62 | default: "install" |
63 | type: "string" |
64 | @@ -140,3 +144,55 @@ |
65 | default: false |
66 | type: boolean |
67 | description: Enables forward proxying |
68 | + metrics_target: |
69 | + default: "" |
70 | + type: string |
71 | + description: Destination for metrics, format "host:port". If not present and |
72 | + valid, metrics disabled. |
73 | + metrics_scheme: |
74 | + default: "dev.$UNIT.squid.$METRIC" |
75 | + type: string |
76 | + description: | |
77 | + Naming scheme for metrics. Special values $UNIT and $METRIC can be used |
78 | + for more complex schemes, e.g. for suffixes for graphite processing . |
79 | + metrics_sample_interval: |
80 | + default: 5 |
81 | + type: int |
82 | + description: Period for metrics cron job to run in minutes |
83 | + metrics: |
84 | + default: | |
85 | + cacheCpuUsage |
86 | + cacheCurrentSwapSize |
87 | + cacheDnsSvcTime.5 |
88 | + cacheHttpErrors |
89 | + cacheHttpAllSvcTime.5 |
90 | + cacheHttpHitSvcTime.5 |
91 | + cacheHttpMissSvcTime.5 |
92 | + cacheHttpNhSvcTime.5 |
93 | + cacheHttpNmSvcTime.5 |
94 | + cacheHttpInKb |
95 | + cacheHttpOutKb |
96 | + cacheMaxResSize |
97 | + cacheMemMaxSize |
98 | + cacheMemUsage |
99 | + cacheNumObjCount |
100 | + cachePeerRtt |
101 | + cacheRequestByteRatio.5 |
102 | + cacheRequestHitRatio.5 |
103 | + cacheSwapHighWM |
104 | + cacheSwapLowWM |
105 | + cacheSwapMaxSize |
106 | + cacheSysNumReads |
107 | + cacheSysPageFaults |
108 | + cacheSysStorage |
109 | + cacheSysVMsize |
110 | + type: string |
111 | + description: " |
112 | + List of SNMP metrics to be exported. Names should match Squid's SNMP |
113 | + names at http://wiki.squid-cache.org/Features/Snmp#Squid_OIDs. By |
114 | + default, this charm uses the 5min sampling when averages are used and |
115 | + specifies the .5 measurements explicitly. If you want to use 1m or 60m |
116 | + timings, you should be explicit (.1/.60, and probably change the cron job |
117 | + frequency. Warning: any metric starting with 'cachePeer...' will produce |
118 | + 1 metric per configured peer, so can increase the number of metrics |
119 | + rapidly if you have lots of peers." |
120 | |
121 | === added file 'files/squid_metrics.py' |
122 | --- files/squid_metrics.py 1970-01-01 00:00:00 +0000 |
123 | +++ files/squid_metrics.py 2014-04-24 20:39:21 +0000 |
124 | @@ -0,0 +1,99 @@ |
125 | +#!/bin/env python |
126 | +import shlex |
127 | +import sys |
128 | +import subprocess |
129 | +import time |
130 | +import ConfigParser |
131 | + |
132 | +config_path = "/usr/local/etc/squid_metrics.ini" |
133 | +cmd = "snmpwalk -v1 -Cc -Oq -c %s -m /usr/share/squid3/mib.txt localhost:%s" |
134 | + |
135 | + |
136 | +def clean(s): |
137 | + """Make a string safe for statsd scheme""" |
138 | + return s.replace('.', '-').replace('/', '-') |
139 | + |
140 | + |
141 | +def load_config(path): |
142 | + config = ConfigParser.SafeConfigParser() |
143 | + config.read(config_path) |
144 | + return { |
145 | + 'unit': config.get('metrics', 'unit'), |
146 | + 'scheme': config.get('metrics', 'scheme'), |
147 | + 'port': config.get('metrics', 'port'), |
148 | + 'community': config.get('metrics', 'community'), |
149 | + 'metrics': config.get('metrics', 'metrics').strip().split(','), |
150 | + } |
151 | + |
152 | + |
153 | +class SNMPMetricFailed(Exception): |
154 | + pass |
155 | + |
156 | + |
157 | +def get_snmp_value(cmd, metric): |
158 | + try: |
159 | + output = subprocess.check_output(cmd + (metric,)) |
160 | + except subprocess.CalledProcessError: |
161 | + raise SNMPMetricFailed() |
162 | + |
163 | + if 'End of MIB' in output: |
164 | + # could not find metric name in SNMP |
165 | + raise SNMPMetricFailed() |
166 | + |
167 | + return output.strip() |
168 | + |
169 | + |
170 | +def get_metrics(config): |
171 | + |
172 | + tstamp = int(time.time()) |
173 | + scheme = config['scheme'].replace('$UNIT', clean(config['unit'])) |
174 | + snmp_cmd = tuple(shlex.split(cmd % (config['community'], config['port']))) |
175 | + |
176 | + try: |
177 | + raw_peer_names = get_snmp_value(snmp_cmd, 'cachePeerName') |
178 | + except SNMPMetricFailed: |
179 | + # no peers configured |
180 | + peer_names = {} |
181 | + else: |
182 | + lines = (line for line in raw_peer_names.split('\n') if ' ' in line) |
183 | + peer_names = dict(line[25:].split(' ') for line in lines) |
184 | + |
185 | + for metric in config['metrics']: |
186 | + # sadly, have to do one call per metric |
187 | + try: |
188 | + output = get_snmp_value(snmp_cmd, metric) |
189 | + except SNMPMetricFailed: |
190 | + # skip metric |
191 | + # TODO log failure to read metric? |
192 | + continue |
193 | + |
194 | + # output is like "SQUID-MIB::<key> <value>" |
195 | + for line in output.split('\n'): |
196 | + # ensure only what we asked, as snmpwalk can be overly generous |
197 | + if metric in line: |
198 | + # strip leading 'SQUID-MIB::' |
199 | + key, value = line[11:].split() |
200 | + # use peer hostname rather than index |
201 | + if 'cachePeer' in key: |
202 | + key, index = key.split('.') |
203 | + name = peer_names.get(index, index) |
204 | + key = clean(key) + '.' + clean(name) |
205 | + else: |
206 | + # avoid introducing uneeded statsd heirarchy |
207 | + key = clean(key.replace('.0', '')) |
208 | + if '$METRIC' in scheme: |
209 | + name = scheme.replace('$METRIC', key) |
210 | + else: |
211 | + name = scheme + ".%s" % key |
212 | + yield (name, value, tstamp) |
213 | + |
214 | + |
215 | +if __name__ == '__main__': |
216 | + |
217 | + if len(sys.argv) > 1: |
218 | + config = load_config(sys.argv[1]) |
219 | + else: |
220 | + config = load_config(config_path) |
221 | + |
222 | + for metric in get_metrics(config): |
223 | + print "%s %s %s" % metric |
224 | |
225 | === modified file 'hooks/hooks.py' |
226 | --- hooks/hooks.py 2014-04-23 10:06:38 +0000 |
227 | +++ hooks/hooks.py 2014-04-24 20:39:21 +0000 |
228 | @@ -23,6 +23,7 @@ |
229 | related_units, |
230 | open_port, |
231 | close_port, |
232 | + local_unit, |
233 | ) |
234 | from charmhelpers.fetch import apt_install |
235 | from charmhelpers.contrib.charmsupport.nrpe import NRPE |
236 | @@ -34,6 +35,10 @@ |
237 | default_squid3_config = "%s/squid.conf" % default_squid3_config_dir |
238 | default_squid3_config_cache_dir = "/var/run/squid3" |
239 | default_nagios_plugin_dir = "/usr/lib/nagios/plugins" |
240 | +metrics_cronjob_path = "/etc/cron.d/squid_metrics" |
241 | +metrics_script_path = "/usr/local/bin/squid_metrics.py" |
242 | +metrics_config_path = "/usr/local/etc/squid_metrics.ini" |
243 | +site_mib_path = "/usr/share/mibs/site" |
244 | Server = collections.namedtuple("Server", "name address port options") |
245 | service_affecting_packages = ['squid3'] |
246 | |
247 | @@ -208,11 +213,19 @@ |
248 | return ''.join(random_chars) |
249 | |
250 | |
251 | +def render_template(template_name, vars): |
252 | + # deferred import so install hook can install jinja2 |
253 | + from jinja2 import Environment, FileSystemLoader |
254 | + templates_dir = os.path.join(os.environ['CHARM_DIR'], 'templates') |
255 | + template_env = Environment(loader=FileSystemLoader(templates_dir)) |
256 | + template = template_env.get_template(template_name) |
257 | + return template.render(vars) |
258 | + |
259 | + |
260 | #------------------------------------------------------------------------------ |
261 | # construct_squid3_config: Convenience function to write squid.conf |
262 | #------------------------------------------------------------------------------ |
263 | def construct_squid3_config(): |
264 | - from jinja2 import Environment, FileSystemLoader |
265 | config_data = config_get() |
266 | reverse_sites = get_reverse_sites() |
267 | only_direct = set() |
268 | @@ -236,9 +249,6 @@ |
269 | 'options': [], |
270 | } |
271 | |
272 | - templates_dir = os.path.join(os.environ['CHARM_DIR'], 'templates') |
273 | - template_env = Environment(loader=FileSystemLoader(templates_dir)) |
274 | - |
275 | config_data['cache_l1'] = int(math.ceil(math.sqrt( |
276 | int(config_data['cache_size_mb']) * 1024 / ( |
277 | 16 * int(config_data['target_objs_per_dir']) * int( |
278 | @@ -261,8 +271,7 @@ |
279 | 'default_refresh_pattern': default_refresh_pattern, |
280 | 'need_localacl_defs': need_localacl_defs, |
281 | } |
282 | - template = template_env.get_template('main_config.template').\ |
283 | - render(templ_vars) |
284 | + template = render_template('main_config.template', templ_vars) |
285 | write_squid3_config('\n'.join( |
286 | (l.strip() for l in str(template).splitlines()))) |
287 | |
288 | @@ -292,6 +301,60 @@ |
289 | squid3_config.write(contents) |
290 | |
291 | |
292 | +def delete_metrics_cronjob(config_path, cron_path): |
293 | + for path in (config_path, cron_path): |
294 | + try: |
295 | + os.unlink(path) |
296 | + except OSError: |
297 | + pass |
298 | + |
299 | + |
300 | +def write_metrics_cronjob(script_path, config_path, cron_path): |
301 | + config_data = config_get() |
302 | + |
303 | + # need the following two configs to be valid |
304 | + metrics_target = config_data['metrics_target'].strip() |
305 | + snmp_community = config_data['snmp_community'].strip() |
306 | + if not snmp_community or not metrics_target or ':' not in metrics_target: |
307 | + log("Required config not found (snmp_community and metrics_target), " |
308 | + "disabling metrics") |
309 | + delete_metrics_cronjob(config_path, cron_path) |
310 | + return |
311 | + |
312 | + # check we can install the mibs ok |
313 | + try: |
314 | + apt_install('snmp-mibs-downloader', fatal=True) |
315 | + except subprocess.CalledProcessError: |
316 | + log("Could not install snmp-mibs-downloader package, " |
317 | + "disabling monitoring", |
318 | + level="ERROR") |
319 | + raise |
320 | + |
321 | + charm_dir = os.environ['CHARM_DIR'] |
322 | + statsd_host, statsd_port = metrics_target.split(':', 1) |
323 | + metrics_list = [s.strip() for s in config_data['metrics'].split()] |
324 | + config_data['metrics_list'] = metrics_list |
325 | + config_data['unit_name'] = local_unit() |
326 | + |
327 | + # ensure script installed |
328 | + shutil.copy2('%s/files/squid_metrics.py' % charm_dir, metrics_script_path) |
329 | + |
330 | + # write the config |
331 | + with open(config_path, 'w') as config: |
332 | + config.write( |
333 | + render_template("squid_metrics_ini.template", config_data)) |
334 | + |
335 | + # write the crontab |
336 | + with open(cron_path, 'w') as cronjob: |
337 | + cronjob.write(render_template("metrics_cronjob.template", { |
338 | + 'interval': config_data['metrics_sample_interval'], |
339 | + 'script': script_path, |
340 | + 'config': config_path, |
341 | + 'statsd_host': statsd_host, |
342 | + 'statsd_port': statsd_port, |
343 | + })) |
344 | + |
345 | + |
346 | #------------------------------------------------------------------------------ |
347 | # service_squid3: Convenience function to start/stop/restart/reload |
348 | # the squid3 service |
349 | @@ -378,7 +441,7 @@ |
350 | |
351 | |
352 | def install_packages(): |
353 | - apt_install("squid3 squidclient python-jinja2".split(), fatal=True) |
354 | + apt_install("squid3 squidclient python-jinja2 snmp".split(), fatal=True) |
355 | ensure_package_status(service_affecting_packages, |
356 | config_get('package_status')) |
357 | |
358 | @@ -387,12 +450,12 @@ |
359 | # Hook functions |
360 | ############################################################################### |
361 | def install_hook(): |
362 | + charm_dir = os.environ['CHARM_DIR'] |
363 | if not os.path.exists(default_squid3_config_dir): |
364 | os.mkdir(default_squid3_config_dir, 0600) |
365 | if not os.path.exists(default_squid3_config_cache_dir): |
366 | os.mkdir(default_squid3_config_cache_dir, 0600) |
367 | - shutil.copy2('%s/files/default.squid3' % ( |
368 | - os.environ['CHARM_DIR']), '/etc/default/squid3') |
369 | + shutil.copy2('%s/files/default.squid3' % charm_dir, '/etc/default/squid3') |
370 | install_packages() |
371 | return True |
372 | |
373 | @@ -405,6 +468,10 @@ |
374 | ensure_package_status(service_affecting_packages, |
375 | config_get('package_status')) |
376 | |
377 | + write_metrics_cronjob(metrics_script_path, |
378 | + metrics_config_path, |
379 | + metrics_cronjob_path) |
380 | + |
381 | if service_squid3("check"): |
382 | updated_service_ports = get_service_ports() |
383 | update_service_ports(old_service_ports, updated_service_ports) |
384 | |
385 | === modified file 'hooks/tests/test_config_changed_hooks.py' |
386 | --- hooks/tests/test_config_changed_hooks.py 2013-08-26 21:18:03 +0000 |
387 | +++ hooks/tests/test_config_changed_hooks.py 2014-04-24 20:39:21 +0000 |
388 | @@ -21,6 +21,7 @@ |
389 | self.notify_cached_website = self.patch_hook("notify_cached_website") |
390 | self.log = self.patch_hook("log") |
391 | self.config_get = self.patch_hook("config_get") |
392 | + self.write_metrics_cronjob = self.patch_hook("write_metrics_cronjob") |
393 | |
394 | def patch_hook(self, hook_name): |
395 | mock_controller = patch.object(hooks, hook_name) |
396 | |
397 | === added file 'hooks/tests/test_metrics.py' |
398 | --- hooks/tests/test_metrics.py 1970-01-01 00:00:00 +0000 |
399 | +++ hooks/tests/test_metrics.py 2014-04-24 20:39:21 +0000 |
400 | @@ -0,0 +1,191 @@ |
401 | +import sys |
402 | +import textwrap |
403 | +from types import ModuleType |
404 | + |
405 | +from testtools import TestCase |
406 | +from mock import patch, mock_open |
407 | + |
408 | +import hooks |
409 | + |
410 | +# import cron script as a standalone module |
411 | +with open('files/squid_metrics.py') as script: |
412 | + source = script.read() |
413 | +squid_metrics = ModuleType('squid_metrics.py') |
414 | +sys.modules['squid_metrics'] = squid_metrics |
415 | +exec source in squid_metrics.__dict__ |
416 | + |
417 | + |
418 | +class MetricsTestCase(TestCase): |
419 | + |
420 | + def add_patch(self, *args, **kwargs): |
421 | + p = patch(*args, **kwargs) |
422 | + self.addCleanup(p.stop) |
423 | + return p.start() |
424 | + |
425 | + def setUp(self): |
426 | + super(MetricsTestCase, self).setUp() |
427 | + |
428 | + self.open = mock_open() |
429 | + self.add_patch("hooks.open", self.open, create=True) |
430 | + self.copy2 = self.add_patch("shutil.copy2") |
431 | + self.config_get = self.add_patch("hooks.config_get") |
432 | + self.local_unit = self.add_patch("hooks.local_unit") |
433 | + self.log = self.add_patch("hooks.log") |
434 | + |
435 | + self.config_get.return_value = { |
436 | + 'metrics_sample_interval': 5, |
437 | + 'metrics_scheme': 'scheme', |
438 | + 'metrics_target': 'localhost:4321', |
439 | + 'snmp_port': '1234', |
440 | + 'snmp_community': 'community', |
441 | + 'metrics': """ a b |
442 | + c """ |
443 | + } |
444 | + self.local_unit.return_value = "unit/0" |
445 | + |
446 | + @patch('hooks.os.unlink') |
447 | + def test_write_metrics_cronjob_disabled_no_community(self, mock_unlink): |
448 | + self.config_get.return_value['snmp_community'] = '' |
449 | + hooks.write_metrics_cronjob('/script', '/config', '/cron') |
450 | + self.assertEqual(mock_unlink.mock_calls[0][1][0], '/config') |
451 | + self.assertEqual(mock_unlink.mock_calls[1][1][0], '/cron') |
452 | + |
453 | + @patch('hooks.os.unlink') |
454 | + def test_write_metrics_cronjob_disabled_no_target(self, mock_unlink): |
455 | + self.config_get.return_value['metrics_target'] = '' |
456 | + hooks.write_metrics_cronjob('/script', '/config', '/cron') |
457 | + self.assertEqual(mock_unlink.mock_calls[0][1][0], '/config') |
458 | + self.assertEqual(mock_unlink.mock_calls[1][1][0], '/cron') |
459 | + |
460 | + @patch('hooks.os.unlink') |
461 | + def test_write_metrics_cronjob_disabled_bad_target(self, mock_unlink): |
462 | + self.config_get.return_value['metrics_target'] = 'sadfsadf' |
463 | + hooks.write_metrics_cronjob('/script', '/config', '/cron') |
464 | + self.assertEqual(mock_unlink.mock_calls[0][1][0], '/config') |
465 | + self.assertEqual(mock_unlink.mock_calls[1][1][0], '/cron') |
466 | + |
467 | + def test_write_metrics_cronjob_enabled(self): |
468 | + self.config_get.return_value['metrics_target'] = 'localhost:4321' |
469 | + |
470 | + hooks.write_metrics_cronjob('/script', '/config', '/cron') |
471 | + |
472 | + # first open |
473 | + config_open_args = self.open.mock_calls[0][1] |
474 | + self.assertEqual(config_open_args, ('/config', 'w')) |
475 | + |
476 | + config_write = self.open.mock_calls[2][1][0] |
477 | + expected_config = textwrap.dedent(""" |
478 | + [metrics] |
479 | + unit: unit/0 |
480 | + scheme: scheme |
481 | + port: 1234 |
482 | + community: community |
483 | + metrics: a,b,c |
484 | + """).strip() |
485 | + self.assertEqual(config_write, expected_config) |
486 | + |
487 | + # 2nd open |
488 | + cron_open_args = self.open.mock_calls[4][1] |
489 | + self.assertEqual(cron_open_args, ('/cron', 'w')) |
490 | + |
491 | + cron_write = self.open.mock_calls[6][1][0] |
492 | + expected_cron = textwrap.dedent(""" |
493 | + # crontab for pushing squid metrics to statsd |
494 | + */5 * * * * root python /script /config | nc localhost 4321 |
495 | + """).strip() |
496 | + self.assertEqual(cron_write, expected_cron) |
497 | + |
498 | + |
499 | +class MetricsJobTestCase(TestCase): |
500 | + |
501 | + def add_patch(self, *args, **kwargs): |
502 | + p = patch(*args, **kwargs) |
503 | + self.addCleanup(p.stop) |
504 | + return p.start() |
505 | + |
506 | + def setUp(self): |
507 | + super(MetricsJobTestCase, self).setUp() |
508 | + |
509 | + self.config = { |
510 | + 'unit': 'unit/0', |
511 | + 'scheme': 'dev.$UNIT.$METRIC.5min', |
512 | + 'port': '1234', |
513 | + 'community': 'public', |
514 | + 'metrics': [], |
515 | + } |
516 | + |
517 | + self.snmp = self.add_patch('squid_metrics.get_snmp_value') |
518 | + |
519 | + self.time = self.add_patch('squid_metrics.time.time') |
520 | + self.time.return_value = 1 |
521 | + |
522 | + def test_periods(self): |
523 | + |
524 | + self.config['metrics'] = [ |
525 | + 'first', 'second', 'third.5', 'forth.60' |
526 | + ] |
527 | + |
528 | + self.snmp.side_effect = [ |
529 | + squid_metrics.SNMPMetricFailed(), # no cache peers |
530 | + 'SQUID-MIB::first 1', |
531 | + 'SQUID-MIB::second.0 2', |
532 | + 'SQUID-MIB::third.5 3', |
533 | + 'SQUID-MIB::forth.60 4', |
534 | + ] |
535 | + |
536 | + metrics = list(squid_metrics.get_metrics(self.config)) |
537 | + |
538 | + self.assertEqual(metrics, [ |
539 | + ('dev.unit-0.first.5min', '1', 1), |
540 | + ('dev.unit-0.second.5min', '2', 1), |
541 | + ('dev.unit-0.third-5.5min', '3', 1), |
542 | + ('dev.unit-0.forth-60.5min', '4', 1), |
543 | + ]) |
544 | + |
545 | + def test_peers_with_names(self): |
546 | + self.config['metrics'] = [ |
547 | + 'cachePeerRtt' |
548 | + ] |
549 | + |
550 | + self.snmp.side_effect = [ |
551 | + ( |
552 | + 'SQUID-MIB::cachePeerName.1 one.com\n' + |
553 | + 'SQUID-MIB::cachePeerName.2 two.org\n' + |
554 | + 'SQUID-MIB::cachePeerName.3 three.net\n' |
555 | + ), |
556 | + ( |
557 | + 'SQUID-MIB::cachePeerRtt.1 1\n' + |
558 | + 'SQUID-MIB::cachePeerRtt.2 2\n' + |
559 | + 'SQUID-MIB::cachePeerRtt.3 3\n' |
560 | + ), |
561 | + ] |
562 | + |
563 | + metrics = list(squid_metrics.get_metrics(self.config)) |
564 | + |
565 | + self.assertEqual(metrics, [ |
566 | + ('dev.unit-0.cachePeerRtt.one-com.5min', '1', 1), |
567 | + ('dev.unit-0.cachePeerRtt.two-org.5min', '2', 1), |
568 | + ('dev.unit-0.cachePeerRtt.three-net.5min', '3', 1), |
569 | + ]) |
570 | + |
571 | + def test_peers_without_names(self): |
572 | + self.config['metrics'] = [ |
573 | + 'cachePeerRtt' |
574 | + ] |
575 | + |
576 | + self.snmp.side_effect = [ |
577 | + squid_metrics.SNMPMetricFailed(), |
578 | + ( |
579 | + 'SQUID-MIB::cachePeerRtt.1 1\n' + |
580 | + 'SQUID-MIB::cachePeerRtt.2 2\n' + |
581 | + 'SQUID-MIB::cachePeerRtt.3 3\n' |
582 | + ), |
583 | + ] |
584 | + |
585 | + metrics = list(squid_metrics.get_metrics(self.config)) |
586 | + |
587 | + self.assertEqual(metrics, [ |
588 | + ('dev.unit-0.cachePeerRtt.1.5min', '1', 1), |
589 | + ('dev.unit-0.cachePeerRtt.2.5min', '2', 1), |
590 | + ('dev.unit-0.cachePeerRtt.3.5min', '3', 1), |
591 | + ]) |
592 | |
593 | === modified file 'templates/main_config.template' |
594 | --- templates/main_config.template 2014-04-23 10:06:38 +0000 |
595 | +++ templates/main_config.template 2014-04-24 20:39:21 +0000 |
596 | @@ -21,9 +21,9 @@ |
597 | snmp_access allow snmp_access snmp_source |
598 | {% endif -%} |
599 | {% endfor -%} |
600 | +snmp_access allow localhost |
601 | snmp_access deny all |
602 | -snmp_port 3401 |
603 | -snmp_incoming_address {{ config.my_ip_address }} |
604 | +snmp_port {{ config.snmp_port }} |
605 | {% endif -%} |
606 | |
607 | via {{ config.via }} |
608 | |
609 | === added file 'templates/metrics_cronjob.template' |
610 | --- templates/metrics_cronjob.template 1970-01-01 00:00:00 +0000 |
611 | +++ templates/metrics_cronjob.template 2014-04-24 20:39:21 +0000 |
612 | @@ -0,0 +1,3 @@ |
613 | +# crontab for pushing squid metrics to statsd |
614 | +*/{{ interval }} * * * * root python {{ script }} {{ config }} | nc {{ statsd_host }} {{statsd_port }} |
615 | + |
616 | |
617 | === added file 'templates/squid_metrics_ini.template' |
618 | --- templates/squid_metrics_ini.template 1970-01-01 00:00:00 +0000 |
619 | +++ templates/squid_metrics_ini.template 2014-04-24 20:39:21 +0000 |
620 | @@ -0,0 +1,6 @@ |
621 | +[metrics] |
622 | +unit: {{ unit_name }} |
623 | +scheme: {{ metrics_scheme }} |
624 | +port: {{ snmp_port }} |
625 | +community: {{ snmp_community }} |
626 | +metrics: {{ metrics_list|join(',') }} |
This looks good to me, and has been tested in a staging environment.