Created
January 6, 2017 15:57
-
-
Save rendicott/4e3a11eb3ca55c959a00506c05370435 to your computer and use it in GitHub Desktop.
nagios plugin to check filesystem usage based on df output
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
This script checks the output of the local | |
'df -P' command and reports the disk usage | |
for the given mount with perfdata. | |
Usage: | |
python check_df_usage.py | |
OK /dev/mapper/centos-root filesystem mounted on / usage percentage is 17 ; | 'used_percentage'=17;90;95;; 'size'=14530560KB;;;; 'used'=2360596KB;;;; 'available'=12169964KB;;;; | |
python check_df_usage.py --mount '/boot' --warn_usage 20 --crit_usage 30 | |
CRITICAL /dev/sda1 filesystem mounted on /boot usage percentage is 34 ; | 'used_percentage'=34;20;30;; 'size'=508588KB;;;; 'used'=168196KB;;;; 'available'=340392KB;;;; | |
Requires: NagPy library (https://github.com/rendicott/nagpy) | |
""" | |
import logging | |
import sys | |
import inspect | |
import gc | |
import os | |
import nagpyrc | |
import subprocess | |
import re | |
from nagpyrc import NagiosReturn | |
from nagpyrc import PerfChunk | |
from nagpyrc import NagiosReturnCode | |
from optparse import OptionParser, OptionGroup | |
sversion = 'v0.1' | |
scriptfilename = os.path.basename(sys.argv[0]) | |
defaultlogfilename = scriptfilename + '.log' | |
def setuplogging(loglevel,printtostdout,logfile): | |
#pretty self explanatory. Takes options and sets up logging. | |
#print "starting up with loglevel",loglevel,logging.getLevelName(loglevel) | |
logging.basicConfig(filename=logfile, | |
filemode='w',level=loglevel, | |
format='%(asctime)s:%(levelname)s:%(message)s') | |
if printtostdout: | |
soh = logging.StreamHandler(sys.stdout) | |
soh.setLevel(loglevel) | |
logger = logging.getLogger() | |
logger.addHandler(soh) | |
def is_number(s): | |
try: | |
float(s) | |
return True | |
except ValueError: | |
return False | |
def execute_command(commandstring): | |
try: | |
output = subprocess.Popen(commandstring,stdout=subprocess.PIPE) | |
return(output) | |
except Exception as e: | |
msg = "Exception calling command: '%s' , Exception: %s" % (commandstring,str(e)) | |
logging.debug(msg) | |
return(msg) | |
class Mount: | |
def __init__(self): | |
self.filesystem = '' | |
self.size = '' | |
self.used = '' | |
self.avail = '' | |
self.usep = '' | |
self.mount = '' | |
def dumpself(self): | |
fmt = '{0:50}{1:10}{2:10}{3:10}{4:5}{5:50}' | |
return(fmt.format(self.filesystem,self.size,self.used,self.avail,self.usep,self.mount)) | |
def parse_size(stringer): | |
unit = '' | |
value = '' | |
r1 = re.compile('(?P<value>\d*)(?P<unit>\w*)') | |
match = re.search(r1,stringer) | |
if match: | |
unit = match.group('unit') | |
value = match.group('value') | |
if unit == '': | |
unit = 'KB' | |
#return("VALUE: '%s', UNIT: '%s'" % (value,unit)) | |
return(unit, value) | |
def main(options): | |
''' The main() method. Program starts here. | |
''' | |
output = execute_command(['/bin/df','-P']) | |
mounts = [] | |
try: | |
for line in output.stdout: | |
chunked = [x.replace('\n','') for x in line.split(' ') if x != ''] | |
m = Mount() | |
m.filesystem = chunked[0] | |
m.size = chunked[1] | |
m.used = chunked[2] | |
m.avail = chunked[3] | |
m.usep = chunked[4].replace('%','') | |
m.mount = chunked[5] | |
mounts.append(m) | |
selected_mount = None | |
for mount in mounts: | |
if mount.mount == options.mount: | |
selected_mount = mount | |
except Exception as e: | |
msg = "Exception processing output from 'df -P' command: " + str(e) | |
logging.debug(msg) | |
print(msg) | |
sys.exit(1) | |
#print('WHOLE::::::::::::::' + selected_mount.dumpself()) | |
error = False | |
try: | |
pc_usage = PerfChunk(stringname='used_percentage',value=selected_mount.usep) | |
pc_usage.warn = str(options.warn_usage) | |
pc_usage.crit = str(options.crit_usage) | |
except: | |
pc_usage = PerfChunk(stringname='used_percentage',value='100') | |
error = True | |
pc_usage.warn = str(options.warn_usage) | |
pc_usage.crit = str(options.crit_usage) | |
if error: | |
nrc = 2 | |
elif int(selected_mount.usep) >= int(options.crit_usage): | |
nrc = 2 | |
elif int(selected_mount.usep) >= int(options.warn_usage): | |
nrc = 1 | |
else: | |
nrc = 0 | |
# build your nagios message and tell it to be warn,crit,ok, etc. | |
# nrc = 1 # WARNING | |
# nrc = 2 # CRITICAL | |
if error: | |
msg = 'error mount unknown' | |
else: | |
msg = '%s filesystem mounted on %s usage percentage is %s' % (selected_mount.filesystem, selected_mount.mount, selected_mount.usep) | |
nm = NagiosReturnCode(returncode=nrc,msgstring=msg) | |
# append the primary performance counter that we care about | |
nm.perfChunkList.append(pc_usage) | |
# build additional performance metrics | |
#print('SIZE:::::' + parse_size(selected_mount.size)) | |
#print('USED:::::' + parse_size(selected_mount.used)) | |
#print('AVAIL:::::' + parse_size(selected_mount.avail)) | |
try: | |
(unit, value) = parse_size(selected_mount.size) | |
pc_size = PerfChunk(stringname='size', value=value, unit=unit) | |
nm.perfChunkList.append(pc_size) | |
except Exception as r: | |
logging.debug("EXCEPTION size: " + str(r)) | |
try: | |
(unit, value) = parse_size(selected_mount.used) | |
pc_used = PerfChunk(stringname='used', value=value, unit=unit) | |
nm.perfChunkList.append(pc_used) | |
except Exception as r: | |
logging.debug("EXCEPTION used: " + str(r)) | |
try: | |
(unit, value) = parse_size(selected_mount.avail) | |
pc_avail = PerfChunk(stringname='available', value=value, unit=unit) | |
nm.perfChunkList.append(pc_avail) | |
except Exception as r: | |
logging.debug("EXCEPTION avail: " + str(r)) | |
nm.genreturncode() # will raise a 'NagiosReturn' exception which is normal | |
if __name__ == '__main__': | |
'''This main section is mostly for parsing arguments to the | |
script and setting up debugging''' | |
from optparse import OptionParser | |
'''set up an additional option group just for debugging parameters''' | |
from optparse import OptionGroup | |
usage = ("%prog [--debug] [--printtostdout] [--logfile] [--version] [--help] [--samplefileoption]") | |
#set up the parser object | |
parser = OptionParser(usage, version='%prog ' + sversion) | |
parser.add_option('--warn_usage', | |
type='string', | |
help=("Warning level for disk usage percentage (Default=90)"),default=90) | |
parser.add_option('--crit_usage', | |
type='string', | |
help=("Critical level for disk usage percentage (Default=95"),default=95) | |
parser.add_option('--mount', | |
type='string', | |
help="If this option is present then only statistics for the specific " + | |
"mount will be parsed. Default behavior is to return stats for " + | |
"just root e.g., '/'. (Default='/')", | |
default='/') | |
parser_debug = OptionGroup(parser,'Debug Options') | |
parser_debug.add_option('-d','--debug',type='string', | |
help=('Available levels are CRITICAL (3), ERROR (2), ' | |
'WARNING (1), INFO (0), DEBUG (-1)'), | |
default='CRITICAL') | |
parser_debug.add_option('-p','--printtostdout',action='store_true', | |
default=False,help='Print all log messages to stdout') | |
parser_debug.add_option('-l','--logfile',type='string',metavar='FILE', | |
help=('Desired filename of log file output. Default ' | |
'is "'+ defaultlogfilename +'"') | |
,default=defaultlogfilename) | |
#officially adds the debuggin option group | |
parser.add_option_group(parser_debug) | |
options,args = parser.parse_args() #here's where the options get parsed | |
try: #now try and get the debugging options | |
loglevel = getattr(logging,options.debug) | |
except AttributeError: #set the log level | |
loglevel = {3:logging.CRITICAL, | |
2:logging.ERROR, | |
1:logging.WARNING, | |
0:logging.INFO, | |
-1:logging.DEBUG, | |
}[int(options.debug)] | |
try: | |
open(options.logfile,'w') #try and open the default log file | |
except: | |
logging.debug("Unable to open log file '%s' for writing." % options.logfile) | |
logging.debug( | |
"Unable to open log file '%s' for writing." % options.logfile) | |
setuplogging(loglevel,options.printtostdout,options.logfile) | |
try: | |
main(options) | |
except NagiosReturn, e: | |
print e.message | |
sys.exit(e.code) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment