Nagios: Monitoring Interface Bandwidth Utilization Using Cacti Data

One area where Nagios is severely lacking is bandwidth utilization monitoring of network devices. Since I already have a fully-functioning Cacti server and a scaled up Nagios server, I wrote my own python plugin to do the job.

Overview

Here’s what the check_port_sturation.py plugin does:

  1. Make SNMP call to determine max speed of an interface
  2. Open specified interface graph via https and download the associated CSV data file.
  3. Compute the 5-minute average Inbound and Outbound bandwidth utilization
  4. Check these values against specified thresholds (given in percentages)
  5. Enter warning or critical state when utilization exceeds thresholds

Let’s begin.

Map ifIndex to Cacti Graph ID

Cacti Device and Graph ID’s are arbitrary so you will need to map them to your devices’ hostname and interface ifIndex values, respectively.

Luckily it’s pretty easy to do this regardless of how many devices and interfaces you are monitoring.

1. Ensure You Are Using Consistent Naming Schemes in Cacti and Nagios

If your Nagios checks are using “dist1”, then use “dist1” for the Hostname and Description fields in Cacti. This will make the mapping and scripting steps easier.

cacti_device_description

2. Update Cacti Graph Description with SNMP ifIndex

Cacti is already polling your device, so why not use it to get all the information we need?

Find the graph template you are using for interface traffic monitoring (I suggest first following my post on Dressing up Cacti graphs) and update the graph title field as follows:

|host_description| |query_ifIndex| |query_ifName| |query_ifAlias|

Variable descriptions:

host_description:  The field covered in Step 1
query_ifIndex:       This is the SNMP index of the interface.
query_ifName:       The SNMP name of the physical interface (Not required)
query_ifAlias:         The description you set for your interface in IOS. (Not required)

Screen shot example:

cacti_nagios_2

Your graphs will now look like this:

cacti_nagios_1

3. Use Built-In Cacti Scripts to Get Device and Graph IDs

(Note: Detailed instructions for Cacti built-in scripts are located here – http://www.cacti.net/downloads/docs/html/scripts.html)

First we want to get a list of our devices and their Cacti device ID’s. This is done by using the following built-in Cacti script:

php /usr/share/cacti/cli/add_graphs.php --list-hosts 

Output will be as follows:

porter@cacti:~$ php /usr/share/cacti/cli/add_graphs.php --list-hosts
Known Hosts: (id, hostname, template, description)
5    core1    5    core1
141    dist1    13    dist1
143    dist2    13    dist2
183    sw-r07-03a    12    sw-r07-03a
184    sw-r07-03c    12    sw-r07-03c
185    sw-r07-04a    12    sw-r07-04a 

With this information we can get a list of the Graph ID’s associated with each host.

php /usr/share/cacti/cli/add_tree.php --list-graphs --host-id=141 

Since we updated the Graph Descriptions earlier, this output now contains all the information we need for our check:

porter@cacti:~$ porter@cacti:~$ php /usr/share/cacti/cli/add_tree.php --list-graphs --host-id=141
Known Host Graphs: (id, name, template)
7318    dist1 437841920 Ethernet4/16 NEXUS2: E4/16 [Po4096]    3: Interface - Traffic (bits/sec)
7319    dist1 437317632 Ethernet3/16 NEXUS2: E3/16 [Po4096]    3: Interface - Traffic (bits/sec)
7322    dist1 369098752 port-channel1 [eth1/1] sw-r03-08a: te0/1    3: Interface - Traffic (bits/sec)
7323    dist1 369098753 port-channel2 [eth1/2] sw-r07-03a: te1/1    3: Interface - Traffic (bits/sec)
7324    dist1 369098754 port-channel3 [eth1/3] sw-r07-03c: te1/1    3: Interface - Traffic (bits/sec)
7325    dist1 369098755 port-channel4 [eth1/4] sw-r07-04a: te1/1    3: Interface - Traffic (bits/sec)

To do both tasks in one step, you can use the following Bash script:

#!/bin/bash
for device in `php /usr/share/cacti/cli/add_graphs.php --list-hosts | awk '{print $1}'`; do
php /usr/share/cacti/cli/add_tree.php --list-graphs --host-id=$device \
| grep Traffic | awk '{print $2";"$4";"$1";"$3}'; \
done 

(Note: The “grep Traffic” portion is filtering out other graph templates)

This will cycle through all of your cacti devices and provide you with a nice semi-colon separated file output in the following format:

hostname;interface_name;graph_id;ifIndex

Example:

dist1;port-channel1;7322;369098752
dist1;port-channel2;7323;369098753
dist1;port-channel3;7324;369098754
dist1;port-channel4;7325;369098755
dist1;port-channel5;7326;369098756

Run this script and save your output to a text file that can then be copied over to your Nagios server:

porter@cacti:~$ get_cacti_data.sh >> cacti_graph_mappings

Installation

You’ll need to have Python 2.7 and the specified modules installed on your Nagios server in order to use this plugin. You will also need to update all paths to suit your environment.

1. Download Plugin

The latest revision of this plugin can be downloaded from the Nagios Exchange:

http://exchange.nagios.org/directory/Plugins/Network-Connections%2C-Stats-and-Bandwidth/Monitoring-Interface-Bandwidth-Utilization-Using-Cacti-Data/details


#!/opt/python/bin/python2.7
# Paul Porter 2013 http://paulgporter.net

import csv
import cStringIO
import datetime
import netsnmp
import requests
import argparse
import sys

# Listing of arguments this command will accept. Defaults are given for some values.

def main(argv=sys.argv[1:]):
parser = argparse.ArgumentParser(description='nagios port saturation check')
parser.add_argument('-H', '--host', required=True,
help='Host we are checking')
parser.add_argument('-C', '--snmp_com', default='public', required=True,
help='SNMP community')
parser.add_argument('-V', '--snmp_ver', type=int, default=2, choices=[1, 2, 3],
help='SNMP version')
parser.add_argument('-g', '--graph_id', required=True,
help='Cacti graph id')
parser.add_argument('-s', '--cacti_server', required=True,
help='Cacti server hostname')
parser.add_argument('-c', '--crit', default=90, type=int,
help='critical saturation level in %')
parser.add_argument('-w', '--warn', default=80, type=int,
help='warning saturation level in %')
parser.add_argument('-i', '--if_index', required=True,
help='ifIndex value for snmp')
args = parser.parse_args(argv)

# Create empty arrays

inbound = []
outbound = []

# Download the data from Cacti. Update the cert path to match yours.

text = requests.get('https://'+ args.cacti_server +'/cacti/graph_xport.php?local_graph_id='+ args.graph_id +'&rra_id=5&view_type=', verify='/etc/ssl/certs/ca-certificates.crt').content

# If download was successful parse the CSV file, skip the headers, and retrieve data from the Inbound and Outbound columns. Otherwise exit with an error.

if len(text) > 1 :
for i in csv.DictReader(cStringIO.StringIO(text[text.index('""') + 3:])):
if datetime.datetime.now() - datetime.datetime.strptime(i['Date'], '%Y-%m-%d %H:%M:%S') <= datetime.timedelta(minutes=17):
inbound.append(float(i['Inbound']) / (100 * 1024 * 1024) * 100),
outbound.append(float(i['Outbound']) / (100 * 1024 * 1024) * 100),
else :
print "ERROR: No Results Found"
sys.exit(text)

# Use SNMP with the provided Hostname and IfIndex values to get the maximum speed of this interface

max_speed = (netsnmp.snmpget(netsnmp.Varbind('.1.3.6.1.2.1.31.1.1.1.15.' + args.if_index), DestHost=args.host, Version=args.snmp_ver, Community=args.snmp_com, UseNumeric=True)[0])

# Takes the data from the Inbound and Outbound columns, converts it to Mbps, and adds to the arrays

avg_inbound = round(sum(inbound) / len(inbound), 2)
avg_outbound = round(sum(outbound) / len(outbound), 2)

# Apply the specified WARN and CRIT levels to the max speed and convert to decimal format
warn_threshold = int(max_speed) * (args.warn * .01)
crit_threshold = int(max_speed) * (args.crit * .01)

# Compare values

if (avg_inbound >= crit_threshold) or (avg_outbound >= crit_threshold) :
print 'CRITICAL: Avg_In= %s Mbps and Avg_Out= %s Mbps' % (avg_inbound, avg_outbound)
elif (warn_threshold <= avg_inbound) or (warn_threshold <= avg_outbound) :
print 'WARNING: Avg_In= %s Mbps and Avg_Out= %s Mbps' % (avg_inbound, avg_outbound)
elif (0 <= avg_inbound <= warn_threshold) and (0 <= avg_outbound <= warn_threshold):
print 'SUCCESS: Avg_In= %s Mbps and Avg_Out= %s Mbps' % (avg_inbound, avg_outbound)

if __name__ == '__main__':
main()

2. Add to Nagios commands.cfg

The command usage is as follows:

usage: check_port_saturation.py [-h] -H HOST -g GRAPH_ID [-s CACTI_SERVER] [-c CRIT] [-w WARN] [-V {1,2,3}] [-C SNMP_COM] -i IF_INDEX 

When you add the command to Nagios, you can pass those options as either values or arguments. Run it a few times from the command line to make sure that it is working properly.

Here is an example which uses defaults for -c,-w,-V, -s, and -C.:

define command {
command_name    check_port_saturation
command_line    /etc/nagios3/plugins/check_port_saturation.py -H $HOSTADDRESS$ -g $ARG1$ -i $ARG2$
}

3. Add to Nagios services.cfg

With the cacti_graph_mappings file we created earlier, it’s easy to feed that to a script to generate the Nagios services configuration for you. If you’re unsure of how to do this, you can run the following example from a command line or bash script to get a basic configuration built.

This command is feeding awk the cacti_graph_mappings file and appending the output to our existing services.cfg file.

awk -F';' '{print "\
define service { \n \
use \t generic-network-service-template \n \
hosts \t "$1" \n \
service_description \t"$2"_Usage \n \
check_command \t check_port_saturation!"$3"!"$4" \n \
} \n"}' cacti_graph_mappings >> /etc/nagios3/conf.d-constant/services.cfg

Output will look as follows:

define service {
use      generic-network-service-template
hosts    dist4
service_description  Ethernet1/45_Usage
check_command       check_port_saturation!23715!436387840
}

define service {
use       generic-network-service-template
hosts     dist4
service_description  Ethernet1/46_Usage
check_command       check_port_saturation!23716!436391936
} 

4. Restart Nagios

You should now see results like this in Nagios:

nag_cacti_ex_3

Finished!

Additional Enhancements

Here are a few other useful ideas for implementing this plugin in your environment…

One Page Viewing of Bandwidth Usage

Cacti has a 100-graphs-per-page viewing limit, which means you’ll have to do some clicking around if you want to get a complete overview of bandwidth usage in your network. By creating a Nagios Service Group for the plug-in we just wrote it’s possible to get a complete listing of bandwidth usage on ALL monitored interfaces on one page.

Here’s an example of how it would look:

cacti_nagios_svc_grp

2. Add Links to the Cacti Graph

Another cool thing you can do is add a link to the associated Cacti graph as a Service Comment.

(Note: Detailed instructions for the nagios.cmd command can be found here – http://nagios.sourceforge.net/docs/3_0/extcommands.html)

So. let’s do this on the bandwidth check for interface Ethernet1/10 on Dist1. To add the comment we would run the following command.

 printf "[%lu] ADD_SVC_COMMENT;dist1;Ethernet1/10_Usage;1;PORTER;<a href="https://netprobe/cacti/graph.php?action=view\&rra_id=all\&local_graph_id=7378">https://netprobe/cacti/graph.php?action=view&rra_id=all&local_graph_id=7378</a>\n" `date +%s` > /var/lib/nagios3/rw/nagios.cmd 

Important: You must use a backslash before the ampersand symbol in the anchor tag otherwise the command will not work correctly.

You will now see a comment icon next to the service description as shown below.

cacti_nagios_svc_comment1

Clicking the comment will open the service description and you will now see a URL at the bottom of the page

cacti_nagios_svc_comment2

Clicking on that link will show you the Cacti graph.

cacti_nagios_svc_comment3

This can easily be scripted for all interfaces using the files we created earlier in this post.

37 comments

    1. Open the check_port_saturation.py script with a text editor and change this line:

      text = requests.get(‘https://’+ args.cacti_server +’/cacti/graph_xport.php?local_graph_id=’+ args.graph_id +’&rra_id=5&view_type=’, verify=’/etc/ssl/certs/ca-certificates.crt’).content

      To this:

      text = requests.get(‘http://’+ args.cacti_server +’/cacti/graph_xport.php?local_graph_id=’+ args.graph_id +’&rra_id=5&view_type=’

  1. When I run the script I am getting an error File “./check_port_saturation.py”, line 45, in main
    if len(text) > 1 :
    TypeError: object of type ‘Response’ has no len()

    1. Nvm I figured out my mistake. I forgot to add ‘.content’ to the end of the previous comment. If you change from https to http the final change should look like

      text = requests.get(‘http://’+ args.cacti_server +’/cacti/graph_xport.php?local_graph_id=’+ args.graph_id +’&rra_id=5&view_type=’).content

      1. Thanks for the swift response Paul. Will give it a try. Oh and thanks for the excellent documentation on a most excellent plug in 🙂

  2. Hello again,

    When i try too run the first service check I get: (Return code of 126 is out of bounds – plugin may not be executable)

    I am using snmp v3 which doesn’t use a community though when running the check manually on the command line I get the following out put.

    # ./check_port_saturation.py -H 192.168.0.5 -v 3 -u snmpusername -p ‘password’ -i 5

    -bash: ./check_port_saturation.py: /opt/python/bin/python2.7: bad interpreter: No such file or directory

    Nagios is reporting: “Return code of 127 is out of bounds – plugin may be missing” which suggests to me it may be an issue with the SNMP. Have I got the syntax right?

    Thanks again.

    Adam

    1. Hey Adam,

      The problem is that you are using SNMPv3 and the current plugin doesn’t ask for credentials or use them when it collects max speed:

      max_speed = (netsnmp.snmpget(netsnmp.Varbind(‘.1.3.6.1.2.1.31.1.1.1.15.’ + args.if_index), DestHost=args.host, Version=args.snmp_ver, Community=args.snmp_com, UseNumeric=True)[0])

      I will have to re-write the plug-in to support it. I’ll send you a version to test with by the end of next week.

      1. Hi Paul, I was wondering how you are progressing with the SNMPv3 plugin. I have had an attempt but my skills in Python are beyond basic 😉

  3. Apologies – it is not seeing the interpreter. I need to pre-append python to get a little further. Still struggling with the syntax though.

  4. Now. I have tried with your guide but when I run the script I am getting an error File “./check_port_saturation.py”, line 45, in main
    if len(text) > 1 :

    I hope your help.
    Thank so much!

  5. I use Ubuntu Server and i modify with:
    #!/opt/python/bin/python2.7
    to this:
    #!/usr/bin/python2.7

    after was error:
    root@nagios:/usr/local/nagios/libexec# ./check_port_saturation.py
    File “./check_port_saturation.py”, line 45
    if length(text) > 1 :
    ^
    IndentationError: unexpected indent

    HOPE with your help!
    Thanks

    1. Hello,

      Python is very picky about the use of formatting and is unhappy with your file.

      Did you modify the file by doing a copy and paste from a different text editor? If so, it can introduce additional formatting that isn’t noticeable at first.

      If you did a copy paste, try downloading the file again and using vim to edit the file instead. This way you don’t have to worry about extra spaces from a copy and paste.

  6. Hello Paul.

    I’m checked from command line and I got this error:

    /usr/local/nagios/libexec/check_port_saturation.py -H next01-cisco-dl-sw1 -C public -s “cacti-server-host” -g 45 -i 10148

    Traceback (most recent call last):
    File “/usr/local/nagios/libexec/check_port_saturation.py”, line 77, in
    main()
    File “/usr/local/nagios/libexec/check_port_saturation.py”, line 47, in main
    if datetime.datetime.now() – datetime.datetime.strptime(i[‘Date’], ‘%Y-%m-%d %H:%M:%S’) <= datetime.timedelta(minutes=17):
    KeyError: 'Date'

    Can you help me?
    Thanks.

    1. # If download was successful parse the CSV file, skip the headers, and retrieve data from the Inbound and Outbound columns. Otherwise exit with an error.

      print “—>%s<—" % (text)

      # 2014-10-14: To review the result information

  7. Really usefull plugin. Combining Cacti and Nagios in this was is very useful to me.

    However, I’m looking to go a step further. I would like to pull Network traffic bandwidth usage data from Cacti into Nagios to feed Nagvis weathermap lines in an attempt to have the best of Nagvis and Cacti weathermap combined as well.

    This plugin seems to be most of the way there but I need it to produce perfData in the required format.

    “example: inUsage=21103.42%;85;98 outUsage=226363.55%;85;98 inBandwidth=105.52MBs outBandwidth=212.22MBs”

    http://docs.nagvis.org/1.7/en_US/lines_weathermap_style.html

    I’ll attempt to modify your plugin and let you know how I get on!

    1. Hi I have now successfully modified your code to present performance data that will drive the Nagvis weathermap feature.

      Let me know if you would likle a copy of my code.

      Thanks!

      Rob

  8. HI, when I run the command to try to pull all the graphs, Id’s and indexes, it comes out as 13;â . Not sure why i’m getting that weird character. Any ideas?

    1. If you copied and pasted that script try typing it out in a terminal window instead. Perhaps some RTF encoding got carried over from a text editor? WordPress sometimes adds extra characters when I paste code in.

      1. Thanks Paul, in doing some testing, it seems that even if I run the add_tree.php comnand with –list-graphs etc… it stills comes up with that odd character….

  9. HI
    Iam new to this cacti and nagios , i had installed cacti and nagios in two differnet box, how to cacti graphs in nagios. or i need to install cacti nad nagios in the same box. please suggest me.

    Regards
    Dinesh.M

  10. Hello Paul.

    I’m checked from command line and I got this error:

    /usr/local/nagios/libexec/check_port_saturation.py -H dell5424 -C public -s “10.100.100.20” -g 2 -i 1

    Traceback (most recent call last):
    File “/usr/local/nagios/libexec/check_port_saturation.py”, line 77, in
    main()
    File “/usr/local/nagios/libexec/check_port_saturation.py”, line 47, in main
    if datetime.datetime.now() – datetime.datetime.strptime(i[‘Date’], ‘%Y-%m-%d %H:%M:%S’) <= datetime.timedelta(minutes=17):
    KeyError: 'Date'

    Can you help me?
    Thanks.

  11. Hi ,

    Do we really need python 2.7 ?? Won’t it be possible with python 2.6. ? getting error as

    Traceback (most recent call last):
    File “./check_port_saturation.py”, line 7, in
    import netsnmp
    ImportError: No module named netsnmp

  12. Hello!

    >KeyError: ‘Date’
    Is because unsuccessful login and gotten empty file.

    I don’t know Python at all, but I managed to hack this script to use http login and snmp v3.

    1. Added SNMP v3 parameters:
    ################################################################################
    ### Added by Alar Smiltinsh on 2016.08.05 for SNMP V3 authentication
    ################################################################################
    parser.add_argument(‘-u’, ‘–snmp_secname’, default=’initial’,
    help=’SNMP SecName (username) (v3)’)
    parser.add_argument(‘-l’, ‘–snmp_seclevel’, default=’noAuthNoPriv’,
    help=’SNMP security level [noAuthNoPriv, authNoPriv, authPriv] (v3)’)
    parser.add_argument(‘-a’, ‘–snmp_authproto’, default=’MD5′,
    help=’SNMP authentication protocol [MD5, SHA] (v3)’)
    parser.add_argument(‘-A’, ‘–snmp_authpass’,
    help=’SNMP authentication passphrase’)
    #parser.add_argument(‘-x’, ‘–snmp_privproto’, default=’DES’,
    parser.add_argument(‘-x’, ‘–snmp_privproto’,
    help=’SNMP privacy protocol [DES] (v3)’)
    parser.add_argument(‘-X’, ‘–snmp_privpass’,
    help=’SNMP privacy passphrase (v3)’)
    ################################################################################

    2.
    ### Commented out by Alar Smiltinsh on 2016.08.05
    ###text = requests.get(‘https://’+ args.cacti_server +’/cacti/graph_xport.php?local_graph_id=’+ args.graph_id +’&rra_id=5&view_type=’, verify=’/etc/ssl/certs/ca-certificates.crt’).content

    ################################################################################
    ### Added by Alar Smiltinsh on 2016.08.05 for HTTP (not HTTPS) login.
    ################################################################################
    ###text = requests.get(‘http://’+ args.cacti_server +’/cacti/graph_xport.php?local_graph_id=’+ args.graph_id +’&rra_id=5&view_type=’, auth=(‘nagios_username’, ‘XXXXXXXXXXXXX’)).content

    from bs4 import BeautifulSoup

    url = ‘http://’+ args.cacti_server +’/cacti/graph_xport.php?local_graph_id=’+ args.graph_id +’&rra_id=5&view_type=’

    #Open session
    s = requests.session()
    http_headers = {“Referer”: url}

    # Retrieve the CSRF token first
    ###s.get(url) # sets cookie
    ###csrf_token = s.cookies[‘csrf_magic’]
    ###print s.cookies[‘csrf_magic’]
    soup = BeautifulSoup(s.get(url).text)
    #csrf_token = soup.find(name=”csrf_magic”)
    csrf_token = soup.find(“input”, value=True)[“value”]

    #print http_headers
    #print s.cookies
    #print ‘——–‘
    #print csrf_token
    #print ‘——–‘
    #print soup
    #print ‘ssssssss’

    # Fill in your details here to be posted to the login form.
    login_data = {
    ‘action’: ‘login’,
    ‘login_username’: ‘nagious_username’,
    ‘login_password’: ‘XXXXXXXXXXXXXXX’,
    ‘__csrf_magic’: csrf_token
    }

    p = s.post(url, data=login_data, headers=http_headers)
    # print the html returned or something more intelligent to see if it’s a successful login page.
    #print p.text

    # An authorised request.
    text = s.get(url).content
    #print text

    #Close session
    s.close()
    #sys.exit()
    ################################################################################

    3.
    ################################################################################
    ### Added by Alar Smiltinsh on 2016.08.05 for SNMP V3 authentication
    ################################################################################
    if args.snmp_ver == 3 :
    if args.snmp_seclevel == ‘authPriv’ :
    max_speed = (netsnmp.snmpget(netsnmp.Varbind(‘.1.3.6.1.2.1.31.1.1.1.15.’ + args.if_index), DestHost=args.host, Version=args.snmp_ver, SecLevel=args.snmp_seclevel, SecName=args.snmp_secname, AuthProto=args.snmp_authproto, AuthPass=args.snmp_authpass, PrivProto=args.snmp_privproto, PrivPass=args.snmp_privpass, Community=args.snmp_com, UseNumeric=True)[0])
    elif args.snmp_seclevel == ‘authNoPriv’ :
    max_speed = (netsnmp.snmpget(netsnmp.Varbind(‘.1.3.6.1.2.1.31.1.1.1.15.’ + args.if_index), DestHost=args.host, Version=args.snmp_ver, SecLevel=args.snmp_seclevel, SecName=args.snmp_secname, AuthProto=args.snmp_authproto, AuthPass=args.snmp_authpass, Community=args.snmp_com, UseNumeric=True)[0])
    #elif args.snmp_seclevel == ‘noAuthNoPriv’ :
    #…
    else : #SNMP V2
    ################################################################################
    max_speed = (netsnmp.snmpget(netsnmp.Varbind(‘.1.3.6.1.2.1.31.1.1.1.15.’ + args.if_index), DestHost=args.host, Version=args.snmp_ver, Community=args.snmp_com, UseNumeric=True)[0])

    4.
    ################################################################################
    ### Modified by Alar Smiltinsh on 2016.08.05 – added return codes for Nagios status detection
    ################################################################################
    if (avg_inbound >= crit_threshold) or (avg_outbound >= crit_threshold) :
    print ‘CRITICAL: Avgerage In = %s Mbps and Average Out = %s Mbps’ % (avg_inbound, avg_outbound)
    sys.exit(2)
    elif (warn_threshold <= avg_inbound) or (warn_threshold <= avg_outbound) :
    print 'WARNING: Average In = %s Mbps and Average Out = %s Mbps' % (avg_inbound, avg_outbound)
    sys.exit(1)
    elif (0 <= avg_inbound <= warn_threshold) and (0 <= avg_outbound <= warn_threshold):
    print 'OK: Average In = %s Mbps and Average Out = %s Mbps' % (avg_inbound, avg_outbound)
    sys.exit(0)
    else:
    sys.exit(3)
    ################################################################################

  13. Hi Paul,

    I am working on this and I have Nagios 4.1.1 and Cacti 0.8.8f running on Ubuntu Server 16.04 LTS. I really appreciate your work and the comments of the other folks following this. The error I am seeing now is the following when I run check_port_saturation.py at the prompt:

    root@NetManager:/usr/local/nagios/libexec# ./check_port_saturation.py -H 172.16.5.38 -g 11 -s 172.16.1.47 -V 2 -C R1verC0untry -i 10107
    Traceback (most recent call last):
    File “./check_port_saturation.py”, line 77, in
    main()
    File “./check_port_saturation.py”, line 60, in main
    avg_inbound = round(sum(inbound) / len(inbound), 2)
    ZeroDivisionError: integer division or modulo by zero

    What is causing this?

    Thanks,
    John

  14. Hello,
    I made some little modification to script to fix this:
    – When Cacti returns NaN in graph_xport, ignore this
    – Return right return codes to Nagios
    – I have DMZ between Nagios and Cacti so I don’t need HTTPS

    — check_port_saturation.orig 2016-10-12 16:13:49.000000000 +0200
    +++ /usr/lib/nagios/plugins/check_port_saturation 2016-10-12 16:01:32.678265253 +0200
    @@ -1,4 +1,4 @@
    -#!/opt/python/bin/python2.7
    +#!/usr/bin/env python2.7
    # Paul Porter 2013 http://paulgporter.net

    import csv
    @@ -38,18 +38,18 @@

    # Download the data from Cacti. Update the cert path to match yours.

    – text = requests.get(‘https://’+ args.cacti_server +’/cacti/graph_xport.php?local_graph_id=’+ args.graph_id +’&rra_id=5&view_type=’, verify=’/etc/ssl/certs/ca-certificates.crt’).content
    + text = requests.get(‘http://’+ args.cacti_server +’/cacti/graph_xport.php?local_graph_id=’+ args.graph_id +’&rra_id=5&view_type=’).content

    # If download was successful parse the CSV file, skip the headers, and retrieve data from the Inbound and Outbound columns. Otherwise exit with an error.

    if len(text) > 1 :
    for i in csv.DictReader(cStringIO.StringIO(text[text.index(‘””‘) + 3:])):
    – if datetime.datetime.now() – datetime.datetime.strptime(i[‘Date’], ‘%Y-%m-%d %H:%M:%S’) <= datetime.timedelta(minutes=17):
    + if datetime.datetime.now() – datetime.datetime.strptime(i['Date'], '%Y-%m-%d %H:%M:%S') = crit_threshold) or (avg_outbound >= crit_threshold) :
    print ‘CRITICAL: Avg_In= %s Mbps and Avg_Out= %s Mbps’ % (avg_inbound, avg_outbound)
    + sys.exit(2)
    elif (warn_threshold <= avg_inbound) or (warn_threshold <= avg_outbound) :
    print 'WARNING: Avg_In= %s Mbps and Avg_Out= %s Mbps' % (avg_inbound, avg_outbound)
    + sys.exit(1)
    elif (0 <= avg_inbound <= warn_threshold) and (0 <= avg_outbound <= warn_threshold):
    print 'SUCCESS: Avg_In= %s Mbps and Avg_Out= %s Mbps' % (avg_inbound, avg_outbound)
    + sys.exit(0)
    + else:
    + print 'UNKNOWN: Cannot get data. avg_inbound "%s", crit_threshold "%s", avg_outbound "%s", warn_threshold "%s"' % (avg_inbound, crit_threshold, avg_outbound, warn_threshold)
    + sys.exit(3)

    if __name__ == '__main__':
    main()

    1. hi. i’ve tried running the initial script and after managing to fix the spaces and stuff it was exiting with error no result but dumping the csv which looked ok to me.

      i have now tried to add these last few lines and it keeps telling me that i have a syntax error in

      if datetime.datetime.now() – datetime.datetime.strptime(i[‘Date’], ‘%Y-%m-%d %H:%M:%S’) = crit_threshold) or (avg_outbound >= crit_threshold) :
      print ‘CRITICAL: Avg_In= %s Mbps and Avg_Out= %s Mbps’ % (avg_inbound, avg_outbound)

      this line

      can you help please? i’d really like to see this thing working.

      thanks

    2. hi. i’ve tried running the initial script and after managing to fix the spaces and stuff it was exiting with error no result but dumping the csv which looked ok to me.

      i have now tried to add these last few lines and it keeps telling me that i have a syntax error in

      if datetime.datetime.now() – datetime.datetime.strptime(i[‘Date’], ‘%Y-%m-%d %H:%M:%S’) = crit_threshold) or (avg_outbound >= crit_threshold) :
      print ‘CRITICAL: Avg_In= %s Mbps and Avg_Out= %s Mbps’ % (avg_inbound, avg_outbound)

      this line

      can you help please? i’d really like to see this thing working.

      thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s