Skip to content

Instantly share code, notes, and snippets.

@rendicott
Created January 6, 2017 15:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rendicott/4e3a11eb3ca55c959a00506c05370435 to your computer and use it in GitHub Desktop.
Save rendicott/4e3a11eb3ca55c959a00506c05370435 to your computer and use it in GitHub Desktop.
nagios plugin to check filesystem usage based on df output
#!/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