Merge lp:~gnuoy/charms/trusty/keystone/add-nrpe-checks into lp:~openstack-charmers-archive/charms/trusty/keystone/next
- Trusty Tahr (14.04)
- add-nrpe-checks
- Merge into next
Proposed by
Liam Young
Status: | Merged |
---|---|
Merged at revision: | 100 |
Proposed branch: | lp:~gnuoy/charms/trusty/keystone/add-nrpe-checks |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/keystone/next |
Diff against target: |
734 lines (+551/-15) 11 files modified
charm-helpers-hooks.yaml (+1/-0) config.yaml (+11/-0) hooks/charmhelpers/contrib/charmsupport/nrpe.py (+308/-0) hooks/charmhelpers/contrib/charmsupport/volumes.py (+159/-0) hooks/charmhelpers/contrib/openstack/utils.py (+6/-0) hooks/charmhelpers/contrib/unison/__init__.py (+29/-14) hooks/charmhelpers/fetch/__init__.py (+8/-1) hooks/keystone_hooks.py (+17/-0) hooks/keystone_utils.py (+8/-0) metadata.yaml (+3/-0) unit_tests/test_keystone_hooks.py (+1/-0) |
To merge this branch: | bzr merge lp:~gnuoy/charms/trusty/keystone/add-nrpe-checks |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Liam Young (community) | Approve | ||
Review via email: mp+246152@code.launchpad.net |
Commit message
Description of the change
Add nrpe support. Based on branch from bradm with a few tweaks
To post a comment you must log in.
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : | # |
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #702 keystone-next for gnuoy mp246152
UNIT OK: passed
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #858 keystone-next for gnuoy mp246152
AMULET OK: passed
Revision history for this message
Liam Young (gnuoy) wrote : | # |
<jamespage> gnuoy, as they are re-syncs + tweaks to the nrpe stuff in the charms, I'm happy to give a conditional +1 across the board based on osci checking things out OK
<gnuoy> jamespage, I'll take that! thanks
...
<gnuoy> jamespage, osci is still working through. But on the subject of those mps, does your +1 stand for branches with no amulet tests?
<jamespage> gnuoy, yes
review:
Approve
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-12-19 10:21:34 +0000 |
3 | +++ charm-helpers-hooks.yaml 2015-01-12 14:00:09 +0000 |
4 | @@ -13,3 +13,4 @@ |
5 | - contrib.peerstorage |
6 | - contrib.network.ip |
7 | - contrib.python.packages |
8 | + - contrib.charmsupport |
9 | |
10 | === modified file 'config.yaml' |
11 | --- config.yaml 2014-12-12 10:41:10 +0000 |
12 | +++ config.yaml 2015-01-12 14:00:09 +0000 |
13 | @@ -226,3 +226,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 2015-01-12 14:00:09 +0000 |
35 | @@ -0,0 +1,308 @@ |
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 | + relations_of_type, |
57 | +) |
58 | + |
59 | +from charmhelpers.core.host import service |
60 | + |
61 | +# This module adds compatibility with the nrpe-external-master and plain nrpe |
62 | +# subordinate charms. To use it in your charm: |
63 | +# |
64 | +# 1. Update metadata.yaml |
65 | +# |
66 | +# provides: |
67 | +# (...) |
68 | +# nrpe-external-master: |
69 | +# interface: nrpe-external-master |
70 | +# scope: container |
71 | +# |
72 | +# and/or |
73 | +# |
74 | +# provides: |
75 | +# (...) |
76 | +# local-monitors: |
77 | +# interface: local-monitors |
78 | +# scope: container |
79 | + |
80 | +# |
81 | +# 2. Add the following to config.yaml |
82 | +# |
83 | +# nagios_context: |
84 | +# default: "juju" |
85 | +# type: string |
86 | +# description: | |
87 | +# Used by the nrpe subordinate charms. |
88 | +# A string that will be prepended to instance name to set the host name |
89 | +# in nagios. So for instance the hostname would be something like: |
90 | +# juju-myservice-0 |
91 | +# If you're running multiple environments with the same services in them |
92 | +# this allows you to differentiate between them. |
93 | +# nagios_servicegroups: |
94 | +# default: "" |
95 | +# type: string |
96 | +# description: | |
97 | +# A comma-separated list of nagios servicegroups. |
98 | +# If left empty, the nagios_context will be used as the servicegroup |
99 | +# |
100 | +# 3. Add custom checks (Nagios plugins) to files/nrpe-external-master |
101 | +# |
102 | +# 4. Update your hooks.py with something like this: |
103 | +# |
104 | +# from charmsupport.nrpe import NRPE |
105 | +# (...) |
106 | +# def update_nrpe_config(): |
107 | +# nrpe_compat = NRPE() |
108 | +# nrpe_compat.add_check( |
109 | +# shortname = "myservice", |
110 | +# description = "Check MyService", |
111 | +# check_cmd = "check_http -w 2 -c 10 http://localhost" |
112 | +# ) |
113 | +# nrpe_compat.add_check( |
114 | +# "myservice_other", |
115 | +# "Check for widget failures", |
116 | +# check_cmd = "/srv/myapp/scripts/widget_check" |
117 | +# ) |
118 | +# nrpe_compat.write() |
119 | +# |
120 | +# def config_changed(): |
121 | +# (...) |
122 | +# update_nrpe_config() |
123 | +# |
124 | +# def nrpe_external_master_relation_changed(): |
125 | +# update_nrpe_config() |
126 | +# |
127 | +# def local_monitors_relation_changed(): |
128 | +# update_nrpe_config() |
129 | +# |
130 | +# 5. ln -s hooks.py nrpe-external-master-relation-changed |
131 | +# ln -s hooks.py local-monitors-relation-changed |
132 | + |
133 | + |
134 | +class CheckException(Exception): |
135 | + pass |
136 | + |
137 | + |
138 | +class Check(object): |
139 | + shortname_re = '[A-Za-z0-9-_]+$' |
140 | + service_template = (""" |
141 | +#--------------------------------------------------- |
142 | +# This file is Juju managed |
143 | +#--------------------------------------------------- |
144 | +define service {{ |
145 | + use active-service |
146 | + host_name {nagios_hostname} |
147 | + service_description {nagios_hostname}[{shortname}] """ |
148 | + """{description} |
149 | + check_command check_nrpe!{command} |
150 | + servicegroups {nagios_servicegroup} |
151 | +}} |
152 | +""") |
153 | + |
154 | + def __init__(self, shortname, description, check_cmd): |
155 | + super(Check, self).__init__() |
156 | + # XXX: could be better to calculate this from the service name |
157 | + if not re.match(self.shortname_re, shortname): |
158 | + raise CheckException("shortname must match {}".format( |
159 | + Check.shortname_re)) |
160 | + self.shortname = shortname |
161 | + self.command = "check_{}".format(shortname) |
162 | + # Note: a set of invalid characters is defined by the |
163 | + # Nagios server config |
164 | + # The default is: illegal_object_name_chars=`~!$%^&*"|'<>?,()= |
165 | + self.description = description |
166 | + self.check_cmd = self._locate_cmd(check_cmd) |
167 | + |
168 | + def _locate_cmd(self, check_cmd): |
169 | + search_path = ( |
170 | + '/usr/lib/nagios/plugins', |
171 | + '/usr/local/lib/nagios/plugins', |
172 | + ) |
173 | + parts = shlex.split(check_cmd) |
174 | + for path in search_path: |
175 | + if os.path.exists(os.path.join(path, parts[0])): |
176 | + command = os.path.join(path, parts[0]) |
177 | + if len(parts) > 1: |
178 | + command += " " + " ".join(parts[1:]) |
179 | + return command |
180 | + log('Check command not found: {}'.format(parts[0])) |
181 | + return '' |
182 | + |
183 | + def write(self, nagios_context, hostname, nagios_servicegroups=None): |
184 | + nrpe_check_file = '/etc/nagios/nrpe.d/{}.cfg'.format( |
185 | + self.command) |
186 | + with open(nrpe_check_file, 'w') as nrpe_check_config: |
187 | + nrpe_check_config.write("# check {}\n".format(self.shortname)) |
188 | + nrpe_check_config.write("command[{}]={}\n".format( |
189 | + self.command, self.check_cmd)) |
190 | + |
191 | + if not os.path.exists(NRPE.nagios_exportdir): |
192 | + log('Not writing service config as {} is not accessible'.format( |
193 | + NRPE.nagios_exportdir)) |
194 | + else: |
195 | + self.write_service_config(nagios_context, hostname, |
196 | + nagios_servicegroups) |
197 | + |
198 | + def write_service_config(self, nagios_context, hostname, |
199 | + nagios_servicegroups=None): |
200 | + for f in os.listdir(NRPE.nagios_exportdir): |
201 | + if re.search('.*{}.cfg'.format(self.command), f): |
202 | + os.remove(os.path.join(NRPE.nagios_exportdir, f)) |
203 | + |
204 | + if not nagios_servicegroups: |
205 | + nagios_servicegroups = nagios_context |
206 | + |
207 | + templ_vars = { |
208 | + 'nagios_hostname': hostname, |
209 | + 'nagios_servicegroup': nagios_servicegroups, |
210 | + 'description': self.description, |
211 | + 'shortname': self.shortname, |
212 | + 'command': self.command, |
213 | + } |
214 | + nrpe_service_text = Check.service_template.format(**templ_vars) |
215 | + nrpe_service_file = '{}/service__{}_{}.cfg'.format( |
216 | + NRPE.nagios_exportdir, hostname, self.command) |
217 | + with open(nrpe_service_file, 'w') as nrpe_service_config: |
218 | + nrpe_service_config.write(str(nrpe_service_text)) |
219 | + |
220 | + def run(self): |
221 | + subprocess.call(self.check_cmd) |
222 | + |
223 | + |
224 | +class NRPE(object): |
225 | + nagios_logdir = '/var/log/nagios' |
226 | + nagios_exportdir = '/var/lib/nagios/export' |
227 | + nrpe_confdir = '/etc/nagios/nrpe.d' |
228 | + |
229 | + def __init__(self, hostname=None): |
230 | + super(NRPE, self).__init__() |
231 | + self.config = config() |
232 | + self.nagios_context = self.config['nagios_context'] |
233 | + if 'nagios_servicegroups' in self.config: |
234 | + self.nagios_servicegroups = self.config['nagios_servicegroups'] |
235 | + else: |
236 | + self.nagios_servicegroups = 'juju' |
237 | + self.unit_name = local_unit().replace('/', '-') |
238 | + if hostname: |
239 | + self.hostname = hostname |
240 | + else: |
241 | + self.hostname = "{}-{}".format(self.nagios_context, self.unit_name) |
242 | + self.checks = [] |
243 | + |
244 | + def add_check(self, *args, **kwargs): |
245 | + self.checks.append(Check(*args, **kwargs)) |
246 | + |
247 | + def write(self): |
248 | + try: |
249 | + nagios_uid = pwd.getpwnam('nagios').pw_uid |
250 | + nagios_gid = grp.getgrnam('nagios').gr_gid |
251 | + except: |
252 | + log("Nagios user not set up, nrpe checks not updated") |
253 | + return |
254 | + |
255 | + if not os.path.exists(NRPE.nagios_logdir): |
256 | + os.mkdir(NRPE.nagios_logdir) |
257 | + os.chown(NRPE.nagios_logdir, nagios_uid, nagios_gid) |
258 | + |
259 | + nrpe_monitors = {} |
260 | + monitors = {"monitors": {"remote": {"nrpe": nrpe_monitors}}} |
261 | + for nrpecheck in self.checks: |
262 | + nrpecheck.write(self.nagios_context, self.hostname, |
263 | + self.nagios_servicegroups) |
264 | + nrpe_monitors[nrpecheck.shortname] = { |
265 | + "command": nrpecheck.command, |
266 | + } |
267 | + |
268 | + service('restart', 'nagios-nrpe-server') |
269 | + |
270 | + for rid in relation_ids("local-monitors"): |
271 | + relation_set(relation_id=rid, monitors=yaml.dump(monitors)) |
272 | + |
273 | + |
274 | +def get_nagios_hostcontext(relation_name='nrpe-external-master'): |
275 | + """ |
276 | + Query relation with nrpe subordinate, return the nagios_host_context |
277 | + |
278 | + :param str relation_name: Name of relation nrpe sub joined to |
279 | + """ |
280 | + for rel in relations_of_type(relation_name): |
281 | + if 'nagios_hostname' in rel: |
282 | + return rel['nagios_host_context'] |
283 | + |
284 | + |
285 | +def get_nagios_hostname(relation_name='nrpe-external-master'): |
286 | + """ |
287 | + Query relation with nrpe subordinate, return the nagios_hostname |
288 | + |
289 | + :param str relation_name: Name of relation nrpe sub joined to |
290 | + """ |
291 | + for rel in relations_of_type(relation_name): |
292 | + if 'nagios_hostname' in rel: |
293 | + return rel['nagios_hostname'] |
294 | + |
295 | + |
296 | +def get_nagios_unit_name(relation_name='nrpe-external-master'): |
297 | + """ |
298 | + Return the nagios unit name prepended with host_context if needed |
299 | + |
300 | + :param str relation_name: Name of relation nrpe sub joined to |
301 | + """ |
302 | + host_context = get_nagios_hostcontext(relation_name) |
303 | + if host_context: |
304 | + unit = "%s:%s" % (host_context, local_unit()) |
305 | + else: |
306 | + unit = local_unit() |
307 | + return unit |
308 | + |
309 | + |
310 | +def add_init_service_checks(nrpe, services, unit_name): |
311 | + """ |
312 | + Add checks for each service in list |
313 | + |
314 | + :param NRPE nrpe: NRPE object to add check to |
315 | + :param list services: List of services to check |
316 | + :param str unit_name: Unit name to use in check description |
317 | + """ |
318 | + for svc in services: |
319 | + upstart_init = '/etc/init/%s.conf' % svc |
320 | + sysv_init = '/etc/init.d/%s' % svc |
321 | + if os.path.exists(upstart_init): |
322 | + nrpe.add_check( |
323 | + shortname=svc, |
324 | + description='process check {%s}' % unit_name, |
325 | + check_cmd='check_upstart_job %s' % svc |
326 | + ) |
327 | + elif os.path.exists(sysv_init): |
328 | + cronpath = '/etc/cron.d/nagios-service-check-%s' % svc |
329 | + cron_file = ('*/5 * * * * root ' |
330 | + '/usr/local/lib/nagios/plugins/check_exit_status.pl ' |
331 | + '-s /etc/init.d/%s status > ' |
332 | + '/var/lib/nagios/service-check-%s.txt\n' % (svc, |
333 | + svc) |
334 | + ) |
335 | + f = open(cronpath, 'w') |
336 | + f.write(cron_file) |
337 | + f.close() |
338 | + nrpe.add_check( |
339 | + shortname=svc, |
340 | + description='process check {%s}' % unit_name, |
341 | + check_cmd='check_status_file.py -f ' |
342 | + '/var/lib/nagios/service-check-%s.txt' % svc, |
343 | + ) |
344 | |
345 | === added file 'hooks/charmhelpers/contrib/charmsupport/volumes.py' |
346 | --- hooks/charmhelpers/contrib/charmsupport/volumes.py 1970-01-01 00:00:00 +0000 |
347 | +++ hooks/charmhelpers/contrib/charmsupport/volumes.py 2015-01-12 14:00:09 +0000 |
348 | @@ -0,0 +1,159 @@ |
349 | +''' |
350 | +Functions for managing volumes in juju units. One volume is supported per unit. |
351 | +Subordinates may have their own storage, provided it is on its own partition. |
352 | + |
353 | +Configuration stanzas:: |
354 | + |
355 | + volume-ephemeral: |
356 | + type: boolean |
357 | + default: true |
358 | + description: > |
359 | + If false, a volume is mounted as sepecified in "volume-map" |
360 | + If true, ephemeral storage will be used, meaning that log data |
361 | + will only exist as long as the machine. YOU HAVE BEEN WARNED. |
362 | + volume-map: |
363 | + type: string |
364 | + default: {} |
365 | + description: > |
366 | + YAML map of units to device names, e.g: |
367 | + "{ rsyslog/0: /dev/vdb, rsyslog/1: /dev/vdb }" |
368 | + Service units will raise a configure-error if volume-ephemeral |
369 | + is 'true' and no volume-map value is set. Use 'juju set' to set a |
370 | + value and 'juju resolved' to complete configuration. |
371 | + |
372 | +Usage:: |
373 | + |
374 | + from charmsupport.volumes import configure_volume, VolumeConfigurationError |
375 | + from charmsupport.hookenv import log, ERROR |
376 | + def post_mount_hook(): |
377 | + stop_service('myservice') |
378 | + def post_mount_hook(): |
379 | + start_service('myservice') |
380 | + |
381 | + if __name__ == '__main__': |
382 | + try: |
383 | + configure_volume(before_change=pre_mount_hook, |
384 | + after_change=post_mount_hook) |
385 | + except VolumeConfigurationError: |
386 | + log('Storage could not be configured', ERROR) |
387 | + |
388 | +''' |
389 | + |
390 | +# XXX: Known limitations |
391 | +# - fstab is neither consulted nor updated |
392 | + |
393 | +import os |
394 | +from charmhelpers.core import hookenv |
395 | +from charmhelpers.core import host |
396 | +import yaml |
397 | + |
398 | + |
399 | +MOUNT_BASE = '/srv/juju/volumes' |
400 | + |
401 | + |
402 | +class VolumeConfigurationError(Exception): |
403 | + '''Volume configuration data is missing or invalid''' |
404 | + pass |
405 | + |
406 | + |
407 | +def get_config(): |
408 | + '''Gather and sanity-check volume configuration data''' |
409 | + volume_config = {} |
410 | + config = hookenv.config() |
411 | + |
412 | + errors = False |
413 | + |
414 | + if config.get('volume-ephemeral') in (True, 'True', 'true', 'Yes', 'yes'): |
415 | + volume_config['ephemeral'] = True |
416 | + else: |
417 | + volume_config['ephemeral'] = False |
418 | + |
419 | + try: |
420 | + volume_map = yaml.safe_load(config.get('volume-map', '{}')) |
421 | + except yaml.YAMLError as e: |
422 | + hookenv.log("Error parsing YAML volume-map: {}".format(e), |
423 | + hookenv.ERROR) |
424 | + errors = True |
425 | + if volume_map is None: |
426 | + # probably an empty string |
427 | + volume_map = {} |
428 | + elif not isinstance(volume_map, dict): |
429 | + hookenv.log("Volume-map should be a dictionary, not {}".format( |
430 | + type(volume_map))) |
431 | + errors = True |
432 | + |
433 | + volume_config['device'] = volume_map.get(os.environ['JUJU_UNIT_NAME']) |
434 | + if volume_config['device'] and volume_config['ephemeral']: |
435 | + # asked for ephemeral storage but also defined a volume ID |
436 | + hookenv.log('A volume is defined for this unit, but ephemeral ' |
437 | + 'storage was requested', hookenv.ERROR) |
438 | + errors = True |
439 | + elif not volume_config['device'] and not volume_config['ephemeral']: |
440 | + # asked for permanent storage but did not define volume ID |
441 | + hookenv.log('Ephemeral storage was requested, but there is no volume ' |
442 | + 'defined for this unit.', hookenv.ERROR) |
443 | + errors = True |
444 | + |
445 | + unit_mount_name = hookenv.local_unit().replace('/', '-') |
446 | + volume_config['mountpoint'] = os.path.join(MOUNT_BASE, unit_mount_name) |
447 | + |
448 | + if errors: |
449 | + return None |
450 | + return volume_config |
451 | + |
452 | + |
453 | +def mount_volume(config): |
454 | + if os.path.exists(config['mountpoint']): |
455 | + if not os.path.isdir(config['mountpoint']): |
456 | + hookenv.log('Not a directory: {}'.format(config['mountpoint'])) |
457 | + raise VolumeConfigurationError() |
458 | + else: |
459 | + host.mkdir(config['mountpoint']) |
460 | + if os.path.ismount(config['mountpoint']): |
461 | + unmount_volume(config) |
462 | + if not host.mount(config['device'], config['mountpoint'], persist=True): |
463 | + raise VolumeConfigurationError() |
464 | + |
465 | + |
466 | +def unmount_volume(config): |
467 | + if os.path.ismount(config['mountpoint']): |
468 | + if not host.umount(config['mountpoint'], persist=True): |
469 | + raise VolumeConfigurationError() |
470 | + |
471 | + |
472 | +def managed_mounts(): |
473 | + '''List of all mounted managed volumes''' |
474 | + return filter(lambda mount: mount[0].startswith(MOUNT_BASE), host.mounts()) |
475 | + |
476 | + |
477 | +def configure_volume(before_change=lambda: None, after_change=lambda: None): |
478 | + '''Set up storage (or don't) according to the charm's volume configuration. |
479 | + Returns the mount point or "ephemeral". before_change and after_change |
480 | + are optional functions to be called if the volume configuration changes. |
481 | + ''' |
482 | + |
483 | + config = get_config() |
484 | + if not config: |
485 | + hookenv.log('Failed to read volume configuration', hookenv.CRITICAL) |
486 | + raise VolumeConfigurationError() |
487 | + |
488 | + if config['ephemeral']: |
489 | + if os.path.ismount(config['mountpoint']): |
490 | + before_change() |
491 | + unmount_volume(config) |
492 | + after_change() |
493 | + return 'ephemeral' |
494 | + else: |
495 | + # persistent storage |
496 | + if os.path.ismount(config['mountpoint']): |
497 | + mounts = dict(managed_mounts()) |
498 | + if mounts.get(config['mountpoint']) != config['device']: |
499 | + before_change() |
500 | + unmount_volume(config) |
501 | + mount_volume(config) |
502 | + after_change() |
503 | + else: |
504 | + before_change() |
505 | + mount_volume(config) |
506 | + after_change() |
507 | + return config['mountpoint'] |
508 | |
509 | === modified file 'hooks/charmhelpers/contrib/openstack/utils.py' |
510 | --- hooks/charmhelpers/contrib/openstack/utils.py 2014-12-19 10:21:34 +0000 |
511 | +++ hooks/charmhelpers/contrib/openstack/utils.py 2015-01-12 14:00:09 +0000 |
512 | @@ -53,6 +53,7 @@ |
513 | ('saucy', 'havana'), |
514 | ('trusty', 'icehouse'), |
515 | ('utopic', 'juno'), |
516 | + ('vivid', 'kilo'), |
517 | ]) |
518 | |
519 | |
520 | @@ -64,6 +65,7 @@ |
521 | ('2013.2', 'havana'), |
522 | ('2014.1', 'icehouse'), |
523 | ('2014.2', 'juno'), |
524 | + ('2015.1', 'kilo'), |
525 | ]) |
526 | |
527 | # The ugly duckling |
528 | @@ -84,6 +86,7 @@ |
529 | ('2.0.0', 'juno'), |
530 | ('2.1.0', 'juno'), |
531 | ('2.2.0', 'juno'), |
532 | + ('2.2.1', 'kilo'), |
533 | ]) |
534 | |
535 | DEFAULT_LOOPBACK_SIZE = '5G' |
536 | @@ -289,6 +292,9 @@ |
537 | 'juno': 'trusty-updates/juno', |
538 | 'juno/updates': 'trusty-updates/juno', |
539 | 'juno/proposed': 'trusty-proposed/juno', |
540 | + 'kilo': 'trusty-updates/kilo', |
541 | + 'kilo/updates': 'trusty-updates/kilo', |
542 | + 'kilo/proposed': 'trusty-proposed/kilo', |
543 | } |
544 | |
545 | try: |
546 | |
547 | === modified file 'hooks/charmhelpers/contrib/unison/__init__.py' |
548 | --- hooks/charmhelpers/contrib/unison/__init__.py 2014-12-19 10:21:34 +0000 |
549 | +++ hooks/charmhelpers/contrib/unison/__init__.py 2015-01-12 14:00:09 +0000 |
550 | @@ -228,7 +228,12 @@ |
551 | return hosts |
552 | |
553 | |
554 | -def sync_path_to_host(path, host, user, verbose=False, cmd=None, gid=None): |
555 | +def sync_path_to_host(path, host, user, verbose=False, cmd=None, gid=None, |
556 | + fatal=False): |
557 | + """Sync path to an specific peer host |
558 | + |
559 | + Propagates exception if operation fails and fatal=True. |
560 | + """ |
561 | cmd = cmd or copy(BASE_CMD) |
562 | if not verbose: |
563 | cmd.append('-silent') |
564 | @@ -245,20 +250,30 @@ |
565 | run_as_user(user, cmd, gid) |
566 | except: |
567 | log('Error syncing remote files') |
568 | - |
569 | - |
570 | -def sync_to_peer(host, user, paths=None, verbose=False, cmd=None, gid=None): |
571 | - '''Sync paths to an specific host''' |
572 | + if fatal: |
573 | + raise |
574 | + |
575 | + |
576 | +def sync_to_peer(host, user, paths=None, verbose=False, cmd=None, gid=None, |
577 | + fatal=False): |
578 | + """Sync paths to an specific peer host |
579 | + |
580 | + Propagates exception if any operation fails and fatal=True. |
581 | + """ |
582 | if paths: |
583 | for p in paths: |
584 | - sync_path_to_host(p, host, user, verbose, cmd, gid) |
585 | - |
586 | - |
587 | -def sync_to_peers(peer_interface, user, paths=None, |
588 | - verbose=False, cmd=None, gid=None): |
589 | - '''Sync all hosts to an specific path''' |
590 | - '''The type of group is integer, it allows user has permissions to ''' |
591 | - '''operate a directory have a different group id with the user id.''' |
592 | + sync_path_to_host(p, host, user, verbose, cmd, gid, fatal) |
593 | + |
594 | + |
595 | +def sync_to_peers(peer_interface, user, paths=None, verbose=False, cmd=None, |
596 | + gid=None, fatal=False): |
597 | + """Sync all hosts to an specific path |
598 | + |
599 | + The type of group is integer, it allows user has permissions to |
600 | + operate a directory have a different group id with the user id. |
601 | + |
602 | + Propagates exception if any operation fails and fatal=True. |
603 | + """ |
604 | if paths: |
605 | for host in collect_authed_hosts(peer_interface): |
606 | - sync_to_peer(host, user, paths, verbose, cmd, gid) |
607 | + sync_to_peer(host, user, paths, verbose, cmd, gid, fatal) |
608 | |
609 | === modified file 'hooks/charmhelpers/fetch/__init__.py' |
610 | --- hooks/charmhelpers/fetch/__init__.py 2014-12-19 10:21:34 +0000 |
611 | +++ hooks/charmhelpers/fetch/__init__.py 2015-01-12 14:00:09 +0000 |
612 | @@ -64,9 +64,16 @@ |
613 | 'trusty-juno/updates': 'trusty-updates/juno', |
614 | 'trusty-updates/juno': 'trusty-updates/juno', |
615 | 'juno/proposed': 'trusty-proposed/juno', |
616 | - 'juno/proposed': 'trusty-proposed/juno', |
617 | 'trusty-juno/proposed': 'trusty-proposed/juno', |
618 | 'trusty-proposed/juno': 'trusty-proposed/juno', |
619 | + # Kilo |
620 | + 'kilo': 'trusty-updates/kilo', |
621 | + 'trusty-kilo': 'trusty-updates/kilo', |
622 | + 'trusty-kilo/updates': 'trusty-updates/kilo', |
623 | + 'trusty-updates/kilo': 'trusty-updates/kilo', |
624 | + 'kilo/proposed': 'trusty-proposed/kilo', |
625 | + 'trusty-kilo/proposed': 'trusty-proposed/kilo', |
626 | + 'trusty-proposed/kilo': 'trusty-proposed/kilo', |
627 | } |
628 | |
629 | # The order of this list is very important. Handlers should be listed in from |
630 | |
631 | === modified file 'hooks/keystone_hooks.py' |
632 | --- hooks/keystone_hooks.py 2014-12-16 23:48:42 +0000 |
633 | +++ hooks/keystone_hooks.py 2015-01-12 14:00:09 +0000 |
634 | @@ -51,6 +51,7 @@ |
635 | register_configs, |
636 | relation_list, |
637 | restart_map, |
638 | + services, |
639 | CLUSTER_RES, |
640 | KEYSTONE_CONF, |
641 | SSH_USER, |
642 | @@ -79,6 +80,8 @@ |
643 | ) |
644 | from charmhelpers.contrib.openstack.context import ADDRESS_TYPES |
645 | |
646 | +from charmhelpers.contrib.charmsupport import nrpe |
647 | + |
648 | hooks = Hooks() |
649 | CONFIGS = register_configs() |
650 | |
651 | @@ -111,6 +114,7 @@ |
652 | |
653 | save_script_rc() |
654 | configure_https() |
655 | + update_nrpe_config() |
656 | CONFIGS.write_all() |
657 | if eligible_leader(CLUSTER_RES): |
658 | migrate_database() |
659 | @@ -375,6 +379,7 @@ |
660 | group='keystone', |
661 | peer_interface='cluster', |
662 | ensure_local_user=True) |
663 | + update_nrpe_config() |
664 | synchronize_ca() |
665 | if eligible_leader(CLUSTER_RES): |
666 | log('Cluster leader - ensuring endpoint configuration' |
667 | @@ -389,6 +394,18 @@ |
668 | CONFIGS.write_all() |
669 | |
670 | |
671 | +@hooks.hook('nrpe-external-master-relation-joined', |
672 | + 'nrpe-external-master-relation-changed') |
673 | +def update_nrpe_config(): |
674 | + # python-dbus is used by check_upstart_job |
675 | + apt_install('python-dbus') |
676 | + hostname = nrpe.get_nagios_hostname() |
677 | + current_unit = nrpe.get_nagios_unit_name() |
678 | + nrpe_setup = nrpe.NRPE(hostname=hostname) |
679 | + nrpe.add_init_service_checks(nrpe_setup, services(), current_unit) |
680 | + nrpe_setup.write() |
681 | + |
682 | + |
683 | def main(): |
684 | try: |
685 | hooks.execute(sys.argv) |
686 | |
687 | === modified file 'hooks/keystone_utils.py' |
688 | --- hooks/keystone_utils.py 2014-12-19 10:21:34 +0000 |
689 | +++ hooks/keystone_utils.py 2015-01-12 14:00:09 +0000 |
690 | @@ -226,6 +226,14 @@ |
691 | if v['services']]) |
692 | |
693 | |
694 | +def services(): |
695 | + ''' Returns a list of services associate with this charm ''' |
696 | + _services = [] |
697 | + for v in restart_map().values(): |
698 | + _services = _services + v |
699 | + return list(set(_services)) |
700 | + |
701 | + |
702 | def determine_ports(): |
703 | '''Assemble a list of API ports for services we are managing''' |
704 | ports = [config('admin-port'), config('service-port')] |
705 | |
706 | === added symlink 'hooks/nrpe-external-master-relation-changed' |
707 | === target is u'keystone_hooks.py' |
708 | === added symlink 'hooks/nrpe-external-master-relation-joined' |
709 | === target is u'keystone_hooks.py' |
710 | === modified file 'metadata.yaml' |
711 | --- metadata.yaml 2014-12-16 20:15:03 +0000 |
712 | +++ metadata.yaml 2015-01-12 14:00:09 +0000 |
713 | @@ -7,6 +7,9 @@ |
714 | implements OpenStack’s Identity API. |
715 | categories: ["misc"] |
716 | provides: |
717 | + nrpe-external-master: |
718 | + interface: nrpe-external-master |
719 | + scope: container |
720 | identity-service: |
721 | interface: keystone |
722 | identity-notifications: |
723 | |
724 | === modified file 'unit_tests/test_keystone_hooks.py' |
725 | --- unit_tests/test_keystone_hooks.py 2014-12-17 17:54:26 +0000 |
726 | +++ unit_tests/test_keystone_hooks.py 2015-01-12 14:00:09 +0000 |
727 | @@ -56,6 +56,7 @@ |
728 | 'ensure_initial_admin', |
729 | 'add_service_to_keystone', |
730 | 'synchronize_ca', |
731 | + 'update_nrpe_config', |
732 | # other |
733 | 'check_call', |
734 | 'execd_preinstall', |
charm_lint_check #673 keystone-next for gnuoy mp246152
LINT OK: passed
Build: http:// 10.245. 162.77: 8080/job/ charm_lint_ check/673/