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

Proposed by Brad Marshall
Status: Merged
Merged at revision: 134
Proposed branch: lp:~brad-marshall/charms/trusty/nova-cloud-controller/add-nrpe-checks
Merge into: lp:~openstack-charmers-archive/charms/trusty/nova-cloud-controller/trunk
Diff against target: 537 lines (+447/-2)
6 files modified
charm-helpers-hooks.yaml (+1/-0)
config.yaml (+11/-0)
hooks/charmhelpers/contrib/charmsupport/nrpe.py (+222/-0)
hooks/charmhelpers/contrib/charmsupport/volumes.py (+156/-0)
hooks/nova_cc_hooks.py (+54/-2)
metadata.yaml (+3/-0)
To merge this branch: bzr merge lp:~brad-marshall/charms/trusty/nova-cloud-controller/add-nrpe-checks
Reviewer Review Type Date Requested Status
Liam Young (community) Disapprove
Review via email: mp+241489@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 #997 trusty-nova-cloud-controller for brad-marshall mp241489
    LINT FAIL: lint-test failed

LINT Results (max last 5 lines):
  hooks/nova_cc_hooks.py:857:80: E501 line too long (92 > 79 characters)
  hooks/nova_cc_hooks.py:887:22: E251 unexpected spaces around keyword / parameter equals
  hooks/nova_cc_hooks.py:887:24: E251 unexpected spaces around keyword / parameter equals
  hooks/nova_cc_hooks.py:892:1: E302 expected 2 blank lines, found 1
  make: *** [lint] Error 1

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

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

UOSCI bot says:
charm_unit_test #832 trusty-nova-cloud-controller for brad-marshall mp241489
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  TOTAL 1061 380 64%
  Ran 96 tests in 10.348s
  FAILED (errors=2)
  mERROR:root:Make target returned non-zero.
ake: *** [unit_test] Error 1

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

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

UOSCI bot says:
charm_amulet_test #377 trusty-nova-cloud-controller for brad-marshall mp241489
    AMULET FAIL: amulet-test failed

AMULET Results (max last 5 lines):
  juju-test.conductor DEBUG : Calling "juju destroy-environment -y osci-sv04"
  WARNING cannot delete security group "juju-osci-sv04-0". Used by another environment?
  juju-test INFO : Results: 1 passed, 2 failed, 0 errored
  ERROR subprocess encountered error code 2
  make: *** [test] Error 2

Full amulet test output: http://paste.ubuntu.com/8955994/
Build: http://10.98.191.181:8080/job/charm_amulet_test/377/

129. By Brad Marshall

[bradm] Add monitoring for sysvinit daemons, 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_lint_check #1088 trusty-nova-cloud-controller for brad-marshall mp241489
    LINT FAIL: lint-test failed

LINT Results (max last 5 lines):
  hooks/nova_cc_hooks.py:896:26: E251 unexpected spaces around keyword / parameter equals
  hooks/nova_cc_hooks.py:896:28: E251 unexpected spaces around keyword / parameter equals
  hooks/nova_cc_hooks.py:896:80: E501 line too long (101 > 79 characters)
  hooks/nova_cc_hooks.py:901:1: E302 expected 2 blank lines, found 1
  make: *** [lint] Error 1

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

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

UOSCI bot says:
charm_unit_test #922 trusty-nova-cloud-controller for brad-marshall mp241489
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  TOTAL 1072 392 63%
  Ran 96 tests in 9.000s
  FAILED (errors=2)
  maERROR:root:Make target returned non-zero.
ke: *** [unit_test] Error 1

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

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

UOSCI bot says:
charm_amulet_test #430 trusty-nova-cloud-controller for brad-marshall mp241489
    AMULET FAIL: amulet-test failed

AMULET Results (max last 5 lines):
  juju-test.conductor DEBUG : Calling "juju destroy-environment -y osci-sv11"
  WARNING cannot delete security group "juju-osci-sv11-0". Used by another environment?
  juju-test INFO : Results: 1 passed, 2 failed, 0 errored
  ERROR subprocess encountered error code 2
  make: *** [test] Error 2

Full amulet test output: http://paste.ubuntu.com/9052240/
Build: http://10.98.191.181:8080/job/charm_amulet_test/430/

130. 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 #1100 trusty-nova-cloud-controller for brad-marshall mp241489
    LINT FAIL: lint-test failed

LINT Results (max last 5 lines):
  hooks/nova_cc_hooks.py:896:26: E251 unexpected spaces around keyword / parameter equals
  hooks/nova_cc_hooks.py:896:28: E251 unexpected spaces around keyword / parameter equals
  hooks/nova_cc_hooks.py:896:80: E501 line too long (101 > 79 characters)
  hooks/nova_cc_hooks.py:901:1: E302 expected 2 blank lines, found 1
  make: *** [lint] Error 1

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

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

UOSCI bot says:
charm_unit_test #934 trusty-nova-cloud-controller for brad-marshall mp241489
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  TOTAL 1072 392 63%
  Ran 96 tests in 10.146s
  FAILED (errors=2)
  mERROR:root:Make target returned non-zero.
ake: *** [unit_test] Error 1

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

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

UOSCI bot says:
charm_amulet_test #442 trusty-nova-cloud-controller for brad-marshall mp241489
    AMULET FAIL: amulet-test failed

AMULET Results (max last 5 lines):
  juju-test.conductor DEBUG : Calling "juju destroy-environment -y osci-sv04"
  WARNING cannot delete security group "juju-osci-sv04-0". Used by another environment?
  juju-test INFO : Results: 1 passed, 2 failed, 0 errored
  ERROR subprocess encountered error code 2
  make: *** [test] Error 2

Full amulet test output: http://paste.ubuntu.com/9053036/
Build: http://10.98.191.181:8080/job/charm_amulet_test/442/

131. 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_lint_check #1116 trusty-nova-cloud-controller for brad-marshall mp241489
    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/nova_cc_hooks.py:857:1: E302 expected 2 blank lines, found 1
  hooks/nova_cc_hooks.py:904:1: E302 expected 2 blank lines, found 1
  make: *** [lint] Error 1

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

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

UOSCI bot says:
charm_unit_test #950 trusty-nova-cloud-controller for brad-marshall mp241489
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  TOTAL 1071 391 63%
  Ran 96 tests in 9.558s
  FAILED (errors=2)
  maERROR:root:Make target returned non-zero.
ke: *** [unit_test] Error 1

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

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

UOSCI bot says:
charm_amulet_test #458 trusty-nova-cloud-controller for brad-marshall mp241489
    AMULET FAIL: amulet-test failed

AMULET Results (max last 5 lines):
  juju-test.conductor DEBUG : Calling "juju destroy-environment -y osci-sv02"
  WARNING cannot delete security group "juju-osci-sv02-0". Used by another environment?
  juju-test INFO : Results: 1 passed, 2 failed, 0 errored
  ERROR subprocess encountered error code 2
  make: *** [test] Error 2

Full amulet test output: http://paste.ubuntu.com/9063966/
Build: http://10.98.191.181:8080/job/charm_amulet_test/458/

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

UOSCI bot says:
charm_lint_check #1250 trusty-nova-cloud-controller for brad-marshall mp241489
    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/nova_cc_hooks.py:857:1: E302 expected 2 blank lines, found 1
  hooks/nova_cc_hooks.py:904:1: E302 expected 2 blank lines, found 1
  make: *** [lint] Error 1

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

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

UOSCI bot says:
charm_unit_test #1084 trusty-nova-cloud-controller for brad-marshall mp241489
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  TOTAL 1071 391 63%
  Ran 96 tests in 10.716s
  FAILED (errors=2)
  mERROR:root:Make target returned non-zero.
ake: *** [unit_test] Error 1

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

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

UOSCI bot says:
charm_amulet_test #553 trusty-nova-cloud-controller for brad-marshall mp241489
    AMULET FAIL: amulet-test failed

AMULET Results (max last 5 lines):
  juju-test.conductor DEBUG : Calling "juju destroy-environment -y osci-sv04"
  WARNING cannot delete security group "juju-osci-sv04-0". Used by another environment?
  juju-test INFO : Results: 1 passed, 2 failed, 0 errored
  ERROR subprocess encountered error code 2
  make: *** [test] Error 2

Full amulet test output: http://paste.ubuntu.com/9281416/
Build: http://10.98.191.181:8080/job/charm_amulet_test/553/

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

Subscribers

People subscribed via source and target branches