Merge lp:~mthaddon/charms/precise/haproxy/get-upstream into lp:charms/haproxy
- Precise Pangolin (12.04)
- get-upstream
- Merge into trunk
Proposed by
Tom Haddon
Status: | Merged |
---|---|
Merged at revision: | 63 |
Proposed branch: | lp:~mthaddon/charms/precise/haproxy/get-upstream |
Merge into: | lp:charms/haproxy |
Diff against target: |
358 lines (+273/-0) (has conflicts) 8 files modified
config.yaml (+10/-0) files/nrpe-external-master/check_haproxy.sh (+33/-0) files/nrpe-external-master/check_haproxy_queue_depth.sh (+30/-0) hooks/hooks.py (+13/-0) hooks/nrpe.py (+170/-0) metadata.yaml (+3/-0) revision (+4/-0) templates/nrpe_service.tmpl (+10/-0) Text conflict in revision |
To merge this branch: | bzr merge lp:~mthaddon/charms/precise/haproxy/get-upstream |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juan L. Negron (community) | Approve | ||
Review via email: mp+139978@code.launchpad.net |
Commit message
Description of the change
Include nrpe-external-
To post a comment you must log in.
- 71. By Tom Haddon
-
Remove illegal characters from description string
Revision history for this message
Juan L. Negron (negronjl) wrote : | # |
Revision history for this message
Juan L. Negron (negronjl) wrote : | # |
This seems to be sane.
Approving ... merging.
-Juan
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'config.yaml' |
2 | --- config.yaml 2012-07-13 21:31:43 +0000 |
3 | +++ config.yaml 2012-12-21 11:12:22 +0000 |
4 | @@ -106,3 +106,13 @@ |
5 | before the first variable, service_name, as above. Service options is a |
6 | comma separated list, server options will be appended as a string to |
7 | the individual server lines for a given listen stanza. |
8 | + nagios_context: |
9 | + default: "juju" |
10 | + type: string |
11 | + description: | |
12 | + Used by the nrpe-external-master subordinate charm. |
13 | + A string that will be prepended to instance name to set the host name |
14 | + in nagios. So for instance the hostname would be something like: |
15 | + juju-postgresql-0 |
16 | + If you're running multiple environments with the same services in them |
17 | + this allows you to differentiate between them. |
18 | |
19 | === added directory 'files' |
20 | === added directory 'files/nrpe-external-master' |
21 | === added file 'files/nrpe-external-master/check_haproxy.sh' |
22 | --- files/nrpe-external-master/check_haproxy.sh 1970-01-01 00:00:00 +0000 |
23 | +++ files/nrpe-external-master/check_haproxy.sh 2012-12-21 11:12:22 +0000 |
24 | @@ -0,0 +1,33 @@ |
25 | +#!/bin/bash |
26 | +#-------------------------------------------- |
27 | +# This file is managed by Juju |
28 | +#-------------------------------------------- |
29 | +# |
30 | +# Copyright 2009,2012 Canonical Ltd. |
31 | +# Author: Tom Haddon |
32 | + |
33 | +CRITICAL=0 |
34 | +NOTACTIVE='' |
35 | +LOGFILE=/var/log/nagios/check_haproxy.log |
36 | +AUTH=$(grep -r "stats auth" /etc/haproxy | head -1 | awk '{print $4}') |
37 | + |
38 | +for appserver in $(grep ' server' /etc/haproxy/haproxy.cfg | awk '{print $2'}); |
39 | +do |
40 | + output=$(/usr/lib/nagios/plugins/check_http -a ${AUTH} -I 127.0.0.1 -p 10000 --regex="class=\"active(2|3).*${appserver}" -e ' 200 OK') |
41 | + if [ $? != 0 ]; then |
42 | + date >> $LOGFILE |
43 | + echo $output >> $LOGFILE |
44 | + /usr/lib/nagios/plugins/check_http -a ${AUTH} -I 127.0.0.1 -p 10000 -v | grep $appserver >> $LOGFILE 2>&1 |
45 | + CRITICAL=1 |
46 | + NOTACTIVE="${NOTACTIVE} $appserver" |
47 | + fi |
48 | +done |
49 | + |
50 | +if [ $CRITICAL = 1 ]; then |
51 | + echo "CRITICAL:${NOTACTIVE}" |
52 | + exit 2 |
53 | +fi |
54 | + |
55 | +echo "OK: All haproxy instances looking good" |
56 | +exit 0 |
57 | + |
58 | |
59 | === added file 'files/nrpe-external-master/check_haproxy_queue_depth.sh' |
60 | --- files/nrpe-external-master/check_haproxy_queue_depth.sh 1970-01-01 00:00:00 +0000 |
61 | +++ files/nrpe-external-master/check_haproxy_queue_depth.sh 2012-12-21 11:12:22 +0000 |
62 | @@ -0,0 +1,30 @@ |
63 | +#!/bin/bash |
64 | +#-------------------------------------------- |
65 | +# This file is managed by Juju |
66 | +#-------------------------------------------- |
67 | +# |
68 | +# Copyright 2009,2012 Canonical Ltd. |
69 | +# Author: Tom Haddon |
70 | + |
71 | +# These should be config options at some stage |
72 | +CURRQthrsh=0 |
73 | +MAXQthrsh=100 |
74 | + |
75 | +AUTH=$(grep -r "stats auth" /etc/haproxy | head -1 | awk '{print $4}') |
76 | + |
77 | +HAPROXYSTATS=$(/usr/lib/nagios/plugins/check_http -a ${AUTH} -I 127.0.0.1 -p 10000 -v) |
78 | + |
79 | +for BACKEND in $(echo $HAPROXYSTATS| xargs -n1 | grep BACKEND | awk -F , '{print $1}') |
80 | +do |
81 | + CURRQ=$(echo "$HAPROXYSTATS" | grep $BACKEND | grep BACKEND | cut -d , -f 3) |
82 | + MAXQ=$(echo "$HAPROXYSTATS" | grep $BACKEND | grep BACKEND | cut -d , -f 4) |
83 | + |
84 | + if [[ $CURRQ -gt $CURRQthrsh || $MAXQ -gt $MAXQthrsh ]] ; then |
85 | + echo "CRITICAL: queue depth for $BACKEND - CURRENT:$CURRQ MAX:$MAXQ" |
86 | + exit 2 |
87 | + fi |
88 | +done |
89 | + |
90 | +echo "OK: All haproxy queue depths looking good" |
91 | +exit 0 |
92 | + |
93 | |
94 | === modified file 'hooks/hooks.py' |
95 | --- hooks/hooks.py 2012-11-20 15:50:24 +0000 |
96 | +++ hooks/hooks.py 2012-12-21 11:12:22 +0000 |
97 | @@ -10,6 +10,7 @@ |
98 | import subprocess |
99 | import sys |
100 | import yaml |
101 | +import nrpe |
102 | |
103 | |
104 | ############################################################################### |
105 | @@ -511,6 +512,9 @@ |
106 | # Hook functions |
107 | ############################################################################### |
108 | def install_hook(): |
109 | + for f in glob.glob('exec.d/*/charm-pre-install'): |
110 | + if os.path.isfile(f) and os.access(f, os.X_OK): |
111 | + subprocess.check_call(['sh', '-c', f]) |
112 | if not os.path.exists(default_haproxy_service_config_dir): |
113 | os.mkdir(default_haproxy_service_config_dir, 0600) |
114 | return ((apt_get_install("haproxy") == enable_haproxy()) is True) |
115 | @@ -595,6 +599,12 @@ |
116 | open("%s/%s.is.proxy" % |
117 | (default_haproxy_service_config_dir, service_name), 'a').close() |
118 | |
119 | +def update_nrpe_config(): |
120 | + nrpe_compat = nrpe.NRPE() |
121 | + nrpe_compat.add_check('haproxy','Check HAProxy', 'check_haproxy.sh') |
122 | + nrpe_compat.add_check('haproxy_queue','Check HAProxy queue depth', 'check_haproxy_queue_depth.sh') |
123 | + nrpe_compat.write() |
124 | + |
125 | ############################################################################### |
126 | # Main section |
127 | ############################################################################### |
128 | @@ -602,6 +612,7 @@ |
129 | install_hook() |
130 | elif hook_name == "config-changed": |
131 | config_changed() |
132 | + update_nrpe_config() |
133 | elif hook_name == "start": |
134 | start_hook() |
135 | elif hook_name == "stop": |
136 | @@ -616,6 +627,8 @@ |
137 | website_interface("joined") |
138 | elif hook_name == "website-relation-changed": |
139 | website_interface("changed") |
140 | +elif hook_name == "nrpe-external-master-relation-changed": |
141 | + update_nrpe_config() |
142 | else: |
143 | print "Unknown hook" |
144 | sys.exit(1) |
145 | |
146 | === added symlink 'hooks/nrpe-external-master-relation-changed' |
147 | === target is u'hooks.py' |
148 | === added file 'hooks/nrpe.py' |
149 | --- hooks/nrpe.py 1970-01-01 00:00:00 +0000 |
150 | +++ hooks/nrpe.py 2012-12-21 11:12:22 +0000 |
151 | @@ -0,0 +1,170 @@ |
152 | +import json |
153 | +import subprocess |
154 | +import pwd |
155 | +import grp |
156 | +import os |
157 | +import re |
158 | +import shlex |
159 | + |
160 | +# This module adds compatibility with the nrpe_external_master |
161 | +# subordinate charm. To use it in your charm: |
162 | +# |
163 | +# 1. Update metadata.yaml |
164 | +# |
165 | +# provides: |
166 | +# (...) |
167 | +# nrpe-external-master: |
168 | +# interface: nrpe-external-master |
169 | +# scope: container |
170 | +# |
171 | +# 2. Add the following to config.yaml |
172 | +# |
173 | +# nagios_context: |
174 | +# default: "juju" |
175 | +# type: string |
176 | +# description: | |
177 | +# Used by the nrpe-external-master subordinate charm. |
178 | +# A string that will be prepended to instance name to set the host name |
179 | +# in nagios. So for instance the hostname would be something like: |
180 | +# juju-myservice-0 |
181 | +# If you're running multiple environments with the same services in them |
182 | +# this allows you to differentiate between them. |
183 | +# |
184 | +# 3. Add custom checks (Nagios plugins) to files/nrpe-external-master |
185 | +# |
186 | +# 4. Update your hooks.py with something like this: |
187 | +# |
188 | +# import nrpe |
189 | +# (...) |
190 | +# def update_nrpe_config(): |
191 | +# nrpe_compat = NRPE("myservice") |
192 | +# nrpe_compat.add_check( |
193 | +# shortname = "myservice", |
194 | +# description = "Check MyService", |
195 | +# check_cmd = "check_http -w 2 -c 10 http://localhost" |
196 | +# ) |
197 | +# nrpe_compat.add_check( |
198 | +# "myservice_other", |
199 | +# "Check for widget failures", |
200 | +# check_cmd = "/srv/myapp/scripts/widget_check" |
201 | +# ) |
202 | +# nrpe_compat.write() |
203 | +# |
204 | +# def config_changed(): |
205 | +# (...) |
206 | +# update_nrpe_config() |
207 | + |
208 | +class ConfigurationError(Exception): |
209 | + '''An error interacting with the Juju config''' |
210 | + pass |
211 | +def config_get(scope=None): |
212 | + '''Return the Juju config as a dictionary''' |
213 | + try: |
214 | + config_cmd_line = ['config-get'] |
215 | + if scope is not None: |
216 | + config_cmd_line.append(scope) |
217 | + config_cmd_line.append('--format=json') |
218 | + return json.loads(subprocess.check_output(config_cmd_line)) |
219 | + except (ValueError, OSError, subprocess.CalledProcessError) as error: |
220 | + subprocess.call(['juju-log', str(error)]) |
221 | + raise ConfigurationError(str(error)) |
222 | + |
223 | +class CheckException(Exception): pass |
224 | +class Check(object): |
225 | + shortname_re = '[A-Za-z0-9-_]*' |
226 | + service_template = """ |
227 | +#--------------------------------------------------- |
228 | +# This file is Juju managed |
229 | +#--------------------------------------------------- |
230 | +define service {{ |
231 | + use active-service |
232 | + host_name {nagios_hostname} |
233 | + service_description {nagios_hostname} {shortname} {description} |
234 | + check_command check_nrpe!check_{shortname} |
235 | + servicegroups {nagios_servicegroup} |
236 | +}} |
237 | +""" |
238 | + def __init__(self, shortname, description, check_cmd): |
239 | + super(Check, self).__init__() |
240 | + # XXX: could be better to calculate this from the service name |
241 | + if not re.match(self.shortname_re, shortname): |
242 | + raise CheckException("shortname must match {}".format(Check.shortname_re)) |
243 | + self.shortname = shortname |
244 | + self.description = description |
245 | + self.check_cmd = self._locate_cmd(check_cmd) |
246 | + |
247 | + def _locate_cmd(self, check_cmd): |
248 | + search_path = ( |
249 | + '/', |
250 | + os.path.join(os.environ['CHARM_DIR'], 'files/nrpe-external-master'), |
251 | + '/usr/lib/nagios/plugins', |
252 | + ) |
253 | + command = shlex.split(check_cmd) |
254 | + for path in search_path: |
255 | + if os.path.exists(os.path.join(path,command[0])): |
256 | + return os.path.join(path, command[0]) + " " + " ".join(command[1:]) |
257 | + subprocess.call(['juju-log', 'Check command not found: {}'.format(command[0])]) |
258 | + return '' |
259 | + |
260 | + def write(self, nagios_context, hostname): |
261 | + for f in os.listdir(NRPE.nagios_exportdir): |
262 | + if re.search('.*check_{}.cfg'.format(self.shortname), f): |
263 | + os.remove(os.path.join(NRPE.nagios_exportdir, f)) |
264 | + |
265 | + templ_vars = { |
266 | + 'nagios_hostname': hostname, |
267 | + 'nagios_servicegroup': nagios_context, |
268 | + 'description': self.description, |
269 | + 'shortname': self.shortname, |
270 | + } |
271 | + nrpe_service_text = Check.service_template.format(**templ_vars) |
272 | + nrpe_service_file = '{}/service__{}_check_{}.cfg'.format( |
273 | + NRPE.nagios_exportdir, hostname, self.shortname) |
274 | + with open(nrpe_service_file, 'w') as nrpe_service_config: |
275 | + nrpe_service_config.write(str(nrpe_service_text)) |
276 | + |
277 | + nrpe_check_file = '/etc/nagios/nrpe.d/check_{}.cfg'.format(self.shortname) |
278 | + with open(nrpe_check_file, 'w') as nrpe_check_config: |
279 | + nrpe_check_config.write("# check {}\n".format(self.shortname)) |
280 | + nrpe_check_config.write("command[check_{}]={}\n".format( |
281 | + self.shortname, self.check_cmd)) |
282 | + |
283 | + def run(self): |
284 | + subprocess.call(self.check_cmd) |
285 | + |
286 | +class NRPE(object): |
287 | + nagios_logdir = '/var/log/nagios' |
288 | + nagios_exportdir = '/var/lib/nagios/export' |
289 | + nrpe_confdir = '/etc/nagios/nrpe.d' |
290 | + def __init__(self): |
291 | + super(NRPE, self).__init__() |
292 | + self.config = config_get() |
293 | + self.nagios_context = self.config['nagios_context'] |
294 | + self.unit_name = os.environ['JUJU_UNIT_NAME'].replace('/', '-') |
295 | + self.hostname = "{}-{}".format(self.nagios_context, self.unit_name) |
296 | + self.checks = [] |
297 | + |
298 | + def add_check(self, *args, **kwargs): |
299 | + self.checks.append( Check(*args, **kwargs) ) |
300 | + |
301 | + def write(self): |
302 | + try: |
303 | + nagios_uid = pwd.getpwnam('nagios').pw_uid |
304 | + nagios_gid = grp.getgrnam('nagios').gr_gid |
305 | + except: |
306 | + subprocess.call(['juju-log', "Nagios user not set up, nrpe checks not updated"]) |
307 | + return |
308 | + |
309 | + if not os.path.exists(NRPE.nagios_exportdir): |
310 | + subprocess.call(['juju-log', 'Exiting as {} is not accessible'.format(NRPE.nagios_exportdir)]) |
311 | + return |
312 | + |
313 | + if not os.path.exists(NRPE.nagios_logdir): |
314 | + os.mkdir(NRPE.nagios_logdir) |
315 | + os.chown(NRPE.nagios_logdir, nagios_uid, nagios_gid) |
316 | + |
317 | + for nrpecheck in self.checks: |
318 | + nrpecheck.write(self.nagios_context, self.hostname) |
319 | + |
320 | + if os.path.isfile('/etc/init.d/nagios-nrpe-server'): |
321 | + subprocess.call(['service', 'nagios-nrpe-server', 'reload']) |
322 | |
323 | === modified file 'metadata.yaml' |
324 | --- metadata.yaml 2012-08-01 05:16:56 +0000 |
325 | +++ metadata.yaml 2012-12-21 11:12:22 +0000 |
326 | @@ -15,3 +15,6 @@ |
327 | interface: http |
328 | munin: |
329 | interface: munin-node |
330 | + nrpe-external-master: |
331 | + interface: nrpe-external-master |
332 | + scope: container |
333 | |
334 | === modified file 'revision' |
335 | --- revision 2012-11-20 15:50:24 +0000 |
336 | +++ revision 2012-12-21 11:12:22 +0000 |
337 | @@ -1,1 +1,5 @@ |
338 | +<<<<<<< TREE |
339 | 24 |
340 | +======= |
341 | +31 |
342 | +>>>>>>> MERGE-SOURCE |
343 | |
344 | === added directory 'templates' |
345 | === added file 'templates/nrpe_service.tmpl' |
346 | --- templates/nrpe_service.tmpl 1970-01-01 00:00:00 +0000 |
347 | +++ templates/nrpe_service.tmpl 2012-12-21 11:12:22 +0000 |
348 | @@ -0,0 +1,10 @@ |
349 | +#--------------------------------------------------- |
350 | +# This file is Juju managed |
351 | +#--------------------------------------------------- |
352 | +define service { |
353 | + use active-service |
354 | + host_name {{ nagios_hostname }} |
355 | + service_description {{ nagios_hostname }} {{ check.description }} |
356 | + check_command check_nrpe!check_{{ check.shortname }} |
357 | + servicegroups {{ nagios_servicegroup }} |
358 | +} |
Reviewing this now.
-Juan