summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorndarshan <dnarayan@redhat.com>2015-01-06 10:47:25 +0530
committerSahina Bose <sabose@redhat.com>2015-02-19 02:21:54 -0800
commita8017b5878561cb40e82f2e7715e0638d87f2600 (patch)
treefcb86c733839276b43f3e81aa563e7fe578d3e19
parent75ec853fc15780c5e00f2211cb0b095e3be7e48f (diff)
nagios-plugins: Disk utilization plugin revamp.
This patch is aimed at revamping the existing check_disk_and_inode plugin in such a way that the plugin behaviour is same for both disk utilization service and brick utilization service. It has just two options include and exclude to include or exclude the mountpoints to be monitoried. This plugin monitors the data, inode, thinpool, thinpool-metadata utilization irrespective of service using this plugin. Change-Id: I98b18d6f3b22915978f8c6381adc99729a4e1161 Bug-Url:https://bugzilla.redhat.com/show_bug.cgi?id=1167771 Signed-off-by: ndarshan <dnarayan@redhat.com> Reviewed-on: http://review.gluster.org/9389 Reviewed-by: Bala FA <barumuga@redhat.com> Reviewed-by: Sahina Bose <sabose@redhat.com>
-rw-r--r--config/nrpe.in2
-rw-r--r--gluster-nagios-addons.spec.in4
-rw-r--r--plugins/Makefile.am2
-rwxr-xr-xplugins/check_disk_and_inode.py443
-rwxr-xr-xplugins/check_mounts.py265
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/mounts.txt21
-rw-r--r--tests/test_disk.py187
-rw-r--r--tests/test_mounts.py380
9 files changed, 672 insertions, 634 deletions
diff --git a/config/nrpe.in b/config/nrpe.in
index 8b4f6e9..f2cf3b0 100644
--- a/config/nrpe.in
+++ b/config/nrpe.in
@@ -1,5 +1,5 @@
Cmnd_Alias NRPE_PATHS = @sbindir@/send_nsca, \
- @libdir@/nagios/plugins/gluster/check_disk_and_inode.py, \
+ @libdir@/nagios/plugins/gluster/check_mounts.py, \
@libdir@/nagios/plugins/gluster/check_vol_utilization.py, \
@libdir@/nagios/plugins/gluster/check_volume_status.py, \
@libdir@/nagios/plugins/gluster/check_gluster_proc_status.py, \
diff --git a/gluster-nagios-addons.spec.in b/gluster-nagios-addons.spec.in
index f3b9f07..dc35720 100644
--- a/gluster-nagios-addons.spec.in
+++ b/gluster-nagios-addons.spec.in
@@ -132,12 +132,12 @@ fi
cat >> %{_sysconfdir}/nagios/nrpe.cfg <<EOF
%{_start_conf_section}
-command[check_disk_and_inode]=sudo %{_libdir}/nagios/plugins/gluster/check_disk_and_inode.py -w 80 -c 90 -l -i /boot -i /var -i /root -n --inode -s
+command[check_disk_and_inode]=sudo %{_libdir}/nagios/plugins/gluster/check_mounts.py -w 80 -c 90
command[check_memory]=%{_libdir}/nagios/plugins/gluster/memory.py -w 80 -c 90 -t 2
command[check_swap_usage]=%{_libdir}/nagios/plugins/gluster/swap.py -w 80 -c 90 -t 2
command[check_cpu_multicore]=%{_libdir}/nagios/plugins/gluster/cpu.py -w 80 -c 90 -t 2
command[check_interfaces]=%{_libdir}/nagios/plugins/gluster/network.py -e lo -e ';vdsmdummy;' -t 2
-command[check_brick_usage]=sudo %{_libdir}/nagios/plugins/gluster/check_disk_and_inode.py -w 80 -c 90 -n -t -i \$ARG1\$
+command[check_brick_usage]=sudo %{_libdir}/nagios/plugins/gluster/check_mounts.py -w 80 -c 90 -i \$ARG1\$
command[check_vol_utilization]=sudo %{_libdir}/nagios/plugins/gluster/check_vol_utilization.py \$ARG1\$ -w \$ARG2\$ -c \$ARG3\$
command[check_vol_status]=sudo %{_libdir}/nagios/plugins/gluster/check_volume_status.py -v \$ARG1\$ -t \$ARG2\$
command[check_proc_status]=sudo %{_libdir}/nagios/plugins/gluster/check_gluster_proc_status.py -t \$ARG1\$
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 47ff64d..ffc121f 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -9,8 +9,8 @@ crond_DATA = \
$(NULL)
dist_glusternagiosplugins_PYTHON = \
- check_disk_and_inode.py \
check_gluster_syslog.py \
+ check_mounts.py \
check_vol_utilization.py \
check_volume_status.py \
check_proc_status.py \
diff --git a/plugins/check_disk_and_inode.py b/plugins/check_disk_and_inode.py
deleted file mode 100755
index d1fc3f5..0000000
--- a/plugins/check_disk_and_inode.py
+++ /dev/null
@@ -1,443 +0,0 @@
-#!/usr/bin/python
-# Copyright (C) 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
-#
-
-
-import os
-import re
-import sys
-import commands
-from optparse import OptionParser
-from glusternagios import utils
-
-WARNING_LEVEL = 80
-CRITICAL_LEVEL = 90
-INVALID_STATUS_CODE = -1
-
-
-def getVal(val):
- dmatch = re.compile('[0-9]+').match(val)
- if (dmatch):
- return float(eval(dmatch.group(0)))
- else:
- return 0
-
-
-def getLVdetails(filename, lvs):
- dev_name = os.path.realpath(filename)
-
- pool = ""
- disk = {}
- for a in lvs:
- dev = os.path.realpath(a['LVM2_LV_PATH'])
- if dev_name == dev:
- if a['LVM2_LV_ATTR'][0] == 'V':
- pool = a['LVM2_POOL_LV']
- disk['thinLv'] = True
- break
- else:
- disk['thinLv'] = False
- return disk
- else:
- return None
- for b in lvs:
- if b['LVM2_LV_NAME'] == pool:
- disk['actualUsedPercent'] = float(b['LVM2_DATA_PERCENT'])
- disk['actualTotalSize'] = float(b['LVM2_LV_SIZE'])
- disk['actualUsed'] = disk['actualTotalSize'] * disk[
- 'actualUsedPercent'] / 100
- return disk
- else:
- return None
-
-
-def getUsageAndFree(command, path, crit, warn, lvm):
- disk = {'path': None, 'usePcent': 0, 'avail': 0,
- 'used': 0, 'size': 0, 'fs': None,
- 'status': None, 'msg': None, 'availPcent': 0,
- 'statusCode': utils.PluginStatusCode.UNKNOWN}
-
- # Check if device exists and permissions are ok
- if not os.access(path, os.F_OK):
- disk['status'] = "Device not found!"
- disk['msg'] = 'no device'
- disk['fs'] = path
- disk['statusCode'] = utils.PluginStatusCode.CRITICAL
- return disk
-
- if not os.access(path, os.R_OK):
- disk['status'] = "Unable to access the device"
- disk['msg'] = 'no access'
- disk['fs'] = path
- disk['statusCode'] = utils.PluginStatusCode.CRITICAL
- return disk
-
- status = commands.getstatusoutput(command)
- # Sample output
- # (0, 'Filesystem 1G-blocks Used Available Use% Mounted on\n/dev/sda1
- # 290G 196G 79G 72% /')
- if status[0] != 0:
- disk['msg'] = 'error:%s' % status[0]
- if status[0] == 256:
- disk['status'] = "Brick/Device path not found!"
- else:
- disk['status'] = status[1]
- disk['statusCode'] = utils.PluginStatusCode.CRITICAL
- return disk
-
- status = status[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])
-
- if disk['usePcent'] >= crit:
- disk['statusCode'] = utils.PluginStatusCode.CRITICAL
- elif disk['usePcent'] >= warn:
- disk['statusCode'] = utils.PluginStatusCode.WARNING
- elif disk['usePcent'] < warn:
- disk['statusCode'] = utils.PluginStatusCode.OK
- disk['availPcent'] = 100 - disk['usePcent']
- return disk
-
-
-def getDisk(path, crit, warn, usage=None, lvm=False):
- if usage:
- return getUsageAndFree("df -B%s %s" % (usage, path),
- path, crit, warn, lvm)
- else:
- return getUsageAndFree("df -BG %s" % path,
- path, crit, warn, lvm)
-
-
-def getInode(path, crit, warn, lvm=False):
- return getUsageAndFree("df -i %s" % path,
- path, crit, warn, lvm)
-
-
-def getMounts(searchQuery, excludeList=[]):
- mountPaths = []
- f = open("/etc/mtab")
- for i in f.readlines():
- if i.startswith(searchQuery):
- if not excludeList:
- mountPaths.append(i.split()[0])
- else:
- device = i.split()
- if not device[0] in options.exclude and\
- not device[1] in options.exclude:
- mountPaths.append(device[0])
- f.close()
- return mountPaths
-
-
-def parse_input():
- parser = OptionParser()
- parser.add_option('-w', '--warning', action='store', type='int',
- 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=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)
- 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)
- parser.add_option('-n', '--ignore', action="store_true",
- dest='ignore',
- help='Ignore errors', default=False)
- parser.add_option('-i', '--include', action='append', type='string',
- dest='mountPath',
- help='Mount path', default=[])
- parser.add_option('-x', '--exclude', action="append", type='string',
- dest='exclude',
- help='Exclude disk/brick')
- parser.add_option('-s', action="store_true", default=False,
- dest='showErrorDisk',
- help='Show critical or warning disks in the status')
- parser.add_option('-t', '--thinPool', action="store_true",
- dest='thinPool',
- help='Lists detail of underlying thin pool',
- default=False)
- return parser.parse_args()
-
-
-def _getMsg(okList, warnList, critList):
- msg = ", ".join(critList)
- errorDiskMsg = msg
- if critList and (warnList or okList):
- msg = "CRITICAL: " + msg
- if warnList:
- if msg:
- msg += "; WARNING: "
- msg += ", ".join(warnList)
- if errorDiskMsg:
- errorDiskMsg += "; WARNING: " + ", ".join(warnList)
- else:
- errorDiskMsg = msg
- if okList:
- if msg:
- msg += "; OK: "
- msg += ", ".join(okList)
- return msg, errorDiskMsg
-
-
-def _getUnitAndType(val):
- unit = utils.convertSize(val, "GB", "TB")
- if unit >= 1:
- return unit, "TB"
- else:
- return val, "GB"
-
-
-def showDiskUsage(warn, crit, mountPaths, toListInode, usage=False,
- isLvm=False, ignoreError=False, showErrorDisk=True,
- thinPool=False):
- diskPerf = []
- warnList = []
- critList = []
- okList = []
- mounts = []
- statusCode = INVALID_STATUS_CODE
- totalUsed = 0
- totalSize = 0
- noOfMounts = len(mountPaths)
- maxPercentUsed = 0
-
- if thinPool:
- rc, out, err = utils.execCmd(["lvm"] +
- ("vgs --unquoted --noheading " +
- "--nameprefixes --separator : " +
- "--nosuffix --units g -o " +
- "lv_path,data_percent,pool_lv,lv_attr,"
- "lv_size,lv_name").split())
- if rc == 0:
- res = []
- for i in out:
- tem = i.split(":")
- dct = {}
- for j in tem:
- tp = j.split("=")
- dct[tp[0].replace(" ", "")] = tp[1]
- res.append(dct)
- else:
- thinPool = False
-
- for path in mountPaths:
- disk = getDisk(path, crit, warn, usage, isLvm)
- inode = getInode(path, crit, warn, isLvm)
- if thinPool:
- thinLv = getLVdetails(disk['fs'], res)
- if thinLv and thinLv['thinLv']:
- if disk['usePcent'] >= crit or thinLv[
- 'actualUsedPercent'] >= crit:
- disk['statusCode'] = utils.PluginStatusCode.CRITICAL
- elif disk['usePcent'] >= warn or thinLv[
- 'actualUsedPercent'] >= warn:
- disk['statusCode'] = utils.PluginStatusCode.WARNING
- elif disk['usePcent'] < warn or thinLv[
- 'actualUsedPercent'] < warn:
- disk['statusCode'] = utils.PluginStatusCode.OK
- else:
- thinPool = False
-
- if disk['path'] in mounts:
- continue
- if not disk['used'] or not inode['used']:
- if not ignoreError:
- sys.exit(utils.PluginStatusCode.UNKNOWN)
-
- if disk['path']:
- mounts.append(disk['path'])
- data = ""
- if usage and disk['path']:
- data = "%s=%.1f%s;%.1f;%.1f;0;%.1f" % (
- disk['path'],
- disk['used'],
- usage,
- 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['size'])
- elif disk['path']:
- if thinPool and thinLv['thinLv']:
- data = "%s=%.2f%%;%s;%s;0;%s" % (
- disk['path'],
- disk['usePcent'],
- warn,
- crit,
- disk['size'])
- data += " Thin-pool=%.2f%%;%s;%s;0;%.1f" % (
- thinLv['actualUsedPercent'],
- warn,
- crit,
- thinLv['actualTotalSize'])
- else:
- data = "%s=%.2f%%;%s;%s;0;%s" % (
- disk['path'],
- disk['usePcent'],
- warn,
- crit,
- disk['size'])
- if toListInode:
- data += " %s=%.2f%%;%s;%s;0;%s" % (
- inode['path'],
- inode['usePcent'],
- warn,
- crit,
- inode['size'])
- diskPerf.append(data)
-
- totalUsed += disk['used']
- totalSize += disk['size']
- if disk['usePcent'] > maxPercentUsed:
- maxPercentUsed = disk['usePcent']
-
- # adding into status message if there is any
- # specfic status found (short msg for list of disks)
- msg = ""
- if disk['status'] and disk['msg']:
- if noOfMounts == 1:
- msg = "%s=%s(%s)" % (disk['fs'], disk['path'],
- disk['status'])
- else:
- msg = "%s(%s)" % (disk['fs'], disk['msg'])
- else:
- if noOfMounts == 1:
- msg = "%s=%s" % (disk['fs'], disk['path'])
- else:
- msg = "%s" % (disk['path'])
-
- if disk['statusCode'] == utils.PluginStatusCode.CRITICAL or \
- inode['statusCode'] == utils.PluginStatusCode.CRITICAL:
- statusCode = utils.PluginStatusCode.CRITICAL
- critList.append(msg)
- elif (disk['statusCode'] == utils.PluginStatusCode.WARNING or
- inode['statusCode'] == utils.PluginStatusCode.WARNING):
- # if any previous disk statusCode is not critical
- # we should not change the statusCode into warning
- if statusCode != utils.PluginStatusCode.CRITICAL:
- statusCode = utils.PluginStatusCode.WARNING
- # just adding warning values into the list
- warnList.append(msg)
- elif disk['statusCode'] == utils.PluginStatusCode.OK:
- if statusCode == INVALID_STATUS_CODE or \
- statusCode == utils.PluginStatusCode.OK:
- statusCode = utils.PluginStatusCode.OK
- okList.append(msg)
- else:
- # added \ to fix E125 pep8 error
- if statusCode != utils.PluginStatusCode.CRITICAL or \
- statusCode != utils.PluginStatusCode.WARNING:
- statusCode = utils.PluginStatusCode.UNKNOWN
- okList.append(msg)
-
- msg, errorDiskMsg = _getMsg(okList, warnList, critList)
-
- if totalUsed == 0 and totalSize == 0:
- # avoid zero div error
- return statusCode, "mount: %s" % msg, diskPerf
- if totalUsed == 0:
- # avoid zero div error
- totUsagePercent = 0
- elif len(mounts) > 1:
- totUsagePercent = totalUsed / totalSize * 100
- else:
- totUsagePercent = maxPercentUsed
- usageMsg = ""
- if not usage:
- totUsedSz, totUsedSzUnit = _getUnitAndType(totalUsed)
- totSpaceSz, totSpaceSzUnit = _getUnitAndType(totalSize)
- usageMsg = "%.1f%% used (%s%s out of %s%s)" % (totUsagePercent,
- totUsedSz,
- totUsedSzUnit,
- totSpaceSz,
- totSpaceSzUnit)
- if thinPool and thinLv['thinLv']:
- usageMsg += " [Thin-pool: %.1f%% (%.1fG out of %.1fG)]" % (
- thinLv['actualUsedPercent'],
- thinLv['actualUsed'],
- thinLv['actualTotalSize'])
- else:
- usageMsg = "%.1f%% used (%s%s out of %s%s)" % (totUsagePercent,
- totalUsed,
- usage,
- totalSize,
- usage)
- if showErrorDisk:
- msg = "%s\n:mount(s): (%s)" % (errorDiskMsg, msg)
- else:
- msg = "%s\n:mount(s): (%s)" % (usageMsg, msg)
-
- return statusCode, 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)
-
- statusCode, msg, diskPerf = showDiskUsage(options.warn,
- options.crit,
- options.mountPath,
- options.inode,
- options.usage,
- options.lvm,
- options.ignore,
- options.showErrorDisk,
- options.thinPool)
-
- if utils.PluginStatusCode.CRITICAL == statusCode:
- sys.stdout.write("%s : %s | %s\n" % (
- utils.PluginStatus.CRITICAL,
- msg,
- " ".join(diskPerf)))
- sys.exit(utils.PluginStatusCode.CRITICAL)
- elif utils.PluginStatusCode.WARNING == statusCode:
- sys.stdout.write("%s : %s | %s\n" % (
- utils.PluginStatus.WARNING,
- msg,
- " ".join(diskPerf)))
- sys.exit(utils.PluginStatusCode.WARNING)
- else:
- if options.showErrorDisk:
- sys.stdout.write("%s %s | %s\n" % (
- utils.PluginStatus.OK, msg, " ".join(diskPerf)))
- else:
- sys.stdout.write("%s : %s | %s\n" % (
- utils.PluginStatus.OK, msg, " ".join(diskPerf)))
diff --git a/plugins/check_mounts.py b/plugins/check_mounts.py
new file mode 100755
index 0000000..342c20a
--- /dev/null
+++ b/plugins/check_mounts.py
@@ -0,0 +1,265 @@
+#!/usr/bin/python
+# Copyright (C) 2015 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
+#
+
+
+import os
+import sys
+import argparse
+import logging
+
+from glusternagios import utils
+from glusternagios.utils import PluginStatusCode, PluginStatus
+
+ONE_GB_BYTES = 1073741824.0
+
+
+def _getMountPoint(path):
+ mount = os.path.realpath(path)
+ while not os.path.ismount(mount):
+ mount = os.path.dirname(mount)
+ return mount
+
+
+def _parseProcMounts(filter=True):
+ mountPoints = {}
+ with open('/proc/mounts', 'r') as f:
+ for line in f:
+ if line.startswith("/") or not filter:
+ mount = {}
+ tokens = line.split()
+ mount['device'] = tokens[0]
+ mount['fsType'] = tokens[2]
+ mount['mountOptions'] = tokens[3]
+ mountPoints[tokens[1]] = mount
+ return mountPoints
+
+
+def _getStats(mountPoint):
+ data = os.statvfs(mountPoint)
+ total = (data.f_blocks * data.f_bsize) / ONE_GB_BYTES
+ free = (data.f_bfree * data.f_bsize) / ONE_GB_BYTES
+ used_percent = 100 - (100.0 * free / total)
+ total_inode = data.f_files
+ free_inode = data.f_ffree
+ used_percent_inode = 100 - (100.0 * free_inode / total_inode)
+ used = total - free
+ used_inode = total_inode - free_inode
+ return {'total': total,
+ 'free': free,
+ 'used_percent': used_percent,
+ 'total_inode': total_inode,
+ 'free_inode': free_inode,
+ 'used_inode': used_inode,
+ 'used': used,
+ 'used_percent_inode': used_percent_inode}
+
+
+def _getOutputText(detail):
+ template = "{mount_point} - {{space - free: {free:0.3f} GiB, " \
+ "used: {used_percent:0.3f}%}}, {{inode - free: {free_inode}" \
+ " , used: {used_percent_inode:0.3f}%}}"
+
+ if detail['thinpool_size']:
+ template += ", {{thinpool-data - free: {thinpool_free:.3f} GiB," \
+ " used: {thinpool_used_percent:.3f}%}}, " \
+ "{{thinpool-metadata - free: {metadata_free:.3f} GiB," \
+ " used: {metadata_used_percent:.3f}%}}"
+ return template.format(**detail)
+
+
+def _getPerfdata(detail, warn, crit):
+ template = "{mount_point}={used_percent:.3f}%;{warn};{crit};0;{total:.3f}"\
+ " {mount_point}.inode={used_percent_inode:.3f}%;{warn};{crit}" \
+ ";0;{total_inode}"
+ if detail['thinpool_size']:
+ template += " {mount_point}.thinpool={thinpool_used_percent:.3f}%;" \
+ "{warn};{crit};0;{thinpool_size:.3f} {mount_point}." \
+ "thinpool-metadata={metadata_used_percent:.3f}%;{warn};{crit};0;" \
+ "{metadata_size:.3f}"
+ return template.format(warn=warn, crit=crit, **detail)
+
+
+def _getStatusInfo(detail, warn, crit):
+ rc = PluginStatus.OK
+ msg = []
+
+ parameter = {'metadata_used_percent': ['thinpool-metadata',
+ 'metadata_used',
+ 'metadata_size', ' GiB'],
+ 'thinpool_used_percent': ['thinpool-data', 'thinpool_used',
+ 'thinpool_size', ' GiB'],
+ 'used_percent': ['space', 'used',
+ 'total', ' GiB'],
+ 'used_percent_inode': ['inode', 'used_inode',
+ 'total_inode', '']}
+
+ for k, v in parameter.iteritems():
+ if not detail[k]:
+ continue
+ if k == 'used_percent_inode':
+ m = "%s used %d / %d%s" % (v[0], detail[v[1]],
+ detail[v[2]], v[3])
+ else:
+ m = "%s used %0.3f / %0.3f%s" % (v[0], detail[v[1]],
+ detail[v[2]], v[3])
+ if detail[k] >= crit:
+ rc = PluginStatus.CRITICAL
+ msg.append(m)
+ elif detail[k] >= warn:
+ if rc != PluginStatus.CRITICAL:
+ rc = PluginStatus.WARNING
+ msg.append(m)
+
+ if rc == PluginStatus.OK:
+ out = ''
+ else:
+ out = "mount point {mount_point} {{{msg}}}".format(msg=", ".join(msg),
+ **detail)
+ return rc, out
+
+
+def parse_input():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-w", "--warning", action="store",
+ required=True, type=int,
+ help="Warning threshold in percentage")
+ parser.add_argument("-c", "--critical", action="store",
+ required=True, type=int,
+ help="Critical threshold in percentage")
+ group = parser.add_mutually_exclusive_group()
+ group.add_argument("-e", "--exclude", action="append", default=[],
+ help="exclude given interface")
+ group.add_argument("-i", "--include", action="append", default=[],
+ help="add given interface for monitoring")
+ args = parser.parse_args()
+ return args
+
+
+def getLvs():
+ lvmCommand = ["lvm", "vgs", "--unquoted", "--noheading",
+ "--nameprefixes", "--separator", "$",
+ "--nosuffix", "--units", "m", "-o",
+ "lv_uuid,lv_name,data_percent,pool_lv,lv_attr,"
+ "lv_size,lv_path,lv_metadata_size,"
+ "metadata_percent,vg_name"]
+ rc, out, err = utils.execCmd(lvmCommand)
+ if rc != 0:
+ logging.error(
+ "lvm command failed.\nCommand=%s\nrc=%s\nout=%s\nerr=%s"
+ % (lvmCommand, rc, out, err)
+ )
+ return None
+ l = map(lambda x: dict(x),
+ map(lambda x: [e.split('=') for e in x],
+ map(lambda x: x.strip().split('$'), out)))
+
+ d = {}
+ for i in l:
+ if i['LVM2_LV_ATTR'][0] == 't':
+ k = "%s/%s" % (i['LVM2_VG_NAME'], i['LVM2_LV_NAME'])
+ else:
+ k = os.path.realpath(i['LVM2_LV_PATH'])
+ d.update({k: i})
+ return d
+
+
+def getMountStats(exclude, include):
+ def _getMounts(exclude=[], include=[]):
+ excludeList = map(_getMountPoint, exclude)
+ includeList = map(_getMountPoint, include)
+ mountPoints = _parseProcMounts()
+ if excludeList:
+ outList = set(mountPoints) - set(excludeList)
+ elif includeList:
+ outList = set(mountPoints).intersection(set(includeList))
+ else:
+ return mountPoints
+ # list comprehension to build dictionary does not work in python 2.6.6
+ mounts = {}
+ for k in outList:
+ mounts[k] = mountPoints[k]
+ return mounts
+
+ def _getThinPoolStat(device):
+ out = {'thinpool_size': None,
+ 'thinpool_used_percent': None,
+ 'metadata_size': None,
+ 'metadata_used_percent': None,
+ 'thinpool_free': None,
+ 'metadata_free': None,
+ 'thinpool_used': None,
+ 'metadata_used': None}
+
+ if lvs and device in lvs and \
+ lvs[device]['LVM2_LV_ATTR'][0] == 'V':
+ thinpool = "%s/%s" % (lvs[device]['LVM2_VG_NAME'],
+ lvs[device]['LVM2_POOL_LV'])
+ out['thinpool_size'] = float(
+ lvs[thinpool]['LVM2_LV_SIZE']) / 1024
+ out['thinpool_used_percent'] = float(
+ lvs[thinpool]['LVM2_DATA_PERCENT'])
+ out['metadata_size'] = float(
+ lvs[thinpool]['LVM2_LV_METADATA_SIZE']) / 1024
+ out['metadata_used_percent'] = float(
+ lvs[thinpool]['LVM2_METADATA_PERCENT'])
+ out['thinpool_free'] = out['thinpool_size'] * (
+ 1 - out['thinpool_used_percent']/100.0)
+ out['thinpool_used'] = out['thinpool_size'] - out['thinpool_free']
+ out['metadata_free'] = out['metadata_size'] * (
+ 1 - out['metadata_used_percent']/100.0)
+ out['metadata_used'] = out['metadata_size'] - out['metadata_free']
+ return out
+
+ mountPoints = _getMounts(exclude, include)
+ lvs = getLvs()
+ mountDetail = {}
+ for mount, info in mountPoints.iteritems():
+ mountDetail[mount] = _getStats(mount)
+ mountDetail[mount].update(
+ _getThinPoolStat(os.path.realpath(info['device']))
+ )
+ mountDetail[mount].update({'mount_point': mount})
+ return mountDetail
+
+
+def getPrintableStatus(mountDetail, warning, critical):
+ finalRc = utils.PluginStatus.OK
+ finalMsg = []
+ finalOut = []
+ finalPerfdata = []
+ for mount, detail in mountDetail.iteritems():
+ finalOut.append(_getOutputText(detail))
+ finalPerfdata.append(_getPerfdata(detail, warning, critical))
+ rc, msg = _getStatusInfo(detail, warning, critical)
+ if msg:
+ finalMsg.append(msg)
+ if getattr(PluginStatusCode, rc) > getattr(PluginStatusCode, finalRc):
+ finalRc = rc
+ return finalRc, finalMsg, finalOut, finalPerfdata
+
+
+if __name__ == '__main__':
+ args = parse_input()
+ mountDetail = getMountStats(args.exclude, args.include)
+ rc, msg, msgDet, perfdata = getPrintableStatus(mountDetail,
+ args.warning,
+ args.critical)
+
+ print "%s: %s" % (rc, ", ".join(msg))
+ print "%s | %s" % ("\n".join(msgDet), "\n".join(perfdata))
+ sys.exit(getattr(PluginStatusCode, rc))
diff --git a/tests/Makefile.am b/tests/Makefile.am
index cdf62d4..1994d43 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -24,6 +24,7 @@ test_modules = \
check_proc_test_data.py \
test_cpu.py \
test_cpu_dataFile.py \
+ test_mounts.py \
test_gluster_proc.py \
test_memory.py \
test_memory_dataFile.py \
@@ -37,6 +38,7 @@ test_modules = \
dist_glusternagiosaddonstests_DATA = \
getLatestStat_exception.xml \
getLatestStat_success.xml \
+ mounts.txt \
$(NULL)
dist_glusternagiosaddonstests_PYTHON = \
diff --git a/tests/mounts.txt b/tests/mounts.txt
new file mode 100644
index 0000000..41c43c8
--- /dev/null
+++ b/tests/mounts.txt
@@ -0,0 +1,21 @@
+rootfs / rootfs rw 0 0
+proc /proc proc rw,relatime 0 0
+sysfs /sys sysfs rw,relatime 0 0
+devtmpfs /dev devtmpfs rw,relatime,size=1016068k,nr_inodes=254017,mode=755 0 0
+devpts /dev/pts devpts rw,relatime,gid=5,mode=620,ptmxmode=000 0 0
+tmpfs /dev/shm tmpfs rw,relatime 0 0
+/dev/mapper/vg_dhcp42149-lv_root / ext4 rw,relatime,barrier=1,data=ordered 0 0
+/proc/bus/usb /proc/bus/usb usbfs rw,relatime 0 0
+/dev/vda1 /boot ext4 rw,relatime,barrier=1,data=ordered 0 0
+/dev/mapper/vg_dhcp42149-lv_home /home ext4 rw,relatime,barrier=1,data=ordered 0 0
+none /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0
+cgroup /cgroup/cpuset cgroup rw,relatime,cpuset 0 0
+cgroup /cgroup/cpu cgroup rw,relatime,cpu 0 0
+cgroup /cgroup/cpuacct cgroup rw,relatime,cpuacct 0 0
+cgroup /cgroup/memory cgroup rw,relatime,memory 0 0
+cgroup /cgroup/devices cgroup rw,relatime,devices 0 0
+cgroup /cgroup/freezer cgroup rw,relatime,freezer 0 0
+cgroup /cgroup/net_cls cgroup rw,relatime,net_cls 0 0
+cgroup /cgroup/blkio cgroup rw,relatime,blkio 0 0
+/dev/mapper/mygroup-thinv1 /bricks/brick1 xfs rw,relatime,attr2,delaylog,logbsize=64k,sunit=128,swidth=128,noquota 0 0
+/dev/mapper/mygroup-thinv2 /bricks/brick2 xfs rw,relatime,attr2,delaylog,logbsize=64k,sunit=128,swidth=128,noquota 0 0
diff --git a/tests/test_disk.py b/tests/test_disk.py
deleted file mode 100644
index b41d3bf..0000000
--- a/tests/test_disk.py
+++ /dev/null
@@ -1,187 +0,0 @@
-#
-# 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 os
-import commands
-from testrunner import PluginsTestCase as TestCaseBase
-from plugins import check_disk_and_inode as checkDisk
-
-
-class TestDisk(TestCaseBase):
- def mock_osaccess(self, path=None, osflag=None):
- return True
-
- 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
- os.access = self.mock_osaccess
- disk = checkDisk.getUsageAndFree(1, "", 80, 90, "")
- 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, "", 80, 90, "")
- 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, "", 80, 90, "")
- 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, "", 80, 90, "")
- 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
- os.access = self.mock_osaccess
- mounts = checkDisk.getMounts("/", [])
-
- self.assertEqual(checkDisk.showDiskUsage(80,
- 90,
- [mounts[1]],
- True,
- usage='BGB'),
- (0, '64.0% used (174.0BGB out of 290.0BGB)\n'
- ':mount(s): (/dev/sda1=/)',
- ['/=174.0BGB;232.0;261.0;0;290.0 '
- '/=174.0;139.2;156.6;0;290.0']))
-
- self.assertEqual(checkDisk.showDiskUsage(80,
- 90,
- [mounts[1]],
- True),
- (0, '64.0% used (174.0GB out of 290.0GB)\n'
- ':mount(s): (/dev/sda1=/)',
- ['/=64.00%;80;90;0;290.0GB '
- '/=64.00%;80;90;0;290.0']))
-
- self.assertEqual(checkDisk.showDiskUsage(80,
- 90,
- [mounts[1]], True),
- (0, '64.0% used (174.0GB out of 290.0GB)\n'
- ':mount(s): (/dev/sda1=/)',
- ['/=64.00%;80;90;0;290.0GB '
- '/=64.00%;80;90;0;290.0']))
-
- self.assertEqual(checkDisk.showDiskUsage(80,
- 90,
- ["/mnt/vol2"], True),
- (0, '47.0% used (22.68359375TB out of '
- '51.607421875TB)\n'
- ':mount(s): (10.70.43.190:vol2=/mnt/vol2)',
- ['/mnt/vol2=47.00%;80;90;0;52846.0GB '
- '/mnt/vol2=47.00%;80;90;0;52846.0']))
-
- self.assertEqual(checkDisk.showDiskUsage(10,
- 20,
- ["/mnt/vol2"], True),
- (2, '47.0% used (22.68359375TB out of '
- '51.607421875TB)\n'
- ':mount(s): (10.70.43.190:vol2=/mnt/vol2)',
- ['/mnt/vol2=47.00%;10;20;0;52846.0GB '
- '/mnt/vol2=47.00%;10;20;0;52846.0']))
-
- # negative test
- self.assertEqual(checkDisk.showDiskUsage(1,
- 100,
- ["/mnt/vol2"], True),
- (1, '47.0% used (22.68359375TB out of '
- '51.607421875TB)\n'
- ':mount(s): (10.70.43.190:vol2=/mnt/vol2)',
- ['/mnt/vol2=47.00%;1;100;0;52846.0GB '
- '/mnt/vol2=47.00%;1;100;0;52846.0']))
diff --git a/tests/test_mounts.py b/tests/test_mounts.py
new file mode 100644
index 0000000..5503e50
--- /dev/null
+++ b/tests/test_mounts.py
@@ -0,0 +1,380 @@
+#
+# 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 mock
+import os
+
+from testrunner import PluginsTestCase as TestCaseBase
+from plugins import check_mounts
+
+
+class diskTests(TestCaseBase):
+ def mock_getMountPoint(self, mount):
+ return mount
+
+ def mock_open(self, filename, mode):
+ return open('mounts.txt', 'r')
+
+ def test_parseProcMounts(self):
+ check_mounts.open = self.mock_open
+ expected = {
+ '/bricks/brick2': {
+ 'device': '/dev/mapper/mygroup-thinv2',
+ 'mountOptions': 'rw,relatime,attr2,delaylog,'
+ 'logbsize=64k,sunit=128,swidth=128,noquota',
+ 'fsType': 'xfs'},
+ '/bricks/brick1': {
+ 'device': '/dev/mapper/mygroup-thinv1',
+ 'mountOptions': 'rw,relatime,attr2,delaylog,'
+ 'logbsize=64k,sunit=128,swidth=128,noquota',
+ 'fsType': 'xfs'},
+ '/home': {
+ 'device': '/dev/mapper/vg_dhcp42149-lv_home',
+ 'mountOptions': 'rw,relatime,barrier=1,'
+ 'data=ordered',
+ 'fsType': 'ext4'},
+ '/boot': {
+ 'device': '/dev/vda1',
+ 'mountOptions': 'rw,relatime,barrier=1,'
+ 'data=ordered',
+ 'fsType': 'ext4'},
+ '/': {
+ 'device': '/dev/mapper/vg_dhcp42149-lv_root',
+ 'mountOptions': 'rw,relatime,barrier=1,data=ordered',
+ 'fsType': 'ext4'},
+ '/proc/bus/usb': {
+ 'device': '/proc/bus/usb',
+ 'mountOptions': 'rw,relatime',
+ 'fsType': 'usbfs'}
+ }
+ actual = check_mounts._parseProcMounts()
+ self.assertEquals(expected, actual)
+
+ def mock_os_statvfs(self):
+ f_bsize = 4096
+ f_frsize = 4096
+ f_blocks = 12868767
+ f_bfree = 11503139
+ f_bavail = 10847779
+ f_files = 3276800
+ f_ffree = 3220784
+ f_favail = 3220784
+ f_flag = 4096
+ f_namemax = 255
+ return os.statvfs_result((f_bsize, f_frsize,
+ f_blocks, f_bfree,
+ f_bavail, f_files,
+ f_ffree, f_favail,
+ f_flag, f_namemax))
+
+ @mock.patch('plugins.check_mounts.os.statvfs')
+ def test_getStats(self, mock_os_statvfs):
+ mock_os_statvfs.return_value = self.mock_os_statvfs()
+ expected = {'used_percent': 10.611956840931228,
+ 'used': 5.2094573974609375,
+ 'free_inode': 3220784,
+ 'used_inode': 56016,
+ 'total_inode': 3276800,
+ 'used_percent_inode': 1.70947265625,
+ 'total': 49.090450286865234,
+ 'free': 43.8809928894043}
+ actual = check_mounts._getStats("mount_point")
+ self.assertEquals(expected, actual)
+
+ def mock_utils_execCommand(self):
+ rc = 0
+ out = [' LVM2_LV_UUID=jTHoCy-qFBS-K1FS-WSUp-SG8J-4R7W-2hI01n$LVM2_LV'
+ '_NAME=mythinpool$LVM2_DATA_PERCENT=1.09$LVM2_POOL_LV=$LVM2_LV'
+ '_ATTR=twi-a-tz--$LVM2_LV_SIZE=1024.00$LVM2_LV_PATH=$LVM2_LV_'
+ 'METADATA_SIZE=4.00$LVM2_METADATA_PERCENT=1.07$LVM2_VG_NAME='
+ 'mygroup']
+ err = []
+ return rc, out, err
+
+ @mock.patch('plugins.check_mounts.utils.execCmd')
+ def test_getLvs(self, mock_utils_execCmd):
+ mock_utils_execCmd.return_value = self.mock_utils_execCommand()
+ expected = {
+ 'mygroup/mythinpool': {
+ 'LVM2_LV_PATH': '',
+ 'LVM2_DATA_PERCENT': '1.09',
+ 'LVM2_LV_ATTR': 'twi-a-tz--',
+ 'LVM2_POOL_LV': '',
+ 'LVM2_LV_NAME': 'mythinpool',
+ 'LVM2_METADATA_PERCENT': '1.07',
+ 'LVM2_VG_NAME': 'mygroup',
+ 'LVM2_LV_SIZE': '1024.00',
+ 'LVM2_LV_UUID': 'jTHoCy-qFBS-K1FS-WSUp-SG8J-4R7W-2hI01n',
+ 'LVM2_LV_METADATA_SIZE': '4.00'}
+ }
+ actual = check_mounts.getLvs()
+ self.assertEquals(expected, actual)
+
+ def mock_getStats(self):
+ return {'used_percent': 3.194726947731752,
+ 'used': 0.031635284423828125,
+ 'free_inode': 1048562,
+ 'used_inode': 14,
+ 'total_inode': 1048576,
+ 'used_percent_inode': 1,
+ 'total': 0.990234375,
+ 'free': 0.9585990905761719}
+
+ def mock_parseProcMounts(self):
+ return {
+ '/brick/brk1': {
+ 'device': '/dev/mapper/mygroup-thinv1',
+ 'mountOptions': 'rw,seclabel,relatime,'
+ 'attr2,inode64,noquota',
+ 'fsType': 'xfs'},
+ '/': {
+ 'device': '/dev/mapper/fedora_dhcp43--63-root',
+ 'mountOptions': 'rw,seclabel,relatime,data=ordered',
+ 'fsType': 'ext4'}
+ }
+
+ def mock_getLvs(self):
+ return {
+ '/dev/mygroup/lvol0': {
+ 'LVM2_LV_PATH': '/dev/mygroup/lvol0',
+ 'LVM2_DATA_PERCENT': '',
+ 'LVM2_LV_ATTR': '-wi-------',
+ 'LVM2_POOL_LV': '',
+ 'LVM2_LV_NAME': 'lvol0',
+ 'LVM2_METADATA_PERCENT': '',
+ 'LVM2_VG_NAME': 'mygroup',
+ 'LVM2_LV_SIZE': '4.00',
+ 'LVM2_LV_UUID': 'NDYC4q-Z57a-DKY3-FQt1-FT63-BuHd-ZScwJZ',
+ 'LVM2_LV_METADATA_SIZE': ''},
+ 'mygroup/mythinpool': {
+ 'LVM2_LV_PATH': '/dev/mygroup/mythinpool',
+ 'LVM2_DATA_PERCENT': '1.21',
+ 'LVM2_LV_ATTR': 'twi-a-tz--',
+ 'LVM2_POOL_LV': '',
+ 'LVM2_LV_NAME': 'mythinpool',
+ 'LVM2_METADATA_PERCENT': '1.37',
+ 'LVM2_VG_NAME': 'mygroup',
+ 'LVM2_LV_SIZE': '1536.00',
+ 'LVM2_LV_UUID': 'viQeR0-JHrs-5g27-vVTp-WoOw-bWFy-goaJfO',
+ 'LVM2_LV_METADATA_SIZE': '4.00'},
+ '/dev/dm-7': {
+ 'LVM2_LV_PATH': '/dev/mygroup/thinv1',
+ 'LVM2_DATA_PERCENT': '1.04',
+ 'LVM2_LV_ATTR': 'Vwi-aotz--',
+ 'LVM2_POOL_LV': 'mythinpool',
+ 'LVM2_LV_NAME': 'thinv1',
+ 'LVM2_METADATA_PERCENT': '',
+ 'LVM2_VG_NAME': 'mygroup',
+ 'LVM2_LV_SIZE': '1024.00',
+ 'LVM2_LV_UUID': 'am1XA3-AgYh-IKL4-LfeB-7XR7-dm8U-vbX2Fr',
+ 'LVM2_LV_METADATA_SIZE': ''}
+ }
+
+ def mock_getThinpoolStat(self):
+ return {'metadata_used': 5.351562500000018e-05,
+ 'thinpool_used_percent': 1.21,
+ 'thinpool_used': 0.01814999999999989,
+ 'metadata_used_percent': 1.37,
+ 'metadata_size': 0.00390625,
+ 'metadata_free': 0.003852734375,
+ 'thinpool_size': 1.5,
+ 'thinpool_free': 1.4818500000000001}
+
+ @mock.patch('plugins.check_mounts.getLvs')
+ @mock.patch('plugins.check_mounts._getStats')
+ @mock.patch('plugins.check_mounts.os.path.realpath')
+ @mock.patch('plugins.check_mounts._parseProcMounts')
+ @mock.patch('plugins.check_mounts._getMountPoint')
+ def test_getMountStats(self, mock_getMountPoint, mock_parseProcMounts,
+ mock_os_path_realpath,
+ mock_getStats, mock_getLvs):
+ mock_getMountPoint.return_value = '/brick/brk1'
+ mock_os_path_realpath.return_value = '/dev/dm-7'
+ mock_parseProcMounts.return_value = self.mock_parseProcMounts()
+ mock_getLvs.return_value = self.mock_getLvs()
+ mock_getStats.return_value = self.mock_getStats()
+ expected = {'/brick/brk1': {
+ 'used_percent': 3.194726947731752,
+ 'used': 0.031635284423828125,
+ 'free_inode': 1048562,
+ 'used_inode': 14,
+ 'free': 0.9585990905761719,
+ 'total_inode': 1048576,
+ 'mount_point': '/brick/brk1',
+ 'metadata_used_percent': 1.37,
+ 'total': 0.990234375,
+ 'thinpool_free': 1.4818500000000001,
+ 'metadata_used': 5.351562500000018e-05,
+ 'thinpool_used_percent': 1.21,
+ 'used_percent_inode': 1,
+ 'thinpool_used': 0.01814999999999989,
+ 'metadata_size': 0.00390625,
+ 'metadata_free': 0.003852734375,
+ 'thinpool_size': 1.5}
+ }
+ include = ['/brick/brk1']
+ exclude = []
+ actual = check_mounts.getMountStats(exclude, include)
+ self.assertEquals(expected, actual)
+
+ def _getDetail(self):
+ return {'used_percent': 3.194726947731752,
+ 'used': 0.031635284423828125,
+ 'free_inode': 1048562,
+ 'used_inode': 14,
+ 'free': 0.9585990905761719,
+ 'total_inode': 1048576,
+ 'mount_point': '/run/gluster/snaps/680bdbbeed47'
+ '44a9bcba941580a5feed/brick1',
+ 'metadata_used_percent': 1.37,
+ 'total': 0.990234375,
+ 'thinpool_free': 1.4818500000000001,
+ 'metadata_used': 5.351562500000018e-05,
+ 'thinpool_used_percent': 1.21,
+ 'used_percent_inode': 1,
+ 'thinpool_used': 0.01814999999999989,
+ 'metadata_size': 0.00390625,
+ 'metadata_free': 0.003852734375,
+ 'thinpool_size': 1.5}
+
+ def test_getOutputTest(self):
+ detail = self._getDetail()
+ actual = check_mounts._getOutputText(detail)
+ expected = "/run/gluster/snaps/680bdbbeed4744a9bcba941580a5feed/" \
+ "brick1 - {space - free: 0.959 GiB, used: 3.195%}, " \
+ "{inode - free: 1048562 , used: 1.000%}, {thinpool-data " \
+ "- free: 1.482 GiB, used: 1.210%}, {thinpool-metadata " \
+ "- free: 0.004 GiB, used: 1.370%}"
+ self.assertEquals(actual, expected)
+
+ def test_getPerfdata(self):
+ detail = self._getDetail()
+ warn = 80
+ crit = 90
+ actual = check_mounts._getPerfdata(detail, warn, crit)
+ expected = "/run/gluster/snaps/680bdbbeed4744a9bcba941580a5feed/" \
+ "brick1=3.195%;80;90;0;0.990 /run/gluster/snaps/" \
+ "680bdbbeed4744a9bcba941580a5feed/brick1.inode=1.000%;80;" \
+ "90;0;1048576 /run/gluster/snaps/680bdbbeed4744a9bcba941" \
+ "580a5feed/brick1.thinpool=1.210%;80;90;0;1.500 /run/" \
+ "gluster/snaps/680bdbbeed4744a9bcba941580a5feed/brick1." \
+ "metadata=1.370%;80;90;0;0.004"
+ self.assertEquals(actual, expected)
+
+ def test_getStatusInfo(self):
+ detail = self._getDetail()
+ warn = 2
+ crit = 4
+ actual = check_mounts._getStatusInfo(detail, warn, crit)
+ expected = ('WARNING',
+ "mount point /run/gluster/snaps/"
+ "680bdbbeed4744a9bcba941580a5feed/brick1 "
+ "{space used 0.032 / 0.990 GiB}")
+ self.assertEquals(actual, expected)
+
+ def test_getPrintableStatus(self):
+ mountDetail = {
+ '/home': {
+ 'used_percent': 0.24067115853902976,
+ 'used': 0.0429229736328125,
+ 'free_inode': 1196017,
+ 'used_inode': 15,
+ 'free': 17.79177474975586,
+ 'total_inode': 1196032,
+ 'mount_point': '/home',
+ 'metadata_used_percent': None,
+ 'total': 17.834697723388672,
+ 'thinpool_free': None,
+ 'metadata_used': None,
+ 'thinpool_used_percent': None,
+ 'used_percent_inode': 1,
+ 'thinpool_used': None,
+ 'metadata_size': None,
+ 'metadata_free': None,
+ 'thinpool_size': None},
+ '/boot': {
+ 'used_percent': 13.709776644000229,
+ 'used': 0.06375885009765625,
+ 'free_inode': 127662,
+ 'used_inode': 354,
+ 'free': 0.4013023376464844,
+ 'total_inode': 128016,
+ 'mount_point': '/boot',
+ 'metadata_used_percent': None,
+ 'total': 0.4650611877441406,
+ 'thinpool_free': None,
+ 'metadata_used': None,
+ 'thinpool_used_percent': None,
+ 'used_percent_inode': 1,
+ 'thinpool_used': None,
+ 'metadata_size': None,
+ 'metadata_free': None,
+ 'thinpool_size': None},
+ '/brick/brk1': {
+ 'used_percent': 3.194726947731752,
+ 'used': 0.031635284423828125,
+ 'free_inode': 1048562,
+ 'used_inode': 14,
+ 'free': 0.9585990905761719,
+ 'total_inode': 1048576,
+ 'mount_point': '/brick/brk1',
+ 'metadata_used_percent': 1.37,
+ 'total': 0.990234375,
+ 'thinpool_free': 1.4818500000000001,
+ 'metadata_used': 5.351562500000018e-05,
+ 'thinpool_used_percent': 1.21,
+ 'used_percent_inode': 1,
+ 'thinpool_used': 0.01814999999999989,
+ 'metadata_size': 0.00390625,
+ 'metadata_free': 0.003852734375,
+ 'thinpool_size': 1.5
+ }
+ }
+ expRc = 'CRITICAL'
+ expMsg = ['mount point /boot {space used 0.064 / 0.465 GiB}',
+ 'mount point /brick/brk1 '
+ '{space used 0.032 / 0.990 GiB}']
+ expOut = ['/boot - {space - free: 0.401 GiB, used: 13.710%},'
+ ' {inode - free: 127662 , used: 1.000%}',
+ '/brick/brk1 - {space - free: 0.959 GiB, used: 3.195%},'
+ ' {inode - free: 1048562 , used: 1.000%}, '
+ '{thinpool-data - free: 1.482 GiB, used: 1.210%},'
+ ' {thinpool-metadata - free: 0.004 GiB, used: 1.370%}',
+ '/home - {space - free: 17.792 GiB, used: 0.241%},'
+ ' {inode - free: 1196017 , used: 1.000%}']
+ expPerfData = ['/boot=13.710%;2;4;0;0.465 /boot.inode='
+ '1.000%;2;4;0;128016',
+ '/brick/brk1=3.195%;2;4;0;0.990 '
+ '/brick/brk1.inode=1.000%;2;4;0;1048576 '
+ '/brick/brk1.thinpool=1.210%;2;4;0;1.500 '
+ '/brick/brk1.metadata=1.370%;2;4;0;0.004',
+ '/home=0.241%;2;4;0;17.835 '
+ '/home.inode=1.000%;2;4;0;1196032']
+ warning = 2
+ critical = 4
+ actRc, actMsg, actOut, actPerfData = check_mounts.getPrintableStatus(
+ mountDetail,
+ warning,
+ critical
+ )
+ self.assertEquals(actRc, expRc)
+ self.assertEquals(actMsg, expMsg)
+ self.assertEquals(actOut, expOut)
+ self.assertEquals(actPerfData, expPerfData)