Merge lp:~brad-marshall/charms/trusty/heat/add-nrpe-checks into lp:~openstack-charmers-archive/charms/trusty/heat/trunk

Proposed by Brad Marshall
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
Reviewer Review Type Date Requested Status
Liam Young (community) Needs Fixing
Review via email: mp+241493@code.launchpad.net

This proposal has been superseded by a proposal from 2014-11-17.

Description of the change

Adds nrpe-external-master interface and adds basic nrpe checks.

To post a comment you must log in.
Revision history for this message
Ryan Beisner (1chb1n) wrote :

UOSCI bot says:
charm_amulet_test #368 trusty-heat for brad-marshall mp241493
    AMULET FAIL: amulet-test missing

AMULET Results (max last 5 lines):
INFO:root:Workspace dir: /var/lib/jenkins/workspace/charm_amulet_test
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/
Build: http://10.98.191.181:8080/job/charm_amulet_test/368/

Revision history for this message
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_relations.py:163:80: E501 line too long (92 > 79 characters)
  hooks/heat_relations.py:190:22: E251 unexpected spaces around keyword / parameter equals
  hooks/heat_relations.py:190:24: E251 unexpected spaces around keyword / parameter equals
  make: *** [lint] Error 1

Full lint test output: http://paste.ubuntu.com/8955709/
Build: http://10.98.191.181:8080/job/charm_lint_check/988/

Revision history for this message
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://paste.ubuntu.com/8955710/
Build: http://10.98.191.181:8080/job/charm_unit_test/823/

Revision history for this message
Liam Young (gnuoy) wrote :

Thanks again for the sorely needed nagios checks. Just a few comments...

Please steal the services() method from nova-cloud-controller and add it to hooks/heat_utils.py and use that to get a list services rather than defining a new list in update_nagios().

Please can the check_upstart_job go into charmhelpers

There appears to be some lint errors:
Running flake8 tests: hooks/heat_relations.py:163:80: E501 line too long (92 > 79 characters)
hooks/heat_relations.py:190:22: E251 unexpected spaces around keyword / parameter equals
hooks/heat_relations.py:190:24: E251 unexpected spaces around keyword / parameter equals
Makefile:5: recipe for target 'lint' failed
make: *** [lint] Error 1

review: Needs Fixing
32. By Brad Marshall

[bradm] Fixes from pep8, used services() rather than hard coded list

Revision history for this message
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://paste.ubuntu.com/9052189/
Build: http://10.98.191.181:8080/job/charm_lint_check/1091/

Revision history for this message
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://paste.ubuntu.com/9052192/
Build: http://10.98.191.181:8080/job/charm_unit_test/925/

Revision history for this message
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/jenkins/workspace/charm_amulet_test
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/9052239/
Build: http://10.98.191.181:8080/job/charm_amulet_test/433/

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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:

Subscribers

People subscribed via source and target branches