~nottrobin/charms/trusty/wsgi-app/trunk

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/contrib/charmsupport/nrpe.py

  • Committer: Robin Winslow
  • Date: 2014-12-02 22:54:40 UTC
  • Revision ID: robin@robinwinslow.co.uk-20141202225440-ruuctvfe7pdh1dd8
Try reverting most of charmhelpers to the old version

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""Compatibility with the nrpe-external-master charm"""
2
 
# Copyright 2012 Canonical Ltd.
3
 
#
4
 
# Authors:
5
 
#  Matthew Wedgwood <matthew.wedgwood@canonical.com>
6
 
 
7
 
import subprocess
8
 
import pwd
9
 
import grp
10
 
import os
11
 
import re
12
 
import shlex
13
 
import yaml
14
 
 
15
 
from charmhelpers.core.hookenv import (
16
 
    config,
17
 
    local_unit,
18
 
    log,
19
 
    relation_ids,
20
 
    relation_set,
21
 
)
22
 
 
23
 
from charmhelpers.core.host import service
24
 
 
25
 
# This module adds compatibility with the nrpe-external-master and plain nrpe
26
 
# subordinate charms. To use it in your charm:
27
 
#
28
 
# 1. Update metadata.yaml
29
 
#
30
 
#   provides:
31
 
#     (...)
32
 
#     nrpe-external-master:
33
 
#       interface: nrpe-external-master
34
 
#       scope: container
35
 
#
36
 
#   and/or
37
 
#
38
 
#   provides:
39
 
#     (...)
40
 
#     local-monitors:
41
 
#       interface: local-monitors
42
 
#       scope: container
43
 
 
44
 
#
45
 
# 2. Add the following to config.yaml
46
 
#
47
 
#    nagios_context:
48
 
#      default: "juju"
49
 
#      type: string
50
 
#      description: |
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:
54
 
#            juju-myservice-0
55
 
#        If you're running multiple environments with the same services in them
56
 
#        this allows you to differentiate between them.
57
 
#    nagios_servicegroups:
58
 
#      default: ""
59
 
#      type: string
60
 
#      description: |
61
 
#        A comma-separated list of nagios servicegroups.
62
 
#        If left empty, the nagios_context will be used as the servicegroup
63
 
#
64
 
# 3. Add custom checks (Nagios plugins) to files/nrpe-external-master
65
 
#
66
 
# 4. Update your hooks.py with something like this:
67
 
#
68
 
#    from charmsupport.nrpe import NRPE
69
 
#    (...)
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"
76
 
#            )
77
 
#        nrpe_compat.add_check(
78
 
#            "myservice_other",
79
 
#            "Check for widget failures",
80
 
#            check_cmd = "/srv/myapp/scripts/widget_check"
81
 
#            )
82
 
#        nrpe_compat.write()
83
 
#
84
 
#    def config_changed():
85
 
#        (...)
86
 
#        update_nrpe_config()
87
 
#
88
 
#    def nrpe_external_master_relation_changed():
89
 
#        update_nrpe_config()
90
 
#
91
 
#    def local_monitors_relation_changed():
92
 
#        update_nrpe_config()
93
 
#
94
 
# 5. ln -s hooks.py nrpe-external-master-relation-changed
95
 
#    ln -s hooks.py local-monitors-relation-changed
96
 
 
97
 
 
98
 
class CheckException(Exception):
99
 
    pass
100
 
 
101
 
 
102
 
class Check(object):
103
 
    shortname_re = '[A-Za-z0-9-_]+$'
104
 
    service_template = ("""
105
 
#---------------------------------------------------
106
 
# This file is Juju managed
107
 
#---------------------------------------------------
108
 
define service {{
109
 
    use                             active-service
110
 
    host_name                       {nagios_hostname}
111
 
    service_description             {nagios_hostname}[{shortname}] """
112
 
                        """{description}
113
 
    check_command                   check_nrpe!{command}
114
 
    servicegroups                   {nagios_servicegroup}
115
 
}}
116
 
""")
117
 
 
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(
123
 
                Check.shortname_re))
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)
131
 
 
132
 
    def _locate_cmd(self, check_cmd):
133
 
        search_path = (
134
 
            '/usr/lib/nagios/plugins',
135
 
            '/usr/local/lib/nagios/plugins',
136
 
        )
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])
141
 
                if len(parts) > 1:
142
 
                    command += " " + " ".join(parts[1:])
143
 
                return command
144
 
        log('Check command not found: {}'.format(parts[0]))
145
 
        return ''
146
 
 
147
 
    def write(self, nagios_context, hostname, nagios_servicegroups=None):
148
 
        nrpe_check_file = '/etc/nagios/nrpe.d/{}.cfg'.format(
149
 
            self.command)
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))
154
 
 
155
 
        if not os.path.exists(NRPE.nagios_exportdir):
156
 
            log('Not writing service config as {} is not accessible'.format(
157
 
                NRPE.nagios_exportdir))
158
 
        else:
159
 
            self.write_service_config(nagios_context, hostname,
160
 
                                      nagios_servicegroups)
161
 
 
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))
167
 
 
168
 
        if not nagios_servicegroups:
169
 
            nagios_servicegroups = nagios_context
170
 
 
171
 
        templ_vars = {
172
 
            'nagios_hostname': hostname,
173
 
            'nagios_servicegroup': nagios_servicegroups,
174
 
            'description': self.description,
175
 
            'shortname': self.shortname,
176
 
            'command': self.command,
177
 
        }
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))
183
 
 
184
 
    def run(self):
185
 
        subprocess.call(self.check_cmd)
186
 
 
187
 
 
188
 
class NRPE(object):
189
 
    nagios_logdir = '/var/log/nagios'
190
 
    nagios_exportdir = '/var/lib/nagios/export'
191
 
    nrpe_confdir = '/etc/nagios/nrpe.d'
192
 
 
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']
199
 
        else:
200
 
            self.nagios_servicegroups = 'juju'
201
 
        self.unit_name = local_unit().replace('/', '-')
202
 
        if hostname:
203
 
            self.hostname = hostname
204
 
        else:
205
 
            self.hostname = "{}-{}".format(self.nagios_context, self.unit_name)
206
 
        self.checks = []
207
 
 
208
 
    def add_check(self, *args, **kwargs):
209
 
        self.checks.append(Check(*args, **kwargs))
210
 
 
211
 
    def write(self):
212
 
        try:
213
 
            nagios_uid = pwd.getpwnam('nagios').pw_uid
214
 
            nagios_gid = grp.getgrnam('nagios').gr_gid
215
 
        except:
216
 
            log("Nagios user not set up, nrpe checks not updated")
217
 
            return
218
 
 
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)
222
 
 
223
 
        nrpe_monitors = {}
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,
230
 
            }
231
 
 
232
 
        service('restart', 'nagios-nrpe-server')
233
 
 
234
 
        for rid in relation_ids("local-monitors"):
235
 
            relation_set(relation_id=rid, monitors=yaml.dump(monitors))