Merge lp:~brad-marshall/charms/trusty/heat/add-nrpe-checks into lp:~openstack-charmers-archive/charms/trusty/heat/trunk
- Trusty Tahr (14.04)
- add-nrpe-checks
- Merge into trunk
Status: | Superseded | ||||
---|---|---|---|---|---|
Proposed branch: | lp:~brad-marshall/charms/trusty/heat/add-nrpe-checks | ||||
Merge into: | lp:~openstack-charmers-archive/charms/trusty/heat/trunk | ||||
Diff against target: |
620 lines (+515/-2) 8 files modified
charm-helpers.yaml (+1/-0) config.yaml (+10/-0) files/nrpe-external-master/check_upstart_job (+72/-0) hooks/charmhelpers/contrib/charmsupport/nrpe.py (+222/-0) hooks/charmhelpers/contrib/charmsupport/volumes.py (+156/-0) hooks/heat_relations.py (+42/-2) hooks/heat_utils.py (+8/-0) metadata.yaml (+4/-0) |
||||
To merge this branch: | bzr merge lp:~brad-marshall/charms/trusty/heat/add-nrpe-checks | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Liam Young (community) | Needs Fixing | ||
Review via email:
|
This proposal has been superseded by a proposal from 2014-11-17.
Commit message
Description of the change
Adds nrpe-external-
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ryan Beisner (1chb1n) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ryan Beisner (1chb1n) wrote : | # |
UOSCI bot says:
charm_lint_check #988 trusty-heat for brad-marshall mp241493
LINT FAIL: lint-test failed
LINT Results (max last 5 lines):
ERROR:root:Make target returned non-zero.
Running flake8 tests: hooks/heat_
hooks/
hooks/
make: *** [lint] Error 1
Full lint test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ryan Beisner (1chb1n) wrote : | # |
UOSCI bot says:
charm_unit_test #823 trusty-heat for brad-marshall mp241493
UNIT FAIL: unit-test failed
UNIT Results (max last 5 lines):
heat_utils 46 6 87% 70-78
TOTAL 170 42 75%
Ran 21 tests in 0.504s
FAILED (errors=2)
make: *** [test] Error 1
Full unit test output: http://
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Liam Young (gnuoy) wrote : | # |
Thanks again for the sorely needed nagios checks. Just a few comments...
Please steal the services() method from nova-cloud-
Please can the check_upstart_job go into charmhelpers
There appears to be some lint errors:
Running flake8 tests: hooks/heat_
hooks/heat_
hooks/heat_
Makefile:5: recipe for target 'lint' failed
make: *** [lint] Error 1
- 32. By Brad Marshall
-
[bradm] Fixes from pep8, used services() rather than hard coded list
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
UOSCI bot says:
charm_lint_check #1091 trusty-heat for brad-marshall mp241493
LINT OK: passed
LINT Results (max last 5 lines):
INFO:root:Searching for: ['@flake8']
INFO:root:command: make -f Makefile lint
Running flake8 tests: OK
Running charm proof: W: metadata name (heat) must match directory name (trusty-heat) exactly for local deployment.
OK
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 #925 trusty-heat for brad-marshall mp241493
UNIT FAIL: unit-test failed
UNIT Results (max last 5 lines):
heat_utils 51 10 80% 70-78, 141-144
TOTAL 177 49 72%
Ran 21 tests in 0.492s
FAILED (errors=2)
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 #433 trusty-heat for brad-marshall mp241493
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://
- 33. By Brad Marshall
-
[bradm] Removed nagios check files as they're now in n-e-m charm, added support for sysvinit daemon monitoring.
Unmerged revisions
- 33. By Brad Marshall
-
[bradm] Removed nagios check files as they're now in n-e-m charm, added support for sysvinit daemon monitoring.
- 32. By Brad Marshall
-
[bradm] Fixes from pep8, used services() rather than hard coded list
- 31. By Brad Marshall
-
[bradm] Check if host_context is defined before using it, checking if files before installing
- 30. By Brad Marshall
-
[bradm] Tweaked check to include host context and unit name
- 29. By Brad Marshall
-
[bradm] Added support to get nagios hostname from nrpe relation
- 28. By Brad Marshall
-
[bradm] Added charmsupport to charmhelpers
- 27. By root <email address hidden>
-
[bradm] initial nrpe checks
Preview Diff
1 | === modified file 'charm-helpers.yaml' |
2 | --- charm-helpers.yaml 2014-08-13 13:45:18 +0000 |
3 | +++ charm-helpers.yaml 2014-11-17 03:39:18 +0000 |
4 | @@ -10,3 +10,4 @@ |
5 | - apache |
6 | - cluster |
7 | - payload.execd |
8 | + - contrib.charmsupport |
9 | |
10 | === modified file 'config.yaml' |
11 | --- config.yaml 2014-04-08 20:05:44 +0000 |
12 | +++ config.yaml 2014-11-17 03:39:18 +0000 |
13 | @@ -44,3 +44,13 @@ |
14 | description: | |
15 | By default, all services will log into their corresponding log files. |
16 | Setting this to True will force all services to log to the syslog. |
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 | |
28 | === added directory 'files' |
29 | === added directory 'files/nrpe-external-master' |
30 | === added file 'files/nrpe-external-master/check_upstart_job' |
31 | --- files/nrpe-external-master/check_upstart_job 1970-01-01 00:00:00 +0000 |
32 | +++ files/nrpe-external-master/check_upstart_job 2014-11-17 03:39:18 +0000 |
33 | @@ -0,0 +1,72 @@ |
34 | +#!/usr/bin/python |
35 | + |
36 | +# |
37 | +# Copyright 2012, 2013 Canonical Ltd. |
38 | +# |
39 | +# Author: Paul Collins <paul.collins@canonical.com> |
40 | +# |
41 | +# Based on http://www.eurion.net/python-snippets/snippet/Upstart%20service%20status.html |
42 | +# |
43 | + |
44 | +import sys |
45 | + |
46 | +import dbus |
47 | + |
48 | + |
49 | +class Upstart(object): |
50 | + def __init__(self): |
51 | + self._bus = dbus.SystemBus() |
52 | + self._upstart = self._bus.get_object('com.ubuntu.Upstart', |
53 | + '/com/ubuntu/Upstart') |
54 | + def get_job(self, job_name): |
55 | + path = self._upstart.GetJobByName(job_name, |
56 | + dbus_interface='com.ubuntu.Upstart0_6') |
57 | + return self._bus.get_object('com.ubuntu.Upstart', path) |
58 | + |
59 | + def get_properties(self, job): |
60 | + path = job.GetInstance([], dbus_interface='com.ubuntu.Upstart0_6.Job') |
61 | + instance = self._bus.get_object('com.ubuntu.Upstart', path) |
62 | + return instance.GetAll('com.ubuntu.Upstart0_6.Instance', |
63 | + dbus_interface=dbus.PROPERTIES_IFACE) |
64 | + |
65 | + def get_job_instances(self, job_name): |
66 | + job = self.get_job(job_name) |
67 | + paths = job.GetAllInstances([], dbus_interface='com.ubuntu.Upstart0_6.Job') |
68 | + return [self._bus.get_object('com.ubuntu.Upstart', path) for path in paths] |
69 | + |
70 | + def get_job_instance_properties(self, job): |
71 | + return job.GetAll('com.ubuntu.Upstart0_6.Instance', |
72 | + dbus_interface=dbus.PROPERTIES_IFACE) |
73 | + |
74 | +try: |
75 | + upstart = Upstart() |
76 | + try: |
77 | + job = upstart.get_job(sys.argv[1]) |
78 | + props = upstart.get_properties(job) |
79 | + |
80 | + if props['state'] == 'running': |
81 | + print 'OK: %s is running' % sys.argv[1] |
82 | + sys.exit(0) |
83 | + else: |
84 | + print 'CRITICAL: %s is not running' % sys.argv[1] |
85 | + sys.exit(2) |
86 | + |
87 | + except dbus.DBusException as e: |
88 | + instances = upstart.get_job_instances(sys.argv[1]) |
89 | + propses = [upstart.get_job_instance_properties(instance) for instance in instances] |
90 | + states = dict([(props['name'], props['state']) for props in propses]) |
91 | + if len(states) != states.values().count('running'): |
92 | + not_running = [] |
93 | + for name in states.keys(): |
94 | + if states[name] != 'running': |
95 | + not_running.append(name) |
96 | + print 'CRITICAL: %d instances of %s not running: %s' % \ |
97 | + (len(not_running), sys.argv[1], not_running.join(', ')) |
98 | + sys.exit(2) |
99 | + else: |
100 | + print 'OK: %d instances of %s running' % (len(states), sys.argv[1]) |
101 | + |
102 | +except dbus.DBusException as e: |
103 | + print 'CRITICAL: failed to get properties of \'%s\' from upstart' % sys.argv[1] |
104 | + sys.exit(2) |
105 | + |
106 | |
107 | === added directory 'hooks/charmhelpers/contrib/charmsupport' |
108 | === added file 'hooks/charmhelpers/contrib/charmsupport/__init__.py' |
109 | === added file 'hooks/charmhelpers/contrib/charmsupport/nrpe.py' |
110 | --- hooks/charmhelpers/contrib/charmsupport/nrpe.py 1970-01-01 00:00:00 +0000 |
111 | +++ hooks/charmhelpers/contrib/charmsupport/nrpe.py 2014-11-17 03:39:18 +0000 |
112 | @@ -0,0 +1,222 @@ |
113 | +"""Compatibility with the nrpe-external-master charm""" |
114 | +# Copyright 2012 Canonical Ltd. |
115 | +# |
116 | +# Authors: |
117 | +# Matthew Wedgwood <matthew.wedgwood@canonical.com> |
118 | + |
119 | +import subprocess |
120 | +import pwd |
121 | +import grp |
122 | +import os |
123 | +import re |
124 | +import shlex |
125 | +import yaml |
126 | + |
127 | +from charmhelpers.core.hookenv import ( |
128 | + config, |
129 | + local_unit, |
130 | + log, |
131 | + relation_ids, |
132 | + relation_set, |
133 | +) |
134 | + |
135 | +from charmhelpers.core.host import service |
136 | + |
137 | +# This module adds compatibility with the nrpe-external-master and plain nrpe |
138 | +# subordinate charms. To use it in your charm: |
139 | +# |
140 | +# 1. Update metadata.yaml |
141 | +# |
142 | +# provides: |
143 | +# (...) |
144 | +# nrpe-external-master: |
145 | +# interface: nrpe-external-master |
146 | +# scope: container |
147 | +# |
148 | +# and/or |
149 | +# |
150 | +# provides: |
151 | +# (...) |
152 | +# local-monitors: |
153 | +# interface: local-monitors |
154 | +# scope: container |
155 | + |
156 | +# |
157 | +# 2. Add the following to config.yaml |
158 | +# |
159 | +# nagios_context: |
160 | +# default: "juju" |
161 | +# type: string |
162 | +# description: | |
163 | +# Used by the nrpe subordinate charms. |
164 | +# A string that will be prepended to instance name to set the host name |
165 | +# in nagios. So for instance the hostname would be something like: |
166 | +# juju-myservice-0 |
167 | +# If you're running multiple environments with the same services in them |
168 | +# this allows you to differentiate between them. |
169 | +# |
170 | +# 3. Add custom checks (Nagios plugins) to files/nrpe-external-master |
171 | +# |
172 | +# 4. Update your hooks.py with something like this: |
173 | +# |
174 | +# from charmsupport.nrpe import NRPE |
175 | +# (...) |
176 | +# def update_nrpe_config(): |
177 | +# nrpe_compat = NRPE() |
178 | +# nrpe_compat.add_check( |
179 | +# shortname = "myservice", |
180 | +# description = "Check MyService", |
181 | +# check_cmd = "check_http -w 2 -c 10 http://localhost" |
182 | +# ) |
183 | +# nrpe_compat.add_check( |
184 | +# "myservice_other", |
185 | +# "Check for widget failures", |
186 | +# check_cmd = "/srv/myapp/scripts/widget_check" |
187 | +# ) |
188 | +# nrpe_compat.write() |
189 | +# |
190 | +# def config_changed(): |
191 | +# (...) |
192 | +# update_nrpe_config() |
193 | +# |
194 | +# def nrpe_external_master_relation_changed(): |
195 | +# update_nrpe_config() |
196 | +# |
197 | +# def local_monitors_relation_changed(): |
198 | +# update_nrpe_config() |
199 | +# |
200 | +# 5. ln -s hooks.py nrpe-external-master-relation-changed |
201 | +# ln -s hooks.py local-monitors-relation-changed |
202 | + |
203 | + |
204 | +class CheckException(Exception): |
205 | + pass |
206 | + |
207 | + |
208 | +class Check(object): |
209 | + shortname_re = '[A-Za-z0-9-_]+$' |
210 | + service_template = (""" |
211 | +#--------------------------------------------------- |
212 | +# This file is Juju managed |
213 | +#--------------------------------------------------- |
214 | +define service {{ |
215 | + use active-service |
216 | + host_name {nagios_hostname} |
217 | + service_description {nagios_hostname}[{shortname}] """ |
218 | + """{description} |
219 | + check_command check_nrpe!{command} |
220 | + servicegroups {nagios_servicegroup} |
221 | +}} |
222 | +""") |
223 | + |
224 | + def __init__(self, shortname, description, check_cmd): |
225 | + super(Check, self).__init__() |
226 | + # XXX: could be better to calculate this from the service name |
227 | + if not re.match(self.shortname_re, shortname): |
228 | + raise CheckException("shortname must match {}".format( |
229 | + Check.shortname_re)) |
230 | + self.shortname = shortname |
231 | + self.command = "check_{}".format(shortname) |
232 | + # Note: a set of invalid characters is defined by the |
233 | + # Nagios server config |
234 | + # The default is: illegal_object_name_chars=`~!$%^&*"|'<>?,()= |
235 | + self.description = description |
236 | + self.check_cmd = self._locate_cmd(check_cmd) |
237 | + |
238 | + def _locate_cmd(self, check_cmd): |
239 | + search_path = ( |
240 | + '/', |
241 | + os.path.join(os.environ['CHARM_DIR'], |
242 | + 'files/nrpe-external-master'), |
243 | + '/usr/lib/nagios/plugins', |
244 | + '/usr/local/lib/nagios/plugins', |
245 | + ) |
246 | + parts = shlex.split(check_cmd) |
247 | + for path in search_path: |
248 | + if os.path.exists(os.path.join(path, parts[0])): |
249 | + command = os.path.join(path, parts[0]) |
250 | + if len(parts) > 1: |
251 | + command += " " + " ".join(parts[1:]) |
252 | + return command |
253 | + log('Check command not found: {}'.format(parts[0])) |
254 | + return '' |
255 | + |
256 | + def write(self, nagios_context, hostname): |
257 | + nrpe_check_file = '/etc/nagios/nrpe.d/{}.cfg'.format( |
258 | + self.command) |
259 | + with open(nrpe_check_file, 'w') as nrpe_check_config: |
260 | + nrpe_check_config.write("# check {}\n".format(self.shortname)) |
261 | + nrpe_check_config.write("command[{}]={}\n".format( |
262 | + self.command, self.check_cmd)) |
263 | + |
264 | + if not os.path.exists(NRPE.nagios_exportdir): |
265 | + log('Not writing service config as {} is not accessible'.format( |
266 | + NRPE.nagios_exportdir)) |
267 | + else: |
268 | + self.write_service_config(nagios_context, hostname) |
269 | + |
270 | + def write_service_config(self, nagios_context, hostname): |
271 | + for f in os.listdir(NRPE.nagios_exportdir): |
272 | + if re.search('.*{}.cfg'.format(self.command), f): |
273 | + os.remove(os.path.join(NRPE.nagios_exportdir, f)) |
274 | + |
275 | + templ_vars = { |
276 | + 'nagios_hostname': hostname, |
277 | + 'nagios_servicegroup': nagios_context, |
278 | + 'description': self.description, |
279 | + 'shortname': self.shortname, |
280 | + 'command': self.command, |
281 | + } |
282 | + nrpe_service_text = Check.service_template.format(**templ_vars) |
283 | + nrpe_service_file = '{}/service__{}_{}.cfg'.format( |
284 | + NRPE.nagios_exportdir, hostname, self.command) |
285 | + with open(nrpe_service_file, 'w') as nrpe_service_config: |
286 | + nrpe_service_config.write(str(nrpe_service_text)) |
287 | + |
288 | + def run(self): |
289 | + subprocess.call(self.check_cmd) |
290 | + |
291 | + |
292 | +class NRPE(object): |
293 | + nagios_logdir = '/var/log/nagios' |
294 | + nagios_exportdir = '/var/lib/nagios/export' |
295 | + nrpe_confdir = '/etc/nagios/nrpe.d' |
296 | + |
297 | + def __init__(self, hostname=None): |
298 | + super(NRPE, self).__init__() |
299 | + self.config = config() |
300 | + self.nagios_context = self.config['nagios_context'] |
301 | + self.unit_name = local_unit().replace('/', '-') |
302 | + if hostname: |
303 | + self.hostname = hostname |
304 | + else: |
305 | + self.hostname = "{}-{}".format(self.nagios_context, self.unit_name) |
306 | + self.checks = [] |
307 | + |
308 | + def add_check(self, *args, **kwargs): |
309 | + self.checks.append(Check(*args, **kwargs)) |
310 | + |
311 | + def write(self): |
312 | + try: |
313 | + nagios_uid = pwd.getpwnam('nagios').pw_uid |
314 | + nagios_gid = grp.getgrnam('nagios').gr_gid |
315 | + except: |
316 | + log("Nagios user not set up, nrpe checks not updated") |
317 | + return |
318 | + |
319 | + if not os.path.exists(NRPE.nagios_logdir): |
320 | + os.mkdir(NRPE.nagios_logdir) |
321 | + os.chown(NRPE.nagios_logdir, nagios_uid, nagios_gid) |
322 | + |
323 | + nrpe_monitors = {} |
324 | + monitors = {"monitors": {"remote": {"nrpe": nrpe_monitors}}} |
325 | + for nrpecheck in self.checks: |
326 | + nrpecheck.write(self.nagios_context, self.hostname) |
327 | + nrpe_monitors[nrpecheck.shortname] = { |
328 | + "command": nrpecheck.command, |
329 | + } |
330 | + |
331 | + service('restart', 'nagios-nrpe-server') |
332 | + |
333 | + for rid in relation_ids("local-monitors"): |
334 | + relation_set(relation_id=rid, monitors=yaml.dump(monitors)) |
335 | |
336 | === added file 'hooks/charmhelpers/contrib/charmsupport/volumes.py' |
337 | --- hooks/charmhelpers/contrib/charmsupport/volumes.py 1970-01-01 00:00:00 +0000 |
338 | +++ hooks/charmhelpers/contrib/charmsupport/volumes.py 2014-11-17 03:39:18 +0000 |
339 | @@ -0,0 +1,156 @@ |
340 | +''' |
341 | +Functions for managing volumes in juju units. One volume is supported per unit. |
342 | +Subordinates may have their own storage, provided it is on its own partition. |
343 | + |
344 | +Configuration stanzas: |
345 | + volume-ephemeral: |
346 | + type: boolean |
347 | + default: true |
348 | + description: > |
349 | + If false, a volume is mounted as sepecified in "volume-map" |
350 | + If true, ephemeral storage will be used, meaning that log data |
351 | + will only exist as long as the machine. YOU HAVE BEEN WARNED. |
352 | + volume-map: |
353 | + type: string |
354 | + default: {} |
355 | + description: > |
356 | + YAML map of units to device names, e.g: |
357 | + "{ rsyslog/0: /dev/vdb, rsyslog/1: /dev/vdb }" |
358 | + Service units will raise a configure-error if volume-ephemeral |
359 | + is 'true' and no volume-map value is set. Use 'juju set' to set a |
360 | + value and 'juju resolved' to complete configuration. |
361 | + |
362 | +Usage: |
363 | + from charmsupport.volumes import configure_volume, VolumeConfigurationError |
364 | + from charmsupport.hookenv import log, ERROR |
365 | + def post_mount_hook(): |
366 | + stop_service('myservice') |
367 | + def post_mount_hook(): |
368 | + start_service('myservice') |
369 | + |
370 | + if __name__ == '__main__': |
371 | + try: |
372 | + configure_volume(before_change=pre_mount_hook, |
373 | + after_change=post_mount_hook) |
374 | + except VolumeConfigurationError: |
375 | + log('Storage could not be configured', ERROR) |
376 | +''' |
377 | + |
378 | +# XXX: Known limitations |
379 | +# - fstab is neither consulted nor updated |
380 | + |
381 | +import os |
382 | +from charmhelpers.core import hookenv |
383 | +from charmhelpers.core import host |
384 | +import yaml |
385 | + |
386 | + |
387 | +MOUNT_BASE = '/srv/juju/volumes' |
388 | + |
389 | + |
390 | +class VolumeConfigurationError(Exception): |
391 | + '''Volume configuration data is missing or invalid''' |
392 | + pass |
393 | + |
394 | + |
395 | +def get_config(): |
396 | + '''Gather and sanity-check volume configuration data''' |
397 | + volume_config = {} |
398 | + config = hookenv.config() |
399 | + |
400 | + errors = False |
401 | + |
402 | + if config.get('volume-ephemeral') in (True, 'True', 'true', 'Yes', 'yes'): |
403 | + volume_config['ephemeral'] = True |
404 | + else: |
405 | + volume_config['ephemeral'] = False |
406 | + |
407 | + try: |
408 | + volume_map = yaml.safe_load(config.get('volume-map', '{}')) |
409 | + except yaml.YAMLError as e: |
410 | + hookenv.log("Error parsing YAML volume-map: {}".format(e), |
411 | + hookenv.ERROR) |
412 | + errors = True |
413 | + if volume_map is None: |
414 | + # probably an empty string |
415 | + volume_map = {} |
416 | + elif not isinstance(volume_map, dict): |
417 | + hookenv.log("Volume-map should be a dictionary, not {}".format( |
418 | + type(volume_map))) |
419 | + errors = True |
420 | + |
421 | + volume_config['device'] = volume_map.get(os.environ['JUJU_UNIT_NAME']) |
422 | + if volume_config['device'] and volume_config['ephemeral']: |
423 | + # asked for ephemeral storage but also defined a volume ID |
424 | + hookenv.log('A volume is defined for this unit, but ephemeral ' |
425 | + 'storage was requested', hookenv.ERROR) |
426 | + errors = True |
427 | + elif not volume_config['device'] and not volume_config['ephemeral']: |
428 | + # asked for permanent storage but did not define volume ID |
429 | + hookenv.log('Ephemeral storage was requested, but there is no volume ' |
430 | + 'defined for this unit.', hookenv.ERROR) |
431 | + errors = True |
432 | + |
433 | + unit_mount_name = hookenv.local_unit().replace('/', '-') |
434 | + volume_config['mountpoint'] = os.path.join(MOUNT_BASE, unit_mount_name) |
435 | + |
436 | + if errors: |
437 | + return None |
438 | + return volume_config |
439 | + |
440 | + |
441 | +def mount_volume(config): |
442 | + if os.path.exists(config['mountpoint']): |
443 | + if not os.path.isdir(config['mountpoint']): |
444 | + hookenv.log('Not a directory: {}'.format(config['mountpoint'])) |
445 | + raise VolumeConfigurationError() |
446 | + else: |
447 | + host.mkdir(config['mountpoint']) |
448 | + if os.path.ismount(config['mountpoint']): |
449 | + unmount_volume(config) |
450 | + if not host.mount(config['device'], config['mountpoint'], persist=True): |
451 | + raise VolumeConfigurationError() |
452 | + |
453 | + |
454 | +def unmount_volume(config): |
455 | + if os.path.ismount(config['mountpoint']): |
456 | + if not host.umount(config['mountpoint'], persist=True): |
457 | + raise VolumeConfigurationError() |
458 | + |
459 | + |
460 | +def managed_mounts(): |
461 | + '''List of all mounted managed volumes''' |
462 | + return filter(lambda mount: mount[0].startswith(MOUNT_BASE), host.mounts()) |
463 | + |
464 | + |
465 | +def configure_volume(before_change=lambda: None, after_change=lambda: None): |
466 | + '''Set up storage (or don't) according to the charm's volume configuration. |
467 | + Returns the mount point or "ephemeral". before_change and after_change |
468 | + are optional functions to be called if the volume configuration changes. |
469 | + ''' |
470 | + |
471 | + config = get_config() |
472 | + if not config: |
473 | + hookenv.log('Failed to read volume configuration', hookenv.CRITICAL) |
474 | + raise VolumeConfigurationError() |
475 | + |
476 | + if config['ephemeral']: |
477 | + if os.path.ismount(config['mountpoint']): |
478 | + before_change() |
479 | + unmount_volume(config) |
480 | + after_change() |
481 | + return 'ephemeral' |
482 | + else: |
483 | + # persistent storage |
484 | + if os.path.ismount(config['mountpoint']): |
485 | + mounts = dict(managed_mounts()) |
486 | + if mounts.get(config['mountpoint']) != config['device']: |
487 | + before_change() |
488 | + unmount_volume(config) |
489 | + mount_volume(config) |
490 | + after_change() |
491 | + else: |
492 | + before_change() |
493 | + mount_volume(config) |
494 | + after_change() |
495 | + return config['mountpoint'] |
496 | |
497 | === modified file 'hooks/heat_relations.py' |
498 | --- hooks/heat_relations.py 2014-04-12 20:48:50 +0000 |
499 | +++ hooks/heat_relations.py 2014-11-17 03:39:18 +0000 |
500 | @@ -20,6 +20,8 @@ |
501 | charm_dir, |
502 | log, |
503 | relation_set, |
504 | + relations_of_type, |
505 | + local_unit, |
506 | open_port, |
507 | unit_get |
508 | ) |
509 | @@ -45,6 +47,7 @@ |
510 | from heat_utils import ( |
511 | do_openstack_upgrade, |
512 | restart_map, |
513 | + services, |
514 | determine_packages, |
515 | register_configs, |
516 | HEAT_CONF, |
517 | @@ -54,6 +57,8 @@ |
518 | |
519 | from charmhelpers.payload.execd import execd_preinstall |
520 | |
521 | +from charmhelpers.contrib.charmsupport.nrpe import NRPE |
522 | + |
523 | hooks = Hooks() |
524 | CONFIGS = register_configs() |
525 | |
526 | @@ -69,8 +74,9 @@ |
527 | if os.path.isdir(_files): |
528 | for f in os.listdir(_files): |
529 | f = os.path.join(_files, f) |
530 | - log('Installing %s to /usr/bin' % f) |
531 | - shutil.copy2(f, '/usr/bin') |
532 | + if os.path.isfile(f): |
533 | + log('Installing %s to /usr/bin' % f) |
534 | + shutil.copy2(f, '/usr/bin') |
535 | |
536 | for port in API_PORTS.values(): |
537 | open_port(port) |
538 | @@ -81,6 +87,7 @@ |
539 | def config_changed(): |
540 | if openstack_upgrade_available('heat-engine'): |
541 | do_openstack_upgrade(CONFIGS) |
542 | + update_nrpe_config() |
543 | CONFIGS.write_all() |
544 | |
545 | |
546 | @@ -154,6 +161,39 @@ |
547 | CONFIGS.write_all() |
548 | |
549 | |
550 | +@hooks.hook('nrpe-external-master-relation-joined', |
551 | + 'nrpe-external-master-relation-changed') |
552 | +def update_nrpe_config(): |
553 | + # Find out if nrpe set nagios_hostname |
554 | + hostname = None |
555 | + host_context = None |
556 | + for rel in relations_of_type('nrpe-external-master'): |
557 | + if 'nagios_hostname' in rel: |
558 | + hostname = rel['nagios_hostname'] |
559 | + host_context = rel['nagios_host_context'] |
560 | + break |
561 | + nrpe = NRPE(hostname=hostname) |
562 | + apt_install('python-dbus') |
563 | + |
564 | + if host_context: |
565 | + current_unit = "%s:%s" % (host_context, local_unit()) |
566 | + else: |
567 | + current_unit = local_unit() |
568 | + |
569 | + services_to_monitor = services() |
570 | + |
571 | + for service in services_to_monitor: |
572 | + upstart_init = '/etc/init/%s.conf' % service |
573 | + if os.path.exists(upstart_init): |
574 | + nrpe.add_check( |
575 | + shortname=service, |
576 | + description='process check {%s}' % current_unit, |
577 | + check_cmd='check_upstart_job %s' % service, |
578 | + ) |
579 | + |
580 | + nrpe.write() |
581 | + |
582 | + |
583 | def main(): |
584 | try: |
585 | hooks.execute(sys.argv) |
586 | |
587 | === modified file 'hooks/heat_utils.py' |
588 | --- hooks/heat_utils.py 2014-04-12 21:40:16 +0000 |
589 | +++ hooks/heat_utils.py 2014-11-17 03:39:18 +0000 |
590 | @@ -134,3 +134,11 @@ |
591 | if svcs: |
592 | _map.append((f, svcs)) |
593 | return OrderedDict(_map) |
594 | + |
595 | + |
596 | +def services(): |
597 | + ''' Returns a list of services associate with this charm ''' |
598 | + _services = [] |
599 | + for v in restart_map().values(): |
600 | + _services = _services + v |
601 | + return list(set(_services)) |
602 | |
603 | === added symlink 'hooks/nrpe-external-master-relation-changed' |
604 | === target is u'heat_relations.py' |
605 | === added symlink 'hooks/nrpe-external-master-relation-joined' |
606 | === target is u'heat_relations.py' |
607 | === modified file 'metadata.yaml' |
608 | --- metadata.yaml 2014-04-16 08:19:26 +0000 |
609 | +++ metadata.yaml 2014-11-17 03:39:18 +0000 |
610 | @@ -5,6 +5,10 @@ |
611 | Heat is the main project in the OpenStack Orchestration program. It implements an |
612 | orchestration engine to launch multiple composite cloud applications based on |
613 | templates in the form of text files that can be treated like code. |
614 | +provides: |
615 | + nrpe-external-master: |
616 | + interface: nrpe-external-master |
617 | + scope: container |
618 | categories: |
619 | - openstack |
620 | requires: |
UOSCI bot says:
charm_amulet_test #368 trusty-heat for brad-marshall mp241493
AMULET FAIL: amulet-test missing
AMULET Results (max last 5 lines): jenkins/ workspace/ charm_amulet_ test
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:// paste.ubuntu. com/8955708/ 10.98.191. 181:8080/ job/charm_ amulet_ test/368/
Build: http://