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

Proposed by Brad Marshall
Status: Merged
Merged at revision: 48
Proposed branch: lp:~brad-marshall/charms/trusty/openstack-dashboard/add-nrpe-checks
Merge into: lp:~openstack-charmers-archive/charms/trusty/openstack-dashboard/trunk
Diff against target: 575 lines (+468/-0)
7 files modified
charm-helpers.yaml (+1/-0)
config.yaml (+15/-0)
hooks/charmhelpers/contrib/charmsupport/nrpe.py (+222/-0)
hooks/charmhelpers/contrib/charmsupport/volumes.py (+156/-0)
hooks/horizon_hooks.py (+63/-0)
hooks/horizon_utils.py (+8/-0)
metadata.yaml (+3/-0)
To merge this branch: bzr merge lp:~brad-marshall/charms/trusty/openstack-dashboard/add-nrpe-checks
Reviewer Review Type Date Requested Status
Liam Young (community) Disapprove
Review via email: mp+241487@code.launchpad.net

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_lint_check #995 trusty-openstack-dashboard for brad-marshall mp241487
    LINT FAIL: lint-test failed

LINT Results (max last 5 lines):
INFO:root:command: make -f Makefile lint
ERROR:root:Make target returned non-zero.
  hooks/horizon_hooks.py:196:80: E501 line too long (92 > 79 characters)
  hooks/horizon_hooks.py:223:1: E302 expected 2 blank lines, found 1
  make: *** [lint] Error 1

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

Revision history for this message
Ryan Beisner (1chb1n) wrote :

UOSCI bot says:
charm_unit_test #830 trusty-openstack-dashboard for brad-marshall mp241487
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  hooks/horizon_utils 73 8 89% 135, 190-202
  TOTAL 241 34 86%
  Ran 39 tests in 1.637s
  FAILED (errors=3)
  make: *** [test] Error 1

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

Revision history for this message
Ryan Beisner (1chb1n) wrote :

UOSCI bot says:
charm_amulet_test #375 trusty-openstack-dashboard for brad-marshall mp241487
    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/8955884/
Build: http://10.98.191.181:8080/job/charm_amulet_test/375/

47. By Brad Marshall

[bradm] Add Added sysvinit daemon monitoring, use services() instead of hard coded daemon list, pep8 fixes

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

UOSCI bot says:
charm_amulet_test #428 trusty-openstack-dashboard for brad-marshall mp241487
    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/9052129/
Build: http://10.98.191.181:8080/job/charm_amulet_test/428/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

UOSCI bot says:
charm_lint_check #1086 trusty-openstack-dashboard for brad-marshall mp241487
    LINT OK: passed

LINT Results (max last 5 lines):
  I: config.yaml: option profile has no default value
  I: config.yaml: option ssl_key has no default value
  I: config.yaml: option vip has no default value
  I: config.yaml: option ssl_cert has no default value
  I: config.yaml: option secret has no default value

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

UOSCI bot says:
charm_unit_test #920 trusty-openstack-dashboard for brad-marshall mp241487
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  hooks/horizon_utils 78 12 85% 135, 160-163, 198-210
  TOTAL 261 52 80%
  Ran 39 tests in 1.768s
  FAILED (errors=3)
  make: *** [test] Error 1

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

48. 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 #1098 trusty-openstack-dashboard for brad-marshall mp241487
    LINT OK: passed

LINT Results (max last 5 lines):
  I: config.yaml: option profile has no default value
  I: config.yaml: option ssl_key has no default value
  I: config.yaml: option vip has no default value
  I: config.yaml: option ssl_cert has no default value
  I: config.yaml: option secret has no default value

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

UOSCI bot says:
charm_amulet_test #440 trusty-openstack-dashboard for brad-marshall mp241487
    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/9052974/
Build: http://10.98.191.181:8080/job/charm_amulet_test/440/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

UOSCI bot says:
charm_unit_test #932 trusty-openstack-dashboard for brad-marshall mp241487
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  hooks/horizon_utils 78 12 85% 135, 160-163, 198-210
  TOTAL 261 52 80%
  Ran 39 tests in 1.783s
  FAILED (errors=3)
  make: *** [test] Error 1

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

49. 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 #456 trusty-openstack-dashboard for brad-marshall mp241487
    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/9063867/
Build: http://10.98.191.181:8080/job/charm_amulet_test/456/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

UOSCI bot says:
charm_lint_check #1114 trusty-openstack-dashboard for brad-marshall mp241487
    LINT OK: passed

LINT Results (max last 5 lines):
  I: config.yaml: option profile has no default value
  I: config.yaml: option ssl_key has no default value
  I: config.yaml: option vip has no default value
  I: config.yaml: option ssl_cert has no default value
  I: config.yaml: option secret has no default value

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

UOSCI bot says:
charm_unit_test #948 trusty-openstack-dashboard for brad-marshall mp241487
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  hooks/horizon_utils 78 12 85% 135, 160-163, 198-210
  TOTAL 260 51 80%
  Ran 39 tests in 1.647s
  FAILED (errors=3)
  make: *** [test] Error 1

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

UOSCI bot says:
charm_lint_check #1248 trusty-openstack-dashboard for brad-marshall mp241487
    LINT OK: passed

LINT Results (max last 5 lines):
  I: config.yaml: option profile has no default value
  I: config.yaml: option ssl_key has no default value
  I: config.yaml: option vip has no default value
  I: config.yaml: option ssl_cert has no default value
  I: config.yaml: option secret has no default value

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

UOSCI bot says:
charm_unit_test #1082 trusty-openstack-dashboard for brad-marshall mp241487
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  hooks/horizon_utils 78 12 85% 135, 160-163, 198-210
  TOTAL 260 51 80%
  Ran 39 tests in 2.030s
  FAILED (errors=3)
  make: *** [test] Error 1

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

UOSCI bot says:
charm_amulet_test #551 trusty-openstack-dashboard for brad-marshall mp241487
    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/9281369/
Build: http://10.98.191.181:8080/job/charm_amulet_test/551/

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-09-12 10:55:03 +0000
3+++ charm-helpers.yaml 2014-11-18 01:25:40 +0000
4@@ -9,3 +9,4 @@
5 - contrib.storage
6 - contrib.network.ip
7 - payload.execd
8+ - contrib.charmsupport
9
10=== modified file 'config.yaml'
11--- config.yaml 2014-10-15 18:19:14 +0000
12+++ config.yaml 2014-11-18 01:25:40 +0000
13@@ -111,3 +111,18 @@
14 In order for this charm to function correctly, the privacy extension
15 must be disabled and a non-temporary address must be
16 configured/available on your network interface.
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-postgresql-0
25+ If you're running multiple environments with the same services in them
26+ this allows you to differentiate between them.
27+ nagios_check_http_params:
28+ default: "-H localhost -I 127.0.0.1 -u '/' -e 200,301,302"
29+ type: string
30+ description: The parameters to pass to the nrpe plugin check_http.
31+
32
33=== added directory 'files'
34=== added directory 'hooks/charmhelpers/contrib/charmsupport'
35=== added file 'hooks/charmhelpers/contrib/charmsupport/__init__.py'
36=== added file 'hooks/charmhelpers/contrib/charmsupport/nrpe.py'
37--- hooks/charmhelpers/contrib/charmsupport/nrpe.py 1970-01-01 00:00:00 +0000
38+++ hooks/charmhelpers/contrib/charmsupport/nrpe.py 2014-11-18 01:25:40 +0000
39@@ -0,0 +1,222 @@
40+"""Compatibility with the nrpe-external-master charm"""
41+# Copyright 2012 Canonical Ltd.
42+#
43+# Authors:
44+# Matthew Wedgwood <matthew.wedgwood@canonical.com>
45+
46+import subprocess
47+import pwd
48+import grp
49+import os
50+import re
51+import shlex
52+import yaml
53+
54+from charmhelpers.core.hookenv import (
55+ config,
56+ local_unit,
57+ log,
58+ relation_ids,
59+ relation_set,
60+)
61+
62+from charmhelpers.core.host import service
63+
64+# This module adds compatibility with the nrpe-external-master and plain nrpe
65+# subordinate charms. To use it in your charm:
66+#
67+# 1. Update metadata.yaml
68+#
69+# provides:
70+# (...)
71+# nrpe-external-master:
72+# interface: nrpe-external-master
73+# scope: container
74+#
75+# and/or
76+#
77+# provides:
78+# (...)
79+# local-monitors:
80+# interface: local-monitors
81+# scope: container
82+
83+#
84+# 2. Add the following to config.yaml
85+#
86+# nagios_context:
87+# default: "juju"
88+# type: string
89+# description: |
90+# Used by the nrpe subordinate charms.
91+# A string that will be prepended to instance name to set the host name
92+# in nagios. So for instance the hostname would be something like:
93+# juju-myservice-0
94+# If you're running multiple environments with the same services in them
95+# this allows you to differentiate between them.
96+#
97+# 3. Add custom checks (Nagios plugins) to files/nrpe-external-master
98+#
99+# 4. Update your hooks.py with something like this:
100+#
101+# from charmsupport.nrpe import NRPE
102+# (...)
103+# def update_nrpe_config():
104+# nrpe_compat = NRPE()
105+# nrpe_compat.add_check(
106+# shortname = "myservice",
107+# description = "Check MyService",
108+# check_cmd = "check_http -w 2 -c 10 http://localhost"
109+# )
110+# nrpe_compat.add_check(
111+# "myservice_other",
112+# "Check for widget failures",
113+# check_cmd = "/srv/myapp/scripts/widget_check"
114+# )
115+# nrpe_compat.write()
116+#
117+# def config_changed():
118+# (...)
119+# update_nrpe_config()
120+#
121+# def nrpe_external_master_relation_changed():
122+# update_nrpe_config()
123+#
124+# def local_monitors_relation_changed():
125+# update_nrpe_config()
126+#
127+# 5. ln -s hooks.py nrpe-external-master-relation-changed
128+# ln -s hooks.py local-monitors-relation-changed
129+
130+
131+class CheckException(Exception):
132+ pass
133+
134+
135+class Check(object):
136+ shortname_re = '[A-Za-z0-9-_]+$'
137+ service_template = ("""
138+#---------------------------------------------------
139+# This file is Juju managed
140+#---------------------------------------------------
141+define service {{
142+ use active-service
143+ host_name {nagios_hostname}
144+ service_description {nagios_hostname}[{shortname}] """
145+ """{description}
146+ check_command check_nrpe!{command}
147+ servicegroups {nagios_servicegroup}
148+}}
149+""")
150+
151+ def __init__(self, shortname, description, check_cmd):
152+ super(Check, self).__init__()
153+ # XXX: could be better to calculate this from the service name
154+ if not re.match(self.shortname_re, shortname):
155+ raise CheckException("shortname must match {}".format(
156+ Check.shortname_re))
157+ self.shortname = shortname
158+ self.command = "check_{}".format(shortname)
159+ # Note: a set of invalid characters is defined by the
160+ # Nagios server config
161+ # The default is: illegal_object_name_chars=`~!$%^&*"|'<>?,()=
162+ self.description = description
163+ self.check_cmd = self._locate_cmd(check_cmd)
164+
165+ def _locate_cmd(self, check_cmd):
166+ search_path = (
167+ '/',
168+ os.path.join(os.environ['CHARM_DIR'],
169+ 'files/nrpe-external-master'),
170+ '/usr/lib/nagios/plugins',
171+ '/usr/local/lib/nagios/plugins',
172+ )
173+ parts = shlex.split(check_cmd)
174+ for path in search_path:
175+ if os.path.exists(os.path.join(path, parts[0])):
176+ command = os.path.join(path, parts[0])
177+ if len(parts) > 1:
178+ command += " " + " ".join(parts[1:])
179+ return command
180+ log('Check command not found: {}'.format(parts[0]))
181+ return ''
182+
183+ def write(self, nagios_context, hostname):
184+ nrpe_check_file = '/etc/nagios/nrpe.d/{}.cfg'.format(
185+ self.command)
186+ with open(nrpe_check_file, 'w') as nrpe_check_config:
187+ nrpe_check_config.write("# check {}\n".format(self.shortname))
188+ nrpe_check_config.write("command[{}]={}\n".format(
189+ self.command, self.check_cmd))
190+
191+ if not os.path.exists(NRPE.nagios_exportdir):
192+ log('Not writing service config as {} is not accessible'.format(
193+ NRPE.nagios_exportdir))
194+ else:
195+ self.write_service_config(nagios_context, hostname)
196+
197+ def write_service_config(self, nagios_context, hostname):
198+ for f in os.listdir(NRPE.nagios_exportdir):
199+ if re.search('.*{}.cfg'.format(self.command), f):
200+ os.remove(os.path.join(NRPE.nagios_exportdir, f))
201+
202+ templ_vars = {
203+ 'nagios_hostname': hostname,
204+ 'nagios_servicegroup': nagios_context,
205+ 'description': self.description,
206+ 'shortname': self.shortname,
207+ 'command': self.command,
208+ }
209+ nrpe_service_text = Check.service_template.format(**templ_vars)
210+ nrpe_service_file = '{}/service__{}_{}.cfg'.format(
211+ NRPE.nagios_exportdir, hostname, self.command)
212+ with open(nrpe_service_file, 'w') as nrpe_service_config:
213+ nrpe_service_config.write(str(nrpe_service_text))
214+
215+ def run(self):
216+ subprocess.call(self.check_cmd)
217+
218+
219+class NRPE(object):
220+ nagios_logdir = '/var/log/nagios'
221+ nagios_exportdir = '/var/lib/nagios/export'
222+ nrpe_confdir = '/etc/nagios/nrpe.d'
223+
224+ def __init__(self, hostname=None):
225+ super(NRPE, self).__init__()
226+ self.config = config()
227+ self.nagios_context = self.config['nagios_context']
228+ self.unit_name = local_unit().replace('/', '-')
229+ if hostname:
230+ self.hostname = hostname
231+ else:
232+ self.hostname = "{}-{}".format(self.nagios_context, self.unit_name)
233+ self.checks = []
234+
235+ def add_check(self, *args, **kwargs):
236+ self.checks.append(Check(*args, **kwargs))
237+
238+ def write(self):
239+ try:
240+ nagios_uid = pwd.getpwnam('nagios').pw_uid
241+ nagios_gid = grp.getgrnam('nagios').gr_gid
242+ except:
243+ log("Nagios user not set up, nrpe checks not updated")
244+ return
245+
246+ if not os.path.exists(NRPE.nagios_logdir):
247+ os.mkdir(NRPE.nagios_logdir)
248+ os.chown(NRPE.nagios_logdir, nagios_uid, nagios_gid)
249+
250+ nrpe_monitors = {}
251+ monitors = {"monitors": {"remote": {"nrpe": nrpe_monitors}}}
252+ for nrpecheck in self.checks:
253+ nrpecheck.write(self.nagios_context, self.hostname)
254+ nrpe_monitors[nrpecheck.shortname] = {
255+ "command": nrpecheck.command,
256+ }
257+
258+ service('restart', 'nagios-nrpe-server')
259+
260+ for rid in relation_ids("local-monitors"):
261+ relation_set(relation_id=rid, monitors=yaml.dump(monitors))
262
263=== added file 'hooks/charmhelpers/contrib/charmsupport/volumes.py'
264--- hooks/charmhelpers/contrib/charmsupport/volumes.py 1970-01-01 00:00:00 +0000
265+++ hooks/charmhelpers/contrib/charmsupport/volumes.py 2014-11-18 01:25:40 +0000
266@@ -0,0 +1,156 @@
267+'''
268+Functions for managing volumes in juju units. One volume is supported per unit.
269+Subordinates may have their own storage, provided it is on its own partition.
270+
271+Configuration stanzas:
272+ volume-ephemeral:
273+ type: boolean
274+ default: true
275+ description: >
276+ If false, a volume is mounted as sepecified in "volume-map"
277+ If true, ephemeral storage will be used, meaning that log data
278+ will only exist as long as the machine. YOU HAVE BEEN WARNED.
279+ volume-map:
280+ type: string
281+ default: {}
282+ description: >
283+ YAML map of units to device names, e.g:
284+ "{ rsyslog/0: /dev/vdb, rsyslog/1: /dev/vdb }"
285+ Service units will raise a configure-error if volume-ephemeral
286+ is 'true' and no volume-map value is set. Use 'juju set' to set a
287+ value and 'juju resolved' to complete configuration.
288+
289+Usage:
290+ from charmsupport.volumes import configure_volume, VolumeConfigurationError
291+ from charmsupport.hookenv import log, ERROR
292+ def post_mount_hook():
293+ stop_service('myservice')
294+ def post_mount_hook():
295+ start_service('myservice')
296+
297+ if __name__ == '__main__':
298+ try:
299+ configure_volume(before_change=pre_mount_hook,
300+ after_change=post_mount_hook)
301+ except VolumeConfigurationError:
302+ log('Storage could not be configured', ERROR)
303+'''
304+
305+# XXX: Known limitations
306+# - fstab is neither consulted nor updated
307+
308+import os
309+from charmhelpers.core import hookenv
310+from charmhelpers.core import host
311+import yaml
312+
313+
314+MOUNT_BASE = '/srv/juju/volumes'
315+
316+
317+class VolumeConfigurationError(Exception):
318+ '''Volume configuration data is missing or invalid'''
319+ pass
320+
321+
322+def get_config():
323+ '''Gather and sanity-check volume configuration data'''
324+ volume_config = {}
325+ config = hookenv.config()
326+
327+ errors = False
328+
329+ if config.get('volume-ephemeral') in (True, 'True', 'true', 'Yes', 'yes'):
330+ volume_config['ephemeral'] = True
331+ else:
332+ volume_config['ephemeral'] = False
333+
334+ try:
335+ volume_map = yaml.safe_load(config.get('volume-map', '{}'))
336+ except yaml.YAMLError as e:
337+ hookenv.log("Error parsing YAML volume-map: {}".format(e),
338+ hookenv.ERROR)
339+ errors = True
340+ if volume_map is None:
341+ # probably an empty string
342+ volume_map = {}
343+ elif not isinstance(volume_map, dict):
344+ hookenv.log("Volume-map should be a dictionary, not {}".format(
345+ type(volume_map)))
346+ errors = True
347+
348+ volume_config['device'] = volume_map.get(os.environ['JUJU_UNIT_NAME'])
349+ if volume_config['device'] and volume_config['ephemeral']:
350+ # asked for ephemeral storage but also defined a volume ID
351+ hookenv.log('A volume is defined for this unit, but ephemeral '
352+ 'storage was requested', hookenv.ERROR)
353+ errors = True
354+ elif not volume_config['device'] and not volume_config['ephemeral']:
355+ # asked for permanent storage but did not define volume ID
356+ hookenv.log('Ephemeral storage was requested, but there is no volume '
357+ 'defined for this unit.', hookenv.ERROR)
358+ errors = True
359+
360+ unit_mount_name = hookenv.local_unit().replace('/', '-')
361+ volume_config['mountpoint'] = os.path.join(MOUNT_BASE, unit_mount_name)
362+
363+ if errors:
364+ return None
365+ return volume_config
366+
367+
368+def mount_volume(config):
369+ if os.path.exists(config['mountpoint']):
370+ if not os.path.isdir(config['mountpoint']):
371+ hookenv.log('Not a directory: {}'.format(config['mountpoint']))
372+ raise VolumeConfigurationError()
373+ else:
374+ host.mkdir(config['mountpoint'])
375+ if os.path.ismount(config['mountpoint']):
376+ unmount_volume(config)
377+ if not host.mount(config['device'], config['mountpoint'], persist=True):
378+ raise VolumeConfigurationError()
379+
380+
381+def unmount_volume(config):
382+ if os.path.ismount(config['mountpoint']):
383+ if not host.umount(config['mountpoint'], persist=True):
384+ raise VolumeConfigurationError()
385+
386+
387+def managed_mounts():
388+ '''List of all mounted managed volumes'''
389+ return filter(lambda mount: mount[0].startswith(MOUNT_BASE), host.mounts())
390+
391+
392+def configure_volume(before_change=lambda: None, after_change=lambda: None):
393+ '''Set up storage (or don't) according to the charm's volume configuration.
394+ Returns the mount point or "ephemeral". before_change and after_change
395+ are optional functions to be called if the volume configuration changes.
396+ '''
397+
398+ config = get_config()
399+ if not config:
400+ hookenv.log('Failed to read volume configuration', hookenv.CRITICAL)
401+ raise VolumeConfigurationError()
402+
403+ if config['ephemeral']:
404+ if os.path.ismount(config['mountpoint']):
405+ before_change()
406+ unmount_volume(config)
407+ after_change()
408+ return 'ephemeral'
409+ else:
410+ # persistent storage
411+ if os.path.ismount(config['mountpoint']):
412+ mounts = dict(managed_mounts())
413+ if mounts.get(config['mountpoint']) != config['device']:
414+ before_change()
415+ unmount_volume(config)
416+ mount_volume(config)
417+ after_change()
418+ else:
419+ before_change()
420+ mount_volume(config)
421+ after_change()
422+ return config['mountpoint']
423
424=== modified file 'hooks/horizon_hooks.py'
425--- hooks/horizon_hooks.py 2014-10-23 13:48:37 +0000
426+++ hooks/horizon_hooks.py 2014-11-18 01:25:40 +0000
427@@ -2,6 +2,7 @@
428 # vim: set ts=4:et
429
430 import sys
431+import os
432 from charmhelpers.core.hookenv import (
433 Hooks, UnregisteredHookError,
434 log,
435@@ -10,6 +11,8 @@
436 relation_set,
437 relation_get,
438 relation_ids,
439+ relations_of_type,
440+ local_unit,
441 unit_get
442 )
443 from charmhelpers.fetch import (
444@@ -28,6 +31,7 @@
445 from horizon_utils import (
446 PACKAGES, register_configs,
447 restart_map,
448+ services,
449 LOCAL_SETTINGS, HAPROXY_CONF,
450 enable_ssl,
451 do_openstack_upgrade,
452@@ -42,6 +46,7 @@
453 from charmhelpers.contrib.hahelpers.apache import install_ca_cert
454 from charmhelpers.contrib.hahelpers.cluster import get_hacluster_config
455 from charmhelpers.payload.execd import execd_preinstall
456+from charmhelpers.contrib.charmsupport import nrpe
457 from base64 import b64decode
458
459 hooks = Hooks()
460@@ -63,6 +68,7 @@
461 def upgrade_charm():
462 execd_preinstall()
463 apt_install(filter_installed_packages(PACKAGES), fatal=True)
464+ update_nrpe_config()
465 CONFIGS.write_all()
466
467
468@@ -93,6 +99,7 @@
469 'OPENSTACK_PORT_HORIZON': 70
470 }
471 save_script_rc(**env_vars)
472+ update_nrpe_config()
473 CONFIGS.write_all()
474 open_port(80)
475 open_port(443)
476@@ -188,6 +195,62 @@
477 hostname=unit_get('private-address'))
478
479
480+@hooks.hook('nrpe-external-master-relation-joined',
481+ 'nrpe-external-master-relation-changed')
482+def update_nrpe_config():
483+ # Find out if nrpe set nagios_hostname
484+ hostname = None
485+ host_context = None
486+ for rel in relations_of_type('nrpe-external-master'):
487+ if 'nagios_hostname' in rel:
488+ hostname = rel['nagios_hostname']
489+ host_context = rel['nagios_host_context']
490+ break
491+ nrpe_compat = nrpe.NRPE(hostname=hostname)
492+
493+ if host_context:
494+ current_unit = "%s:%s" % (host_context, local_unit())
495+ else:
496+ current_unit = local_unit()
497+
498+ conf = nrpe_compat.config
499+ check_http_params = conf.get('nagios_check_http_params')
500+ if check_http_params:
501+ nrpe_compat.add_check(
502+ shortname='vhost',
503+ description='Check Virtual Host {%s}' % current_unit,
504+ check_cmd='check_http %s' % check_http_params
505+ )
506+
507+ services_to_monitor = services()
508+ for service in services_to_monitor:
509+ upstart_init = '/etc/init/%s.conf' % service
510+ sysv_init = '/etc/init.d/%s' % service
511+
512+ if os.path.exists(upstart_init):
513+ nrpe_compat.add_check(
514+ shortname=service,
515+ description='process check {%s}' % current_unit,
516+ check_cmd='check_upstart_job %s' % check_http_params
517+ )
518+ elif os.path.exists(sysv_init):
519+ cronpath = '/etc/cron.d/nagios-service-check-%s' % service
520+ cron_template = '*/5 * * * * root \
521+/usr/local/lib/nagios/plugins/check_exit_status.pl -s /etc/init.d/%s \
522+status > /var/lib/nagios/service-check-%s.txt\n' % (service, service)
523+ f = open(cronpath, 'w')
524+ f.write(cron_template)
525+ f.close()
526+ nrpe_compat.add_check(
527+ shortname=service,
528+ description='process check {%s}' % current_unit,
529+ check_cmd='check_status_file.py -f \
530+/var/lib/nagios/service-check-%s.txt' % service,
531+ )
532+
533+ nrpe_compat.write()
534+
535+
536 def main():
537 try:
538 hooks.execute(sys.argv)
539
540=== modified file 'hooks/horizon_utils.py'
541--- hooks/horizon_utils.py 2014-10-15 19:47:09 +0000
542+++ hooks/horizon_utils.py 2014-11-18 01:25:40 +0000
543@@ -155,6 +155,14 @@
544 return OrderedDict(_map)
545
546
547+def services():
548+ ''' Returns a list of services associate with this charm '''
549+ _services = []
550+ for v in restart_map().values():
551+ _services = _services + v
552+ return list(set(_services))
553+
554+
555 def enable_ssl():
556 ''' Enable SSL support in local apache2 instance '''
557 subprocess.call(['a2ensite', 'default-ssl'])
558
559=== added symlink 'hooks/nrpe-external-master-relation-changed'
560=== target is u'horizon_hooks.py'
561=== added symlink 'hooks/nrpe-external-master-relation-joined'
562=== target is u'horizon_hooks.py'
563=== modified file 'metadata.yaml'
564--- metadata.yaml 2013-07-16 12:10:26 +0000
565+++ metadata.yaml 2014-11-18 01:25:40 +0000
566@@ -6,6 +6,9 @@
567 with instances, images, volumes and networks within an OpenStack deployment.
568 categories: ["misc"]
569 provides:
570+ nrpe-external-master:
571+ interface: nrpe-external-master
572+ scope: container
573 website:
574 interface: http
575 requires:

Subscribers

People subscribed via source and target branches