diff options
author | Peter Palfrader <peter@palfrader.org> | 2011-06-20 09:51:01 +0000 |
---|---|---|
committer | weasel <weasel@bc3d92e2-beff-0310-a7cd-cc87d7ac0ede> | 2011-06-20 09:51:01 +0000 |
commit | 26dc0f8f4ec62e9bae102fdefe894885bf668b03 (patch) | |
tree | 40ea04258924189a897e07e61ba2eac174d1cd22 /nagios-check-rdiff-backup | |
parent | 08be39dd7cbe60d54bd0387f145aa734823ab02f (diff) |
Add nagios-check-rdiff-backup
git-svn-id: svn+ssh://asteria.noreply.org/svn/weaselutils/trunk@486 bc3d92e2-beff-0310-a7cd-cc87d7ac0ede
Diffstat (limited to 'nagios-check-rdiff-backup')
-rwxr-xr-x | nagios-check-rdiff-backup | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/nagios-check-rdiff-backup b/nagios-check-rdiff-backup new file mode 100755 index 0000000..7df30af --- /dev/null +++ b/nagios-check-rdiff-backup @@ -0,0 +1,151 @@ +#!/usr/bin/python + +# Copyright 2010, 2011 Peter Palfrader +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import datetime +import dateutil.parser +import optparse +import os +import re +import sys +import glob + + +parser = optparse.OptionParser() +parser.set_usage("%prog [options] <backuprepository>") +parser.add_option("-w", "--warn", metavar="AGE", dest="warn", + help="Warn if backup older than (default: 28h)") +parser.add_option("-c", "--critical", metavar="AGE", dest="critical", + help="Warn if backup older than (default: 72h)") +(options, args) = parser.parse_args() + +if len(args) == 0: + parser.print_help() + sys.exit(1) + +log = [] +exitcode = 0 +backup_per_code = {} + +def code_to_prefix(code): + if code == 3: return 'UNKNOWN: ' + elif code == 2: return 'CRITICAL: ' + elif code == 1: return 'WARNING: ' + elif code == 0: return 'OK: ' + else: raise ValueError + +def convert_time(s, default_unit='h'): + m = re.match('([0-9]+)([smhdw])?$', s) + if m is None: raise ValueError + ticks = int(m.group(1)) + unit = m.group(2) + if unit is None: unit = default_unit + + if unit == 's': None + elif unit == 'm': ticks *= 60 + elif unit == 'h': ticks *= 60*60 + elif unit == 'd': ticks *= 60*60*24 + elif unit == 'w': ticks *= 60*60*24*7 + else: raise ValueError + return ticks + +def record(code, base, msg): + global exitcode + + if not code in backup_per_code: backup_per_code[code] = [] + backup_per_code[code].append(base) + + prefix = code_to_prefix(code) + log.append("%s%s: %s"%(prefix, base, msg)) + + if code > exitcode: exitcode = code + +def get_ts_from_fn(base, fn): + m = re.match('current_mirror\.(.*)\.data$', fn) + if m is None: + record(2, base, "backup wedged - cannot parse current mirrors filename '%s'."%(fn)) + return None + try: + ts = dateutil.parser.parse(m.group(1)) + except ValueError: + record(2, base, "backup wedged - cannot parse datestring '%s' from filename '%s'."%(m.group(1), fn)) + return None + return ts + +if options.warn is None: options.warn = '28' +if options.critical is None: options.critical = '72' +options.warn = datetime.timedelta(seconds = convert_time(options.warn)) +options.critical = datetime.timedelta(seconds = convert_time(options.critical)) + + +for base in args: + data_dir = os.path.join(base, 'rdiff-backup-data') + + if not os.path.exists(base): + record(2, base, "not a directory") + continue + if not os.path.isdir(data_dir): + record(2, base, "does not seem to be an rdiff-backup backup directory") + continue + os.chdir(data_dir) + + current_mirrors = glob.glob('current_mirror.*.data') + if len(current_mirrors) == 0: + record(2, base, "no current backups? (current_mirror.* not found)") + continue + elif len(current_mirrors) == 2: # one backup is currently running, presumably + current_mirrors.sort() + elif len(current_mirrors) == 1: # only one backup is current, good. + None + else: + record(2, base, "backup wedged - too many current_mirror.* files") + continue + + ts = get_ts_from_fn(base, current_mirrors[0]) + age = datetime.datetime.now(ts.tzinfo) - ts + if age > options.critical: + record(2, base, "backup is old (%s)."%(age)) + continue + elif age > options.warn: + record(1, base, "backup is old (%s)."%(age)) + continue + else: + record(0, base, "backup is current (age: %s)."%(age)) + continue + + + + +def record(code, base, msg): + + if not code in backup_per_code: backup_per_code[code] = [] + backup_per_code[code].append(base) + +report = [] +keys = backup_per_code.keys() +keys.sort(reverse=True) +for code in keys: + prefix = code_to_prefix(code) + report.append( prefix + ', '.join(backup_per_code[code]) ) +print '; '.join(report) +for l in log: print l +sys.exit(exitcode) |