Merge lp:~brad-marshall/charms/trusty/ceilometer/add-nrpe-checks into lp:~openstack-charmers-archive/charms/trusty/ceilometer/trunk
- Trusty Tahr (14.04)
- add-nrpe-checks
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 64 | ||||
Proposed branch: | lp:~brad-marshall/charms/trusty/ceilometer/add-nrpe-checks | ||||
Merge into: | lp:~openstack-charmers-archive/charms/trusty/ceilometer/trunk | ||||
Diff against target: |
596 lines (+466/-1) 7 files modified
charm-helpers.yaml (+1/-0) config.yaml (+10/-1) hooks/ceilometer_hooks.py (+55/-0) hooks/ceilometer_utils.py (+19/-0) hooks/charmhelpers/contrib/charmsupport/nrpe.py (+222/-0) hooks/charmhelpers/contrib/charmsupport/volumes.py (+156/-0) metadata.yaml (+3/-0) |
||||
To merge this branch: | bzr merge lp:~brad-marshall/charms/trusty/ceilometer/add-nrpe-checks | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Liam Young (community) | Disapprove | ||
Review via email:
|
This proposal supersedes a proposal from 2014-11-12.
Commit message
Description of the change
Adds nrpe-external-
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ryan Beisner (1chb1n) wrote : Posted in a previous version of this proposal | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ryan Beisner (1chb1n) wrote : Posted in a previous version of this proposal | # |
UOSCI bot says:
charm_unit_test #827 trusty-ceilometer for brad-marshall mp241498
UNIT FAIL: unit-test failed
UNIT Results (max last 5 lines):
hooks/
TOTAL 180 24 87%
Ran 25 tests in 0.729s
FAILED (errors=3)
make: *** [test] Error 1
Full unit test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ryan Beisner (1chb1n) wrote : Posted in a previous version of this proposal | # |
UOSCI bot says:
charm_amulet_test #372 trusty-ceilometer for brad-marshall mp241498
AMULET FAIL: amulet-test missing
AMULET Results (max last 5 lines):
INFO:root:Workspace dir: /var/lib/
INFO:root:Reading file: Makefile
INFO:root:Searching for: ['@juju test']
INFO:root:Search string not found in makefile target commands.
ERROR:root:No make target was executed.
Full amulet test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Liam Young (gnuoy) wrote : Posted in a previous version of this proposal | # |
Thank you for the mp, the nagios checks are sorely needed. It looks fine, there just a few things it would be good to get fixed up.
The list of services that comprise a ceilometer deployment are already compiled as part of the service context in ceilometer_
That being said, it looks like the existing charm has a list of new icehouse packages which are being added to the package list in ceilometer_utils.py but the corresponding services are not being added to the CONFIG_FILES OrderedDict. This means that the ceilometer-alarm* and ceilometer-
So, what I think is needed is:
1) Steal the services() method from nova-cloud-
2) Define a list of ICEHOUSE_SERVICES (probably exactly the same as ICEHOUSE_PACKAGES) and conditionally add (depending on ostack release) to the CEILOMETER_CONF service in register_configs():
if (get_os_
>= 'icehouse'):
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Liam Young (gnuoy) wrote : Posted in a previous version of this proposal | # |
Also, could you move the check_upstart_job into charmhelpers as it seems to be common across these mps?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal | # |
UOSCI bot says:
charm_unit_test #917 trusty-ceilometer for brad-marshall mp241498
UNIT FAIL: unit-test failed
UNIT Results (max last 5 lines):
hooks/
TOTAL 200 41 80%
Ran 25 tests in 0.747s
FAILED (errors=3)
make: *** [test] Error 1
Full unit test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal | # |
UOSCI bot says:
charm_amulet_test #425 trusty-ceilometer for brad-marshall mp241498
AMULET FAIL: amulet-test missing
AMULET Results (max last 5 lines):
INFO:root:Workspace dir: /var/lib/
INFO:root:Reading file: Makefile
INFO:root:Searching for: ['@juju test']
INFO:root:Search string not found in makefile target commands.
ERROR:root:No make target was executed.
Full amulet test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal | # |
UOSCI bot says:
charm_lint_check #1083 trusty-ceilometer for brad-marshall mp241498
LINT OK: passed
LINT Results (max last 5 lines):
I: config.yaml: option os-internal-network has no default value
I: config.yaml: option os-admin-network has no default value
I: config.yaml: option ssl_ca has no default value
I: config.yaml: option ssl_cert has no default value
I: config.yaml: option os-public-network has no default value
Full lint test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_amulet_test #434 trusty-ceilometer for brad-marshall mp241917
AMULET FAIL: amulet-test missing
AMULET Results (max last 5 lines):
INFO:root:Workspace dir: /var/lib/
INFO:root:Reading file: Makefile
INFO:root:Searching for: ['@juju test']
INFO:root:Search string not found in makefile target commands.
ERROR:root:No make target was executed.
Full amulet test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_unit_test #926 trusty-ceilometer for brad-marshall mp241917
UNIT FAIL: unit-test failed
UNIT Results (max last 5 lines):
hooks/
TOTAL 200 41 80%
Ran 25 tests in 0.836s
FAILED (errors=3)
make: *** [test] Error 1
Full unit test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_lint_check #1092 trusty-ceilometer for brad-marshall mp241917
LINT OK: passed
LINT Results (max last 5 lines):
I: config.yaml: option os-internal-network has no default value
I: config.yaml: option os-admin-network has no default value
I: config.yaml: option ssl_ca has no default value
I: config.yaml: option ssl_cert has no default value
I: config.yaml: option os-public-network has no default value
Full lint test output: http://
Build: http://
- 63. By Brad Marshall
-
[bradm] Removed puppet header from nagios_plugin module
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_lint_check #1103 trusty-ceilometer for brad-marshall mp241917
LINT OK: passed
LINT Results (max last 5 lines):
I: config.yaml: option os-internal-network has no default value
I: config.yaml: option os-admin-network has no default value
I: config.yaml: option ssl_ca has no default value
I: config.yaml: option ssl_cert has no default value
I: config.yaml: option os-public-network has no default value
Full lint test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_unit_test #937 trusty-ceilometer for brad-marshall mp241917
UNIT FAIL: unit-test failed
UNIT Results (max last 5 lines):
hooks/
TOTAL 200 41 80%
Ran 25 tests in 0.751s
FAILED (errors=3)
make: *** [test] Error 1
Full unit test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_amulet_test #445 trusty-ceilometer for brad-marshall mp241917
AMULET FAIL: amulet-test missing
AMULET Results (max last 5 lines):
INFO:root:Workspace dir: /var/lib/
INFO:root:Reading file: Makefile
INFO:root:Searching for: ['@juju test']
INFO:root:Search string not found in makefile target commands.
ERROR:root:No make target was executed.
Full amulet test output: http://
Build: http://
- 64. By Brad Marshall
-
[bradm] Removed nagios check files that were moved to nrpe-external-
master charm
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_amulet_test #453 trusty-ceilometer for brad-marshall mp241917
AMULET FAIL: amulet-test missing
AMULET Results (max last 5 lines):
INFO:root:Workspace dir: /var/lib/
INFO:root:Reading file: Makefile
INFO:root:Searching for: ['@juju test']
INFO:root:Search string not found in makefile target commands.
ERROR:root:No make target was executed.
Full amulet test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_lint_check #1111 trusty-ceilometer for brad-marshall mp241917
LINT OK: passed
LINT Results (max last 5 lines):
I: config.yaml: option os-internal-network has no default value
I: config.yaml: option os-admin-network has no default value
I: config.yaml: option ssl_ca has no default value
I: config.yaml: option ssl_cert has no default value
I: config.yaml: option os-public-network has no default value
Full lint test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_unit_test #945 trusty-ceilometer for brad-marshall mp241917
UNIT FAIL: unit-test failed
UNIT Results (max last 5 lines):
hooks/
TOTAL 199 40 80%
Ran 25 tests in 0.731s
FAILED (errors=3)
make: *** [test] Error 1
Full unit test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_lint_check #1254 trusty-ceilometer for brad-marshall mp241917
LINT OK: passed
LINT Results (max last 5 lines):
I: config.yaml: option os-internal-network has no default value
I: config.yaml: option os-admin-network has no default value
I: config.yaml: option ssl_ca has no default value
I: config.yaml: option ssl_cert has no default value
I: config.yaml: option os-public-network has no default value
Full lint test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_unit_test #1088 trusty-ceilometer for brad-marshall mp241917
UNIT FAIL: unit-test failed
UNIT Results (max last 5 lines):
hooks/
TOTAL 199 40 80%
Ran 25 tests in 0.833s
FAILED (errors=3)
make: *** [test] Error 1
Full unit test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_amulet_test #557 trusty-ceilometer for brad-marshall mp241917
AMULET FAIL: amulet-test missing
AMULET Results (max last 5 lines):
INFO:root:Workspace dir: /var/lib/
INFO:root:Reading file: Makefile
INFO:root:Searching for: ['@juju test']
INFO:root:Search string not found in makefile target commands.
ERROR:root:No make target was executed.
Full amulet test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Liam Young (gnuoy) wrote : | # |
Thank for the mp. The new nrpe support is very gratefully received !
I've taken this branch and centralised the common code between this and the other nrpe branches and moved it to charm-helpers. To land it I created a new branch from this one which has now been merged into the 'next' charm. The 'next' charms will overwrite the stable ones in a couple of weeks.
Preview Diff
1 | === modified file 'charm-helpers.yaml' |
2 | --- charm-helpers.yaml 2014-07-24 10:23:25 +0000 |
3 | +++ charm-helpers.yaml 2014-11-18 01:03:04 +0000 |
4 | @@ -7,3 +7,4 @@ |
5 | - contrib.hahelpers |
6 | - contrib.storage.linux |
7 | - contrib.network.ip |
8 | + - contrib.charmsupport |
9 | |
10 | === modified file 'config.yaml' |
11 | --- config.yaml 2014-10-01 15:22:55 +0000 |
12 | +++ config.yaml 2014-11-18 01:03:04 +0000 |
13 | @@ -58,6 +58,16 @@ |
14 | description: | |
15 | SSL CA to use with the certificate and key provided - this is only |
16 | required if you are providing a privately signed ssl_cert and ssl_key. |
17 | + nagios_context: |
18 | + default: "juju" |
19 | + type: string |
20 | + description: | |
21 | + Used by the nrpe-external-master subordinate charm. |
22 | + A string that will be prepended to instance name to set the host name |
23 | + in nagios. So for instance the hostname would be something like: |
24 | + juju-myservice-0 |
25 | + If you're running multiple environments with the same services in them |
26 | + this allows you to differentiate between them. |
27 | # Network configuration options |
28 | # by default all access is over 'private-address' |
29 | os-admin-network: |
30 | @@ -84,4 +94,3 @@ |
31 | 192.168.0.0/24) |
32 | . |
33 | This network will be used for public endpoints. |
34 | - |
35 | |
36 | === added directory 'files' |
37 | === modified file 'hooks/ceilometer_hooks.py' |
38 | --- hooks/ceilometer_hooks.py 2014-10-01 15:22:55 +0000 |
39 | +++ hooks/ceilometer_hooks.py 2014-11-18 01:03:04 +0000 |
40 | @@ -2,14 +2,17 @@ |
41 | |
42 | import base64 |
43 | import sys |
44 | +import os |
45 | from charmhelpers.fetch import ( |
46 | apt_install, filter_installed_packages, |
47 | apt_update |
48 | ) |
49 | from charmhelpers.core.hookenv import ( |
50 | open_port, |
51 | + local_unit, |
52 | relation_set, |
53 | relation_ids, |
54 | + relations_of_type, |
55 | config, |
56 | Hooks, UnregisteredHookError, |
57 | log |
58 | @@ -29,6 +32,7 @@ |
59 | CEILOMETER_ROLE, |
60 | register_configs, |
61 | restart_map, |
62 | + services, |
63 | get_ceilometer_context, |
64 | do_openstack_upgrade |
65 | ) |
66 | @@ -37,6 +41,7 @@ |
67 | canonical_url, |
68 | PUBLIC, INTERNAL, ADMIN |
69 | ) |
70 | +from charmhelpers.contrib.charmsupport.nrpe import NRPE |
71 | |
72 | hooks = Hooks() |
73 | CONFIGS = register_configs() |
74 | @@ -89,6 +94,7 @@ |
75 | def config_changed(): |
76 | if openstack_upgrade_available('ceilometer-common'): |
77 | do_openstack_upgrade(CONFIGS) |
78 | + update_nrpe_config() |
79 | CONFIGS.write_all() |
80 | ceilometer_joined() |
81 | for rid in relation_ids('identity-service'): |
82 | @@ -98,6 +104,7 @@ |
83 | @hooks.hook('upgrade-charm') |
84 | def upgrade_charm(): |
85 | install() |
86 | + update_nrpe_config() |
87 | any_changed() |
88 | |
89 | |
90 | @@ -137,6 +144,54 @@ |
91 | for relid in relation_ids('ceilometer-service'): |
92 | relation_set(relid, context) |
93 | |
94 | + |
95 | +@hooks.hook('nrpe-external-master-relation-joined', |
96 | + 'nrpe-external-master-relation-changed') |
97 | +def update_nrpe_config(): |
98 | + # Find out if nrpe set nagios_hostname |
99 | + hostname = None |
100 | + host_context = None |
101 | + for rel in relations_of_type('nrpe-external-master'): |
102 | + if 'nagios_hostname' in rel: |
103 | + hostname = rel['nagios_hostname'] |
104 | + host_context = rel['nagios_host_context'] |
105 | + break |
106 | + nrpe = NRPE(hostname=hostname) |
107 | + apt_install('python-dbus') |
108 | + |
109 | + if host_context: |
110 | + current_unit = "%s:%s" % (host_context, local_unit()) |
111 | + else: |
112 | + current_unit = local_unit() |
113 | + |
114 | + services_to_monitor = services() |
115 | + |
116 | + for service in services_to_monitor: |
117 | + upstart_init = '/etc/init/%s.conf' % service |
118 | + sysv_init = '/etc/init.d/%s' % service |
119 | + if os.path.exists(upstart_init): |
120 | + nrpe.add_check( |
121 | + shortname=service, |
122 | + description='process check {%s}' % current_unit, |
123 | + check_cmd='check_upstart_job %s' % service, |
124 | + ) |
125 | + elif os.path.exists(sysv_init): |
126 | + cronpath = '/etc/cron.d/nagios-service-check-%s' % service |
127 | + cron_template = '*/5 * * * * root \ |
128 | +/usr/local/lib/nagios/plugins/check_exit_status.pl -s /etc/init.d/%s \ |
129 | +status > /var/lib/nagios/service-check-%s.txt\n' % (service, service) |
130 | + f = open(cronpath, 'w') |
131 | + f.write(cron_template) |
132 | + f.close() |
133 | + nrpe.add_check( |
134 | + shortname=service, |
135 | + description='process check {%s}' % current_unit, |
136 | + check_cmd='check_status_file.py -f \ |
137 | + /var/lib/nagios/service-check-%s.txt' % service, |
138 | + ) |
139 | + |
140 | + nrpe.write() |
141 | + |
142 | if __name__ == '__main__': |
143 | try: |
144 | hooks.execute(sys.argv) |
145 | |
146 | === modified file 'hooks/ceilometer_utils.py' |
147 | --- hooks/ceilometer_utils.py 2014-10-23 16:03:49 +0000 |
148 | +++ hooks/ceilometer_utils.py 2014-11-18 01:03:04 +0000 |
149 | @@ -50,6 +50,12 @@ |
150 | 'ceilometer-agent-notification' |
151 | ] |
152 | |
153 | +ICEHOUSE_SERVICES = [ |
154 | + 'ceilometer-alarm-notifier', |
155 | + 'ceilometer-alarm-evaluator', |
156 | + 'ceilometer-agent-notification' |
157 | +] |
158 | + |
159 | CEILOMETER_ROLE = "ResellerAdmin" |
160 | |
161 | |
162 | @@ -90,6 +96,11 @@ |
163 | configs = templating.OSConfigRenderer(templates_dir=TEMPLATES, |
164 | openstack_release=release) |
165 | |
166 | + if (get_os_codename_install_source(config('openstack-origin')) |
167 | + >= 'icehouse'): |
168 | + CONFIG_FILES[CEILOMETER_CONF]['services'] = \ |
169 | + CONFIG_FILES[CEILOMETER_CONF]['services'] + ICEHOUSE_SERVICES |
170 | + |
171 | for conf in CONFIG_FILES: |
172 | configs.register(conf, CONFIG_FILES[conf]['hook_contexts']) |
173 | |
174 | @@ -120,6 +131,14 @@ |
175 | return _map |
176 | |
177 | |
178 | +def services(): |
179 | + ''' Returns a list of services associate with this charm ''' |
180 | + _services = [] |
181 | + for v in restart_map().values(): |
182 | + _services = _services + v |
183 | + return list(set(_services)) |
184 | + |
185 | + |
186 | def get_ceilometer_context(): |
187 | ''' Retrieve a map of all current relation data for agent configuration ''' |
188 | ctxt = {} |
189 | |
190 | === added directory 'hooks/charmhelpers/contrib/charmsupport' |
191 | === added file 'hooks/charmhelpers/contrib/charmsupport/__init__.py' |
192 | === added file 'hooks/charmhelpers/contrib/charmsupport/nrpe.py' |
193 | --- hooks/charmhelpers/contrib/charmsupport/nrpe.py 1970-01-01 00:00:00 +0000 |
194 | +++ hooks/charmhelpers/contrib/charmsupport/nrpe.py 2014-11-18 01:03:04 +0000 |
195 | @@ -0,0 +1,222 @@ |
196 | +"""Compatibility with the nrpe-external-master charm""" |
197 | +# Copyright 2012 Canonical Ltd. |
198 | +# |
199 | +# Authors: |
200 | +# Matthew Wedgwood <matthew.wedgwood@canonical.com> |
201 | + |
202 | +import subprocess |
203 | +import pwd |
204 | +import grp |
205 | +import os |
206 | +import re |
207 | +import shlex |
208 | +import yaml |
209 | + |
210 | +from charmhelpers.core.hookenv import ( |
211 | + config, |
212 | + local_unit, |
213 | + log, |
214 | + relation_ids, |
215 | + relation_set, |
216 | +) |
217 | + |
218 | +from charmhelpers.core.host import service |
219 | + |
220 | +# This module adds compatibility with the nrpe-external-master and plain nrpe |
221 | +# subordinate charms. To use it in your charm: |
222 | +# |
223 | +# 1. Update metadata.yaml |
224 | +# |
225 | +# provides: |
226 | +# (...) |
227 | +# nrpe-external-master: |
228 | +# interface: nrpe-external-master |
229 | +# scope: container |
230 | +# |
231 | +# and/or |
232 | +# |
233 | +# provides: |
234 | +# (...) |
235 | +# local-monitors: |
236 | +# interface: local-monitors |
237 | +# scope: container |
238 | + |
239 | +# |
240 | +# 2. Add the following to config.yaml |
241 | +# |
242 | +# nagios_context: |
243 | +# default: "juju" |
244 | +# type: string |
245 | +# description: | |
246 | +# Used by the nrpe subordinate charms. |
247 | +# A string that will be prepended to instance name to set the host name |
248 | +# in nagios. So for instance the hostname would be something like: |
249 | +# juju-myservice-0 |
250 | +# If you're running multiple environments with the same services in them |
251 | +# this allows you to differentiate between them. |
252 | +# |
253 | +# 3. Add custom checks (Nagios plugins) to files/nrpe-external-master |
254 | +# |
255 | +# 4. Update your hooks.py with something like this: |
256 | +# |
257 | +# from charmsupport.nrpe import NRPE |
258 | +# (...) |
259 | +# def update_nrpe_config(): |
260 | +# nrpe_compat = NRPE() |
261 | +# nrpe_compat.add_check( |
262 | +# shortname = "myservice", |
263 | +# description = "Check MyService", |
264 | +# check_cmd = "check_http -w 2 -c 10 http://localhost" |
265 | +# ) |
266 | +# nrpe_compat.add_check( |
267 | +# "myservice_other", |
268 | +# "Check for widget failures", |
269 | +# check_cmd = "/srv/myapp/scripts/widget_check" |
270 | +# ) |
271 | +# nrpe_compat.write() |
272 | +# |
273 | +# def config_changed(): |
274 | +# (...) |
275 | +# update_nrpe_config() |
276 | +# |
277 | +# def nrpe_external_master_relation_changed(): |
278 | +# update_nrpe_config() |
279 | +# |
280 | +# def local_monitors_relation_changed(): |
281 | +# update_nrpe_config() |
282 | +# |
283 | +# 5. ln -s hooks.py nrpe-external-master-relation-changed |
284 | +# ln -s hooks.py local-monitors-relation-changed |
285 | + |
286 | + |
287 | +class CheckException(Exception): |
288 | + pass |
289 | + |
290 | + |
291 | +class Check(object): |
292 | + shortname_re = '[A-Za-z0-9-_]+$' |
293 | + service_template = (""" |
294 | +#--------------------------------------------------- |
295 | +# This file is Juju managed |
296 | +#--------------------------------------------------- |
297 | +define service {{ |
298 | + use active-service |
299 | + host_name {nagios_hostname} |
300 | + service_description {nagios_hostname}[{shortname}] """ |
301 | + """{description} |
302 | + check_command check_nrpe!{command} |
303 | + servicegroups {nagios_servicegroup} |
304 | +}} |
305 | +""") |
306 | + |
307 | + def __init__(self, shortname, description, check_cmd): |
308 | + super(Check, self).__init__() |
309 | + # XXX: could be better to calculate this from the service name |
310 | + if not re.match(self.shortname_re, shortname): |
311 | + raise CheckException("shortname must match {}".format( |
312 | + Check.shortname_re)) |
313 | + self.shortname = shortname |
314 | + self.command = "check_{}".format(shortname) |
315 | + # Note: a set of invalid characters is defined by the |
316 | + # Nagios server config |
317 | + # The default is: illegal_object_name_chars=`~!$%^&*"|'<>?,()= |
318 | + self.description = description |
319 | + self.check_cmd = self._locate_cmd(check_cmd) |
320 | + |
321 | + def _locate_cmd(self, check_cmd): |
322 | + search_path = ( |
323 | + '/', |
324 | + os.path.join(os.environ['CHARM_DIR'], |
325 | + 'files/nrpe-external-master'), |
326 | + '/usr/lib/nagios/plugins', |
327 | + '/usr/local/lib/nagios/plugins', |
328 | + ) |
329 | + parts = shlex.split(check_cmd) |
330 | + for path in search_path: |
331 | + if os.path.exists(os.path.join(path, parts[0])): |
332 | + command = os.path.join(path, parts[0]) |
333 | + if len(parts) > 1: |
334 | + command += " " + " ".join(parts[1:]) |
335 | + return command |
336 | + log('Check command not found: {}'.format(parts[0])) |
337 | + return '' |
338 | + |
339 | + def write(self, nagios_context, hostname): |
340 | + nrpe_check_file = '/etc/nagios/nrpe.d/{}.cfg'.format( |
341 | + self.command) |
342 | + with open(nrpe_check_file, 'w') as nrpe_check_config: |
343 | + nrpe_check_config.write("# check {}\n".format(self.shortname)) |
344 | + nrpe_check_config.write("command[{}]={}\n".format( |
345 | + self.command, self.check_cmd)) |
346 | + |
347 | + if not os.path.exists(NRPE.nagios_exportdir): |
348 | + log('Not writing service config as {} is not accessible'.format( |
349 | + NRPE.nagios_exportdir)) |
350 | + else: |
351 | + self.write_service_config(nagios_context, hostname) |
352 | + |
353 | + def write_service_config(self, nagios_context, hostname): |
354 | + for f in os.listdir(NRPE.nagios_exportdir): |
355 | + if re.search('.*{}.cfg'.format(self.command), f): |
356 | + os.remove(os.path.join(NRPE.nagios_exportdir, f)) |
357 | + |
358 | + templ_vars = { |
359 | + 'nagios_hostname': hostname, |
360 | + 'nagios_servicegroup': nagios_context, |
361 | + 'description': self.description, |
362 | + 'shortname': self.shortname, |
363 | + 'command': self.command, |
364 | + } |
365 | + nrpe_service_text = Check.service_template.format(**templ_vars) |
366 | + nrpe_service_file = '{}/service__{}_{}.cfg'.format( |
367 | + NRPE.nagios_exportdir, hostname, self.command) |
368 | + with open(nrpe_service_file, 'w') as nrpe_service_config: |
369 | + nrpe_service_config.write(str(nrpe_service_text)) |
370 | + |
371 | + def run(self): |
372 | + subprocess.call(self.check_cmd) |
373 | + |
374 | + |
375 | +class NRPE(object): |
376 | + nagios_logdir = '/var/log/nagios' |
377 | + nagios_exportdir = '/var/lib/nagios/export' |
378 | + nrpe_confdir = '/etc/nagios/nrpe.d' |
379 | + |
380 | + def __init__(self, hostname=None): |
381 | + super(NRPE, self).__init__() |
382 | + self.config = config() |
383 | + self.nagios_context = self.config['nagios_context'] |
384 | + self.unit_name = local_unit().replace('/', '-') |
385 | + if hostname: |
386 | + self.hostname = hostname |
387 | + else: |
388 | + self.hostname = "{}-{}".format(self.nagios_context, self.unit_name) |
389 | + self.checks = [] |
390 | + |
391 | + def add_check(self, *args, **kwargs): |
392 | + self.checks.append(Check(*args, **kwargs)) |
393 | + |
394 | + def write(self): |
395 | + try: |
396 | + nagios_uid = pwd.getpwnam('nagios').pw_uid |
397 | + nagios_gid = grp.getgrnam('nagios').gr_gid |
398 | + except: |
399 | + log("Nagios user not set up, nrpe checks not updated") |
400 | + return |
401 | + |
402 | + if not os.path.exists(NRPE.nagios_logdir): |
403 | + os.mkdir(NRPE.nagios_logdir) |
404 | + os.chown(NRPE.nagios_logdir, nagios_uid, nagios_gid) |
405 | + |
406 | + nrpe_monitors = {} |
407 | + monitors = {"monitors": {"remote": {"nrpe": nrpe_monitors}}} |
408 | + for nrpecheck in self.checks: |
409 | + nrpecheck.write(self.nagios_context, self.hostname) |
410 | + nrpe_monitors[nrpecheck.shortname] = { |
411 | + "command": nrpecheck.command, |
412 | + } |
413 | + |
414 | + service('restart', 'nagios-nrpe-server') |
415 | + |
416 | + for rid in relation_ids("local-monitors"): |
417 | + relation_set(relation_id=rid, monitors=yaml.dump(monitors)) |
418 | |
419 | === added file 'hooks/charmhelpers/contrib/charmsupport/volumes.py' |
420 | --- hooks/charmhelpers/contrib/charmsupport/volumes.py 1970-01-01 00:00:00 +0000 |
421 | +++ hooks/charmhelpers/contrib/charmsupport/volumes.py 2014-11-18 01:03:04 +0000 |
422 | @@ -0,0 +1,156 @@ |
423 | +''' |
424 | +Functions for managing volumes in juju units. One volume is supported per unit. |
425 | +Subordinates may have their own storage, provided it is on its own partition. |
426 | + |
427 | +Configuration stanzas: |
428 | + volume-ephemeral: |
429 | + type: boolean |
430 | + default: true |
431 | + description: > |
432 | + If false, a volume is mounted as sepecified in "volume-map" |
433 | + If true, ephemeral storage will be used, meaning that log data |
434 | + will only exist as long as the machine. YOU HAVE BEEN WARNED. |
435 | + volume-map: |
436 | + type: string |
437 | + default: {} |
438 | + description: > |
439 | + YAML map of units to device names, e.g: |
440 | + "{ rsyslog/0: /dev/vdb, rsyslog/1: /dev/vdb }" |
441 | + Service units will raise a configure-error if volume-ephemeral |
442 | + is 'true' and no volume-map value is set. Use 'juju set' to set a |
443 | + value and 'juju resolved' to complete configuration. |
444 | + |
445 | +Usage: |
446 | + from charmsupport.volumes import configure_volume, VolumeConfigurationError |
447 | + from charmsupport.hookenv import log, ERROR |
448 | + def post_mount_hook(): |
449 | + stop_service('myservice') |
450 | + def post_mount_hook(): |
451 | + start_service('myservice') |
452 | + |
453 | + if __name__ == '__main__': |
454 | + try: |
455 | + configure_volume(before_change=pre_mount_hook, |
456 | + after_change=post_mount_hook) |
457 | + except VolumeConfigurationError: |
458 | + log('Storage could not be configured', ERROR) |
459 | +''' |
460 | + |
461 | +# XXX: Known limitations |
462 | +# - fstab is neither consulted nor updated |
463 | + |
464 | +import os |
465 | +from charmhelpers.core import hookenv |
466 | +from charmhelpers.core import host |
467 | +import yaml |
468 | + |
469 | + |
470 | +MOUNT_BASE = '/srv/juju/volumes' |
471 | + |
472 | + |
473 | +class VolumeConfigurationError(Exception): |
474 | + '''Volume configuration data is missing or invalid''' |
475 | + pass |
476 | + |
477 | + |
478 | +def get_config(): |
479 | + '''Gather and sanity-check volume configuration data''' |
480 | + volume_config = {} |
481 | + config = hookenv.config() |
482 | + |
483 | + errors = False |
484 | + |
485 | + if config.get('volume-ephemeral') in (True, 'True', 'true', 'Yes', 'yes'): |
486 | + volume_config['ephemeral'] = True |
487 | + else: |
488 | + volume_config['ephemeral'] = False |
489 | + |
490 | + try: |
491 | + volume_map = yaml.safe_load(config.get('volume-map', '{}')) |
492 | + except yaml.YAMLError as e: |
493 | + hookenv.log("Error parsing YAML volume-map: {}".format(e), |
494 | + hookenv.ERROR) |
495 | + errors = True |
496 | + if volume_map is None: |
497 | + # probably an empty string |
498 | + volume_map = {} |
499 | + elif not isinstance(volume_map, dict): |
500 | + hookenv.log("Volume-map should be a dictionary, not {}".format( |
501 | + type(volume_map))) |
502 | + errors = True |
503 | + |
504 | + volume_config['device'] = volume_map.get(os.environ['JUJU_UNIT_NAME']) |
505 | + if volume_config['device'] and volume_config['ephemeral']: |
506 | + # asked for ephemeral storage but also defined a volume ID |
507 | + hookenv.log('A volume is defined for this unit, but ephemeral ' |
508 | + 'storage was requested', hookenv.ERROR) |
509 | + errors = True |
510 | + elif not volume_config['device'] and not volume_config['ephemeral']: |
511 | + # asked for permanent storage but did not define volume ID |
512 | + hookenv.log('Ephemeral storage was requested, but there is no volume ' |
513 | + 'defined for this unit.', hookenv.ERROR) |
514 | + errors = True |
515 | + |
516 | + unit_mount_name = hookenv.local_unit().replace('/', '-') |
517 | + volume_config['mountpoint'] = os.path.join(MOUNT_BASE, unit_mount_name) |
518 | + |
519 | + if errors: |
520 | + return None |
521 | + return volume_config |
522 | + |
523 | + |
524 | +def mount_volume(config): |
525 | + if os.path.exists(config['mountpoint']): |
526 | + if not os.path.isdir(config['mountpoint']): |
527 | + hookenv.log('Not a directory: {}'.format(config['mountpoint'])) |
528 | + raise VolumeConfigurationError() |
529 | + else: |
530 | + host.mkdir(config['mountpoint']) |
531 | + if os.path.ismount(config['mountpoint']): |
532 | + unmount_volume(config) |
533 | + if not host.mount(config['device'], config['mountpoint'], persist=True): |
534 | + raise VolumeConfigurationError() |
535 | + |
536 | + |
537 | +def unmount_volume(config): |
538 | + if os.path.ismount(config['mountpoint']): |
539 | + if not host.umount(config['mountpoint'], persist=True): |
540 | + raise VolumeConfigurationError() |
541 | + |
542 | + |
543 | +def managed_mounts(): |
544 | + '''List of all mounted managed volumes''' |
545 | + return filter(lambda mount: mount[0].startswith(MOUNT_BASE), host.mounts()) |
546 | + |
547 | + |
548 | +def configure_volume(before_change=lambda: None, after_change=lambda: None): |
549 | + '''Set up storage (or don't) according to the charm's volume configuration. |
550 | + Returns the mount point or "ephemeral". before_change and after_change |
551 | + are optional functions to be called if the volume configuration changes. |
552 | + ''' |
553 | + |
554 | + config = get_config() |
555 | + if not config: |
556 | + hookenv.log('Failed to read volume configuration', hookenv.CRITICAL) |
557 | + raise VolumeConfigurationError() |
558 | + |
559 | + if config['ephemeral']: |
560 | + if os.path.ismount(config['mountpoint']): |
561 | + before_change() |
562 | + unmount_volume(config) |
563 | + after_change() |
564 | + return 'ephemeral' |
565 | + else: |
566 | + # persistent storage |
567 | + if os.path.ismount(config['mountpoint']): |
568 | + mounts = dict(managed_mounts()) |
569 | + if mounts.get(config['mountpoint']) != config['device']: |
570 | + before_change() |
571 | + unmount_volume(config) |
572 | + mount_volume(config) |
573 | + after_change() |
574 | + else: |
575 | + before_change() |
576 | + mount_volume(config) |
577 | + after_change() |
578 | + return config['mountpoint'] |
579 | |
580 | === added symlink 'hooks/nrpe-external-master-relation-changed' |
581 | === target is u'ceilometer_hooks.py' |
582 | === added symlink 'hooks/nrpe-external-master-relation-joined' |
583 | === target is u'ceilometer_hooks.py' |
584 | === modified file 'metadata.yaml' |
585 | --- metadata.yaml 2013-10-20 22:30:27 +0000 |
586 | +++ metadata.yaml 2014-11-18 01:03:04 +0000 |
587 | @@ -12,6 +12,9 @@ |
588 | - miscellaneous |
589 | - openstack |
590 | provides: |
591 | + nrpe-external-master: |
592 | + interface: nrpe-external-master |
593 | + scope: container |
594 | ceilometer-service: |
595 | interface: ceilometer |
596 | requires: |
UOSCI bot says:
charm_lint_check #992 trusty-ceilometer for brad-marshall mp241498
LINT FAIL: lint-test failed
LINT Results (max last 5 lines): ceilometer_ hooks.py: 146:80: E501 line too long (92 > 79 characters) ceilometer_ hooks.py: 174:22: E251 unexpected spaces around keyword / parameter equals ceilometer_ hooks.py: 174:24: E251 unexpected spaces around keyword / parameter equals
ERROR:root:Make target returned non-zero.
hooks/
hooks/
hooks/
make: *** [lint] Error 1
Full lint test output: http:// paste.ubuntu. com/8955755/ 10.98.191. 181:8080/ job/charm_ lint_check/ 992/
Build: http://