summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gluster-nagios-addons.spec.in7
-rwxr-xr-xplugins/check_disk_and_inode.py272
-rw-r--r--tests/test_disk.py187
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']))