An example showing the 'warning' state: 
And an example showing the 'critical' state:
It's customizable, but I chose this method, since what typically happens when there is a WLC problem is AP's begin roaming around to various WLC's that are all part of the same mobility group. This can yield a lot of alerts, if you specify 'Critical' for both AP's missing AND AP's found unexpectedly.
I wrote it in Python. The usage is fairly simple, just populate a file in your conf.d directory called "wlc-<#>-aps_expected. Note, this relies on netsnmp and the correct mibs to be installed. This is currently for AirOS WLC's only.
usage: check_wlc_ap.py -H -f
Below are some sample config modifications needed to make this work.
/etc/nagios3/commands.cfg:
define command{
command_name check_wlc_ap
command_line /usr/lib/nagios/plugins/check_wlc_ap.py -H $HOSTADDRESS$ -f $ARG1$
}
In order for me to get the correct email output you need to modify the "service macro" to include "long" output...meaning, instead of a single line in the result email it will include all the lines that are put to stdout (in my case all the ap's that are missing)
vi /etc/nagios3/commands.cfg:
under 'notify-service-by-email' I added "LONGSERVICEOUTPUT" directly after " "SERVICEOUTPUT". Resulting command is as follows:
# 'notify-service-by-email' command definition
define command{
command_name notify-service-by-email
command_line /usr/bin/printf "%b" "***** Nagios *****nnNotification Type: $NOTIFICATIONTYPE$nnService: $SERVICEDESC$nHost: $HOSTALIAS$nAddress: $HOSTADDRESS$nState: $SERVICESTATE$nnDate/Time: $LONGDATETIME$nnAdditional Info:n$SERVICEOUTPUT$n$LONGSERVICEOUTPUT$" | /usr/bin/mail -s "** $NOTIFICATIONTYPE$ Service Alert: $HOSTALIAS$/$SERVICEDESC$ is $SERVICESTATE$ **" $CONTACTEMAIL$
}
The plugin:
Note, be sure to put in your WLC RO snmp string (and leave the space after it) and also tell the script the path/name of your aps_expected file (the file containing only ap names w/ out carriage return at the end)
#!/usr/bin/python
#######
# this is a script to check the currently joined Access Points to a Cisco Wireless Lan Controller.
# It relies on a file, passed as an argument, which contains the access points that "should" exist on said WLC.
# It will report a Critical error if ap's are not there, and a Warning error if an ap is there, but it shouldn't be
# (ie ap there but not in the list)
# edited July 23 2013 by Mike Albano
########
import commands, sys, re, os, syslog
from sets import Set
#make sure arguments are passed to script
if len(sys.argv) < 4:
sys.exit("usage: check_wlc_ap.py -H <wlc_ip_address> -f <aps_expected file>")
#create list from snmpget, and regex out just the AP's
get_aps = commands.getoutput('snmpwalk -v2c -c <community_string_here> ' + sys.argv[2] + ' 1.3.6.1.4.1.14179.2.2.1.1.3')
search_aps = re.findall(r'\"(\w.+)\"', get_aps)
#print the differences between the 2 sets, created below, using message passed to function
def list_aps(apset, message):
if len(apset) == 0:
return
print message
for item in sorted(apset):
print item
#log the messages to syslog
syslog.syslog('%s - %s' % (message, item))
def main():
#create 2 empty sets
configuredaps = Set()
activeaps = Set()
#add to configuredaps Set by looping over sys.argv[4]
apfile = open(sys.argv[4], 'rU')
for line in apfile:
configuredaps.add(line.strip())
#add to activeaps Set by looping over regex result (search_aps)
for item in search_aps:
activeaps.add(item)
list_aps(configuredaps - activeaps, "The following APs are down: ")
list_aps(activeaps - configuredaps, "The following APs were found but dont belong here: ")
#exit with Critical if aps are down, Warning if don't belong on WLC
if configuredaps - activeaps:
sys.exit(2)
if activeaps - configuredaps:
sys.exit(1)
main()

