home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.lbl.gov / 2014.05.ftp.ee.lbl.gov.tar / ftp.ee.lbl.gov / acld-1.11.tar.gz / acld-1.11.tar / acld-1.11 / check_acld.py.in < prev    next >
Text File  |  2011-10-06  |  9KB  |  363 lines

  1. #!@PYTHON@
  2. """check_acld - nagios plugin for acld"""
  3. # @(#) $Id: check_acld.py.in 792 2011-10-06 21:47:07Z leres $ (LBL)
  4. #
  5. # Copyright (c) 2011
  6. #    The Regents of the University of California.  All rights reserved.
  7. #
  8. # Redistribution and use in source and binary forms, with or without
  9. # modification, are permitted provided that: (1) source code distributions
  10. # retain the above copyright notice and this paragraph in its entirety, (2)
  11. # distributions including binary code include the above copyright notice and
  12. # this paragraph in its entirety in the documentation or other materials
  13. # provided with the distribution, and (3) all advertising materials mentioning
  14. # features or use of this software display the following acknowledgement:
  15. # ``This product includes software developed by the University of California,
  16. # Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  17. # the University nor the names of its contributors may be used to endorse
  18. # or promote products derived from this software without specific prior
  19. # written permission.
  20. # THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  21. # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  22. # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  23. #
  24.  
  25. import optparse
  26. import os
  27. import re
  28. import subprocess
  29. import sys
  30.  
  31. OPTS = None
  32. PROG = '?'
  33. ACLDBIN = '@PREFIX@/libexec'
  34.  
  35. STR2STATUS = {
  36.     'OK':    0,
  37.     'WARNING':    1,
  38.     'CRITICAL':    2,
  39.     'UNKNOWN':    3,
  40. }
  41.  
  42. STATUS2STR = {
  43.     0: 'OK',
  44.     1: 'WARNING',
  45.     2: 'CRITICAL',
  46.     3: 'UNKNOWN',
  47. }
  48.  
  49. # Adjust our path
  50. pathstr = 'PATH'
  51. if not ACLDBIN in os.environ[pathstr].split(':'):
  52.     os.environ[pathstr] = '%s:%s' % (ACLDBIN, os.environ[pathstr])
  53.  
  54. def checkdroprestore(data):
  55.     """Test drop/restore"""
  56.     results = []
  57.     addrs = data['args']
  58.     for addr in addrs:
  59.     result = None
  60.     for what in ['drop', 'restore']:
  61.         data['sout'] = ''
  62.         data['serr'] = ''
  63.         runacl(data, [what, addr])
  64.         if data['code'] != 0:
  65.         data['status'] = STR2STATUS['CRITICAL']
  66.         result = '%s-%s!' % (what, addr)
  67.         break
  68.     if result:
  69.         results.append(result)
  70.     elif OPTS.verbose > 0:
  71.         results.append(addr)
  72.  
  73.     if results == []:
  74.     results.append('OK')
  75.  
  76.     prefix = ', test drop/restore'
  77.     if len(addrs) != 1:
  78.     prefix += 's'
  79.     prefix += ': '
  80.  
  81.     data['msg'] += prefix + ' '.join(results)
  82.  
  83. def checkfull(data):
  84.     """Check if the acl is too full"""
  85.     pct = OPTS.fullpct
  86.     re_hiwater = re.compile(r'\A# hiwater for ACL (\S+) is (\d+)\Z')
  87.     re_limit = re.compile(r'\Alimit (\d+) (.+)\Z')
  88.     hiwaters = {}
  89.     limits = []
  90.     for line in data['sout'].split('\n'):
  91.     m = re_hiwater.search(line)
  92.     if m != None:
  93.         hiwaters[m.group(1)] = int(m.group(2))
  94.         continue
  95.  
  96.     m = re_limit.search(line)
  97.     if m != None:
  98.         # List of ACL names followed by limit value
  99.         limits.append([m.group(2).split(), int(m.group(1))])
  100.         continue
  101.  
  102.     results = []
  103.     for (acls, limit) in limits:
  104.     hiwater = 0
  105.     # Sum
  106.     for acl in acls:
  107.         hiwater += hiwaters[acl]
  108.  
  109.     if limit <= 0:
  110.         val = 0
  111.     else:
  112.         val = (100 * hiwater) / limit
  113.     result = '%s=%d%%' % ('+'.join(acls), val)
  114.     if val >= pct:
  115.         result += '!'
  116.         data['status'] = STR2STATUS['CRITICAL']
  117.         results.append(result)
  118.     elif OPTS.verbose > 0:
  119.         results.append(result)
  120.  
  121.     if results == []:
  122.     results.append('OK')
  123.  
  124.     data['msg'] += ', hiwater PCTs: ' + ' '.join(results)
  125.  
  126. def checkrate(data):
  127.     """Check if the add rate is ok"""
  128.     rate = OPTS.rate
  129.     re_rate = re.compile(r'\A# rate for ACL (\S+) is (\d+) acl/min\Z')
  130.     acls = {}
  131.     for line in data['sout'].split('\n'):
  132.     m = re_rate.search(line)
  133.     if m == None:
  134.         continue
  135.     acls[m.group(1)] = int(m.group(2))
  136.  
  137.     keys = acls.keys()
  138.     keys.sort()
  139.  
  140.     results = []
  141.     for key in acls:
  142.     val = acls[key]
  143.     result = '%s=%d' % (key, val)
  144.     if val >= rate:
  145.         result += '!'
  146.         data['status'] = STR2STATUS['CRITICAL']
  147.         results.append(result)
  148.     elif OPTS.verbose > 0:
  149.         results.append(result)
  150.  
  151.     if results == []:
  152.     results.append('OK')
  153.     else:
  154.     results[-1] += ' acl/min'
  155.  
  156.     data['msg'] += ', drop rates: ' + ' '.join(results)
  157.  
  158. def checkseq(data):
  159.     """Check if any ACLs have high sequence numbers"""
  160.     pct = OPTS.seqpct
  161.     m = re.search(r'^seqrange (\d+) (\d+)\n', data['sout'], re.MULTILINE)
  162.     if m == None:
  163.     data['status'] = STR2STATUS['UNKNOWN']
  164.     data['msg'] += " Can't find seqrange"
  165.     return
  166.     seqrange = (int(m.group(1)), int(m.group(2)))
  167.     size = seqrange[1] - seqrange[0]
  168.     if size < 0:
  169.     data['status'] = STR2STATUS['UNKNOWN']
  170.     data['msg'] += " Can't figure out seqrange size"
  171.     return
  172.  
  173.     re_lastseq = re.compile(r'\A# lastseq for ACL (\S+) is (\d+)\Z')
  174.  
  175.     lines = data['sout'].split('\n')
  176.     results = []
  177.     for line in lines:
  178.     m = re_lastseq.search(line)
  179.     if m == None:
  180.         continue
  181.     acl = m.group(1)
  182.     lastseq = int(m.group(2))
  183.     n = lastseq - seqrange[0]
  184.     if n < 0:
  185.         n = 0
  186.     val = (100 * n) / size
  187.     result = '%s=%d%%' % (acl, val)
  188.     if val >= pct:
  189.         result += '!'
  190.         data['status'] = STR2STATUS['CRITICAL']
  191.         results.append(result)
  192.     elif OPTS.verbose > 0:
  193.         results.append(result)
  194.  
  195.     if results == []:
  196.     results.append('OK')
  197.  
  198.     data['msg'] += ', sequence number PCTs: ' + ' '.join(results)
  199.  
  200. def checkstate(data):
  201.     """Check if the state is ok, return a dict containing information"""
  202.  
  203.     # Extract host
  204.     m = re.search(r'^# host (.+)\n', data['sout'], re.MULTILINE)
  205.     if m == None:
  206.     data['status'] = STR2STATUS['UNKNOWN']
  207.     data['msg'] += "Can't determine acld host"
  208.     return
  209.     data['host'] = m.group(1)
  210.  
  211.     # Extract state
  212.     m = re.search(r'^# state (.+)\n', data['sout'], re.MULTILINE)
  213.     if m == None:
  214.     data['status'] = STR2STATUS['UNKNOWN']
  215.     data['msg'] += "can't find state"
  216.     return
  217.     data['state'] = m.group(1)
  218.  
  219.     if data['state'] != 'loggedin':
  220.     data['status'] = STR2STATUS['CRITICAL']
  221.     data['msg'] += 'acld on %s not logged in' % (data['host'])
  222.     else:
  223.     data['msg'] += 'acld on %s logged in and ready' % (data['host'])
  224.  
  225. def reportandexit(data):
  226.     """Produce the nagios report and then exit with the appropriate code"""
  227.     status = data['status']
  228.     print '%s: %s' % (STATUS2STR[status], data['msg'])
  229.     return status
  230.  
  231. def runacl(data, args):
  232.     """Check the status of an acl result"""
  233.     cmd = ['acl.exp' ]
  234.  
  235.     # Set up environment
  236.     if OPTS.addr:
  237.     estr = 'ACLIPADDR'
  238.     if estr in os.environ:
  239.         oldaddrenv = os.environ[estr]
  240.     else:
  241.         oldaddrenv = None
  242.     os.environ[estr] = OPTS.addr
  243.  
  244.     if OPTS.port:
  245.     estr = 'ACLPORT'
  246.     if estr in os.environ:
  247.         oldportenv = os.environ[estr]
  248.     else:
  249.         oldportenv = None
  250.     os.environ[estr] = unicode(OPTS.port)
  251.  
  252.     cmd.extend(args)
  253.     try:
  254.     child = subprocess.Popen(cmd,
  255.         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  256.     except OSError, e:
  257.     data['code'] = 1
  258.     data['msg'] += '%s: %s' % (cmd[0], e.strerror)
  259.     finally:
  260.     # Child I/O
  261.     (data['sout'], data['serr']) = child.communicate()
  262.     data['code'] = child.returncode
  263.  
  264.     # Restore environment
  265.     if OPTS.addr:
  266.     estr = 'ACLIPADDR'
  267.     if oldaddrenv != None:
  268.         os.environ[estr] = oldaddrenv
  269.     else:
  270.         del os.environ[estr]
  271.  
  272.     if OPTS.port:
  273.     estr = 'ACLPORT'
  274.     if oldportenv != None:
  275.         os.environ[estr] = oldportenv
  276.     else:
  277.         del os.environ[estr]
  278.  
  279. def main(argv=sys.argv):
  280.     """Main program"""
  281.     global OPTS
  282.     global PROG
  283.  
  284.     PROG = os.path.basename(argv[0])
  285.  
  286.     usage = [
  287.     'usage: %prog [-v] [-a addr] [-p port] [-u user] [-R rate]'
  288.     '    [-H hiwaterpct] [-F fullpct] [addr ...]',
  289.     ]
  290.     version = '$Revision: 792 $'.lstrip('$').rstrip('$')
  291.  
  292.     parser = optparse.OptionParser(usage='\n'.join(usage), version=version)
  293.     parser.add_option('-v', None,
  294.         action='count', dest='verbose', default=0,
  295.             help='increase verbosity')
  296.     parser.add_option('-a', None,
  297.         action='store', dest='addr',
  298.             help='IP address of acld')
  299.     parser.add_option('-p', None,
  300.         action='store', dest='port', type='int',
  301.             help='TCP port of acld')
  302.     parser.add_option('-u', None,
  303.         action='store', dest='user', default=None,
  304.             help='USER to log requests as')
  305.  
  306.     parser.add_option('-R', None,
  307.         action='store', dest='rate', default=None, type='int',
  308.             help='ACL drop rate to report critical')
  309.     parser.add_option('-F', None,
  310.         action='store', dest='fullpct', default=None, type='int',
  311.             help='ACL percentage used to report critical')
  312.     parser.add_option('-H', None,
  313.         action='store', dest='seqpct', default=None, type='int',
  314.             help='lastseq in use percentage to report critical')
  315.  
  316.     (OPTS, args) = parser.parse_args()
  317.  
  318.     data = {
  319.     'args': args,
  320.     'code': -1,
  321.     'msg': '',
  322.     'serr': '',
  323.     'sout': '',
  324.     'status': STR2STATUS['OK'],
  325.     }
  326.  
  327.     # Optionally set the user these requests are always done on behalf of
  328.     if OPTS.user != None:
  329.     os.environ['USER'] = OPTS.user
  330.  
  331.     runacl(data, ['state'])
  332.  
  333.     if data['code'] != 0:
  334.     data['status'] = STR2STATUS['UNKNOWN']
  335.     if data['msg'] == '':
  336.         data['msg'] = 'acl.exp state failed'
  337.     return reportandexit(data)
  338.  
  339.     # Are we logged in?
  340.     checkstate(data)
  341.  
  342.     # Are any drop rates too high?
  343.     if OPTS.rate != None:
  344.     checkrate(data)
  345.  
  346.     # Are any ACL lists getting to full?
  347.     if OPTS.fullpct != None:
  348.     checkfull(data)
  349.  
  350.     # Are any sequence numbers getting to high?
  351.     if OPTS.seqpct != None:
  352.     checkseq(data)
  353.  
  354.     # Are any drop rates too high (run this test last)
  355.     if OPTS.seqpct:
  356.     checkdroprestore(data)
  357.  
  358.     # That's all, folks!
  359.     return reportandexit(data)
  360.  
  361. if __name__ == "__main__":
  362.     sys.exit(main())
  363.