diff options
author | Timothy Asir <tim.gluster@gmail.com> | 2014-03-17 14:01:40 +0530 |
---|---|---|
committer | Bala.FA <barumuga@redhat.com> | 2014-04-29 10:14:32 +0530 |
commit | 71cdd37492727d427fc0feae978ce60424f4b4df (patch) | |
tree | bcabf3c7b46bfc67ed0569ea1c4c3855cb7cf7e6 | |
parent | b42b8a71399b59ec93ed41efb58f2f3ae12fc8ab (diff) |
Enhanced check_disk_and_inode plugin
Add option to include / exclude disk
Add option to get disk usage without inode usage
Add unit test
Change-Id: Ifa8c13033269fea184d2dedc720dba4239770336
Signed-off-by: Timothy Asir <tim.gluster@gmail.com>
Reviewed-on: https://cuckoo.blr.redhat.com:8443/18
Reviewed-by: Sahina Bose <sabose@redhat.com>
-rw-r--r-- | gluster-nagios-addons.spec.in | 7 | ||||
-rwxr-xr-x | plugins/check_disk_and_inode.py | 272 | ||||
-rw-r--r-- | tests/test_disk.py | 187 |
3 files changed, 345 insertions, 121 deletions
diff --git a/gluster-nagios-addons.spec.in b/gluster-nagios-addons.spec.in index 980a44d..3034334 100644 --- a/gluster-nagios-addons.spec.in +++ b/gluster-nagios-addons.spec.in @@ -116,13 +116,18 @@ rm -rf %{buildroot} %_init_restart iptables %endif +if grep -q "dont_blame_nrpe=0" %{_sysconfdir}/nagios/nrpe.cfg ; then + sed -i -e 's/dont_blame_nrpe=0/dont_blame_nrpe=1/g' %{_sysconfdir}/nagios/nrpe.cfg +fi + cat >> %{_sysconfdir}/nagios/nrpe.cfg <<EOF ### gluster nrpe plugins ### -command[check_disk_and_inode]=%{_libdir}/nagios/plugins/gluster/check_disk_and_inode.py -w 80 -c 90 -l -i /boot -i /var -i /root -n +command[check_disk_and_inode]=%{_libdir}/nagios/plugins/gluster/check_disk_and_inode.py -w 80 -c 90 -l -i /boot -i /var -i /root -n --inode command[check_memory]=%{_libdir}/nagios/plugins/gluster/memory.py -w 80 -c 90 command[check_swap_usage]=%{_libdir}/nagios/plugins/gluster/swap.py -w 80 -c 90 command[check_cpu_multicore]=%{_libdir}/nagios/plugins/gluster/cpu.py -w 80 -c 90 command[check_interfaces]=%{_libdir}/nagios/plugins/gluster/network.py -e lo -e ';vdsmdummy;' +command[check_brick_usage]=/usr/lib64/nagios/plugins/gluster/check_disk_and_inode.py -w 80 -c 90 -u MB -n -i \$ARG1\$ EOF %_init_enable nrpe %_init_restart crond diff --git a/plugins/check_disk_and_inode.py b/plugins/check_disk_and_inode.py index 02c5cd2..5989180 100755 --- a/plugins/check_disk_and_inode.py +++ b/plugins/check_disk_and_inode.py @@ -22,50 +22,50 @@ import re import sys import commands from optparse import OptionParser +from glusternagios import utils +WARNING_LEVEL = 80 +CRITICAL_LEVEL = 90 -def getUsageAndFree(command, lvm): - status = commands.getstatusoutput(command)[1].split() - path = status[-1] - usagePer = status[-2] - availSpace = status[-3] - usedSpace = status[-4] - device = status[-6].split("-")[-1] - dmatch = re.compile('[0-9]+').match(usagePer) + +def getVal(val): + dmatch = re.compile('[0-9]+').match(val) if (dmatch): - usage = eval(dmatch.group(0)) - return (float(usage), float(100 - usage), usedSpace, - availSpace, device, path) + return float(eval(dmatch.group(0))) else: - return None, None, None, None, None, None + return 0 -def getDisk(path, readable=False, lvm=False): - if readable: - return getUsageAndFree("df -m %s" % path, lvm) +def getUsageAndFree(command, lvm): + disk = {'path': None, 'usePercent': None, 'avail': None, + 'used': None, 'size': None, 'fs': None} + status = commands.getstatusoutput(command)[1].split() + disk['path'] = status[-1] + disk['avail'] = getVal(status[-3]) + disk['used'] = getVal(status[-4]) + disk['size'] = getVal(status[-5]) + disk['fs'] = status[-6] + disk['usePcent'] = getVal(status[-2]) + disk['availPcent'] = 100 - disk['usePcent'] + return disk + + +def getDisk(path, usage=None, lvm=False): + if usage: + return getUsageAndFree("df -B%s %s" % (usage, path), lvm) else: - return getUsageAndFree("df -kh %s" % path, lvm) + return getUsageAndFree("df -BG %s" % path, lvm) -def getInode(path, readable=False, lvm=False): +def getInode(path, lvm=False): return getUsageAndFree("df -i %s" % path, lvm) -def appendStatus(lst, level, typ, device, mpath, usage): - if 2 == level: - level = "crit" - elif 1 == level: - level = "warn" - else: - level = "ok" - lst.append("%s:%s:%s;%s;%s" % (level, device, mpath, usage)) - - -def getMounts(searchQuery=None, excludeList=[]): +def getMounts(searchQuery, excludeList=[]): mountPaths = [] f = open("/etc/mtab") for i in f.readlines(): - if searchQuery and i.startswith(searchQuery): + if i.startswith(searchQuery): if not excludeList: mountPaths.append(i.split()[0]) else: @@ -80,124 +80,156 @@ def getMounts(searchQuery=None, excludeList=[]): def parse_input(): parser = OptionParser() parser.add_option('-w', '--warning', action='store', type='int', - dest='warn', help='Warning count in %', default=80) + dest='warn', + help='Warning count in %', default=WARNING_LEVEL) parser.add_option('-c', '--critical', action='store', type='int', - dest='crit', help='Critical count in %', default=90) - parser.add_option('-u', '--usage', action="store_true", dest='usage', - help='Output disk and inode usage', default=False) + dest='crit', + help='Critical count in %', default=CRITICAL_LEVEL) + parser.add_option('-u', '--usage', action="store", dest='usage', + help='Usage in %/GB/MB/KB', default=None) parser.add_option('-l', '--lvm', action="store_true", - dest='lvm', help='List lvm mounts', default=False) + dest='lvm', + help='List lvm mounts', default=False) + parser.add_option('-d', '--inode', action="store_true", dest='inode', + help='List inode usage along with disk/brick usage', + default=False) parser.add_option('-a', '--all', action="store_true", - dest='all', help='List all mounts', default=False) + dest='all', + help='List all mounts', default=False) parser.add_option('-n', '--ignore', action="store_true", - dest='ignore', help='Ignore errors', default=False) + dest='ignore', + help='Ignore errors', default=False) parser.add_option('-i', '--include', action='append', type='string', - dest='mountPath', help='Mount path', default=[]) + dest='mountPath', + help='Mount path', default=[]) parser.add_option('-x', '--exclude', action="append", type='string', - dest='exclude', help='Exclude disk') + dest='exclude', + help='Exclude disk/brick') return parser.parse_args() -if __name__ == '__main__': - disk = [] +def showDiskUsage(warn, crit, mountPaths, toListInode, usage=False, + isLvm=False, ignoreError=False): + diskPerf = [] warnList = [] critList = [] diskList = [] mounts = [] level = -1 - (options, args) = parse_input() - if len(args) > 2: - if args[0].isdigit() and args[1].isdigit(): - warn = int(args[0]) - crit = int(args[1]) - options.mountPath = args[2:] - else: - warn = 80 - crit = 90 - options.mountPath = args - else: - crit = options.crit - warn = options.warn + for path in mountPaths: + disk = getDisk(path, + usage, + isLvm) - if options.lvm: - searchQuery = "/dev/mapper" - elif options.all: - searchQuery = None - else: - searchQuery = "/" + inode = getInode(path, + isLvm) - if not options.mountPath or options.lvm or options.all: - options.mountPath += getMounts(searchQuery, options.exclude) - - #if not options.mountPath: - # parser.print_help() - # sys.exit(1) - - for path in options.mountPath: - diskUsage, diskFree, used, avail, dev, mpath = getDisk(path, - options.usage, - options.lvm) - inodeUsage, inodeFree, iused, iavail, idev, ipath = getInode( - path, - options.usage, - options.lvm) - if mpath in mounts: + if disk['path'] in mounts: continue - if not used or not iused: - if options.ignore: + if not disk['used'] or not inode['used']: + if ignoreError: continue else: - sys.exit(3) - - mounts.append(mpath) - if options.usage: - total = (float(used) + float(avail)) / 1000 - itot = (float(iused) + float(iavail)) / 1000 - disk.append("%s=%.1f;%.1f;%.1f;0;%.1f %s=%.1f;%.1f;%.1f;0;%.1f" % ( - mpath, - float(used) / 1000, - warn * total / 100, - crit * total / 100, - total, - ipath, - float(iused) / 1000, - warn * itot / 100, - crit * itot / 100, - itot)) + sys.exit(utils.PluginStatusCode.UNKNOWN) + + mounts.append(disk['path']) + if usage: + data = "%s=%.1f;%.1f;%.1f;0;%.1f" % ( + disk['path'], + disk['used'], + warn * disk['size'] / 100, + crit * disk['size'] / 100, + disk['size']) + if toListInode: + data += " %s=%.1f;%.1f;%.1f;0;%.1f" % ( + inode['path'], + inode['used'], + warn * inode['used'] / 100, + crit * inode['used'] / 100, + inode['used']) else: - disk.append("%s=%.2f;%s;%s;0;100 %s=%.2f;%s;%s;0;100" % ( - mpath, diskUsage, warn, crit, ipath, inodeUsage, warn, crit)) - - if diskUsage >= crit or inodeUsage >= crit: - if diskUsage >= crit: - critList.append("crit:disk:%s;%s;%s" % (dev, mpath, diskUsage)) + data = "%s=%.2f;%s;%s;0;100" % ( + disk['path'], + disk['usePcent'], + warn, + crit) + + if toListInode: + data += " %s=%.2f;%s;%s;0;100" % ( + inode['path'], + inode['usePcent'], + warn, + crit) + diskPerf.append(data) + + if disk['usePcent'] >= crit or inode['usePcent'] >= crit: + if disk['usePcent'] >= crit: + critList.append( + "crit:disk:%s;%s;%s" % (disk['fs'], + disk['path'], + disk['usePcent'])) else: - critList.append("crit:inode:%s;%s;%s" % (idev, ipath, - inodeUsage)) - if not level > 1: - level = 2 - elif (diskUsage >= warn and diskUsage < crit) or ( - inodeUsage >= warn and inodeUsage < crit): - if diskUsage >= warn: - warnList.append("warn:disk:%s;%s;%s" % (dev, mpath, diskUsage)) + critList.append("crit:inode:%s;%s;%s" % (inode['fs'], + inode['path'], + inode['usePcent'])) + if not level > utils.PluginStatusCode.WARNING: + level = utils.PluginStatusCode.CRITICAL + elif (disk['usePcent'] >= warn and disk['usePcent'] < crit) or ( + inode['usePcent'] >= warn and inode['usePcent'] < crit): + if disk['usePcent'] >= warn: + warnList.append("warn:disk:%s;%s;%s" % (disk['fs'], + disk['path'], + disk['usePcent'])) else: - warnList.append("warn:inode:%s;%s;%s" % (idev, ipath, - inodeUsage)) - if not level > 0: - level = 1 + warnList.append("warn:inode:%s;%s;%s" % (inode['fs'], + inode['path'], + inode['usePcent'])) + if not level > utils.PluginStatusCode.OK: + level = utils.PluginStatusCode.WARNING else: - diskList.append("%s:%s" % (dev, mpath)) + diskList.append("%s=%s" % (disk['fs'], disk['path'])) msg = " ".join(critList + warnList) if not msg: msg += " disks:mounts:(" + ",".join(diskList) + ")" - if 2 == level: - print "CRITICAL : %s | %s" % (msg, " ".join(disk)) - sys.exit(2) - elif 1 == level: - print "WARNING : %s | %s" % (msg, " ".join(disk)) - sys.exit(1) + return level, msg, diskPerf + + +if __name__ == '__main__': + (options, args) = parse_input() + + if options.lvm: + searchQuery = "/dev/mapper" + else: + searchQuery = "/" + + if not options.mountPath or options.lvm or options.all: + options.mountPath += getMounts(searchQuery, options.exclude) + + level, msg, diskPerf = showDiskUsage(options.warn, + options.crit, + options.mountPath, + options.inode, + options.usage, + options.lvm, + options.ignore) + + if utils.PluginStatusCode.CRITICAL == level: + sys.stdout.write("%s : %s | %s\n" % ( + utils.PluginStatus.CRITICAL, + msg, + " ".join(diskPerf))) + sys.exit(utils.PluginStatusCode.CRITICAL) + elif utils.PluginStatusCode.WARNING == level: + sys.stdout.write("%s : %s | %s\n" % ( + utils.PluginStatus.WARNING, + msg, + " ".join(diskPerf))) + sys.exit(utils.PluginStatusCode.WARNING) else: - print "OK : %s | %s" % (msg, " ".join(disk)) + sys.stdout.write("%s : %s | %s\n" % ( + utils.PluginStatus.OK, + msg, + " ".join(diskPerf))) diff --git a/tests/test_disk.py b/tests/test_disk.py new file mode 100644 index 0000000..a9096c2 --- /dev/null +++ b/tests/test_disk.py @@ -0,0 +1,187 @@ +# +# Copyright 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Refer to the README and COPYING files for full details of the license +# + +import commands +from testrunner import PluginsTestCase as TestCaseBase +from plugins import check_disk_and_inode as checkDisk + + +class TestDisk(TestCaseBase): + def mock_getstatusoutput(self, i): + out = [ + "Filesystem Size Used Avail Use% Mounted on", + "/dev/sda1 290G 174G 102G 64% /", + "/dev/sdb1 3.9G 0 3.9G 0% /var", + "/dev/sdc1 290G 200G 100G 40% /mnt1", + "/dev/mapper/vg_test1-lv_one " + "35852 1774 32257 85% /lvm1", + "- 994 1 994 1% /dev", + "/dev/mapper/vg_demonode2-lv1 " + "50G 11G 36G 24% /mnt/lv4", + "/dev/vda1 485M 36M 424M 8% /mnt/abc1", + "/dev/mapper/vg_demonode2-lv_2 " + "5.5G 4.3G 933M 83% /mnt/abc2", + "none 0 0 0 - " + "/proc/sys/fs/binfmt_misc", + "10.70.43.190:/exports/abc 50G 11G 36G 24% /mnt", + "10.70.43.190:vol3 50G 11G 36G 24% /mnt/vol3", + "10.70.43.190:vol2 52846MB 23228MB 26934MB 47% /mnt/vol2"] + + if type(i) is str: + disk = i.split()[-1] + for diskDetail in out: + if diskDetail.find(disk) >= 0: + return 0, diskDetail + else: + return 0, out[0] + out[i] + return 0, "" + + def mock_open(self, fileName): + out = ["/dev/mapper/vg_demonode2-lv_1 /mnt/abc1 ext4 rw 0 0", + "proc /proc proc rw 0 0", + "sysfs /sys sysfs rw 0 0", + "devpts /dev/pts devpts rw,gid=5,mode=620 0 0", + "tmpfs /dev/shm tmpfs rw 0 0", + "/dev/sda1 /boot ext4 rw 0 0", + "/dev/mapper/vg_demonode2-lv_2 /mnt/abc2 ext4 rw 0 0", + "none /proc/sys/fs/binfmt_misc binfmt_misc rw 0 0", + "sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw 0 0", + "10.70.43.190:/exports/abc /mnt nfs rw,vers=4,addr=10.70.43.190" + ",clientaddr=10.70.43.190 0 0", + "10.70.43.190:vol2 /mnt/vol2 nfs rw,addr=10.70.43.190 0 0", + "10.70.43.190:vol3 /mnt/vol3 nfs rw,addr=10.70.43.190 0 0"] + + class file(): + def readlines(self): + return out + + def close(self): + return None + return file() + + def test_getUsageAndFree(self): + commands.getstatusoutput = self.mock_getstatusoutput + disk = checkDisk.getUsageAndFree(1, True) + self.assertEqual(disk['usePcent'], 64) + self.assertEqual(disk['availPcent'], 36) + self.assertEqual(disk['used'], 174) + self.assertEqual(disk['avail'], 102) + self.assertEqual(disk['path'], '/') + + disk = checkDisk.getUsageAndFree(2, True) + self.assertEqual(disk['usePcent'], 0) + self.assertEqual(disk['availPcent'], 100) + self.assertEqual(disk['used'], 0) + self.assertEqual(disk['avail'], 3.0) + self.assertEqual(disk['path'], '/var') + + disk = checkDisk.getUsageAndFree(3, True) + self.assertEqual(disk['usePcent'], 40) + self.assertEqual(disk['availPcent'], 60) + self.assertEqual(disk['used'], 200) + self.assertEqual(disk['avail'], 100) + self.assertEqual(disk['path'], '/mnt1') + + disk = checkDisk.getUsageAndFree(4, True) + self.assertEqual(disk['usePcent'], 85) + self.assertEqual(disk['availPcent'], 15) + self.assertEqual(disk['used'], 1774) + self.assertEqual(disk['avail'], 32257) + self.assertEqual(disk['path'], '/lvm1') + + def test_getMounts(self): + checkDisk.open = self.mock_open + mounts = checkDisk.getMounts("/", []) + self.assertEqual(mounts[0], "/dev/mapper/vg_demonode2-lv_1") + self.assertEqual(mounts[1], "/dev/sda1") + self.assertEqual(mounts[2], "/dev/mapper/vg_demonode2-lv_2") + + mounts = checkDisk.getMounts("/dev/mapper", []) + self.assertEqual(mounts[0], "/dev/mapper/vg_demonode2-lv_1") + self.assertEqual(mounts[1], "/dev/mapper/vg_demonode2-lv_2") + + mounts = checkDisk.getMounts("", []) + self.assertEqual(len(mounts), 12) + + def test_diskUsage(self): + commands.getstatusoutput = self.mock_getstatusoutput + checkDisk.open = self.mock_open + mounts = checkDisk.getMounts("/", []) + + self.assertEqual(checkDisk.showDiskUsage(80, + 90, + [mounts[1]], + True, + usage='BGB', + ignoreError=True), + (-1, ' disks:mounts:(/dev/sda1=/)', + ['/=174.0;232.0;261.0;0;290.0 ' + '/=174.0;139.2;156.6;0;174.0'])) + + self.assertEqual(checkDisk.showDiskUsage(80, + 90, + [mounts[1]], True, + ignoreError=True), + (-1, ' disks:mounts:(/dev/sda1=/)', + ['/=64.00;80;90;0;100 /=64.00;80;90;0;100'])) + + self.assertEqual(checkDisk.showDiskUsage(80, + 90, + ["/mnt/vol2"], True, + ignoreError=True), + (-1, ' disks:mounts:(10.70.43.190:vol2=/mnt/vol2)', + ['/mnt/vol2=47.00;80;90;0;100 ' + '/mnt/vol2=47.00;80;90;0;100'])) + + self.assertEqual(checkDisk.showDiskUsage(80, + 90, + ["/mnt/vol2"], True, + usage="MB", + ignoreError=True), + (-1, ' disks:mounts:(10.70.43.190:vol2=/mnt/vol2)', + ['/mnt/vol2=23228.0;42276.8;47561.4;0;52846.0 ' + '/mnt/vol2=23228.0;18582.4;20905.2;0;23228.0'])) + + self.assertEqual(checkDisk.showDiskUsage(10, + 20, + ["/mnt/vol2"], True, + usage="MB", + ignoreError=True), + (2, 'crit:disk:10.70.43.190:vol2;/mnt/vol2;47.0', + ['/mnt/vol2=23228.0;5284.6;10569.2;0;52846.0 ' + '/mnt/vol2=23228.0;2322.8;4645.6;0;23228.0'])) + + # negative test + self.assertEqual(checkDisk.showDiskUsage(-1, + 200, + ["/mnt/vol2"], True, + usage="MB", + ignoreError=True), + (1, 'warn:disk:10.70.43.190:vol2;/mnt/vol2;47.0', + ['/mnt/vol2=23228.0;-528.5;105692.0;0;52846.0 ' + '/mnt/vol2=23228.0;-232.3;46456.0;0;23228.0'])) + + # testing warning level + self.assertEqual(checkDisk.showDiskUsage(40, 50, ["/mnt/vol2"], True, + usage="MB", + ignoreError=True), + (1, 'warn:disk:10.70.43.190:vol2;/mnt/vol2;47.0', + ['/mnt/vol2=23228.0;21138.4;26423.0;0;52846.0 ' + '/mnt/vol2=23228.0;9291.2;11614.0;0;23228.0'])) |