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

Proposed by Brad Marshall
Status: Merged
Merged at revision: 100
Proposed branch: lp:~brad-marshall/charms/trusty/keystone/add-nrpe-checks
Merge into: lp:~openstack-charmers-archive/charms/trusty/keystone/trunk
Diff against target: 559 lines (+459/-0)
7 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/keystone_hooks.py (+58/-0)
hooks/keystone_utils.py (+8/-0)
metadata.yaml (+3/-0)
To merge this branch: bzr merge lp:~brad-marshall/charms/trusty/keystone/add-nrpe-checks
Reviewer Review Type Date Requested Status
Liam Young (community) Disapprove
Review via email: mp+241492@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 #1000 trusty-keystone for brad-marshall mp241492
    LINT FAIL: lint-test failed

LINT Results (max last 5 lines):
  hooks/keystone_hooks.py:377:80: E501 line too long (92 > 79 characters)
  hooks/keystone_hooks.py:398:18: E251 unexpected spaces around keyword / parameter equals
  hooks/keystone_hooks.py:398:20: E251 unexpected spaces around keyword / parameter equals
  hooks/keystone_hooks.py:403:1: E302 expected 2 blank lines, found 1
  make: *** [lint] Error 1

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

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

UOSCI bot says:
charm_unit_test #835 trusty-keystone for brad-marshall mp241492
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  hooks/keystone_utils 387 202 48% 204, 218, 242-247, 290-299, 306-321, 328-336, 341-351, 358-384, 389-398, 403-417, 422-444, 449-466, 480-503, 512-517, 522, 529-539, 544-552, 557-562, 566-573, 581-586, 597-612, 616-624, 649-650, 729, 732, 781-794, 818-822, 826-838
  TOTAL 826 431 48%
  Ran 37 tests in 3.096s
  FAILED (errors=5)
  make: *** [unit_test] Error 1

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

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

UOSCI bot says:
charm_amulet_test #380 trusty-keystone for brad-marshall mp241492
    AMULET FAIL: amulet-test failed

AMULET Results (max last 5 lines):
  WARNING cannot delete security group "juju-osci-sv05". Used by another environment?
  WARNING cannot delete security group "juju-osci-sv05-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/8956016/
Build: http://10.98.191.181:8080/job/charm_amulet_test/380/

93. By Brad Marshall

[bradm] Added sysvinit daemon monitoring, switched to using services() instead of hard coded list, pep8 fixes

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

UOSCI bot says:
charm_lint_check #1090 trusty-keystone for brad-marshall mp241492
    LINT OK: passed

LINT Results (max last 5 lines):
  I: config.yaml: option ssl_ca has no default value
  I: config.yaml: option os-public-network has no default value
  I: config.yaml: option os-admin-network has no default value
  I: config.yaml: option ssl_cert has no default value
  I: config.yaml: option os-internal-network has no default value

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

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

UOSCI bot says:
charm_unit_test #924 trusty-keystone for brad-marshall mp241492
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  hooks/keystone_utils 392 206 47% 204, 218, 225-228, 250-255, 298-307, 314-329, 336-344, 349-359, 366-392, 397-406, 411-425, 430-452, 457-474, 488-511, 520-525, 530, 537-547, 552-560, 565-570, 574-581, 589-594, 605-620, 624-632, 657-658, 737, 740, 789-802, 826-830, 834-846
  TOTAL 844 448 47%
  Ran 37 tests in 3.298s
  FAILED (errors=5)
  make: *** [unit_test] Error 1

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

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

UOSCI bot says:
charm_amulet_test #432 trusty-keystone for brad-marshall mp241492
    AMULET FAIL: amulet-test failed

AMULET Results (max last 5 lines):
  juju-test.conductor DEBUG : Calling "juju destroy-environment -y osci-sv05"
  WARNING cannot delete security group "juju-osci-sv05-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/9052270/
Build: http://10.98.191.181:8080/job/charm_amulet_test/432/

94. 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 #1101 trusty-keystone for brad-marshall mp241492
    LINT OK: passed

LINT Results (max last 5 lines):
  I: config.yaml: option ssl_ca has no default value
  I: config.yaml: option os-public-network has no default value
  I: config.yaml: option os-admin-network has no default value
  I: config.yaml: option ssl_cert has no default value
  I: config.yaml: option os-internal-network has no default value

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

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

UOSCI bot says:
charm_unit_test #935 trusty-keystone for brad-marshall mp241492
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  hooks/keystone_utils 392 206 47% 204, 218, 225-228, 250-255, 298-307, 314-329, 336-344, 349-359, 366-392, 397-406, 411-425, 430-452, 457-474, 488-511, 520-525, 530, 537-547, 552-560, 565-570, 574-581, 589-594, 605-620, 624-632, 657-658, 737, 740, 789-802, 826-830, 834-846
  TOTAL 844 448 47%
  Ran 37 tests in 3.299s
  FAILED (errors=5)
  make: *** [unit_test] Error 1

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

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

UOSCI bot says:
charm_amulet_test #443 trusty-keystone for brad-marshall mp241492
    AMULET FAIL: amulet-test failed

AMULET Results (max last 5 lines):
  juju-test.conductor DEBUG : Calling "juju destroy-environment -y osci-sv07"
  WARNING cannot delete security group "juju-osci-sv07-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/9053047/
Build: http://10.98.191.181:8080/job/charm_amulet_test/443/

95. 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 #1117 trusty-keystone for brad-marshall mp241492
    LINT FAIL: lint-test failed

LINT Results (max last 5 lines):
INFO:root:Searching for: ['@flake8']
INFO:root:command: make -f Makefile lint
ERROR:root:Make target returned non-zero.
  hooks/keystone_hooks.py:411:13: F841 local variable 'checkpath' is assigned to but never used
  make: *** [lint] Error 1

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

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

UOSCI bot says:
charm_unit_test #951 trusty-keystone for brad-marshall mp241492
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  hooks/keystone_utils 392 206 47% 204, 218, 225-228, 250-255, 298-307, 314-329, 336-344, 349-359, 366-392, 397-406, 411-425, 430-452, 457-474, 488-511, 520-525, 530, 537-547, 552-560, 565-570, 574-581, 589-594, 605-620, 624-632, 657-658, 737, 740, 789-802, 826-830, 834-846
  TOTAL 844 448 47%
  Ran 37 tests in 3.149s
  FAILED (errors=5)
  make: *** [unit_test] Error 1

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

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

UOSCI bot says:
charm_amulet_test #459 trusty-keystone for brad-marshall mp241492
    AMULET FAIL: amulet-test failed

AMULET Results (max last 5 lines):
  WARNING cannot delete security group "juju-osci-sv07". Used by another environment?
  WARNING cannot delete security group "juju-osci-sv07-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/9064014/
Build: http://10.98.191.181:8080/job/charm_amulet_test/459/

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

UOSCI bot says:
charm_lint_check #1251 trusty-keystone for brad-marshall mp241492
    LINT FAIL: lint-test failed

LINT Results (max last 5 lines):
INFO:root:Searching for: ['@flake8']
INFO:root:command: make -f Makefile lint
ERROR:root:Make target returned non-zero.
  hooks/keystone_hooks.py:411:13: F841 local variable 'checkpath' is assigned to but never used
  make: *** [lint] Error 1

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

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

UOSCI bot says:
charm_unit_test #1085 trusty-keystone for brad-marshall mp241492
    UNIT FAIL: unit-test failed

UNIT Results (max last 5 lines):
  hooks/keystone_utils 392 206 47% 204, 218, 225-228, 250-255, 298-307, 314-329, 336-344, 349-359, 366-392, 397-406, 411-425, 430-452, 457-474, 488-511, 520-525, 530, 537-547, 552-560, 565-570, 574-581, 589-594, 605-620, 624-632, 657-658, 737, 740, 789-802, 826-830, 834-846
  TOTAL 844 448 47%
  Ran 37 tests in 3.447s
  FAILED (errors=5)
  make: *** [unit_test] Error 1

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

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

UOSCI bot says:
charm_amulet_test #554 trusty-keystone for brad-marshall mp241492
    AMULET FAIL: amulet-test failed

AMULET Results (max last 5 lines):
  WARNING cannot delete security group "juju-osci-sv05-0". Used by another environment?
  WARNING cannot delete security group "juju-osci-sv05". 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/9281431/
Build: http://10.98.191.181:8080/job/charm_amulet_test/554/

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

Subscribers

People subscribed via source and target branches