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

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

This proposal supersedes a proposal from 2014-11-12.

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 : Posted in a previous version of this proposal

UOSCI bot says:
charm_lint_check #992 trusty-ceilometer for brad-marshall mp241498
    LINT FAIL: lint-test failed

LINT Results (max last 5 lines):
ERROR:root:Make target returned non-zero.
  hooks/ceilometer_hooks.py:146:80: E501 line too long (92 > 79 characters)
  hooks/ceilometer_hooks.py:174:22: E251 unexpected spaces around keyword / parameter equals
  hooks/ceilometer_hooks.py:174:24: E251 unexpected spaces around keyword / parameter equals
  make: *** [lint] Error 1

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

Revision history for this message
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/ceilometer_utils 58 1 98% 100
  TOTAL 180 24 87%
  Ran 25 tests in 0.729s
  FAILED (errors=3)
  make: *** [test] Error 1

Full unit test output: http://paste.ubuntu.com/8955757/
Build: http://10.98.191.181:8080/job/charm_unit_test/827/

Revision history for this message
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/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/8955875/
Build: http://10.98.191.181:8080/job/charm_amulet_test/372/

Revision history for this message
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_utils.py. This includes logic to adjust the list depending on what Openstack release is being deployed. I think this mechanism should be used rather than defining a new list directly in update_nrpe_config()

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-agent-notification services are not going to be restarted on changes to ceilometer.conf

So, what I think is needed is:
1) Steal the services() method from nova-cloud-controller and use that to get a list of services in update_nrpe_config()
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_codename_install_source(config('openstack-origin'))
            >= 'icehouse'):
        CONFIG_FILES[CEILOMETER_CONF]['services'] = CONFIG_FILES[CEILOMETER_CONF]['services'] + ICEHOUSE_SERVICES

review: Needs Fixing
Revision history for this message
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?

Revision history for this message
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/ceilometer_utils 66 6 91% 101, 111, 136-139
  TOTAL 200 41 80%
  Ran 25 tests in 0.747s
  FAILED (errors=3)
  make: *** [test] Error 1

Full unit test output: http://paste.ubuntu.com/9051427/
Build: http://10.98.191.181:8080/job/charm_unit_test/917/

Revision history for this message
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/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/9051426/
Build: http://10.98.191.181:8080/job/charm_amulet_test/425/

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

Revision history for this message
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/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/9052684/
Build: http://10.98.191.181:8080/job/charm_amulet_test/434/

Revision history for this message
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/ceilometer_utils 66 6 91% 101, 111, 136-139
  TOTAL 200 41 80%
  Ran 25 tests in 0.836s
  FAILED (errors=3)
  make: *** [test] Error 1

Full unit test output: http://paste.ubuntu.com/9052686/
Build: http://10.98.191.181:8080/job/charm_unit_test/926/

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

63. By Brad Marshall

[bradm] Removed puppet header from nagios_plugin module

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

Revision history for this message
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/ceilometer_utils 66 6 91% 101, 111, 136-139
  TOTAL 200 41 80%
  Ran 25 tests in 0.751s
  FAILED (errors=3)
  make: *** [test] Error 1

Full unit test output: http://paste.ubuntu.com/9053016/
Build: http://10.98.191.181:8080/job/charm_unit_test/937/

Revision history for this message
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/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/9053034/
Build: http://10.98.191.181:8080/job/charm_amulet_test/445/

64. By Brad Marshall

[bradm] Removed nagios check files that were moved to nrpe-external-master charm

Revision history for this message
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/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/9063500/
Build: http://10.98.191.181:8080/job/charm_amulet_test/453/

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

Revision history for this message
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/ceilometer_utils 66 6 91% 101, 111, 136-139
  TOTAL 199 40 80%
  Ran 25 tests in 0.731s
  FAILED (errors=3)
  make: *** [test] Error 1

Full unit test output: http://paste.ubuntu.com/9063502/
Build: http://10.98.191.181:8080/job/charm_unit_test/945/

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

Revision history for this message
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/ceilometer_utils 66 6 91% 101, 111, 136-139
  TOTAL 199 40 80%
  Ran 25 tests in 0.833s
  FAILED (errors=3)
  make: *** [test] Error 1

Full unit test output: http://paste.ubuntu.com/9281322/
Build: http://10.98.191.181:8080/job/charm_unit_test/1088/

Revision history for this message
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/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/9281434/
Build: http://10.98.191.181:8080/job/charm_amulet_test/557/

Revision history for this message
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.

review: Disapprove

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-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:

Subscribers

People subscribed via source and target branches