1
"""Compatibility with the nrpe-external-master charm"""
2
# Copyright 2012 Canonical Ltd.
5
# Matthew Wedgwood <matthew.wedgwood@canonical.com>
15
from charmhelpers.core.hookenv import (
23
from charmhelpers.core.host import service
25
# This module adds compatibility with the nrpe-external-master and plain nrpe
26
# subordinate charms. To use it in your charm:
28
# 1. Update metadata.yaml
32
# nrpe-external-master:
33
# interface: nrpe-external-master
41
# interface: local-monitors
45
# 2. Add the following to config.yaml
51
# Used by the nrpe subordinate charms.
52
# A string that will be prepended to instance name to set the host name
53
# in nagios. So for instance the hostname would be something like:
55
# If you're running multiple environments with the same services in them
56
# this allows you to differentiate between them.
57
# nagios_servicegroups:
61
# A comma-separated list of nagios servicegroups.
62
# If left empty, the nagios_context will be used as the servicegroup
64
# 3. Add custom checks (Nagios plugins) to files/nrpe-external-master
66
# 4. Update your hooks.py with something like this:
68
# from charmsupport.nrpe import NRPE
70
# def update_nrpe_config():
71
# nrpe_compat = NRPE()
72
# nrpe_compat.add_check(
73
# shortname = "myservice",
74
# description = "Check MyService",
75
# check_cmd = "check_http -w 2 -c 10 http://localhost"
77
# nrpe_compat.add_check(
79
# "Check for widget failures",
80
# check_cmd = "/srv/myapp/scripts/widget_check"
84
# def config_changed():
86
# update_nrpe_config()
88
# def nrpe_external_master_relation_changed():
89
# update_nrpe_config()
91
# def local_monitors_relation_changed():
92
# update_nrpe_config()
94
# 5. ln -s hooks.py nrpe-external-master-relation-changed
95
# ln -s hooks.py local-monitors-relation-changed
98
class CheckException(Exception):
103
shortname_re = '[A-Za-z0-9-_]+$'
104
service_template = ("""
105
#---------------------------------------------------
106
# This file is Juju managed
107
#---------------------------------------------------
110
host_name {nagios_hostname}
111
service_description {nagios_hostname}[{shortname}] """
113
check_command check_nrpe!{command}
114
servicegroups {nagios_servicegroup}
118
def __init__(self, shortname, description, check_cmd):
119
super(Check, self).__init__()
120
# XXX: could be better to calculate this from the service name
121
if not re.match(self.shortname_re, shortname):
122
raise CheckException("shortname must match {}".format(
124
self.shortname = shortname
125
self.command = "check_{}".format(shortname)
126
# Note: a set of invalid characters is defined by the
127
# Nagios server config
128
# The default is: illegal_object_name_chars=`~!$%^&*"|'<>?,()=
129
self.description = description
130
self.check_cmd = self._locate_cmd(check_cmd)
132
def _locate_cmd(self, check_cmd):
134
'/usr/lib/nagios/plugins',
135
'/usr/local/lib/nagios/plugins',
137
parts = shlex.split(check_cmd)
138
for path in search_path:
139
if os.path.exists(os.path.join(path, parts[0])):
140
command = os.path.join(path, parts[0])
142
command += " " + " ".join(parts[1:])
144
log('Check command not found: {}'.format(parts[0]))
147
def write(self, nagios_context, hostname, nagios_servicegroups=None):
148
nrpe_check_file = '/etc/nagios/nrpe.d/{}.cfg'.format(
150
with open(nrpe_check_file, 'w') as nrpe_check_config:
151
nrpe_check_config.write("# check {}\n".format(self.shortname))
152
nrpe_check_config.write("command[{}]={}\n".format(
153
self.command, self.check_cmd))
155
if not os.path.exists(NRPE.nagios_exportdir):
156
log('Not writing service config as {} is not accessible'.format(
157
NRPE.nagios_exportdir))
159
self.write_service_config(nagios_context, hostname,
160
nagios_servicegroups)
162
def write_service_config(self, nagios_context, hostname,
163
nagios_servicegroups=None):
164
for f in os.listdir(NRPE.nagios_exportdir):
165
if re.search('.*{}.cfg'.format(self.command), f):
166
os.remove(os.path.join(NRPE.nagios_exportdir, f))
168
if not nagios_servicegroups:
169
nagios_servicegroups = nagios_context
172
'nagios_hostname': hostname,
173
'nagios_servicegroup': nagios_servicegroups,
174
'description': self.description,
175
'shortname': self.shortname,
176
'command': self.command,
178
nrpe_service_text = Check.service_template.format(**templ_vars)
179
nrpe_service_file = '{}/service__{}_{}.cfg'.format(
180
NRPE.nagios_exportdir, hostname, self.command)
181
with open(nrpe_service_file, 'w') as nrpe_service_config:
182
nrpe_service_config.write(str(nrpe_service_text))
185
subprocess.call(self.check_cmd)
189
nagios_logdir = '/var/log/nagios'
190
nagios_exportdir = '/var/lib/nagios/export'
191
nrpe_confdir = '/etc/nagios/nrpe.d'
193
def __init__(self, hostname=None):
194
super(NRPE, self).__init__()
195
self.config = config()
196
self.nagios_context = self.config['nagios_context']
197
if 'nagios_servicegroups' in self.config:
198
self.nagios_servicegroups = self.config['nagios_servicegroups']
200
self.nagios_servicegroups = 'juju'
201
self.unit_name = local_unit().replace('/', '-')
203
self.hostname = hostname
205
self.hostname = "{}-{}".format(self.nagios_context, self.unit_name)
208
def add_check(self, *args, **kwargs):
209
self.checks.append(Check(*args, **kwargs))
213
nagios_uid = pwd.getpwnam('nagios').pw_uid
214
nagios_gid = grp.getgrnam('nagios').gr_gid
216
log("Nagios user not set up, nrpe checks not updated")
219
if not os.path.exists(NRPE.nagios_logdir):
220
os.mkdir(NRPE.nagios_logdir)
221
os.chown(NRPE.nagios_logdir, nagios_uid, nagios_gid)
224
monitors = {"monitors": {"remote": {"nrpe": nrpe_monitors}}}
225
for nrpecheck in self.checks:
226
nrpecheck.write(self.nagios_context, self.hostname,
227
self.nagios_servicegroups)
228
nrpe_monitors[nrpecheck.shortname] = {
229
"command": nrpecheck.command,
232
service('restart', 'nagios-nrpe-server')
234
for rid in relation_ids("local-monitors"):
235
relation_set(relation_id=rid, monitors=yaml.dump(monitors))